diff --git a/kernel/tools/perf/files/patches/mageia/3rd-3rdparty-1.0-tree.patch b/kernel/tools/perf/files/patches/mageia/3rd-3rdparty-1.0-tree.patch new file mode 100644 index 0000000000..233389b482 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-3rdparty-1.0-tree.patch @@ -0,0 +1,181 @@ + + 3rdparty/mkbuild.pl | 92 +++++++++++++++++++++++++++++++++++++++++++++ + Documentation/3rdparty.txt | 76 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 168 insertions(+) + +diff -Nurp linux-2.6.37/3rdparty/mkbuild.pl linux-2.6.37.3rdparty/3rdparty/mkbuild.pl +--- linux-2.6.37/3rdparty/mkbuild.pl 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/mkbuild.pl 2004-04-23 14:59:03.000000000 +0300 +@@ -0,0 +1,92 @@ ++#!/usr/bin/perl -w ++# ++# Version 1.0 ++# ++# Copyright 2001 Jeff Garzik ++# Copyright 2002 Juan Quintela ++# Copyright 2003 Nicolas Planel ++# ++# This software may be used and distributed according to the terms ++# of the GNU General Public License, incorporated herein by reference. ++# ++# ++# Run "mkbuild.pl" ++# ++# This program generates the following files ++# Makefile ++# Makefile.drivers ++# Config.in ++# using the information in the subdirs of this directory. ++# ++# subdirs need to have: ++# a Config.in file ++# a Makefile with a O_TARGET/L_TARGET targets ++# The config.in should set a CONFIG_ to m/y. ++ ++use strict; ++ ++opendir(THISDIR, "."); ++# get dirs without . and .. garbage ++my (@modules) = grep(!/\.\.?$/,grep(-d, readdir(THISDIR))); ++closedir(THISDIR); ++ ++generate_kconfig(@modules); ++generate_makefile(@modules); ++exit(0); ++ ++########################################################################## ++ ++sub generate_makefile { ++ my (@modules) = @_; ++ ++ local *F; ++ open F, "> Makefile" or die "Cannot create new Makefile: $!\n"; ++ print F <<'EOM'; ++# ++# THIS IS AN AUTOMATICALLY GENERATED FILE. DO NOT EDIT. ++# ++ ++EOM ++ printf F "obj- := 3rdparty.o # Dummy rule to force built-in.o to be made\n"; ++ printf F "obj-\$(%s) += %s\n", to_CONFIG($_), $_ . '/' foreach @modules; ++} ++ ++sub generate_kconfig { ++ my (@modules) = @_; ++ ++ local *F; ++ open F, "> Kconfig" or die "Cannot create Kconfig: $!\n"; ++ print F <<"EOM"; ++# ++# THIS IS AN AUTOMATICALLY GENERATED FILE. DO NOT EDIT. ++# ++ ++menu "Unofficial 3rd party kernel additions" ++ ++EOM ++ ++ foreach (@modules) { ++ die "No Kconfig in $_.\n" if ! -r "$_/Kconfig"; ++ print F "source 3rdparty/$_/Kconfig\n"; ++ } ++ print F "\n\nendmenu\n"; ++} ++ ++sub to_CONFIG { ++ local $_ = $_[0]; ++ tr/a-z/A-Z/; ++ s/[\-\. ]/_/g; ++ "CONFIG_$_"; ++} ++ ++sub find_target { ++ my ($module_dir) = @_; ++ ++ local *F; ++ open(F, "$module_dir/Makefile") or die "$module_dir/Makefile: $!\n"; ++ while () { ++ chomp; ++ return $1 if (/[LO]_TARGET.*:=\s+(\S+)/); ++ } ++} ++ +diff -Nurp linux-2.6.37/Documentation/3rdparty.txt linux-2.6.37.3rdparty/Documentation/3rdparty.txt +--- linux-2.6.37/Documentation/3rdparty.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/Documentation/3rdparty.txt 2003-11-22 01:07:26.000000000 +0200 +@@ -0,0 +1,76 @@ ++ ++Third-Party Kernel Source Module Support, or ++an easy way to add modules to your kernel build. ++ ++ ++ ++Vendors quite often add additional drivers and features to the kernel ++which require nothing more than modifying Kconfig, Makefile, and ++adding one or more files to a sub-directory. As a single discrete task, ++this is not a problem. However, using patches to add modules to the ++kernel very often results in patch conflicts, resulting in needless time ++wastage as developers regenerate an otherwise working kernel patch. ++ ++This is designed as a solution to these problems. It is NOT designed as ++a replacement for the kernel build system, but merely as a tool for ++vendors and system administrators to ease the pain of patch management. ++ ++The key feature of this system is the distinct lack of patches. Drivers ++are installed via unpacking a tarball. ++ ++ ++ ++Adding a directory to the build (usually from a tarball) ++-------------------------------------------------------- ++If a directory exists inside the 3rdparty sub-directory that contains a ++proper Makefile, it can be added to the build. It also needs a ++Kconfig file. ++ ++ cd /usr/src/linux-2.4.3/3rdparty ++ bzcat /tmp/my-driver2.tar.bz2 | tar xf - # creates "my2" dir ++ ++ ++Limitations ++----------- ++There are some limitations to this system. This system is only ++designed to support a very common case. If you find yourself running ++into limitations (kernel build experts can spot them right off), ++then you should probably be patching the kernel instead of using ++mkbuild.pl for that particular module. ++ ++FIXME: actually list the limitations ++ ++ ++ ++Other notes ++----------- ++Link order is controlled by the order of mkbuild.pl executions. ++ ++"make mrproper" will erase Makefile.meta, and empty Kconfig, Makefile, ++and Makefile.drivers. ++ ++IMPORTANT NOTE: Because this feature modifies the kernel's makefiles and ++configuration system, you MUST complete all mkbuild.pl runs before ++running any "make" command. ++ ++Building in the 3rdparty dir ++---------------------------- ++ ++If you use modules that: ++ - are contained in one subdir with the name of the module ++ - has a Makefile ++ - has a Kconfig file ++ ++The system calls the ./mkbuild.pl script. It will search for ++subdirectories, and will try to build each of them as a module. ++Things to note: ++ ++ The dependencies will be done in a module called: ++ ++ 3rdparty// ++ ++depending of CONFIG_. ++ ++ is the value of O_TARGET/L_TARGET. ++ ++ diff --git a/kernel/tools/perf/files/patches/mageia/3rd-3rdparty-merge.patch b/kernel/tools/perf/files/patches/mageia/3rd-3rdparty-merge.patch new file mode 100644 index 0000000000..b2ab8c0898 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-3rdparty-merge.patch @@ -0,0 +1,189 @@ + +Include 3rdparty directory into the main build-system. + +Original author is unknown. +(Was either Juan Quintela or Jeff Garzik) + +Signed-off-by: Luiz Fernando N. Capitulino +Signed-off-by: Herton Ronaldo Krzesinski +Signed-off-by: Thomas Backlund + + Makefile | 2 +- + arch/alpha/Kconfig | 1 + + arch/ia64/Kconfig | 2 ++ + arch/mips/Kconfig | 2 ++ + arch/powerpc/Kconfig | 2 ++ + arch/sparc/Kconfig | 2 ++ + arch/x86/Kconfig | 2 ++ + scripts/kconfig/Makefile | 33 ++++++++++++++++++--------------- + 8 files changed, 30 insertions(+), 16 deletions(-) + +diff -Nurp linux-4.2.2/arch/alpha/Kconfig linux-4.2.2-3rd/arch/alpha/Kconfig +--- linux-4.2.2/arch/alpha/Kconfig 2015-08-30 21:34:09.000000000 +0300 ++++ linux-4.2.2-3rd/arch/alpha/Kconfig 2015-09-29 23:02:44.024347272 +0300 +@@ -750,3 +750,4 @@ source "crypto/Kconfig" + + source "lib/Kconfig" + ++source "3rdparty/Kconfig" +diff -Nurp linux-4.2.2/arch/ia64/Kconfig linux-4.2.2-3rd/arch/ia64/Kconfig +--- linux-4.2.2/arch/ia64/Kconfig 2015-08-30 21:34:09.000000000 +0300 ++++ linux-4.2.2-3rd/arch/ia64/Kconfig 2015-09-29 23:02:44.024347272 +0300 +@@ -613,3 +613,5 @@ source "lib/Kconfig" + + config IOMMU_HELPER + def_bool (IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB || IA64_GENERIC || SWIOTLB) ++ ++source "3rdparty/Kconfig" +diff -Nurp linux-4.2.2/arch/mips/Kconfig linux-4.2.2-3rd/arch/mips/Kconfig +--- linux-4.2.2/arch/mips/Kconfig 2015-08-30 21:34:09.000000000 +0300 ++++ linux-4.2.2-3rd/arch/mips/Kconfig 2015-09-29 23:02:44.024347272 +0300 +@@ -2944,3 +2944,5 @@ source "crypto/Kconfig" + source "lib/Kconfig" + + source "arch/mips/kvm/Kconfig" ++ ++source "3rdparty/Kconfig" +diff -Nurp linux-4.2.2/arch/powerpc/Kconfig linux-4.2.2-3rd/arch/powerpc/Kconfig +--- linux-4.2.2/arch/powerpc/Kconfig 2015-08-30 21:34:09.000000000 +0300 ++++ linux-4.2.2-3rd/arch/powerpc/Kconfig 2015-09-29 23:02:44.025347276 +0300 +@@ -1112,3 +1112,5 @@ config PPC_LIB_RHEAP + source "arch/powerpc/kvm/Kconfig" + + source "kernel/livepatch/Kconfig" ++ ++source "3rdparty/Kconfig" +diff -Nurp linux-4.2.2/arch/sparc/Kconfig linux-4.2.2-3rd/arch/sparc/Kconfig +--- linux-4.2.2/arch/sparc/Kconfig 2015-08-30 21:34:09.000000000 +0300 ++++ linux-4.2.2-3rd/arch/sparc/Kconfig 2015-09-29 23:02:44.025347276 +0300 +@@ -569,3 +569,5 @@ source "security/Kconfig" + source "crypto/Kconfig" + + source "lib/Kconfig" ++ ++source "3rdparty/Kconfig" +diff -Nurp linux-4.2.2/arch/x86/Kconfig linux-4.2.2-3rd/arch/x86/Kconfig +--- linux-4.2.2/arch/x86/Kconfig 2015-08-30 21:34:09.000000000 +0300 ++++ linux-4.2.2-3rd/arch/x86/Kconfig 2015-09-29 23:02:44.025347276 +0300 +@@ -2601,3 +2601,5 @@ source "crypto/Kconfig" + source "arch/x86/kvm/Kconfig" + + source "lib/Kconfig" ++ ++source "3rdparty/Kconfig" +diff -Nurp linux-4.2.2/Makefile linux-4.2.2-3rd/Makefile +--- linux-4.2.2/Makefile 2015-09-29 22:13:44.743650710 +0300 ++++ linux-4.2.2-3rd/Makefile 2015-09-29 23:02:44.026347280 +0300 +@@ -546,7 +546,7 @@ scripts: scripts_basic include/config/au + + # Objects we will link into vmlinux / subdirs we need to visit + init-y := init/ +-drivers-y := drivers/ sound/ firmware/ ++drivers-y := drivers/ sound/ firmware/ 3rdparty/ + net-y := net/ + libs-y := lib/ + core-y := usr/ +diff -Nurp linux-4.6/scripts/kconfig/Makefile linux-4.6-3rd/scripts/kconfig/Makefile +--- linux-4.6/scripts/kconfig/Makefile ++++ linux-4.6-3rd/scripts/kconfig/Makefile +@@ -18,26 +18,26 @@ endif + # We need this, in case the user has it in its environment + unexport CONFIG_ + +-xconfig: $(obj)/qconf ++xconfig: $(obj)/qconf 3rdparty/Makefile + $< $(silent) $(Kconfig) + +-gconfig: $(obj)/gconf ++gconfig: $(obj)/gconf 3rdparty/Makefile + $< $(silent) $(Kconfig) + +-menuconfig: $(obj)/mconf ++menuconfig: $(obj)/mconf 3rdparty/Makefile + $< $(silent) $(Kconfig) + +-config: $(obj)/conf ++config: $(obj)/conf 3rdparty/Makefile + $< $(silent) --oldaskconfig $(Kconfig) + +-nconfig: $(obj)/nconf ++nconfig: $(obj)/nconf 3rdparty/Makefile + $< $(silent) $(Kconfig) + +-silentoldconfig: $(obj)/conf ++silentoldconfig: $(obj)/conf 3rdparty/Makefile + $(Q)mkdir -p include/config include/generated + $< $(silent) --$@ $(Kconfig) + +-localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf ++localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf 3rdparty/Makefile + $(Q)mkdir -p include/config include/generated + $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config + $(Q)if [ -f .config ]; then \ +@@ -80,7 +80,7 @@ simple-targets := oldconfig allnoconfig + alldefconfig randconfig listnewconfig olddefconfig + PHONY += $(simple-targets) + +-$(simple-targets): $(obj)/conf ++$(simple-targets): $(obj)/conf 3rdparty/Makefile + $< $(silent) --$@ $(Kconfig) + + PHONY += oldnoconfig savedefconfig defconfig +@@ -88,12 +88,12 @@ PHONY += oldnoconfig savedefconfig defco + # oldnoconfig is an alias of olddefconfig, because people already are dependent + # on its behavior (sets new symbols to their default value but not 'n') with the + # counter-intuitive name. +-oldnoconfig: olddefconfig ++oldnoconfig: olddefconfig 3rdparty/Makefile + +-savedefconfig: $(obj)/conf ++savedefconfig: $(obj)/conf 3rdparty/Makefile + $< $(silent) --$@=defconfig $(Kconfig) + +-defconfig: $(obj)/conf ++defconfig: $(obj)/conf 3rdparty/Makefile + ifeq ($(KBUILD_DEFCONFIG),) + $< $(silent) --defconfig $(Kconfig) + else +@@ -106,26 +106,26 @@ else + endif + endif + +-%_defconfig: $(obj)/conf ++%_defconfig: $(obj)/conf 3rdparty/Makefile + $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig) + + configfiles=$(wildcard $(srctree)/kernel/configs/$@ $(srctree)/arch/$(SRCARCH)/configs/$@) + +-%.config: $(obj)/conf ++%.config: $(obj)/conf 3rdparty/Makefile + $(if $(call configfiles),, $(error No configuration exists for this target on this architecture)) + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh -m .config $(configfiles) + +$(Q)yes "" | $(MAKE) -f $(srctree)/Makefile oldconfig + + PHONY += kvmconfig +-kvmconfig: kvm_guest.config ++kvmconfig: kvm_guest.config 3rdparty/Makefile + @: + + PHONY += xenconfig +-xenconfig: xen.config ++xenconfig: xen.config 3rdparty/Makefile + @: + + PHONY += tinyconfig +-tinyconfig: ++tinyconfig: + $(Q)$(MAKE) -f $(srctree)/Makefile allnoconfig tiny.config + + # Help text used by make help +@@ -188,6 +188,9 @@ gconf-objs := gconf.o zconf.tab.o + + hostprogs-y := conf nconf mconf kxgettext qconf gconf + ++3rdparty/Makefile: ++ pushd $(srctree)/3rdparty ; $(PERL) ./mkbuild.pl ; popd ++ + clean-files := qconf.moc .tmp_qtcheck .tmp_gtkcheck + clean-files += zconf.tab.c zconf.lex.c zconf.hash.c gconf.glade.h + clean-files += config.pot linux.pot diff --git a/kernel/tools/perf/files/patches/mageia/3rd-acerhk-0.5.35.patch b/kernel/tools/perf/files/patches/mageia/3rd-acerhk-0.5.35.patch new file mode 100644 index 0000000000..5d61570f7b --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-acerhk-0.5.35.patch @@ -0,0 +1,4212 @@ + 3rdparty/acerhk/AUTHORS | 1 + 3rdparty/acerhk/COPYING | 340 ++++ + 3rdparty/acerhk/INSTALL | 109 + + 3rdparty/acerhk/Makefile | 65 + 3rdparty/acerhk/NEWS | 16 + 3rdparty/acerhk/README | 215 ++ + 3rdparty/acerhk/acerhk.c | 2999 ++++++++++++++++++++++++++++++++++++++++ + 3rdparty/acerhk/acerhk.h | 91 + + 3rdparty/acerhk/doc/FAQ | 150 ++ + 3rdparty/acerhk/doc/IOCTL | 61 + 3rdparty/acerhk/doc/acertm.def | 56 + 3rdparty/acerhk/doc/keycodes | 26 + 3rdparty/acerhk/doc/md95400.def | 14 + 13 files changed, 4143 insertions(+) +diff -Nurp linux-2.6.37/3rdparty/acerhk/acerhk.c linux-2.6.37.3rdparty/3rdparty/acerhk/acerhk.c +--- linux-2.6.37/3rdparty/acerhk/acerhk.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/acerhk.c 2007-02-10 17:46:23.000000000 +0200 +@@ -0,0 +1,2999 @@ ++/********************************************************************* ++ * Filename: acerhk.c ++ * Version: 0.5 ++ * ++ * Copyright (C) 2002-2006, Olaf Tauber (olaf-tauber@versanet.de) ++ * ++ * Description: kernel driver for Acer Travelmate and similar ++ * laptops special keys ++ * Author: Olaf Tauber ++ * Created at: Mon Apr 29 22:16:42 2002 ++ * Modified at: Mon Oct 16 21:36:44 2006 ++ * Modified by: Olaf Tauber ++ * Modified at: Thu Nov 24 13:03:01 2005 ++ * Modified by: Antonio Cuni ++ * Modified at: Wed Oct 27 19:47:11 CEST 2004 ++ * Modified by: Joachim Fenkes ++ * ++ * This program is free software; you can redistribute ++ * it and/or modify it under the terms of the GNU General ++ * Public License as published by the Free Software ++ * Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be ++ * useful, but WITHOUT ANY WARRANTY; without even the implied ++ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ++ * PURPOSE. See the GNU General Public License for more ++ * details. ++ * ++ * You should have received a copy of the GNU General Public ++ * License along with this program; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place, ++ * Suite 330, Boston, MA 02111-1307 USA ++ * ++ * ++ */ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++ ++/* This driver is heavily dependent on the architecture, don't let ++ * anyone without an X86 machine use it. On laptops with AMD64 ++ * architecture this driver is only useable in 32 bit mode. ++ */ ++#ifdef CONFIG_X86 ++ ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) ++#define KERNEL26 ++#include ++#else ++#include ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) ++#define STATIC_INPUT_DEV ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "acerhk.h" ++ ++/* #define ACERDEBUG */ ++/* #define DUMMYHW */ ++ ++#define ACERHK_VERSION "0.5.35" ++#define MODULE_NAME "acerhk" ++ ++/* maximum number of polling loops, adjust it if needed to values between ++ * 1 and 32 ++ */ ++#define MAX_POLLING_LOOPS 16U ++ ++/* maximum length for model string */ ++#define ACERHK_MODEL_STRLEN 16 ++/* size of mapped areas */ ++#define AREA_SIZE 0xffff ++/* needed for colussi algorithm */ ++#define XSIZE 20 ++ ++/* Module parameters */ ++static int poll=1; ++static int autowlan; ++static int usedritek=1; ++static int wlan_state=-1; ++static int bluetooth_state=-1; ++static int verbose; ++static unsigned int force_series; ++#ifdef KERNEL26 ++module_param(poll, int, 0444); ++module_param(autowlan, int, 0444); ++module_param(usedritek, int, 0444); ++module_param(verbose, int, 0444); ++module_param(wlan_state, int, 0444); ++module_param(bluetooth_state, int, 0444); ++module_param(force_series, uint, 0444); ++#else ++MODULE_PARM(poll, "i"); ++MODULE_PARM(autowlan, "i"); ++MODULE_PARM(wlan_state, "i"); ++MODULE_PARM(bluetooth_state, "i"); ++MODULE_PARM(usedritek, "i"); ++MODULE_PARM(verbose, "i"); ++MODULE_PARM(force_series, "i"); ++#endif ++MODULE_PARM_DESC(poll, "start polling timer"); ++MODULE_PARM_DESC(autowlan, "automatic switching of wlan hardware"); ++MODULE_PARM_DESC(wlan_state, "(assumed) initial state of WLAN LED/hardware"); ++MODULE_PARM_DESC(bluetooth_state, "(assumed) initial state of Bluetooth LED/hardware"); ++MODULE_PARM_DESC(usedritek, "enable dritek keyboard extension"); ++MODULE_PARM_DESC(verbose, "output additional information"); ++MODULE_PARM_DESC(force_series, "force laptop series, skip autodetection"); ++ ++/* input device */ ++static struct input_dev *acerhk_input_dev_ptr; ++#ifdef STATIC_INPUT_DEV ++static struct input_dev acerhk_input_dev; ++#endif ++ ++/* mapped IO area from 0xf0000 */ ++static void *reg1; ++/* mapped IO area from 0xe0000 */ ++static void *reg2; ++/* Pointer to mapped area at 0x400 on 520 series */ ++static void *preg400; ++/* location of IO routine in mapped area */ ++static unsigned int bios_routine; ++/* index of CMOS port to get key event */ ++static unsigned int cmos_index; ++/* function for bios call */ ++static bios_call call_bios; ++/* address of model string */ ++static char *acerhk_model_addr; ++/* copied string, maximum length 16 ('TravelMate xxx') */ ++static char acerhk_model_string[ACERHK_MODEL_STRLEN]; ++/* type of hardware access */ ++static t_acer_type acerhk_type; ++/* travelmate series */ ++static unsigned int acerhk_series; ++/* supported features for this model */ ++static unsigned int acerhk_model_features; ++/* map of acer key codes to acer key names */ ++static unsigned char acerhk_key2name[0xff]; ++/* map of acer key names to key events */ ++static t_map_name2event acerhk_name2event; ++/* timer for polling key presses */ ++static struct timer_list acerhk_timer_poll; ++/* polling active */ ++static int acerhk_polling_state; ++/* polling delay */ ++static unsigned acerhk_polling_delay = HZ/5; ++/* wlan hardware toggle */ ++static int acerhk_wlan_state; ++/* bluetooth hardware toggle */ ++static int acerhk_bluetooth_state; ++ ++/* bluetooth blinking state; added by Antonio Cuni ++ possible values: ++ -1: blinking disabled (default) ++ 0: blinking enabled, led currently off ++ 1: blinking enabled, led currently on ++*/ ++static int acerhk_blueled_blinking = -1; ++/* delay between two changes of state, in jiffies */ ++static unsigned acerhk_blueled_blinking_delay; ++/* timer for blinking */ ++static struct timer_list acerhk_timer_blinking; ++ ++/* function prototypes */ ++static void start_polling(void); ++static void stop_polling(void); ++ ++/* Added by Antonio Cuni */ ++static void start_blinking(void); ++static void stop_blinking(void); ++ ++/* {{{ Experimental use of dritek keyboard extension */ ++ ++#define EC_STATUS_REG 0x66 /* Status register of EC (R) */ ++#define EC_CNTL_REG 0x66 /* Controller command register of EC (W) */ ++#define EC_DATA_REG 0x62 /* EC data register (R/W) */ ++ ++#ifdef KERNEL26 ++ ++#include ++ ++#define KBD_STATUS_REG 0x64 /* Status register (R) */ ++#define KBD_CNTL_REG 0x64 /* Controller command register (W) */ ++#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ ++ ++#else ++ ++#ifndef KEY_MEDIA ++#define KEY_MEDIA 226 ++#endif ++ ++#define preempt_disable() do { } while (0) ++#define preempt_enable_no_resched() do { } while (0) ++#define preempt_enable() do { } while (0) ++#define preempt_check_resched() do { } while (0) ++#include ++ ++#endif ++ ++static inline int my_i8042_read_status(void) ++{ ++ return inb(KBD_STATUS_REG); ++} ++static int my_i8042_wait_write(void) ++{ ++ int i = 0; ++ while ((my_i8042_read_status() & 0x02) && (i < 10000)) { ++ udelay(50); ++ i++; ++ } ++ return -(i == 10000); ++} ++static void send_kbd_cmd(unsigned char cmd, unsigned char val) ++{ ++ if (usedritek) { ++ preempt_disable(); ++ if (!my_i8042_wait_write()) ++ outb(cmd, KBD_CNTL_REG); ++ if (!my_i8042_wait_write()) ++ outb(val, KBD_DATA_REG); ++ preempt_enable_no_resched(); ++ } else { ++ printk(KERN_INFO"acerhk: request for accessing EC ignored\n" ++ KERN_INFO"acerhk: Use of dritek keyboard extension not enabled, use module\n" ++ KERN_INFO"acerhk: parameter usedritek=1 to do that (possibly dangerous)\n"); ++ } ++} ++#ifdef ACERDEBUG ++static inline int my_i8042_read_ecstatus(void) ++{ ++ return inb(EC_STATUS_REG); ++} ++static int my_i8042_wait_ecwrite(void) ++{ ++ int i = 0; ++ while ((my_i8042_read_ecstatus() & 0x02) && (i < 10000)) { ++ udelay(50); ++ i++; ++ } ++ return -(i == 10000); ++} ++static void send_ec_cmd(unsigned char cmd, unsigned char val) ++{ ++ if (usedritek) { ++ preempt_disable(); ++ if (!my_i8042_wait_ecwrite()) ++ outb(cmd, EC_CNTL_REG); ++ if (!my_i8042_wait_ecwrite()) ++ outb(val, EC_DATA_REG); ++ preempt_enable_no_resched(); ++ } else { ++ printk(KERN_INFO"acerhk: request for accessing EC ignored\n" ++ KERN_INFO"acerhk: Use of dritek keyboard extension not enabled, use module\n" ++ KERN_INFO"acerhk: parameter usedritek=1 to do that (possibly dangerous)\n"); ++ } ++} ++#endif ++#ifdef ACERDEBUG ++static void enable_mute_led_ec(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling mute led via EC\n"); ++ send_kbd_cmd(0x59, 0x94); ++} ++static void disable_mute_led_ec(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling mute led via EC\n"); ++ send_kbd_cmd(0x59, 0x95); ++} ++static void enable_dmm_function(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling WLAN via EC variant 2\n"); ++ send_kbd_cmd(0x45, 0xd3); ++} ++#endif ++static void enable_wlan_ec_1(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling WLAN via EC variant 1\n"); ++ send_kbd_cmd(0xe7, 0x01); ++ acerhk_wlan_state = 1; ++} ++static void disable_wlan_ec_1(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling WLAN via EC variant 1\n"); ++ send_kbd_cmd(0xe7, 0x00); ++ acerhk_wlan_state = 0; ++} ++static void enable_bluetooth_ec_1(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling Bluetooth via EC variant 1\n"); ++ send_kbd_cmd(0xe7, 0x03); ++ acerhk_bluetooth_state = 1; ++} ++static void disable_bluetooth_ec_1(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling Bluetooth via EC variant 1\n"); ++ send_kbd_cmd(0xe7, 0x02); ++ acerhk_bluetooth_state = 0; ++} ++static void enable_wlan_ec_2(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling WLAN via EC variant 2\n"); ++ send_kbd_cmd(0x45, acerhk_bluetooth_state ? 0xa2 : 0xa0); ++ acerhk_wlan_state = 1; ++} ++static void disable_wlan_ec_2(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling WLAN via EC variant 2\n"); ++ send_kbd_cmd(0x45, acerhk_bluetooth_state ? 0xa1 : 0xa3); ++ acerhk_wlan_state = 0; ++} ++static void enable_bluetooth_ec_2(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling Bluetooth via EC variant 2\n"); ++ send_kbd_cmd(0x45, acerhk_wlan_state ? 0xa2 : 0xa1); ++ acerhk_bluetooth_state = 1; ++} ++static void disable_bluetooth_ec_2(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling Bluetooth via EC variant 2\n"); ++ send_kbd_cmd(0x45, acerhk_wlan_state ? 0xa0 : 0xa3); ++ acerhk_bluetooth_state = 0; ++} ++#ifdef ACERDEBUG ++static void enable_wireless_ec(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling wireless hardware\n"); ++ if (usedritek) { ++ preempt_disable(); ++ if (!my_i8042_wait_ecwrite()) ++ outb(0x4d, EC_CNTL_REG); ++ if (!my_i8042_wait_ecwrite()) ++ outb(0xd2, EC_DATA_REG); ++ if (!my_i8042_wait_ecwrite()) ++ outb(0x01, EC_DATA_REG); ++ preempt_enable_no_resched(); ++ } ++ acerhk_wlan_state = 1; ++} ++static void disable_wireless_ec(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling wireless hardware\n"); ++ if (usedritek) { ++ preempt_disable(); ++ if (!my_i8042_wait_ecwrite()) ++ outb(0x4d, EC_CNTL_REG); ++ if (!my_i8042_wait_ecwrite()) ++ outb(0xd2, EC_DATA_REG); ++ if (!my_i8042_wait_ecwrite()) ++ outb(0x00, EC_DATA_REG); ++ preempt_enable_no_resched(); ++ } ++ acerhk_wlan_state = 0; ++} ++#endif ++static void enable_dritek_keyboard(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling dritek keyboard extension\n"); ++ send_kbd_cmd(0x59, 0x90); ++} ++static void disable_dritek_keyboard(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling dritek keyboard extension\n"); ++ send_kbd_cmd(0x59, 0x91); ++} ++static void enable_mail_led_ec_1(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling mail led via EC variant 1\n"); ++ send_kbd_cmd(0xe8, 0x01); ++} ++static void disable_mail_led_ec_1(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling mail led via EC variant 1\n"); ++ send_kbd_cmd(0xe8, 0x00); ++} ++ ++static void enable_mail_led_ec_2(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling mail led via EC variant 2\n"); ++ send_kbd_cmd(0x59, 0x92); ++} ++static void disable_mail_led_ec_2(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling mail led via EC variant 2\n"); ++ send_kbd_cmd(0x59, 0x93); ++} ++static void enable_mail_led_ec_3(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling mail led via EC variant 3\n"); ++ if (usedritek) { ++ preempt_disable(); ++ if (!my_i8042_wait_write()) ++ outl(0x80008894, 0xCF8); ++ if (!my_i8042_wait_write()) ++ outw(0xC061, 0xCFC); ++ preempt_enable_no_resched(); ++ } ++} ++static void disable_mail_led_ec_3(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling mail led via EC variant 3\n"); ++ if (usedritek) { ++ preempt_disable(); ++ if (!my_i8042_wait_write()) ++ outl(0x80008894, 0xCF8); ++ if (!my_i8042_wait_write()) ++ outw(0xC060, 0xCFC); ++ preempt_enable_no_resched(); ++ } ++} ++ ++/* }}} */ ++ ++/* {{{ string search functions */ ++ ++/* This is the Colussi algorithm, the code is taken from ++ http://www-igm.univ-mlv.fr/~lecroq/string ++*/ ++int preColussi(char *x, int m, int *h, int *next, int *shift) ++{ ++ int i, k, nd, q, r, s; ++ int hmax[XSIZE], kmin[XSIZE], nhd0[XSIZE], rmin[XSIZE]; ++ /* Computation of hmax */ ++ i = k = 1; ++ do { ++ while (x[i] == x[i - k]) ++ i++; ++ hmax[k] = i; ++ q = k + 1; ++ while (hmax[q - k] + k < i) { ++ hmax[q] = hmax[q - k] + k; ++ q++; ++ } ++ k = q; ++ if (k == i + 1) ++ i = k; ++ } while (k <= m); /* Computation of kmin */ ++ memset(kmin, 0, m*sizeof(int)); ++ r = 0; ++ for (i = m; i >= 1; --i) ++ if (hmax[i] < m) ++ kmin[hmax[i]] = i; /* Computation of rmin */ ++ for (i = m - 1; i >= 0; --i) { ++ if (hmax[i + 1] == m) ++ r = i + 1; ++ if (kmin[i] == 0) ++ rmin[i] = r; ++ else ++ rmin[i] = 0; ++ } /* Computation of h */ ++ s = -1; ++ r = m; ++ for (i = 0; i < m; ++i) ++ if (kmin[i] == 0) ++ h[--r] = i; ++ else ++ h[++s] = i; ++ nd = s; /* Computation of shift */ ++ for (i = 0; i <= nd; ++i) ++ shift[i] = kmin[h[i]]; ++ for (i = nd + 1; i < m; ++i) ++ shift[i] = rmin[h[i]]; ++ shift[m] = rmin[0]; /* Computation of nhd0 */ ++ s = 0; ++ for (i = 0; i < m; ++i) { ++ nhd0[i] = s; ++ if (kmin[i] > 0) ++ ++s; ++ } /* Computation of next */ ++ for (i = 0; i <= nd; ++i) ++ next[i] = nhd0[h[i] - kmin[h[i]]]; ++ for (i = nd + 1; i < m; ++i) ++ next[i] = nhd0[m - rmin[h[i]]]; ++ next[m] = nhd0[m - rmin[h[m - 1]]]; return(nd); ++} ++ ++int COLUSSI(char *x, int m, char *y, int n) { ++ int i, j, last, nd, ++ h[XSIZE], next[XSIZE], shift[XSIZE]; /* Processing */ ++ int match_pos; /* position of first match */ ++ nd = preColussi(x, m, h, next, shift); /* Searching */ ++ i = j = 0; ++ last = -1; ++ match_pos = -1; ++ while ( (match_pos == -1) ++ && (j <= n - m) ) { ++ while (i < m && last < j + h[i] && ++ x[h[i]] == y[j + h[i]]) ++ i++; ++ if (i >= m || last >= j + h[i]) { ++ /* Match found, bail out */ ++ match_pos = j; ++ i = m; ++ } ++ if (i > nd) ++ last = j + m - 1; ++ j += shift[i]; ++ i = next[i]; ++ } ++ return match_pos; ++} ++ ++/* }}} */ ++ ++/* {{{ hardware access functions */ ++ ++/* call_bios_ ++ * ++ * call request handler in mapped system rom ++ * ++ * the request is handed over via all 6 general purpose registers, results are ++ * taken from them and copied back to buf ++ */ ++static asmlinkage void call_bios_6xx(struct register_buffer *buf) ++{ ++ if (bios_routine) { ++ local_irq_disable(); ++ __asm__ __volatile__( ++ "movl %1,%%edx\n\t" ++ "pusha\n\t" ++ "movl %%edx,%%ebp\n\t" ++ "movl (%%ebp),%%eax\n\t" ++ "movl 4(%%ebp),%%ebx\n\t" ++ "movl 8(%%ebp),%%ecx\n\t" ++ "movl 12(%%ebp),%%edx\n\t" ++ "movl 16(%%ebp),%%edi\n\t" ++ "movl 20(%%ebp),%%esi\n\t" ++ "pushl %%ebp\n\t" ++ "call *%0\n\t" ++ "popl %%ebp\n\t" ++ "movl %%eax, (%%ebp)\n\t" ++ "movl %%ebx, 4(%%ebp)\n\t" ++ "movl %%ecx, 8(%%ebp)\n\t" ++ "movl %%edx, 12(%%ebp)\n\t" ++ "movl %%edi, 16(%%ebp)\n\t" ++ "movl %%esi, 20(%%ebp)\n\t" ++ "popa\n\t" ++ : ++ :"m" (bios_routine), "m" (buf) ++ :"%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi", "%ebp" ++ ); ++ local_irq_enable(); ++ } ++} ++ ++static asmlinkage void call_bios_52x(struct register_buffer *buf) ++{ ++ if (bios_routine) { ++ local_irq_disable(); ++ __asm__ __volatile__( ++ "movl %2,%%edx\n\t" ++ "pusha\n\t" ++ "movl %%edx,%%ebp\n\t" ++ "movl (%%ebp),%%eax\n\t" ++ "movl 4(%%ebp),%%ebx\n\t" ++ "movl 8(%%ebp),%%ecx\n\t" ++ "movl 12(%%ebp),%%edx\n\t" ++ "movl 16(%%ebp),%%edi\n\t" ++ "movl 20(%%ebp),%%esi\n\t" ++ "pushl %%ebp\n\t" ++ "movl %1, %%ebp\n\t" ++ "call *%0\n\t" ++ "popl %%ebp\n\t" ++ "movl %%eax, (%%ebp)\n\t" ++ "movl %%ebx, 4(%%ebp)\n\t" ++ "movl %%ecx, 8(%%ebp)\n\t" ++ "movl %%edx, 12(%%ebp)\n\t" ++ "movl %%edi, 16(%%ebp)\n\t" ++ "movl %%esi, 20(%%ebp)\n\t" ++ "popa\n\t" ++ : ++ :"m" (bios_routine), "m" (preg400), "m" (buf) ++ :"%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi", "%ebp" ++ ); ++ local_irq_enable(); ++ } ++} ++ ++#define PRINT_BUFFER(x) \ ++ printk(KERN_INFO"acerhk: eax=0x%x ebx=0x%x ecx=0x%x edx=0x%x\n" \ ++ "acerhk: edi=0x%x esi=0x%x ebp=0x%x\n", \ ++ x.eax, x.ebx, x.ecx, x.edx, x.edi, x.esi, x.ebp); ++ ++/* get_fnkey_event ++ * ++ * gets the first (oldest) key id from the queue of events ++ * ++ * return value: id of key ++ */ ++static int get_fnkey_event(void) ++{ ++ struct register_buffer regs; ++ regs.eax = 0x9610; ++ regs.ebx = 0x61C; ++ /* clear other registers, some models need this */ ++ regs.ecx = 0; ++ regs.edx = 0; ++ preempt_disable(); ++ call_bios(®s); ++ preempt_enable_no_resched(); ++ return regs.eax & 0xffff; ++} ++ ++/* get_thermal_event ++ * ++ * does what? ++ * ++ * return value: event ? ++ */ ++static int get_thermal_event(void) ++{ ++ struct register_buffer regs; ++ if (acerhk_model_features & TM_F_THERMAL) { ++ regs.eax = 0x9612; ++ regs.ebx = 0x12e; ++ preempt_disable(); ++ call_bios(®s); ++ preempt_enable_no_resched(); ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: thermal event = 0x%x\n", regs.eax); ++ } else { ++ regs.eax = 0x00; ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: thermal event not supported\n"); ++ } ++ return regs.eax & 0xffff; ++} ++ ++#ifdef ACERDEBUG ++/* pbutton_fct ++ * ++ * does what? ++ * ++ * return value: ? ++ */ ++static int pbutton_fct(void) ++{ ++ struct register_buffer regs; ++ if (acerhk_model_features & TM_F_PBUTTON) { ++ regs.eax = 0x9612; ++ regs.ebx = 0x10b; ++ regs.ecx = 0x2; ++ preempt_disable(); ++ call_bios(®s); ++ preempt_enable_no_resched(); ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: pbutton = 0x%x\n", regs.eax); ++ } else { ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: pbutton function not supported\n"); ++ regs.eax = 0x00; ++ } ++ return regs.eax & 0xffff; ++} ++#endif ++ ++/* wbutton_fct_1 ++ * ++ * turn on installed Bluetooth hardware together with the corresponding LED ++ * ++ * val: 0 turns off the LED ++ * 1 turns the LED to green/blue ++ * ++ * return value: ? ++ */ ++static int wbutton_fct_1(int val) ++{ ++ struct register_buffer regs; ++ if (acerhk_model_features & TM_F_WBUTTON) { ++ acerhk_bluetooth_state = val; ++ regs.eax = 0x9610; ++ regs.ebx = ((val & 0xff) << 8) | 0x34; ++ preempt_disable(); ++ call_bios(®s); ++ preempt_enable_no_resched(); ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: wbutton1 = 0x%x\n", regs.eax); ++ } else { ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: wbutton function 1 not supported\n"); ++ regs.eax = 0x00; ++ } ++ return regs.eax & 0xffff; ++} ++ ++/* wbutton_fct_2 ++ * ++ * turn on installed WLAN hardware together with the corresponding LED ++ * ++ * val: 0 turns off the LED ++ * 1 turns the LED to orange ++ * ++ * return value: ? ++ */ ++static int wbutton_fct_2(int val) ++{ ++ struct register_buffer regs; ++ if (acerhk_model_features & TM_F_WBUTTON) { ++ acerhk_wlan_state = val; ++ regs.eax = 0x9610; ++ regs.ebx = ((val & 0xff) << 8) | 0x35; ++ preempt_disable(); ++ call_bios(®s); ++ preempt_enable_no_resched(); ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: wbutton2 = 0x%x\n", regs.eax); ++ } else { ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: wbutton function 2 not supported\n"); ++ regs.eax = 0x00; ++ } ++ return regs.eax & 0xffff; ++} ++ ++/* get_cmos_index ++ * ++ * gets index of CMOS port from ROM. The number of events is monitored ++ * in this port. ++ * ++ * return value: index of CMOS port ++ */ ++static int get_cmos_index(void) ++{ ++ struct register_buffer regs; ++ regs.eax = 0x9610; ++ regs.ebx = 0x51C; ++ preempt_disable(); ++ call_bios(®s); ++ preempt_enable_no_resched(); ++ cmos_index = regs.ecx & 0xff; ++ if (verbose) ++ printk(KERN_INFO"acerhk: cmos index set to 0x%x\n", cmos_index); ++ return cmos_index; ++} ++ ++/* get_nr_events ++ * ++ * gets the number of cached events (keys pressed) in queue. Up to 31 events ++ * are cached. ++ * ++ * return value: number of events in queue ++ */ ++static int get_nr_events(void) ++{ ++ unsigned long flags; ++ unsigned char c = 0; ++ ++ spin_lock_irqsave (&rtc_lock, flags); ++#ifndef DUMMYHW ++ if (cmos_index) ++ c = CMOS_READ(cmos_index); ++ else if (verbose > 3) ++ printk(KERN_INFO"acerhk: get_nr_events - no valid cmos index set\n"); ++#endif ++ spin_unlock_irqrestore (&rtc_lock, flags); ++ return c; ++} ++ ++/* set_mail_led ++ * ++ * change state of mail led ++ * ++ * val: 0 - switch led off ++ * 1 - switch led on (blinking) ++ * ++ * return value: 1 - action succesfull (val valid) ++ * 0 - no action taken (val invalid) ++ */ ++static int set_mail_led(int val) ++{ ++ struct register_buffer regs; ++ if (acerhk_model_features & TM_F_MAIL_LED) { ++ regs.eax = 0x9610; ++ regs.ebx = ((val & 0xff) << 8) | 0x31; ++ preempt_disable(); ++ call_bios(®s); ++ preempt_enable_no_resched(); ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: mail led set to = 0x%x\n", val); ++ } else if (acerhk_model_features & TM_F_MAIL_LED_EC) { ++ if (val == 1) ++ enable_mail_led_ec_1(); ++ else if (val == 0) ++ disable_mail_led_ec_1(); ++ } else if (acerhk_model_features & TM_F_MAIL_LED_EC2) { ++ if (val == 1) ++ enable_mail_led_ec_2(); ++ else if (val == 0) ++ disable_mail_led_ec_2(); ++ } else if (acerhk_model_features & TM_F_MAIL_LED_EC3) { ++ if (val == 1) ++ enable_mail_led_ec_3(); ++ else if (val == 0) ++ disable_mail_led_ec_3(); ++ } else { ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: mail led not supported\n"); ++ regs.eax = 0x00; ++ } ++ return regs.eax & 0xffff; ++} ++ ++/* launch_connect ++ * ++ * does what? ++ * val: 1 - only known value from windows driver ++ */ ++static int launch_connect(int val) ++{ ++ struct register_buffer regs; ++ if (acerhk_model_features & TM_F_CONNECT) { ++ regs.eax = 0x9610; ++ regs.ebx = ((val & 0xff) << 8) | 0x2e; ++ preempt_disable(); ++ call_bios(®s); ++ preempt_enable_no_resched(); ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: connect(%d) = 0x%x\n", val, regs.eax); ++ } else { ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: connect not supported\n"); ++ regs.eax = 0x00; ++ } ++ return regs.eax & 0xffff; ++} ++ ++/* }}} */ ++ ++/* {{{ hardware probing */ ++ ++static struct proc_dir_entry *proc_acer_dir; ++ ++static unsigned int __init find_hk_area(void) ++{ ++ int offset, sig; ++ unsigned int fkt; ++ fkt = 0; ++ sig = -1; /* offset to signature in io area */ ++ /* Look for signature, start at 0xf0000, search until 0xffff0 */ ++ for (offset = 0;offset < 0xfffd; offset += 16) { ++ if (readl(reg1 + offset) == 0x30552142) { ++ sig = offset; ++ offset = 0xffff; ++ } ++ } ++ if (sig < 0) ++ printk(KERN_WARNING"acerhk: could not find request handler, possibly not all functions available\n"); ++ else { ++ /* compute location of bios routine */ ++ fkt = readl(reg1 + sig + 5); ++ /* adjust fkt to address of mapped IO area */ ++ if (fkt >= 0xf0000) ++ fkt = (unsigned int)reg1 + fkt - 0xf0000; ++ else if (fkt >= 0xe0000) ++ fkt = (unsigned int)reg1 + fkt - 0xe0000; ++ else ++ fkt = 0; ++ } ++ return fkt; ++} ++ ++static void print_features(void) ++{ ++ int i; ++ printk(KERN_INFO"acerhk: supported keys:"); ++ for (i = 0; i < 255; i++) { ++ switch (acerhk_key2name[i]) { ++ case k_help: printk(" help"); break; ++ case k_setup: printk(" setup"); break; ++ case k_p1: printk(" p1"); break; ++ case k_p2: printk(" p2"); break; ++ case k_p3: printk(" p3"); break; ++ case k_www: printk(" www"); break; ++ case k_mail: printk(" mail"); break; ++ case k_wireless: printk(" wireless"); break; ++ case k_power: printk(" power"); break; ++ case k_mute: printk(" mute"); break; ++ case k_volup: printk(" volup"); break; ++ case k_voldn: printk(" voldn"); break; ++ case k_res: printk(" res"); break; ++ case k_close: printk(" close"); break; ++ case k_open: printk(" open"); break; ++ case k_wireless2: printk(" wireless2"); break; ++ case k_play: printk(" play"); break; ++ case k_stop: printk(" stop"); break; ++ case k_prev: printk(" prev"); break; ++ case k_next: printk(" next"); break; ++ case k_display: printk(" display"); break; ++ default: break; ++ } ++ } ++ printk("\n"); ++ if (acerhk_model_features & TM_F_MUTE_LED_EC) ++ printk(KERN_INFO"acerhk: mute led is supported\n"); ++ if (acerhk_model_features & TM_F_MAIL_LED) ++ printk(KERN_INFO"acerhk: mail led is supported\n"); ++ else if (acerhk_model_features & TM_F_MAIL_LED_EC) ++ printk(KERN_INFO"acerhk: mail led (EC) is supported\n"); ++ else if (acerhk_model_features & TM_F_MAIL_LED_EC2) ++ printk(KERN_INFO"acerhk: mail led (EC2) is supported\n"); ++ else if (acerhk_model_features & TM_F_MAIL_LED_EC3) ++ printk(KERN_INFO"acerhk: mail led (EC3) is supported\n"); ++ if (acerhk_model_features & TM_F_WLAN_EC1) ++ printk(KERN_INFO"acerhk: wlan control (EC1) is supported\n"); ++ else if (acerhk_model_features & TM_F_WLAN_EC2) ++ printk(KERN_INFO"acerhk: wlan control (EC2) is supported\n"); ++ if (acerhk_model_features & TM_F_BLUE_EC1) ++ printk(KERN_INFO"acerhk: bluetooth control (EC1) is supported\n"); ++ else if (acerhk_model_features & TM_F_BLUE_EC2) ++ printk(KERN_INFO"acerhk: bluetooth control (EC2) is supported\n"); ++ printk(KERN_INFO"acerhk: supported functions:"); ++ if (acerhk_model_features & TM_F_CONNECT) ++ printk(" connect"); ++ if (acerhk_model_features & TM_F_THERMAL) ++ printk(" thermal"); ++ if (acerhk_model_features & TM_F_PBUTTON) ++ printk(" pbutton"); ++ if (acerhk_model_features & TM_F_WBUTTON) ++ printk(" wbutton"); ++ printk("\n"); ++} ++ ++static void __init setup_keymap_model(unsigned int series) ++{ ++ /* clear mapping keycode -> keyname, */ ++ memset(&acerhk_key2name[0], k_none, sizeof(acerhk_key2name)); ++ /* first set the common keys, namely FnF1 and FnF2, */ ++ acerhk_key2name[1] = k_help; ++ acerhk_key2name[2] = k_setup; ++ /* then set known keycodes according to model */ ++ switch (series) { ++ case 110: ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[3] = k_power; ++ acerhk_key2name[8] = k_mute; ++ acerhk_key2name[32] = k_volup; ++ acerhk_key2name[33] = k_voldn; ++ /* C110 generates 2 extra codes when opening/closing the lid */ ++ acerhk_key2name[74] = k_close; ++ acerhk_key2name[75] = k_open; ++ break; ++ case 300: /* treat C300 like C100 with Bluetooth button */ ++ acerhk_key2name[68] = k_wireless2; ++ case 100: ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[49] = k_www; ++ acerhk_key2name[54] = k_mail; ++ acerhk_key2name[3] = k_power; ++ acerhk_key2name[8] = k_mute; ++ acerhk_key2name[32] = k_volup; ++ acerhk_key2name[33] = k_voldn; ++ break; ++ default: ++ /* only the two common keys are supported */ ++ break; ++ case 210: ++ acerhk_key2name[19] = k_p1; ++ acerhk_key2name[20] = k_p2; ++ acerhk_key2name[17] = k_www; ++ acerhk_key2name[18] = k_mail; ++ break; ++ case 220: ++ case 260: /* 260 with same keys? */ ++ acerhk_key2name[49] = k_p1; ++ acerhk_key2name[19] = k_p2; ++ acerhk_key2name[18] = k_www; ++ acerhk_key2name[17] = k_mail; ++ break; ++ case 230: ++ case 280: /* 280 with same keys? */ ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[54] = k_www; ++ break; ++ case 1500: ++ acerhk_key2name[0x49] = k_setup; ++ acerhk_key2name[0x36] = k_www; ++ acerhk_key2name[0x31] = k_mail; ++ acerhk_key2name[0x11] = k_p1; ++ acerhk_key2name[0x12] = k_p2; ++ acerhk_key2name[0x30] = k_wireless; ++ acerhk_key2name[0x44] = k_wireless2; ++ acerhk_key2name[0x03] = k_power; ++ break; ++ case 240: ++ acerhk_key2name[0x31] = k_www; ++ acerhk_key2name[0x36] = k_mail; ++ acerhk_key2name[0x11] = k_p1; ++ acerhk_key2name[0x12] = k_p2; ++ acerhk_key2name[0x44] = k_wireless; ++ acerhk_key2name[0x30] = k_wireless2; ++ acerhk_key2name[0x03] = k_power; ++ acerhk_key2name[0x08] = k_mute; ++ // acerhk_key2name[] = k_volup; ++ // acerhk_key2name[] = k_voldn; ++ break; ++ case 2900: ++ acerhk_key2name[0x31] = k_mail; /* with led */ ++ acerhk_key2name[0x36] = k_www; ++ acerhk_key2name[0x11] = k_p1; ++ acerhk_key2name[0x12] = k_p2; ++ acerhk_key2name[0x30] = k_wireless; /* wireless, with led, related with autowlan=1 */ ++ break; ++ case 250: /* enriqueg@altern.org */ ++ /* TravelMate 254LMi_DT manual common for 240/250 series, but key order ++ differ from 240 already present on acerhk driver */ ++ /* TravelMate 254LMi_DT: 6 buttons: left to right: mail, www, p1, p2, bluetooth, wireless */ ++ acerhk_key2name[0x31] = k_mail; /* with led */ ++ acerhk_key2name[0x36] = k_www; ++ acerhk_key2name[0x11] = k_p1; ++ acerhk_key2name[0x12] = k_p2; ++ acerhk_key2name[0x44] = k_wireless2; /* bluetooth, hw optional */ ++ acerhk_key2name[0x30] = k_wireless; /* wireless, with led, related with autowlan=1 */ ++ acerhk_key2name[0x03] = k_power; /* Fn+F3 */ ++ acerhk_key2name[0x08] = k_mute; /* Fn+F8 */ ++ break; ++ case 380: ++ /* TM 380 has same codes as TM 370, with an additional one */ ++ acerhk_key2name[0x03] = k_power; ++ case 370: ++ acerhk_key2name[0x30] = k_wireless; ++ acerhk_key2name[0x11] = k_p1; ++ acerhk_key2name[0x12] = k_p2; ++ acerhk_key2name[0x13] = k_p3; ++ acerhk_key2name[0x36] = k_www; ++ acerhk_key2name[0x31] = k_mail; ++ break; ++ case 360: ++ /* 360 series has the same layout as 350, with an ++ additional wireless key */ ++ acerhk_key2name[64] = k_wireless; ++ case 350: ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[20] = k_p3; ++ acerhk_key2name[21] = k_www; ++ acerhk_key2name[19] = k_mail; ++ break; ++ case 520: ++ acerhk_key2name[19] = k_p1; ++ acerhk_key2name[20] = k_p2; ++ acerhk_key2name[17] = k_www; ++ acerhk_key2name[18] = k_mail; ++ break; ++ case 610: ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[19] = k_p3; ++ acerhk_key2name[21] = k_www; ++ acerhk_key2name[20] = k_mail; ++ acerhk_key2name[64] = k_wireless; ++ break; ++ case 630: ++ /* 630 has all keys of 620 plus one */ ++ acerhk_key2name[8] = k_mute; ++ case 620: ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[19] = k_p3; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[3] = k_power; ++ acerhk_key2name[32] = k_volup; ++ acerhk_key2name[33] = k_voldn; ++ break; ++ case 290: ++ case 420: ++ case 430: ++ case 530: ++ case 540: ++ case 650: ++ case 660: ++ case 800: ++ case 1450: ++ case 2300: ++ case 2350: ++ case 4000: ++ case 4050: ++ case 6000: ++ case 8000: ++ case 4100: ++ case 4150: ++ case 4500: ++ case 4600: ++ case 4650: ++ case 1680: ++ case 1690: ++ /* keys are handled by dritek EC */ ++ acerhk_key2name[1] = k_none; ++ acerhk_key2name[2] = k_none; ++ break; ++ case 1300: ++ case 1310: ++ case 1350: ++ case 1360: ++ case 1400: ++ case 1700: ++ case 1800: ++ case 2000: ++ case 2010: ++ case 2020: ++ /* Aspire 13xx series laptops use dritek hardware, no ++ acerhk-mapping needed ++ VolUp and VolDown are managed as normal keys ++ 1300/1310 series should have P1, P2, Mail, WWW, Mute buttons ++ 1353 has bluetooth, wifi, p1, p2, www, mail, help, setup, power ++ and mute ++ Aspire 1400/1450/Ferrari use dritek EC, too ++ 1450 should have bluetooth, wifi, p1, p2, www, mail, help, ++ setup, power and mute ++ Aspire 1700 uses dritek EC, too ++ 1700 should have bluetooth, wifi, p1, p2, www, mail, help, ++ setup, power and mute ++ need the MM-buttons Activation? (forward, shuffle, ...) ++ 2000 hast lots of MM buttons ++ 2010 should have bluetooth, wifi, p1, p2, www, mail, help, ++ setup, power and mute ++ */ ++ acerhk_key2name[1] = k_none; ++ acerhk_key2name[2] = k_none; ++ break; ++ case 1600: ++ /* Aspire 1600 has acer keycode 0x49 for FnF2 */ ++ acerhk_key2name[73] = k_setup; ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[19] = k_p3; ++ acerhk_key2name[3] = k_power; ++ acerhk_key2name[8] = k_mute; ++ /* VolUp and VolDown keys doesn't seem to be managed as special keys ++ but as normal keys ! */ ++ break; ++ case 5020: /* Aspire 5020 has 0x6a for Fn+F2 */ ++ acerhk_key2name[2] = k_none; ++ acerhk_key2name[106] = k_setup; ++ acerhk_key2name[3] = k_power; ++ acerhk_key2name[5] = k_display; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[68] = k_wireless2; ++ break; ++ case 2410: /* TM 2410 is very similar to Aspire 5020, but has 0x6s for Fn-F3 */ ++ acerhk_key2name[2] = k_none; ++ acerhk_key2name[106] = k_setup; ++ acerhk_key2name[109] = k_power; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[68] = k_wireless2; ++ break; ++ case 40100: ++ /* Medion MD40100, 4 keys */ ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[55] = k_res; ++ break; ++ case 96500: ++ case 95400: ++ /* Medion MD95400, many keys */ ++ acerhk_key2name[49] = k_mail; /* 1 */ ++ acerhk_key2name[54] = k_www; /* 2 */ ++ acerhk_key2name[48] = k_wireless; /* 3 */ ++ acerhk_key2name[68] = k_wireless2; /* 4 (Bluetooth) */ ++ ++ acerhk_key2name[17] = k_p1; /* 5 */ ++ acerhk_key2name[18] = k_p2; /* 6 */ ++ acerhk_key2name[36] = k_play; /* 7 */ ++ acerhk_key2name[37] = k_stop; /* 8 */ ++ acerhk_key2name[34] = k_prev; /* 9 */ ++ acerhk_key2name[35] = k_next; /* 10 */ ++ acerhk_key2name[33] = k_voldn; /* 11 */ ++ acerhk_key2name[32] = k_volup; /* 12 */ ++ acerhk_key2name[38] = k_p3; /* 13 */ ++ acerhk_key2name[8] = k_mute; /* 14 */ ++ ++ acerhk_key2name[1] = k_help; /* FN+F1 (Help) */ ++ acerhk_key2name[5] = k_display; /* FN+F3 (Display switch) */ ++ acerhk_key2name[6] = k_res; /* FN+F4 (Display ein/ausschalten) */ ++ break; ++ case 42200: ++ /* Medion MD42200, 7 keys, no setup */ ++ acerhk_key2name[2] = k_none; ++ acerhk_key2name[5] = k_display; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ break; ++ case 9783: ++ /* Medion MD9783, 6 keys + info, no setup */ ++ acerhk_key2name[2] = k_none; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[19] = k_p3; ++ acerhk_key2name[8] = k_mute; ++ break; ++ case 7400: ++ /* Amilo Pro V2000 does not have Help and Setup key (?) ++ Amilo M 7400 has Help key, disabling only setup ++ */ ++ acerhk_key2name[2] = k_none; ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ break; ++ case 1559: ++ acerhk_key2name[6] = k_display; /* FN+F4 (Display ein/ausschalten) */ ++ case 1555: ++ /* AOpen (Ahtec Signal 1555M) is similar to FS Amilo M */ ++ acerhk_key2name[2] = k_none; ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[34] = k_prev; ++ acerhk_key2name[35] = k_next; ++ acerhk_key2name[36] = k_play; ++ acerhk_key2name[37] = k_stop; ++ break; ++ case 6800: ++ case 7820: ++ /* Amilo D does not have Setup key */ ++ acerhk_key2name[2] = k_none; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[19] = k_p3; ++ acerhk_key2name[8] = k_mute; ++ break; ++ } ++} ++ ++static void __init setup_model_features(unsigned int series) ++{ ++ switch (series) { ++ case 200: ++ case 210: ++ case 520: ++ /* nothing special */ ++ acerhk_model_features = 0; ++ acerhk_type = TM_old; ++ break; ++ case 220: ++ case 230: ++ case 260: ++ case 280: ++ case 360: ++ case 40100: /* Medion MD40100 */ ++ case 95400: /* Medion MD95400 */ ++ case 96500: /* Medion MD96500 */ ++ /* all special functions, no mail led */ ++ acerhk_model_features = 0x00f00000; ++ acerhk_type = TM_new; ++ break; ++ case 42200: /* Medion MD42200 */ ++ /* has WLAN button, should call connect() */ ++ acerhk_model_features = TM_F_WBUTTON | TM_F_CONNECT; ++ acerhk_type = TM_old; ++ break; ++ case 9783: /* Medion MD9783 */ ++ /* only email led */ ++ acerhk_model_features = TM_F_MAIL_LED; ++ acerhk_type = TM_new; ++ break; ++ case 1600: ++ acerhk_type = TM_new; ++ /* Do Aspire 1600 series have special functions or not ? I enable ++ them, perhaps it helps with problems Francois Valenduc has */ ++ acerhk_model_features = 0x00f00000; ++ break; ++ case 300: ++ case 100: ++ case 110: ++ case 240: ++ case 350: ++ case 610: ++ case 620: ++ case 630: ++ /* all special functions, mail led */ ++ acerhk_model_features = TM_F_MAIL_LED | 0x00f00000; ++ acerhk_type = TM_new; ++ break; ++ case 370: ++ case 380: ++ case 2410: ++ case 2900: /* Medion MD2900 */ ++ case 2100: /* TM 2100 uses same driver as 5020 */ ++ case 5020: /* Aspire 5020 is still old hardware */ ++ acerhk_model_features = TM_F_MAIL_LED | TM_F_CONNECT| TM_F_WBUTTON; ++ acerhk_type = TM_new; ++ break; ++ case 7400: ++ case 1555: ++ case 1559: ++ /* all special functions for Fujitsu-Siemens Amilo M7400, Pro V2000; AOpen */ ++ acerhk_model_features = 0x00f00000; ++ acerhk_type = TM_new; ++ break; ++ case 6800: ++ case 7820: ++ /* mail led and all special functions for FS Amilo D */ ++ acerhk_model_features = TM_F_MAIL_LED | 0x00f00000; ++ acerhk_type = TM_new; ++ break; ++ case 2350: ++ case 4050: ++ acerhk_wlan_state = 1; // Default state is on ++ case 290: ++ /* no special functions, wireless hardware controlled by EC */ ++ acerhk_model_features = TM_F_WLAN_EC2 | TM_F_BLUE_EC2; ++ acerhk_type = TM_dritek; ++ break; ++ case 650: ++ case 1300: ++ case 1310: ++ case 1400: ++ case 1700: ++ /* all special functions, wireless hardware can be controlled */ ++ acerhk_model_features = 0x00f00000; ++ acerhk_type = TM_dritek; ++ break; ++ case 4100: ++ case 4600: ++ case 1680: ++ case 1690: /* Aspire 1680/1690 should be similar to TM 4100/4600 */ ++ /* mail led, wireless and bluetooth controlled the old way, but keys are ++ controlled by normal keyboard controller, so mark as dritek and ++ deactivate dritek use */ ++ acerhk_model_features = TM_F_MAIL_LED | TM_F_WBUTTON; ++ acerhk_type = TM_dritek; ++ usedritek=0; ++ break; ++ case 660: ++ case 800: ++ /* all special functions, mail led */ ++ acerhk_model_features = TM_F_MAIL_LED | 0x00f00000; ++ acerhk_type = TM_dritek; ++ break; ++ case 1350: ++ case 1360: ++ /* mail led, handled by EC, wireless HW is not (yet) controllable ? */ ++ acerhk_model_features = TM_F_MAIL_LED_EC|TM_F_WLAN_EC1; ++ acerhk_type = TM_dritek; ++ break; ++ case 1450: ++ /* Bluetooth/Wlan led, Mail led handled by EC (variant 3) */ ++ acerhk_model_features = TM_F_MAIL_LED_EC3|TM_F_WBUTTON; ++ acerhk_type = TM_dritek; ++ break; ++ case 1500: ++ /* Bluetooth/Wlan led */ ++ acerhk_model_features = TM_F_WBUTTON; ++ acerhk_type = TM_new; ++ break; ++ case 420: ++ case 430: ++ /* all functions and dritek EC, mail LED is handled by EC, second ++ variant. An additional led is available, mute. (really?) ++ */ ++ acerhk_type = TM_dritek; ++ acerhk_model_features = TM_F_MUTE_LED_EC|TM_F_MAIL_LED_EC2; ++ break; ++ case 2300: ++ case 4000: ++ case 4500: ++ /* wireless hardware, hopefully under control of my driver */ ++ acerhk_type = TM_dritek; ++ acerhk_model_features = TM_F_BLUE_EC1|TM_F_WLAN_EC1; ++ break; ++ case 3200: ++ /* test, if this model uses old style wlan control */ ++ acerhk_model_features = TM_F_WBUTTON; ++ acerhk_type = TM_dritek; ++ break; ++ case 6000: ++ case 8000: ++ /* 6000 and 8000 have wireless hardware, but I don't know how to handle, ++ so I choose no features */ ++ acerhk_type = TM_dritek; ++ break; ++ case 530: ++ case 540: ++ case 2000: ++ /* No features (?) dritek EC, mail LED is handled by EC but ++ different from other Aspire series */ ++ acerhk_type = TM_dritek; ++ acerhk_model_features = TM_F_MAIL_LED_EC2; ++ break; ++ case 4150: ++ case 4650: ++ /* Dritek EC, bluetooth, wifi, mail */ ++ /* According to Andreas Stumpfl his TM 4652LMi does also work as series ++ 3200, which might mean that the BIOS function accesses the EC */ ++ acerhk_type = TM_dritek; ++ acerhk_model_features = TM_F_MAIL_LED_EC2 | TM_F_WLAN_EC2 | TM_F_BLUE_EC2; ++ break; ++ case 1800: ++ case 2010: ++ case 2020: ++ /* Dritek EC, bluetooth, wifi, mail */ ++ acerhk_type = TM_dritek; ++ acerhk_model_features = TM_F_MAIL_LED_EC2 | TM_F_WLAN_EC2 | TM_F_BLUE_EC2; ++ acerhk_wlan_state = 1; // Default state is on ++ break; ++ case 250: /* enriqueg@altern.org */ ++ /* TravelMate254LMi_DT : mail led, bluetooth (button present, hw optional), wifi (with led) */ ++ acerhk_model_features = TM_F_MAIL_LED| ++ TM_F_WBUTTON ; ++ acerhk_type = TM_new; ++ acerhk_wlan_state = 0; //Initial state is off on 254LMi_DT ++ break; ++ default: ++ /* nothing special */ ++ acerhk_model_features = 0; ++ acerhk_type = TM_unknown; ++ break; ++ } ++ /* set the correct bios call function according to type */ ++ if ((acerhk_type == TM_new) || (acerhk_type == TM_dritek)) { ++ call_bios = call_bios_6xx; ++ if (verbose > 2) ++ printk(KERN_INFO"acerhk: using call_bios_6xx mode\n"); ++ } else { ++ call_bios = call_bios_52x; ++ if (verbose > 2) ++ printk(KERN_INFO"acerhk: using call_bios_52x mode\n"); ++ } ++ /* remove key file on dritek hardware */ ++ if (acerhk_type == TM_dritek) { ++ remove_proc_entry("key", proc_acer_dir); ++ } ++ /* setup available keys */ ++ setup_keymap_model(acerhk_series); ++ if (verbose > 1) ++ print_features(); ++} ++ ++static unsigned int __init determine_laptop_series(char * str) ++{ ++ /* 0 means unknown series, handled like TM 200 */ ++ unsigned int series = 0; ++ if (strncmp(str, "TravelMate ", 11) == 0) { ++ switch (str[11]) { ++ case 'C': ++ if (str[12] == '1') { ++ if (str[13] == '0') { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates TM C100 series\n"); ++ series = 100; ++ } else if (str[13] == '1') { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates TM C110 series\n"); ++ series = 110; ++ } ++ } else if (str[12] == '3') { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates TM C300 series\n"); ++ series = 300; ++ } ++ break; ++ case 'F': ++ if (str[12] == '4') { ++ series = 230; ++ } ++ break; ++ case '2': ++ if (str[14] == '0') { ++ /* newer Travelmate 2xxx series */ ++ switch (str[12]) { ++ case '0': ++ case '5': ++ series = 2000; // 2000 and 2500 are the same ++ break; ++ case '1': ++ if (str[13] == '0') ++ series = 2100; ++ break; ++ case '2': ++ case '7': ++ series = 2200; // 2200 and 2700 are the same ++ break; ++ case '3': ++ if (str[13] == '0') ++ series = 4000; // 2300 is the same as 4000 ++ else if (str[13] == '5') ++ series = 4050; // 2350 is the same as 4050 ++ break; ++ case '4': ++ if (str[13] == '1') ++ series = 2410; ++ break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM 2xxx series\n"); ++ break; ++ } ++ } else { ++ /* older Travelmate 2xx series */ ++ switch (str[12]) { ++ case '0': series = 200; break; ++ case '1': series = 210; break; ++ case '2': series = 220; break; ++ case '4': series = 240; break; ++ case '5': series = 250; break; /* enriqueg@altern.org */ ++ case '6': series = 260; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM 2xx series\n"); ++ break; ++ } ++ } ++ break; ++ case '3': ++ switch (str[12]) { ++ case '0': series = 3200; break; /* TM 3000 works like TM 3200 */ ++ /* Travelmate 3xx series */ ++ case '5': series = 350; break; ++ case '6': series = 360; break; ++ case '7': series = 370; break; ++ case '8': series = 380; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM 3xx series\n"); ++ break; ++ } ++ break; ++ case '4': ++ if ( (strnlen(str, ACERHK_MODEL_STRLEN-1) == 15) && ++ (str[14] == '0') ) { /* Travelmate 4xxx series */ ++ switch (str[12]) { ++ case '0': /* 4000 and 4500 are the same */ ++ case '5': ++ series = 4000; ++ break; ++ case '1': ++ case '6': /* 4100 and 4600 are the same */ ++ series = 4100; ++ break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM 4xxx series\n"); ++ break; ++ } ++ } else { /* Travelmate 4xx series */ ++ switch (str[12]) { ++ case '2': series = 420; break; ++ case '3': series = 430; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM 4xx series\n"); ++ break; ++ } ++ } ++ break; ++ case '5': /* Travelmate 5xx series */ ++ if (str[12] == '2') ++ series = 520; ++ else if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM 5xx series\n"); ++ break; ++ case '6': /* older Travelmate 6xx series */ ++ switch (str[12]) { ++ case '1': series = 610; break; ++ case '2': series = 620; break; ++ case '3': series = 630; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM 6xx series\n"); ++ break; ++ } ++ break; ++ default: ++ printk(KERN_INFO"acerhk: model string indicates unknown TM xxx series\n"); ++ break; ++ } ++ if (series && verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates TM %d series\n", series); ++ } ++ /* newer Travelmate series do not have a space after 'TravelMate' */ ++ else if (strncmp(str, "TravelMate", 10) == 0) { ++ switch (str[10]) { ++ case '2': ++ if (str[11] == '9') { ++ series = 290; ++ } else { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM2xx series\n"); ++ } ++ break; ++ case '3': ++ if (str[11] == '2' && str[14] == '3') { ++ // TM 3200 uses "TravelMate32003" ++ series = 3200; ++ } else { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM3xxx series\n"); ++ } ++ break; ++ case '4': ++ switch (str[11]) { ++ case '3': series = 430; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM4xx series\n"); ++ break; ++ } ++ break; ++ case '5': ++ switch (str[11]) { ++ case '3': series = 530; break; ++ case '4': series = 540; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM5xx series\n"); ++ break; ++ } ++ break; ++ case '6': ++ switch (str[11]) { ++ case '5': series = 650; break; ++ case '6': series = 660; break; ++ case '0': ++ if (strncmp(str, "TravelMate60003", 15) == 0) { ++ series = 6000; break; ++ } ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM6xx series\n"); ++ break; ++ } ++ break; ++ case '8': ++ if (strncmp(str, "TravelMate80003", 15) == 0) { ++ series = 8000; ++ } else if (str[11] == '0') { ++ series = 800; ++ } else { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM8xx series\n"); ++ } ++ break; ++ default: ++ printk(KERN_INFO"acerhk: model string indicates unknown TMxxx series\n"); ++ break; ++ } ++ if (series && verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates TM%d series\n", series); ++ } ++ else if (strncmp(str, "Aspire ", 7) == 0) { ++ switch(str[7]) { ++ case '1': /* Aspire 1xxx series */ ++ switch(str[8]) { ++ case '3': /* Aspire 13xx series */ ++ switch (str[9]) { ++ case '0': series = 1300; break; ++ case '1': series = 1310; break; ++ case '5': series = 1350; break; ++ case '6': series = 1360; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 13xx series\n"); ++ break; ++ } ++ break; ++ case '4': /* Aspire 14xx series */ ++ switch (str[9]) { ++ case '0': series = 1400; break; ++ case '5': series = 1450; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 14xx series\n"); ++ break; ++ } ++ break; ++ case '5': series = 1500; break; ++ case '6': /* Aspire 14xx series */ ++ switch (str[9]) { ++ case '0': series = 1600; break; ++ case '8': ++ case '9': series = 1680; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 16xx series\n"); ++ break; ++ } ++ break; ++ case '7': series = 1700; break; ++ case '8': series = 1800; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 1xxx series\n"); ++ break; ++ } ++ break; ++ case '2': /* Aspire 2xxx series */ ++ if (str[8] == '0') { ++ switch (str[9]) { ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 20xx series\n"); ++ break; ++ case '0': series = 2000; break; ++ case '1': series = 2010; break; ++ case '2': series = 2020; break; ++ } ++ } else { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 2xxx series\n"); ++ } ++ break; ++ case '3': /* Aspire 3xxx series */ ++ if (str[8] == '0') { ++ switch (str[9]) { ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 30xx series\n"); ++ break; ++ case '2': series = 5020; break; /* Aspire 3020/5020 are identical */ ++ } ++ } else { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 3xxx series\n"); ++ } ++ break; ++ case '5': /* Aspire 5xxx series */ ++ if (str[8] == '0') { ++ switch (str[9]) { ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 50xx series\n"); ++ break; ++ case '2': series = 5020; break; ++ } ++ } else { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 5xxx series\n"); ++ } ++ break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire series\n"); ++ break; ++ } ++ if (series && verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates Aspire %d series\n", series); ++ } ++ else if (strncmp(str, "Extensa ", 8) == 0) { ++ /* Extensa series */ ++ switch (str[8]) { ++ case '3': ++ switch (str[9]) { ++ case '0': ++ series = 3000; break; ++ default: break; ++ } ++ break; ++ default: break; ++ } ++ if (series && verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates Extensa %d series\n", series); ++ else if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Extensa series\n"); ++ } ++ else if (strncmp(str, "Amilo ", 6) == 0) { ++ switch (str[6]) { ++ case 'D': /* complete string is "Amilo D-Series", there seems to be no model number */ ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates FS Amilo D series\n"); ++ /* this is the model number of my Amilo */ ++ series = 7820; ++ break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown FS Amilo XX series\n"); ++ series = 7820; ++ } ++ } ++ else if (strncmp(str, "AMILO ", 6) == 0) { ++ switch (str[6]) { ++ case 'D': /* AMILO D 6800 P4-2000 */ ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates FS AMILO D series\n"); ++ series = 6800; ++ break; ++ case 'M': ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates FS AMILO M(7400) series\n"); ++ series = 7400; ++ break; ++ case 'P': ++ /* it is assumed, that 'AMILO P' appears only on Amilo Pro Series */ ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates FS AMILO Pro (V2000) series\n"); ++ series = 7400; ++ break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown FS AMILO XX series\n"); ++ series = 6800; ++ } ++ } ++ else if (strncmp(str, "MEDIONPC", 8) == 0) { ++ uint medionmodel; ++ if ((medionmodel = COLUSSI("WIM 2040", 4, reg1, AREA_SIZE)) >= 0) { ++ printk(KERN_INFO"acerhk: found Medion model string:'%s'\n", (char*)reg1+medionmodel); ++ series = 96500; ++ } else { ++ if ((medionmodel = COLUSSI("MD 9", 4, reg1, AREA_SIZE)) >= 0) { ++ printk(KERN_INFO"acerhk: found Medion model string:'%s'\n", (char*)reg1+medionmodel); ++ } ++ series = 95400; ++ } ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates a medion MD %d\n", series); ++ } ++ else if (strncmp(str, "MEDIONNB", 8) == 0) { ++ /* Search for the Product string of the MD9783. */ ++ if (COLUSSI("MD 42200", 8, reg1, AREA_SIZE) >= 0) { ++ if (verbose>1) ++ printk(KERN_INFO"acerhk: model string indicates a Medion MD 42200\n"); ++ series = 42200; ++ } else if (COLUSSI("MD 9783", 7, reg1, AREA_SIZE) >= 0){ ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates a medion MD 9783\n"); ++ series = 9783; ++ } else if (COLUSSI("WIM 2000", 7, reg1, AREA_SIZE) >= 0){ ++ if (verbose>1) ++ printk(KERN_INFO"acerhk: model string indicates a Medion MD 2900\n"); ++ series = 2900; ++ } else { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates a medion MD40100\n"); ++ series = 40100; ++ } ++ } else if (strncmp(str, "AOpen", 5) == 0) { ++ if (strncmp(str, "AOpen*EzRestore", 15) == 0) { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates a AOpen 1559\n"); ++ series = 1559; ++ } else { ++ /* Unless I know of other models no further differentiation, ++ although there is a second part of the model string */ ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates a AOpen\n"); ++ series = 1555; ++ } ++ } else if (strncmp(str, "CL56", 4) == 0) { ++ /* Unless I know of other models no further differentiation, ++ although there are strings with more numbers ("CL561" on a Compal ++ CL56/Zepto 4200, reported by Stian B. Barmen) ++ It has the same functions as Acer Aspire 2010 ++ */ ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates a Compal CL56 (or similar)\n"); ++ series = 2010; ++ } else if (strncmp(str, "Geneva2", 7) == 0) { ++ /* This might be an Aspire 9110 which is very similar to 4650 */ ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates an Aspire 9110\n"); ++ series = 4650; ++ } else { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates no supported hardware\n"); ++ } ++ return (series); ++} ++ ++static void __init probe_model(void) { ++ int offset; /* offset from beginning of reg1 to Model string */ ++ if (verbose) ++ printk(KERN_INFO"acerhk: start search for model string at %p\n", reg1); ++ /* first we look for Travelmate, if it isn't one we try to identify other ++ laptops, such as Medion or Aspire */ ++ offset = COLUSSI("Travel", 6, reg1, AREA_SIZE); ++ /* Try to detect Aspire laptops */ ++ if (offset < 0) ++ offset = COLUSSI("Aspire", 6, reg1, AREA_SIZE); ++ /* Try to detect Extensa laptops */ ++ if (offset < 0) ++ offset = COLUSSI("Extensa", 7, reg1, AREA_SIZE); ++ /* Try to detect Medion laptops */ ++ if (offset < 0) ++ offset = COLUSSI("MEDION", 6, reg1, AREA_SIZE); ++ /* Try to detect AOpen laptops */ ++ if (offset < 0) ++ offset = COLUSSI("AOpen", 5, reg1, AREA_SIZE); ++ /* Try to detect Fujitsu Siemens Amilo laptops */ ++ if (offset < 0) ++ offset = COLUSSI("Amilo", 5, reg1, AREA_SIZE); ++ if (offset < 0) ++ offset = COLUSSI("AMILO", 5, reg1, AREA_SIZE); ++ /* Try to detect Compal */ ++ if (offset < 0) ++ offset = COLUSSI("CL56", 4, reg1, AREA_SIZE); ++ /* That might be an Aspire 9110 */ ++ if (offset < 0) ++ offset = COLUSSI("Geneva2", 7, reg1, AREA_SIZE); ++ if (offset >= 0) { ++ acerhk_model_addr = reg1 + offset; ++ /* copy the string, but not more than 15 characters */ ++ strncpy(acerhk_model_string, acerhk_model_addr, ACERHK_MODEL_STRLEN-1); ++ if (verbose) ++ printk(KERN_INFO"acerhk: found model string '%s' at %p\n", ++ acerhk_model_string, acerhk_model_addr); ++ if (bios_routine && verbose > 2) ++ printk(KERN_INFO"acerhk: offset from model string to function address: 0x%lx\n", ++ bios_routine - (unsigned long)acerhk_model_addr); ++ acerhk_series = determine_laptop_series(acerhk_model_string); ++ } else { ++ printk(KERN_WARNING"acerhk: Could not find model string, will assume type 200 series\n"); ++ acerhk_series = 200; ++ } ++} ++ ++/* }}} */ ++ ++/* {{{ key polling and translation */ ++ ++static void print_mapping(void) ++{ ++ printk(KERN_INFO"acerhk: key mapping:\n"); ++ printk("acerhk: help 0x%x\n", acerhk_name2event[k_help]); ++ printk("acerhk: setup 0x%x\n", acerhk_name2event[k_setup]); ++ printk("acerhk: p1 0x%x\n", acerhk_name2event[k_p1]); ++ printk("acerhk: p2 0x%x\n", acerhk_name2event[k_p2]); ++ printk("acerhk: p3 0x%x\n", acerhk_name2event[k_p3]); ++ printk("acerhk: www 0x%x\n", acerhk_name2event[k_www]); ++ printk("acerhk: mail 0x%x\n", acerhk_name2event[k_mail]); ++ printk("acerhk: wireless 0x%x\n", acerhk_name2event[k_wireless]); ++ printk("acerhk: power 0x%x\n", acerhk_name2event[k_power]); ++ printk("acerhk: mute 0x%x\n", acerhk_name2event[k_mute]); ++ printk("acerhk: volup 0x%x\n", acerhk_name2event[k_volup]); ++ printk("acerhk: voldn 0x%x\n", acerhk_name2event[k_voldn]); ++ printk("acerhk: res 0x%x\n", acerhk_name2event[k_res]); ++ printk("acerhk: close 0x%x\n", acerhk_name2event[k_close]); ++ printk("acerhk: open 0x%x\n", acerhk_name2event[k_open]); ++ printk("acerhk: wireless2 0x%x\n", acerhk_name2event[k_wireless2]); ++ printk("acerhk: play 0x%x\n", acerhk_name2event[k_play]); ++ printk("acerhk: stop 0x%x\n", acerhk_name2event[k_stop]); ++ printk("acerhk: prev 0x%x\n", acerhk_name2event[k_prev]); ++ printk("acerhk: next 0x%x\n", acerhk_name2event[k_next]); ++ printk("acerhk: display 0x%x\n", acerhk_name2event[k_display]); ++} ++ ++static void set_keymap_name(t_key_names name, unsigned int key) ++{ ++ acerhk_name2event[name] = key; ++} ++ ++static void init_keymap_input(void) ++{ ++ /* these values for input keys are chosen to match the key names on the ++ actual Acer laptop */ ++ set_keymap_name(k_none, KEY_RESERVED); ++ set_keymap_name(k_help, KEY_HELP); ++ set_keymap_name(k_setup, KEY_CONFIG); ++ set_keymap_name(k_p1, KEY_PROG1); ++ set_keymap_name(k_p2, KEY_PROG2); ++ set_keymap_name(k_p3, KEY_PROG3); ++ set_keymap_name(k_www, KEY_WWW); ++ set_keymap_name(k_mail, KEY_MAIL); ++ set_keymap_name(k_wireless, KEY_XFER); ++ set_keymap_name(k_power, KEY_POWER); ++ set_keymap_name(k_mute, KEY_MUTE); ++ set_keymap_name(k_volup, KEY_VOLUMEUP); ++ set_keymap_name(k_voldn, KEY_VOLUMEDOWN); ++ set_keymap_name(k_res, KEY_CONFIG); ++ set_keymap_name(k_close, KEY_CLOSE); ++ set_keymap_name(k_open, KEY_OPEN); ++ /* I am not really happy with the selections for wireless and wireless2, ++ but coffee looks good. Michal Veselenyi proposed this value */ ++ set_keymap_name(k_wireless2, KEY_COFFEE); ++ set_keymap_name(k_play, KEY_PLAYPAUSE); ++ set_keymap_name(k_stop, KEY_STOPCD); ++ set_keymap_name(k_prev, KEY_PREVIOUSSONG); ++ set_keymap_name(k_next, KEY_NEXTSONG); ++ set_keymap_name(k_display, KEY_MEDIA); /* also not happy with this */ ++ if (verbose > 1) ++ print_mapping(); ++} ++ ++static int filter_idle_value(int keycode) ++{ ++ int validkey = 0; ++ if (keycode != 0x0 && ++ keycode != 0x9610 && ++ keycode != 0xc100 && /* Francois Valenduc, Aspire 1601 LC */ ++ keycode != 0x8610 && ++ keycode != 0x861 && ++ keycode != 0x8650 && ++ keycode != 0x865) ++ validkey = keycode; ++ if (verbose > 4 && !validkey) ++ printk(KERN_INFO"acerhk: throw away idle value 0x%x\n", keycode); ++ return validkey; ++} ++ ++static void send_key_event(t_key_names key) ++{ ++ unsigned int input_key; ++ if (key != k_none) { ++ /* convert key name to kernel keycode */ ++ input_key = acerhk_name2event[key]; ++ if (verbose > 2) ++ printk(KERN_INFO"acerhk: translated acer key name 0x%x to input key 0x%x\n", ++ key, input_key); ++ /* send press and release together, as there is no such event from acer as 'release' */ ++ input_report_key(acerhk_input_dev_ptr, input_key, 1); ++ input_report_key(acerhk_input_dev_ptr, input_key, 0); ++ } ++} ++ ++static t_key_names transl8_key_code(int keycode) ++{ ++ t_key_names keyname = k_none; ++ /* first filter out idle values */ ++ if ( (keycode = filter_idle_value(keycode)) ) { ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: received key code 0x%x\n", keycode); ++ /* translate keycode to key name */ ++ if (keycode >= 0 && keycode <= 255) ++ keyname = acerhk_key2name[keycode]; ++ else { ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: keycode 0x%x too big, will use only 8 bits\n", keycode); ++ /* use only lower 8 bits of value to distinguish keys */ ++ keyname = acerhk_key2name[keycode&0xff]; ++ } ++ /* produce some log information for higher verbosity levels */ ++ if (keyname != k_none && verbose > 2) ++ printk(KERN_INFO"acerhk: translated acer key code 0x%x to key name 0x%x\n", ++ keycode, keyname); ++ else if (keyname == k_none && verbose > 3) ++ printk(KERN_INFO"acerhk: translated acer key code 0x%x to no key\n", ++ keycode); ++ if (autowlan) { ++ /* if automatic switching of wlan hardware is enabled, do it here ++ on wireless key press */ ++ if (keyname == k_wireless2) { ++ if (acerhk_bluetooth_state) ++ wbutton_fct_1(0); ++ else ++ wbutton_fct_1(1); ++ } ++ if (keyname == k_wireless) { ++ if (acerhk_wlan_state) ++ wbutton_fct_2(0); ++ else ++ wbutton_fct_2(1); ++ } ++ } ++ } ++ return keyname; ++} ++ ++/* polling timer handler */ ++static void acerhk_poll_event(unsigned long save_size) ++{ ++#ifndef DUMMYHW ++ unsigned int max = MAX_POLLING_LOOPS; ++ /* make sure not to loop more then 32 times */ ++ if (!max || max > 32) ++ max = 32; ++ if (acerhk_type != TM_dritek) { ++ while (get_nr_events() && max--) { ++ send_key_event(transl8_key_code(get_fnkey_event())); ++ } ++ } else { ++ send_key_event(transl8_key_code(get_fnkey_event())); ++ } ++#endif ++ acerhk_timer_poll.expires = jiffies + acerhk_polling_delay; ++ add_timer(&acerhk_timer_poll); ++} ++ ++/* blinking timer handler; added by Antonio Cuni */ ++static void acerhk_blink_event(unsigned long not_used) ++{ ++ if (acerhk_blueled_blinking != -1) { ++ acerhk_blueled_blinking = !acerhk_blueled_blinking; ++#ifndef DUMMYHW ++ wbutton_fct_1(acerhk_blueled_blinking); ++#endif ++ acerhk_timer_blinking.expires = jiffies + acerhk_blueled_blinking_delay; ++ add_timer(&acerhk_timer_blinking); ++ } ++ else ++ printk(KERN_WARNING "acerhk: blinking event called, but blinking not active\n"); ++} ++ ++static void init_input(void) ++{ ++ int i; ++ ++#ifndef KERNEL26 ++ /* request keyboard input module */ ++ request_module("keybdev"); ++ if (verbose > 3) ++ printk(KERN_INFO"requested keyboard input driver\n"); ++#endif ++ ++#ifndef STATIC_INPUT_DEV ++ /* allocate acerhk input device */ ++ acerhk_input_dev_ptr=input_allocate_device(); ++ /* enter some name */ ++ acerhk_input_dev_ptr->name = "Acer hotkey driver"; ++#else ++ acerhk_input_dev_ptr=&acerhk_input_dev; ++#endif ++ ++ /* some laptops have a mail led, should I announce it here? */ ++ acerhk_input_dev_ptr->evbit[0] = BIT(EV_KEY); ++ /* announce keys to input system ++ * the generated keys can be changed on runtime, ++ * but to publish those changes the device needs to ++ * get reconnected (I dont't know any other way) ++ * Therefore I enable all possible keys */ ++ for (i = KEY_RESERVED; i < BTN_MISC; i++) ++ set_bit(i, acerhk_input_dev_ptr->keybit); ++ /* set mapping keyname -> input event */ ++ init_keymap_input(); ++ if (verbose) ++ printk(KERN_INFO"acerhk: registered input device\n"); ++ input_register_device(acerhk_input_dev_ptr); ++ init_timer(&acerhk_timer_poll); ++ acerhk_polling_state = 0; ++} ++ ++static void stop_polling(void) ++{ ++ if (acerhk_polling_state == 1) { ++ del_timer(&acerhk_timer_poll); ++ if (verbose) ++ printk(KERN_INFO"acerhk: key polling stopped\n"); ++ acerhk_polling_state = 0; ++ } else ++ if (verbose) ++ printk(KERN_INFO"acerhk: key polling not active\n"); ++} ++ ++static void start_polling(void) ++{ ++ if (acerhk_polling_state != 1) { ++ acerhk_timer_poll.function = acerhk_poll_event; ++ acerhk_timer_poll.expires = jiffies + acerhk_polling_delay; ++ acerhk_timer_poll.data = get_nr_events(); ++ add_timer(&acerhk_timer_poll); ++ acerhk_polling_state = 1; ++ if (acerhk_type == TM_dritek) { ++ printk(KERN_INFO"acerhk: Your hardware does not need polling enabled for hotkeys to work, " ++ "you can safely disable polling by using the module parameter poll=0 (unless you " ++ "want to play around with the driver and see if there are buttons which need polling).\n"); ++ } ++ if (verbose) ++ printk(KERN_INFO"acerhk: starting key polling, every %d ms\n", acerhk_polling_delay); ++ } else ++ if (verbose) ++ printk(KERN_INFO"acerhk: key polling already active\n"); ++} ++ ++/* addedd by Antonio Cuni */ ++static void start_blinking(void) ++{ ++ if (acerhk_blueled_blinking == -1) { ++ // blinking was disabled... enable it! ++ acerhk_timer_blinking.function = acerhk_blink_event; ++ acerhk_timer_blinking.expires = jiffies + acerhk_blueled_blinking_delay; ++ acerhk_timer_blinking.data = 0; // not used ++ add_timer(&acerhk_timer_blinking); ++ acerhk_blueled_blinking = 0; ++ if (verbose) ++ printk(KERN_INFO "acerhk: starting blueled blinking\n"); ++ } else ++ if (verbose) ++ printk(KERN_INFO "acerhk: blueled already blinking\n"); ++} ++ ++/* Added by Antonio Cuni */ ++static void stop_blinking(void) ++{ ++ if (acerhk_blueled_blinking != -1) { ++ del_timer(&acerhk_timer_blinking); ++ if (verbose) ++ printk(KERN_INFO "acerhk: blueled blinking stopped\n"); ++ acerhk_blueled_blinking = -1; ++ } ++} ++ ++static void release_input(void) ++{ ++ stop_polling(); ++ input_unregister_device(acerhk_input_dev_ptr); ++} ++ ++/* }}} */ ++ ++/* {{{ procfs functions */ ++ ++#ifndef CONFIG_PROC_FS ++ ++static int acerhk_proc_init(void) ++{ ++ return 1; ++} ++#else ++ ++/* This macro frees the machine specific function from bounds checking and ++ * things like that... */ ++#define PRINT_PROC(fmt,args...) \ ++ do { \ ++ *len += sprintf( buffer+*len, fmt, ##args ); \ ++ if (*begin + *len > offset + size) \ ++ return( 0 ); \ ++ if (*begin + *len < offset) { \ ++ *begin += *len; \ ++ *len = 0; \ ++ } \ ++ } while(0) ++ ++static int pc_proc_infos( char *buffer, int *len, ++ off_t *begin, off_t offset, int size ) ++{ ++ PRINT_PROC( "Acer hotkeys version %s\n", ACERHK_VERSION); ++ PRINT_PROC( "Model(Type)\t: %s(", acerhk_model_string); ++ switch(acerhk_type) { ++ default: ++ PRINT_PROC( "unknown)\n"); ++ break; ++ case TM_old: ++ PRINT_PROC( "old)\n"); ++ break; ++ case TM_new: ++ PRINT_PROC( "new)\n"); ++ break; ++ case TM_dritek: ++ PRINT_PROC( "Dritek)\n"); ++ break; ++ } ++ if (bios_routine != 0) { ++ PRINT_PROC( "request handler\t: 0x%x\n", bios_routine); ++ if (cmos_index) { ++ PRINT_PROC( "CMOS index\t: 0x%x\n", cmos_index); ++ PRINT_PROC( "events pending\t: %u\n", get_nr_events()); ++ } else { ++ PRINT_PROC( "CMOS index\t: not available\n"); ++ } ++ if (acerhk_polling_state == 1) ++ PRINT_PROC( "kernel polling\t: active\n"); ++ else ++ PRINT_PROC( "kernel polling\t: inactive\n"); ++ PRINT_PROC( "autoswitch wlan\t: "); ++ if (autowlan == 1) ++ PRINT_PROC( "enabled\n"); ++ else ++ PRINT_PROC( "disabled\n"); ++ } else { ++ PRINT_PROC( "request handler\t: not found\n"); ++ PRINT_PROC( "kernel polling\t: not possible\n"); ++ } ++ /* model specific infos */ ++ if (acerhk_type == TM_dritek) { ++ PRINT_PROC( "use of Dritek EC: "); ++ if (usedritek) ++ PRINT_PROC( "enabled\n"); ++ else ++ PRINT_PROC( "disabled\n"); ++ } ++ if (acerhk_type == TM_old) ++ PRINT_PROC( "preg400\t\t: 0x%p\n", preg400); ++ return (1); ++} ++ ++static int acerhk_proc_info( char *buffer, char **start, off_t offset, ++ int size, int *eof, void *data ) ++{ ++ int len = 0; ++ off_t begin = 0; ++ ++ *eof = pc_proc_infos( buffer, &len, &begin, offset, size ); ++ ++ if (offset >= begin + len) ++ return( 0 ); ++ *start = buffer + (offset - begin); ++ return( size < begin + len - offset ? size : begin + len - offset ); ++ ++} ++ ++static int acerhk_proc_key( char *buffer, char **start, off_t offset, ++ int size, int *eof, void *data ) ++{ ++ if (size >= 5 && offset == 0) { ++ if (acerhk_type == TM_dritek || acerhk_polling_state == 1) { ++ snprintf(buffer+offset, size, "n/a\n"); ++ } else { ++ snprintf(buffer+offset, size, "0x%02x\n", filter_idle_value(get_fnkey_event())); ++ } ++ *eof = 1; ++ return 5; ++ } ++ *eof = 1; ++ return 0; ++} ++ ++static int acerhk_proc_led(struct file* file, const char* buffer, ++ unsigned long count, void* data) ++{ ++ char str[4]; ++ int len; ++ if (count > 4) ++ len = 4; ++ else ++ len = count; ++ if (copy_from_user(str, buffer, len)) ++ return -EFAULT; ++ str[3] = '\0'; ++ if ( ( (len >= 2) && (!strncmp(str, "on", 2) || !strncmp(str, "an", 2)) ) ++ || str[0] == '1') ++ set_mail_led(1); ++ else ++ set_mail_led(0); ++ return len; ++} ++ ++static int acerhk_proc_wirelessled(struct file* file, const char* buffer, ++ unsigned long count, void* data) ++{ ++ char str[4]; ++ int len; ++ if (count > 4) ++ len = 4; ++ else ++ len = count; ++ if (copy_from_user(str, buffer, len)) ++ return -EFAULT; ++ str[3] = '\0'; ++ if ( ( (len >= 2) && (!strncmp(str, "on", 2) || !strncmp(str, "an", 2)) ) ++ || str[0] == '1') { ++ if (acerhk_model_features & TM_F_WLAN_EC1) ++ enable_wlan_ec_1(); ++ else if (acerhk_model_features & TM_F_WLAN_EC2) ++ enable_wlan_ec_2(); ++ else ++ wbutton_fct_2(1); ++ } ++ else { ++ if (acerhk_model_features & TM_F_WLAN_EC1) ++ disable_wlan_ec_1(); ++ else if (acerhk_model_features & TM_F_WLAN_EC2) ++ disable_wlan_ec_2(); ++ else ++ wbutton_fct_2(0); ++ } ++ return len; ++} ++ ++ ++/* Modified by Antonio Cuni: added support for blinking ++ possible values: ++ - off, 0: led always off ++ - on, an, 1: led alway on ++ - n (a number): led blinking; n is the delay between ++ two changes of state, in jiffies; n must ++ be > 50, to prevent the user from overloading ++ the kernel. ++ ++ */ ++static int acerhk_proc_blueled(struct file* file, const char* buffer, ++ unsigned long count, void* data) ++{ ++ const int MAXLEN=11; ++ char str[MAXLEN]; ++ int len; ++ int isNumber; ++ ++ if (count > MAXLEN) ++ len = MAXLEN; ++ else ++ len = count; ++ if (copy_from_user(str, buffer, len)) ++ return -EFAULT; ++ str[MAXLEN - 1] = '\0'; ++ ++ /* try to parse a number */ ++ isNumber = sscanf(str, "%u", &acerhk_blueled_blinking_delay); ++ /* if the delay is 0, turn off the led */ ++ if (isNumber && acerhk_blueled_blinking_delay != 0 && acerhk_blueled_blinking_delay != 1) { ++ if (acerhk_blueled_blinking_delay < 50) ++ printk(KERN_INFO"acerhk: blinking request rejected. The delay must be > 50.\n"); ++ else { ++ if (verbose) ++ printk(KERN_INFO"acerhk: blinking delay set to %u.\n", acerhk_blueled_blinking_delay); ++ start_blinking(); ++ } ++ } else if (acerhk_blueled_blinking_delay == 1 || !strncmp(str, "on", 2) || !strncmp(str, "an", 2)) { ++ stop_blinking(); ++ if (acerhk_model_features & TM_F_BLUE_EC1) ++ enable_bluetooth_ec_1(); ++ else if (acerhk_model_features & TM_F_BLUE_EC2) ++ enable_bluetooth_ec_2(); ++ else ++ wbutton_fct_1(1); ++ } else { ++ /* it's 0 or everything else */ ++ stop_blinking(); ++ if (acerhk_model_features & TM_F_BLUE_EC1) ++ disable_bluetooth_ec_1(); ++ else if (acerhk_model_features & TM_F_BLUE_EC2) ++ disable_bluetooth_ec_2(); ++ else ++ wbutton_fct_1(0); ++ } ++ return len; ++} ++ ++#ifdef ACERDEBUG ++static void do_debug(const char* buffer, unsigned long len) ++{ ++ unsigned int h, i; ++ switch (buffer[0]) { ++ case 'b': ++ /* test WLAN on TM 4001 */ ++ switch (buffer[1]) { ++ case '0': ++ disable_wlan_ec_1(); ++ break; ++ case '1': ++ default: ++ enable_wlan_ec_1(); ++ } ++ break; ++ case 'B': ++ /* test BLUETOOTH on TM 4001 */ ++ switch (buffer[1]) { ++ case '0': ++ disable_bluetooth_ec_1(); ++ break; ++ case '1': ++ default: ++ enable_bluetooth_ec_1(); ++ } ++ break; ++ case 'D': ++ /* test "DMM Function Enabled" entry of TM 4150/4650 */ ++ enable_dmm_function(); ++ break; ++ case 'i': ++ case '1': ++#ifndef KERNEL26 ++ MOD_INC_USE_COUNT; ++#endif ++ break; ++ case 'e': ++ switch (buffer[1]) { ++ case '1': ++ start_polling(); ++ break; ++ default: ++ stop_polling(); ++ } ++ break; ++ case 'k': ++ for (i = 0; i <= 255;i++) { ++ input_report_key(acerhk_input_dev_ptr, i, 1); ++ input_report_key(acerhk_input_dev_ptr, i, 0); ++ } ++ break; ++ case 'm': ++ /* set mapping key names -> input events */ ++ sscanf(&buffer[2],"%x", &i); ++ h = buffer[1] - '0' + 1; ++ printk("acerhk: key name %x maps to %x\n", h, i); ++ acerhk_name2event[h] = i; ++ break; ++ case 'M': ++ /* test mute LED on dritek hardware */ ++ switch (buffer[1]) { ++ case '0': ++ disable_mute_led_ec(); ++ break; ++ case '1': ++ default: ++ enable_mute_led_ec(); ++ } ++ break; ++ case 'p': ++ printk("acerhk: pbutton = 0x%x\n", pbutton_fct()); ++ break; ++ case 's': ++ /* send key event to test the key translation in input system */ ++ sscanf(&buffer[1],"%x", &h); ++ printk("acerhk: sending key event 0x%x\n", h); ++ input_report_key(acerhk_input_dev_ptr, h, 1); ++ input_report_key(acerhk_input_dev_ptr, h, 0); ++ break; ++ case 'S': ++ /* simulate key codes to test the key translation in acerhk */ ++ sscanf(&buffer[1],"%x", &h); ++ send_key_event(transl8_key_code(h)); ++ break; ++ case 't': ++ printk("acerhk: thermal event = 0x%x\n", get_thermal_event()); ++ break; ++ case 'w': ++ /* test the wbutton functions, someone really needs to have another look ++ at the windows driver */ ++ switch (buffer[1]) { ++ case '2': ++ printk("acerhk: wbutton_2(%d) = 0x%x\n", buffer[2]-'0', wbutton_fct_2(buffer[2]-'0')); ++ break; ++ case '1': ++ default: ++ printk("acerhk: wbutton_1(%d) = 0x%x\n", buffer[2]-'0', wbutton_fct_1(buffer[2]-'0')); ++ } ++ break; ++ case 'W': ++ /* test wireless HW/LED on some models using dritek hardware */ ++ switch (buffer[1]) { ++ case '0': ++ disable_wireless_ec(); ++ break; ++ case '1': ++ default: ++ enable_wireless_ec(); ++ } ++ break; ++ case 'v': ++ verbose = buffer[1]-'0'; ++ printk("acerhk: verbosity level changed to %d\n", verbose); ++ break; ++ case 'd': ++ case '0': ++ default: ++#ifndef KERNEL26 ++ MOD_DEC_USE_COUNT; ++#endif ++ break; ++ } ++} ++ ++static int acerhk_proc_debug(struct file* file, const char* buffer, ++ unsigned long count, void* data) ++{ ++ char str[5]; ++ int len; ++ if (count > 5) ++ len = 5; ++ else ++ len = count; ++ if (copy_from_user(str, buffer, len)) ++ return -EFAULT; ++ str[4] = '\0'; ++ do_debug(str, len); ++ return len; ++} ++#endif ++ ++static int acerhk_proc_init(void) ++{ ++ int retval; ++ struct proc_dir_entry *entry; ++ /* create own directory */ ++ proc_acer_dir = proc_mkdir("driver/acerhk", NULL); ++ if (proc_acer_dir == NULL) { ++ retval = 0; ++ printk(KERN_INFO"acerhk: could not create /proc/driver/acerhk\n"); ++ } ++ else { ++ proc_acer_dir->owner = THIS_MODULE; ++ /* now create several files, first general info ... */ ++ entry = create_proc_read_entry("info", ++ 0444, proc_acer_dir, acerhk_proc_info, NULL); ++ if (entry == NULL) { ++ printk(KERN_INFO"acerhk: cannot create info file\n"); ++ remove_proc_entry("driver/acerhk", NULL); ++ retval = 0; ++ } else { ++ entry->owner = THIS_MODULE; ++ /* ... last pressed key ... */ ++ entry = create_proc_read_entry("key", ++ 0444, proc_acer_dir, acerhk_proc_key, NULL); ++ if (entry == NULL) { ++ printk(KERN_INFO"acerhk: cannot create key file\n"); ++ remove_proc_entry("info", proc_acer_dir); ++ remove_proc_entry("driver/acerhk", NULL); ++ retval = 0; ++ } else { ++ entry->owner = THIS_MODULE; ++ /* ... and led control file */ ++ entry = create_proc_entry("led", 0222, proc_acer_dir); ++ if (entry == NULL) { ++ printk(KERN_INFO"acerhk: cannot create LED file\n"); ++ remove_proc_entry("info", proc_acer_dir); ++ remove_proc_entry("key", proc_acer_dir); ++ remove_proc_entry("driver/acerhk", NULL); ++ retval = 0; ++ } ++ else { ++ entry->write_proc = acerhk_proc_led; ++ entry->owner = THIS_MODULE; ++ /* ... and wireless led controll file */ ++ entry = create_proc_entry("wirelessled", 0222, proc_acer_dir); ++ if (entry == NULL) { ++ printk(KERN_INFO"acerhk: cannot create wirelessled file\n"); ++ remove_proc_entry("info", proc_acer_dir); ++ remove_proc_entry("key", proc_acer_dir); ++ remove_proc_entry("led", proc_acer_dir); ++ remove_proc_entry("driver/acerhk", NULL); ++ retval = 0; ++ } ++ else { ++ entry->write_proc = acerhk_proc_wirelessled; ++ entry->owner = THIS_MODULE; ++ /* ... and bluetooth led controll file */ ++ entry = create_proc_entry("blueled", 0222, proc_acer_dir); ++ if (entry == NULL) { ++ printk(KERN_INFO"acerhk: cannot create blueled file\n"); ++ remove_proc_entry("info", proc_acer_dir); ++ remove_proc_entry("key", proc_acer_dir); ++ remove_proc_entry("led", proc_acer_dir); ++ remove_proc_entry("wirelessled", proc_acer_dir); ++ remove_proc_entry("driver/acerhk", NULL); ++ retval = 0; ++ } else { ++ entry->write_proc = acerhk_proc_blueled; ++ entry->owner = THIS_MODULE; ++ retval = 1; ++#ifdef ACERDEBUG ++ /* add extra file for debugging purposes */ ++ entry = create_proc_entry("debug", 0222, proc_acer_dir); ++ if (entry == NULL) { ++ printk(KERN_INFO"acerhk: cannot create debug file\n"); ++ remove_proc_entry("info", proc_acer_dir); ++ remove_proc_entry("key", proc_acer_dir); ++ remove_proc_entry("led", proc_acer_dir); ++ remove_proc_entry("wirelessled", proc_acer_dir); ++ remove_proc_entry("blueled", proc_acer_dir); ++ remove_proc_entry("driver/acerhk", NULL); ++ retval = 0; ++ } ++ else { ++ entry->write_proc = acerhk_proc_debug; ++ entry->owner = THIS_MODULE; ++ retval = 1; ++ } ++#endif ++ } ++ } ++ } ++ } ++ } ++ } ++ return retval; ++} ++ ++static void acerhk_proc_cleanup(void) ++{ ++ if (proc_acer_dir) { ++ remove_proc_entry("info", proc_acer_dir); ++ /* On dritek type hardware key file is already removed */ ++ if (acerhk_type != TM_dritek) ++ remove_proc_entry("key", proc_acer_dir); ++ remove_proc_entry("led", proc_acer_dir); ++ remove_proc_entry("wirelessled", proc_acer_dir); ++ remove_proc_entry("blueled", proc_acer_dir); ++#ifdef ACERDEBUG ++ remove_proc_entry("debug", proc_acer_dir); ++#endif ++ remove_proc_entry("driver/acerhk", NULL); ++ proc_acer_dir = NULL; ++ } ++} ++ ++#endif /* CONFIG_PROC_FS */ ++ ++/* }}} */ ++ ++/* {{{ file operations */ ++ ++static int acerhk_ioctl( struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg ) ++{ ++ int retval; ++ switch( cmd ) { ++ case ACERHK_GET_KEYCOUNT: ++ { ++ char nr; ++ nr = get_nr_events(); ++ put_user(nr, (char*)arg); ++ retval = 0; ++ break; ++ } ++ case ACERHK_GET_KEYID: ++ { ++ char id; ++ id = get_fnkey_event(); ++ put_user(id, (char*)arg); ++ retval = 0; ++ break; ++ } ++ case ACERHK_CONNECT: ++ launch_connect(1); ++ retval = 0; ++ break; ++ case ACERHK_START_POLLING: ++ start_polling(); ++ retval = 0; ++ break; ++ case ACERHK_STOP_POLLING: ++ stop_polling(); ++ retval = 0; ++ break; ++ case ACERHK_DISCONNECT: ++ launch_connect(0); ++ retval = 0; ++ break; ++ case ACERHK_GET_THERMAL_EVENT: ++ { ++ short event; ++ event = get_thermal_event(); ++ put_user(event, (short*)arg); ++ retval = 0; ++ break; ++ } ++ case ACERHK_MAIL_LED_OFF: ++ set_mail_led(0); ++ retval = 0; ++ break; ++ case ACERHK_MAIL_LED_ON: ++ set_mail_led(1); ++ retval = 0; ++ break; ++ case ACERHK_GET_KEY_MAP: ++ if (copy_to_user((t_map_name2event*)arg, &acerhk_name2event, sizeof(acerhk_name2event))) ++ retval = -EFAULT; ++ else ++ retval = 0; ++ break; ++ case ACERHK_SET_KEY_MAP: ++ if (copy_from_user(&acerhk_name2event, (t_map_name2event*)arg, sizeof(acerhk_name2event))) ++ retval = -EFAULT; ++ else { ++ if (verbose) { ++ printk(KERN_INFO"acerhk: changed key mapping\n"); ++ print_mapping(); ++ } ++ retval = 0; ++ } ++ break; ++ default: ++ retval = -EINVAL; ++ } ++ return retval; ++} ++ ++#ifdef ACERDEBUG ++static ssize_t acerhk_write (struct file* file, const char* buffer, size_t length, loff_t* offset) ++{ ++ if (length) ++ do_debug(buffer, length); ++ return length; ++} ++#endif ++ ++static int acerhk_open( struct inode *inode, struct file *file ) ++{ ++ return 0; ++} ++ ++static int acerhk_release( struct inode *inode, struct file *file ) ++{ ++ return 0; ++} ++ ++static struct file_operations acerhk_fops = { ++ owner: THIS_MODULE, ++ ioctl: acerhk_ioctl, ++ open: acerhk_open, ++#ifdef ACERDEBUG ++ write: acerhk_write, ++#endif ++ release: acerhk_release, ++}; ++ ++static struct miscdevice acerhk_dev = { ++ MISC_DYNAMIC_MINOR, ++ "acerhk", ++ &acerhk_fops ++}; ++ ++/* }}} */ ++ ++static void __init model_init(void) ++{ ++ /* set callroutine, features and keymap for model */ ++ setup_model_features(acerhk_series); ++ /* override initial state of wireless hardware if specified by module options */ ++ if (wlan_state >= 0) acerhk_wlan_state = wlan_state; ++ if (bluetooth_state >= 0) acerhk_bluetooth_state = bluetooth_state; ++ /* Launch connect only if available */ ++ if (acerhk_model_features & TM_F_CONNECT) { ++ if (verbose) ++ printk(KERN_INFO"acerhk: Model type %d, calling launch_connect(1)\n", ++ acerhk_type); ++ launch_connect(1); ++ } ++ if ( acerhk_type != TM_dritek ) { ++ get_cmos_index(); ++ } ++ if ( acerhk_type == TM_dritek ) { ++ enable_dritek_keyboard(); ++ } ++ /* added by Antonio Cuni */ ++ init_timer(&acerhk_timer_blinking); ++} ++ ++ ++static void __exit acerhk_cleanup_module (void); ++static int __init acerhk_init(void) ++{ ++ int ret; ++ ++ ret = misc_register( &acerhk_dev ); ++ if (ret) { ++ printk(KERN_ERR "acerhk: can't misc_register on minor=%d\n", ACERHK_MINOR); ++ ret = -EAGAIN; ++ } ++ else if (!acerhk_proc_init()) { ++ printk(KERN_ERR "acerhk: can't create procfs entries\n"); ++ ret = -ENOMEM; ++ misc_deregister( &acerhk_dev ); ++ } ++ else { ++ reg1 = ioremap(0xf0000, 0xffff); ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: area from 0xf000 to 0xffff mapped to %p\n", reg1); ++ reg2 = ioremap(0xe0000, 0xffff); ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: area from 0xe000 to 0xffff mapped to %p\n", reg2); ++ /* the area 0x400 is used as data area by earlier (520) series */ ++ preg400 = ioremap(0x400, 0xfff); ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: area from 0x400 to 0x13ff mapped to %p\n", preg400); ++ /* attach to input system */ ++ init_input(); ++ memset(acerhk_model_string, 0x00, ACERHK_MODEL_STRLEN); ++#ifdef DUMMYHW ++ acerhk_model_addr = (void*)0x12345678; ++ /* copy the string, but not more than 15 characters */ ++ strncpy(acerhk_model_string, "TravelmateDummy", ACERHK_MODEL_STRLEN-1); ++ /* set callroutine for model */ ++ if (force_series) ++ acerhk_series = force_series; ++ else ++ acerhk_series = 2000; ++ setup_model_features(acerhk_series); ++ printk(KERN_INFO "Acer Travelmate hotkey driver v" ACERHK_VERSION " dummy\n"); ++ if ( acerhk_type == TM_dritek ) ++ enable_dritek_keyboard(); ++ if (poll) ++ start_polling(); ++ init_timer(&acerhk_timer_blinking); ++#else ++ bios_routine = find_hk_area(); ++ if (!force_series) ++ probe_model(); ++ else { ++ if (verbose) ++ printk(KERN_INFO"acerhk: forced laptop series to %d\n", force_series); ++ acerhk_series = force_series; ++ } ++ /* do model specific initialization */ ++ model_init(); ++ /* Without a bios routine we cannot do anything except on dritek ++ type HW, unload on other types */ ++ if (bios_routine || (acerhk_type == TM_dritek)) { ++ ret = 0; ++ if (verbose && bios_routine) ++ printk(KERN_INFO"acerhk: bios routine found at 0x%x\n", bios_routine); ++ printk(KERN_INFO "Acer Travelmate hotkey driver v" ACERHK_VERSION "\n"); ++ /* If automatic switching of wlan is wanted but polling is disabled, ++ automatically enable it */ ++ if (!poll && autowlan) { ++ printk(KERN_INFO "Automatic switching of wireless hardware needs polling, enabling it\n"); ++ poll = 1; ++ } ++ /* start automatic polling of key presses if wanted and bios routine found */ ++ if (poll && bios_routine) ++ start_polling(); ++ } else { ++ printk(KERN_ERR "acerhk: can't find bios routine, cannot do anything for you, sorry!\n"); ++ ret = -ENOMEM; ++ acerhk_cleanup_module(); ++ } ++#endif ++ } ++ return ret; ++} ++ ++static void __exit acerhk_cleanup_module (void) ++{ ++ acerhk_proc_cleanup(); ++ stop_blinking(); ++ if (reg1) ++ iounmap(reg1); ++ if (reg2) ++ iounmap(reg2); ++ if (preg400) ++ iounmap(preg400); ++ release_input(); ++ misc_deregister( &acerhk_dev ); ++ if ( acerhk_type == TM_dritek ) { ++ disable_dritek_keyboard(); ++ } ++ if (verbose > 2) ++ printk(KERN_INFO "acerhk: unloaded\n"); ++} ++ ++module_init(acerhk_init); ++module_exit(acerhk_cleanup_module); ++ ++MODULE_AUTHOR("Olaf Tauber"); ++MODULE_DESCRIPTION("AcerHotkeys extra buttons keyboard driver"); ++MODULE_LICENSE("GPL"); ++ ++#ifndef KERNEL26 ++EXPORT_NO_SYMBOLS; ++#endif ++ ++#else ++#error This driver is only available for X86 architecture ++#endif ++/* ++ * Local variables: ++ * c-indent-level: 4 ++ * tab-width: 4 ++ * End: ++ */ ++ +diff -Nurp linux-2.6.37/3rdparty/acerhk/acerhk.h linux-2.6.37.3rdparty/3rdparty/acerhk/acerhk.h +--- linux-2.6.37/3rdparty/acerhk/acerhk.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/acerhk.h 2005-06-17 00:10:12.000000000 +0300 +@@ -0,0 +1,91 @@ ++#ifndef __ACERHK_H__ ++#define __ACERHK_H__ ++ ++#include ++ ++#define ACERHK_MINOR MISC_DYNAMIC_MINOR ++ ++#define ACERHK_GET_KEYCOUNT _IOR('p', 0x01, char) /* Get number of cached key presses */ ++#define ACERHK_GET_KEYID _IOR('p', 0x02, char) /* Get first key in queue */ ++#define ACERHK_CONNECT _IO('p', 0x03) /* ? */ ++#define ACERHK_DISCONNECT _IO('p', 0x04) /* ? */ ++#define ACERHK_GET_THERMAL_EVENT _IOR('p', 0x05, short) /* ? */ ++#define ACERHK_MAIL_LED_OFF _IO('p', 0x10) /* switch mail LED off */ ++#define ACERHK_MAIL_LED_ON _IO('p', 0x11) /* switch mail LED on (blinking) */ ++#define ACERHK_START_POLLING _IO('p', 0x12) /* poll keys in kernel, send real key events */ ++#define ACERHK_STOP_POLLING _IO('p', 0x13) /* stop key polling in kernel */ ++#define ACERHK_GET_KEY_MAP _IOR('p', 0x20, int) /* Get mapping of key names to key events, */ ++#define ACERHK_SET_KEY_MAP _IOW('p', 0x21, int) /* Set mapping of key names to key events */ ++ ++/* all possible keys (known to me) */ ++typedef enum e_key_names { ++ k_none = 0, ++ k_help = 1, /* Fn+F1 */ ++ k_setup = 2, /* Fn+F2 */ ++ k_p1 = 3, ++ k_p2 = 4, ++ k_p3 = 5, ++ k_www = 6, ++ k_mail = 7, ++ k_wireless = 8, ++ k_power = 9, /* Fn+F3 */ ++ k_mute = 10, /* Fn+F8 */ ++ k_volup = 11, /* Fn+Up */ ++ k_voldn = 12, /* Fn+Down */ ++ k_res = 13, /* resolution change on Medion MD 40100 */ ++ k_close = 14, /* if lid is closed in tablet mode */ ++ k_open = 15, /* if lid is opend in tablet mode */ ++ k_wireless2 = 16, /* second wireless button on TM 243LC */ ++ k_play = 17, /* Play/Pause found on AOpen */ ++ k_stop = 18, /* Stop/Eject found on AOpen */ ++ k_prev = 19, /* Prev found on AOpen */ ++ k_next = 20, /* Next found on AOpen */ ++ k_display = 21 /* Change internal/external display on MD 42200 */ ++} t_key_names; ++#define NR_KEY_NAMES 22 ++typedef unsigned int t_map_name2event[NR_KEY_NAMES]; ++ ++#ifdef __KERNEL__ ++ ++/* available features */ ++#define TM_F_WLAN_EC1 0x00000010 ++#define TM_F_BLUE_EC1 0x00000020 ++#define TM_F_WLAN_EC2 0x00000040 ++#define TM_F_BLUE_EC2 0x00000080 ++#define TM_F_MUTE_LED_EC 0x00001000 ++#define TM_F_MAIL_LED 0x00010000 ++#define TM_F_MAIL_LED_EC 0x00020000 ++#define TM_F_MAIL_LED_EC2 0x00040000 ++#define TM_F_MAIL_LED_EC3 0x00080000 ++ ++#define TM_F_CONNECT 0x00100000 ++#define TM_F_THERMAL 0x00200000 ++#define TM_F_PBUTTON 0x00400000 ++#define TM_F_WBUTTON 0x00800000 ++ ++typedef enum acer_type { ++ TM_unknown, ++ /* 200, 210, 520, 600 and 730 series, Medion MD42200 */ ++ TM_old, ++ /* C100, C110, 220, 230, 240, 260, 350, 360, 610, 620, 630, 740 series ++ Medion MD40100, Aspire 1600, FS Amilo */ ++ TM_new, ++ /* Aspire 13xx, 14xx, 1700, TM 290, 650, 660, 800 */ ++ TM_dritek ++} t_acer_type; ++ ++struct register_buffer { ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ unsigned int edi; ++ unsigned int esi; ++ unsigned int ebp; ++}; ++ ++typedef asmlinkage void (*bios_call) (struct register_buffer *); ++ ++#endif ++ ++#endif +diff -Nurp linux-2.6.37/3rdparty/acerhk/AUTHORS linux-2.6.37.3rdparty/3rdparty/acerhk/AUTHORS +--- linux-2.6.37/3rdparty/acerhk/AUTHORS 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/AUTHORS 2006-11-10 00:02:55.000000000 +0200 +@@ -0,0 +1 @@ ++Olaf Tauber +\ Ingen nyrad vid filslut +diff -Nurp linux-2.6.37/3rdparty/acerhk/COPYING linux-2.6.37.3rdparty/3rdparty/acerhk/COPYING +--- linux-2.6.37/3rdparty/acerhk/COPYING 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/COPYING 2002-05-08 22:01:52.000000000 +0300 +@@ -0,0 +1,340 @@ ++ GNU GENERAL PUBLIC LICENSE ++ Version 2, June 1991 ++ ++ Copyright (C) 1989, 1991 Free Software Foundation, Inc. ++ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ Everyone is permitted to copy and distribute verbatim copies ++ of this license document, but changing it is not allowed. ++ ++ Preamble ++ ++ The licenses for most software are designed to take away your ++freedom to share and change it. By contrast, the GNU General Public ++License is intended to guarantee your freedom to share and change free ++software--to make sure the software is free for all its users. This ++General Public License applies to most of the Free Software ++Foundation's software and to any other program whose authors commit to ++using it. (Some other Free Software Foundation software is covered by ++the GNU Library General Public License instead.) You can apply it to ++your programs, too. ++ ++ When we speak of free software, we are referring to freedom, not ++price. Our General Public Licenses are designed to make sure that you ++have the freedom to distribute copies of free software (and charge for ++this service if you wish), that you receive source code or can get it ++if you want it, that you can change the software or use pieces of it ++in new free programs; and that you know you can do these things. ++ ++ To protect your rights, we need to make restrictions that forbid ++anyone to deny you these rights or to ask you to surrender the rights. ++These restrictions translate to certain responsibilities for you if you ++distribute copies of the software, or if you modify it. ++ ++ For example, if you distribute copies of such a program, whether ++gratis or for a fee, you must give the recipients all the rights that ++you have. You must make sure that they, too, receive or can get the ++source code. And you must show them these terms so they know their ++rights. ++ ++ We protect your rights with two steps: (1) copyright the software, and ++(2) offer you this license which gives you legal permission to copy, ++distribute and/or modify the software. ++ ++ Also, for each author's protection and ours, we want to make certain ++that everyone understands that there is no warranty for this free ++software. If the software is modified by someone else and passed on, we ++want its recipients to know that what they have is not the original, so ++that any problems introduced by others will not reflect on the original ++authors' reputations. ++ ++ Finally, any free program is threatened constantly by software ++patents. We wish to avoid the danger that redistributors of a free ++program will individually obtain patent licenses, in effect making the ++program proprietary. To prevent this, we have made it clear that any ++patent must be licensed for everyone's free use or not licensed at all. ++ ++ The precise terms and conditions for copying, distribution and ++modification follow. ++ ++ GNU GENERAL PUBLIC LICENSE ++ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ++ ++ 0. This License applies to any program or other work which contains ++a notice placed by the copyright holder saying it may be distributed ++under the terms of this General Public License. The "Program", below, ++refers to any such program or work, and a "work based on the Program" ++means either the Program or any derivative work under copyright law: ++that is to say, a work containing the Program or a portion of it, ++either verbatim or with modifications and/or translated into another ++language. (Hereinafter, translation is included without limitation in ++the term "modification".) Each licensee is addressed as "you". ++ ++Activities other than copying, distribution and modification are not ++covered by this License; they are outside its scope. The act of ++running the Program is not restricted, and the output from the Program ++is covered only if its contents constitute a work based on the ++Program (independent of having been made by running the Program). ++Whether that is true depends on what the Program does. ++ ++ 1. You may copy and distribute verbatim copies of the Program's ++source code as you receive it, in any medium, provided that you ++conspicuously and appropriately publish on each copy an appropriate ++copyright notice and disclaimer of warranty; keep intact all the ++notices that refer to this License and to the absence of any warranty; ++and give any other recipients of the Program a copy of this License ++along with the Program. ++ ++You may charge a fee for the physical act of transferring a copy, and ++you may at your option offer warranty protection in exchange for a fee. ++ ++ 2. You may modify your copy or copies of the Program or any portion ++of it, thus forming a work based on the Program, and copy and ++distribute such modifications or work under the terms of Section 1 ++above, provided that you also meet all of these conditions: ++ ++ a) You must cause the modified files to carry prominent notices ++ stating that you changed the files and the date of any change. ++ ++ b) You must cause any work that you distribute or publish, that in ++ whole or in part contains or is derived from the Program or any ++ part thereof, to be licensed as a whole at no charge to all third ++ parties under the terms of this License. ++ ++ c) If the modified program normally reads commands interactively ++ when run, you must cause it, when started running for such ++ interactive use in the most ordinary way, to print or display an ++ announcement including an appropriate copyright notice and a ++ notice that there is no warranty (or else, saying that you provide ++ a warranty) and that users may redistribute the program under ++ these conditions, and telling the user how to view a copy of this ++ License. (Exception: if the Program itself is interactive but ++ does not normally print such an announcement, your work based on ++ the Program is not required to print an announcement.) ++ ++These requirements apply to the modified work as a whole. If ++identifiable sections of that work are not derived from the Program, ++and can be reasonably considered independent and separate works in ++themselves, then this License, and its terms, do not apply to those ++sections when you distribute them as separate works. But when you ++distribute the same sections as part of a whole which is a work based ++on the Program, the distribution of the whole must be on the terms of ++this License, whose permissions for other licensees extend to the ++entire whole, and thus to each and every part regardless of who wrote it. ++ ++Thus, it is not the intent of this section to claim rights or contest ++your rights to work written entirely by you; rather, the intent is to ++exercise the right to control the distribution of derivative or ++collective works based on the Program. ++ ++In addition, mere aggregation of another work not based on the Program ++with the Program (or with a work based on the Program) on a volume of ++a storage or distribution medium does not bring the other work under ++the scope of this License. ++ ++ 3. You may copy and distribute the Program (or a work based on it, ++under Section 2) in object code or executable form under the terms of ++Sections 1 and 2 above provided that you also do one of the following: ++ ++ a) Accompany it with the complete corresponding machine-readable ++ source code, which must be distributed under the terms of Sections ++ 1 and 2 above on a medium customarily used for software interchange; or, ++ ++ b) Accompany it with a written offer, valid for at least three ++ years, to give any third party, for a charge no more than your ++ cost of physically performing source distribution, a complete ++ machine-readable copy of the corresponding source code, to be ++ distributed under the terms of Sections 1 and 2 above on a medium ++ customarily used for software interchange; or, ++ ++ c) Accompany it with the information you received as to the offer ++ to distribute corresponding source code. (This alternative is ++ allowed only for noncommercial distribution and only if you ++ received the program in object code or executable form with such ++ an offer, in accord with Subsection b above.) ++ ++The source code for a work means the preferred form of the work for ++making modifications to it. For an executable work, complete source ++code means all the source code for all modules it contains, plus any ++associated interface definition files, plus the scripts used to ++control compilation and installation of the executable. However, as a ++special exception, the source code distributed need not include ++anything that is normally distributed (in either source or binary ++form) with the major components (compiler, kernel, and so on) of the ++operating system on which the executable runs, unless that component ++itself accompanies the executable. ++ ++If distribution of executable or object code is made by offering ++access to copy from a designated place, then offering equivalent ++access to copy the source code from the same place counts as ++distribution of the source code, even though third parties are not ++compelled to copy the source along with the object code. ++ ++ 4. You may not copy, modify, sublicense, or distribute the Program ++except as expressly provided under this License. Any attempt ++otherwise to copy, modify, sublicense or distribute the Program is ++void, and will automatically terminate your rights under this License. ++However, parties who have received copies, or rights, from you under ++this License will not have their licenses terminated so long as such ++parties remain in full compliance. ++ ++ 5. You are not required to accept this License, since you have not ++signed it. However, nothing else grants you permission to modify or ++distribute the Program or its derivative works. These actions are ++prohibited by law if you do not accept this License. Therefore, by ++modifying or distributing the Program (or any work based on the ++Program), you indicate your acceptance of this License to do so, and ++all its terms and conditions for copying, distributing or modifying ++the Program or works based on it. ++ ++ 6. Each time you redistribute the Program (or any work based on the ++Program), the recipient automatically receives a license from the ++original licensor to copy, distribute or modify the Program subject to ++these terms and conditions. You may not impose any further ++restrictions on the recipients' exercise of the rights granted herein. ++You are not responsible for enforcing compliance by third parties to ++this License. ++ ++ 7. If, as a consequence of a court judgment or allegation of patent ++infringement or for any other reason (not limited to patent issues), ++conditions are imposed on you (whether by court order, agreement or ++otherwise) that contradict the conditions of this License, they do not ++excuse you from the conditions of this License. If you cannot ++distribute so as to satisfy simultaneously your obligations under this ++License and any other pertinent obligations, then as a consequence you ++may not distribute the Program at all. For example, if a patent ++license would not permit royalty-free redistribution of the Program by ++all those who receive copies directly or indirectly through you, then ++the only way you could satisfy both it and this License would be to ++refrain entirely from distribution of the Program. ++ ++If any portion of this section is held invalid or unenforceable under ++any particular circumstance, the balance of the section is intended to ++apply and the section as a whole is intended to apply in other ++circumstances. ++ ++It is not the purpose of this section to induce you to infringe any ++patents or other property right claims or to contest validity of any ++such claims; this section has the sole purpose of protecting the ++integrity of the free software distribution system, which is ++implemented by public license practices. Many people have made ++generous contributions to the wide range of software distributed ++through that system in reliance on consistent application of that ++system; it is up to the author/donor to decide if he or she is willing ++to distribute software through any other system and a licensee cannot ++impose that choice. ++ ++This section is intended to make thoroughly clear what is believed to ++be a consequence of the rest of this License. ++ ++ 8. If the distribution and/or use of the Program is restricted in ++certain countries either by patents or by copyrighted interfaces, the ++original copyright holder who places the Program under this License ++may add an explicit geographical distribution limitation excluding ++those countries, so that distribution is permitted only in or among ++countries not thus excluded. In such case, this License incorporates ++the limitation as if written in the body of this License. ++ ++ 9. The Free Software Foundation may publish revised and/or new versions ++of the General Public License from time to time. Such new versions will ++be similar in spirit to the present version, but may differ in detail to ++address new problems or concerns. ++ ++Each version is given a distinguishing version number. If the Program ++specifies a version number of this License which applies to it and "any ++later version", you have the option of following the terms and conditions ++either of that version or of any later version published by the Free ++Software Foundation. If the Program does not specify a version number of ++this License, you may choose any version ever published by the Free Software ++Foundation. ++ ++ 10. If you wish to incorporate parts of the Program into other free ++programs whose distribution conditions are different, write to the author ++to ask for permission. For software which is copyrighted by the Free ++Software Foundation, write to the Free Software Foundation; we sometimes ++make exceptions for this. Our decision will be guided by the two goals ++of preserving the free status of all derivatives of our free software and ++of promoting the sharing and reuse of software generally. ++ ++ NO WARRANTY ++ ++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY ++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN ++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES ++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED ++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS ++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE ++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, ++REPAIR OR CORRECTION. ++ ++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING ++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR ++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, ++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING ++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED ++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY ++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER ++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE ++POSSIBILITY OF SUCH DAMAGES. ++ ++ END OF TERMS AND CONDITIONS ++ ++ How to Apply These Terms to Your New Programs ++ ++ If you develop a new program, and you want it to be of the greatest ++possible use to the public, the best way to achieve this is to make it ++free software which everyone can redistribute and change under these terms. ++ ++ To do so, attach the following notices to the program. It is safest ++to attach them to the start of each source file to most effectively ++convey the exclusion of warranty; and each file should have at least ++the "copyright" line and a pointer to where the full notice is found. ++ ++ ++ Copyright (C) 19yy ++ ++ 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 ++ ++ ++Also add information on how to contact you by electronic and paper mail. ++ ++If the program is interactive, make it output a short notice like this ++when it starts in an interactive mode: ++ ++ Gnomovision version 69, Copyright (C) 19yy name of author ++ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. ++ This is free software, and you are welcome to redistribute it ++ under certain conditions; type `show c' for details. ++ ++The hypothetical commands `show w' and `show c' should show the appropriate ++parts of the General Public License. Of course, the commands you use may ++be called something other than `show w' and `show c'; they could even be ++mouse-clicks or menu items--whatever suits your program. ++ ++You should also get your employer (if you work as a programmer) or your ++school, if any, to sign a "copyright disclaimer" for the program, if ++necessary. Here is a sample; alter the names: ++ ++ Yoyodyne, Inc., hereby disclaims all copyright interest in the program ++ `Gnomovision' (which makes passes at compilers) written by James Hacker. ++ ++ , 1 April 1989 ++ Ty Coon, President of Vice ++ ++This General Public License does not permit incorporating your program into ++proprietary programs. If your program is a subroutine library, you may ++consider it more useful to permit linking proprietary applications with the ++library. If this is what you want to do, use the GNU Library General ++Public License instead of this License. +diff -Nurp linux-2.6.37/3rdparty/acerhk/doc/acertm.def linux-2.6.37.3rdparty/3rdparty/acerhk/doc/acertm.def +--- linux-2.6.37/3rdparty/acerhk/doc/acertm.def 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/doc/acertm.def 2003-08-24 19:46:37.000000000 +0300 +@@ -0,0 +1,56 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ Konfiguration ++ ++ Mute/Unmute ++ Lauter ++ Leiser ++ ++ Terminal ++ XEmacs ++ Play/Pause ++ Play/Pause ++ ++ ++ ++ +diff -Nurp linux-2.6.37/3rdparty/acerhk/doc/FAQ linux-2.6.37.3rdparty/3rdparty/acerhk/doc/FAQ +--- linux-2.6.37/3rdparty/acerhk/doc/FAQ 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/doc/FAQ 2005-11-10 19:45:33.000000000 +0200 +@@ -0,0 +1,150 @@ ++****************************************************************************** ++ ++Q: I have a (non Acer) notebook which is not recognized by your driver but I ++think it should. What information do you need? ++ ++A: If it is a non-Acer laptop I would like to know, what makes you think that ++your laptop would work with my driver. A windows driver/utility package of the ++name "LaunchManager" or "EasyButton" is a good hint. If it is clear that your ++hardware is okay, I need the string with your model name from BIOS. Please ++don't ask me how to do it. To find out which functions of your laptop the ++driver will support, it is best, if you can tell me where to get this ++"LaunchManager" or "EasyButton" package. ++If it is a model from 2003 or newer then chances are good that it's a dritek ++type one. In this case try the option "force_series=6000" to at least enable ++the keys. ++ ++****************************************************************************** ++ ++Q: Why can't I activate my wireless hardware on Acer TM 420/430/6000/8000 ...? ++ ++A: On many newer laptops (Dritek type) I do not now how to do this, ++sorry. Someone would need to find out how windows does it. Volunteers? ++ ++****************************************************************************** ++ ++Q: I know that wireless hardware is supported on my Aspire 1690/TravelMate4600, ++but I cannot get it to work, why? ++ ++A: On these model (and similar) the wireless hardware is controlled on two ++different levels. One is controlled by acerhk's xxxled file, the other level ++is controlled by the key itself. To actually activate the hardware you need to ++write '1' to the xxled file and you need to press the corresponding button. ++Example: ++echo 1 > /proc/driver/acerhk/wirelessled ++ ++ ++****************************************************************************** ++ ++Q: Why do I always get 0x00 from /proc/driver/acerhk/key? ++ ++A1: Check the type of your laptop if /proc/driver/acerhk/info. If it is ++"Dritek", you cannot read the keys from the driver. Starting from version ++0.5.17 you get "n/a" out of the key file in this case. ++A2: If you have polling enabled (default) you will almost always read 0x00 ++from this file. This is because in every polling cycle it is checked for key ++events and if there is one, it is instantly translated and sent to the kernel ++input system. Starting with version 0.5.20 you get "n/a" out of the key file ++in this case. ++ ++****************************************************************************** ++ ++Q: When I press a key, nothing happens. Why are they not working? ++ ++A: Most keys won't do anything by themself. If nothing happens, that is ++because no programm knows what to do with the new keys. You need to assign ++actions to them, use the hotkey manager of your desktop to do that. If ++using Gnome, you find it under desktop settings - keyboard shortcuts. ++ ++****************************************************************************** ++ ++Q: The driver works for my laptop, but not all of the keys are working. What ++can I do? ++ ++A: There are some keys/key combinations which generate an ACPI event, ++e.g. Fn+F4 on some models or the lid button. ++If you have a different laptop than the one which got detected (or you used ++"force_series=xxx" anyway), then it is possible that the mapping acerhk uses ++to translate the codes from the buttons to key events is wrong. ++In this case, load the driver with "verbose=4" and press the buttons which do ++not work. Then look for messages from acerhk of the form "translated acer key ++code xxx to no key". Note these codes together with the button they belong to ++and send me this list along with the model name of your laptop. ++If you do not see a usable name in /proc/driver/acerhk/info please try the ++tools dmidecode/biosdecode/vpddecode to find this name. ++ ++****************************************************************************** ++Q: I press the wireless key but the hardware doesn't get activated, what's wrong? ++ ++A: The driver is only on older models (non-Dritek type) able to read ++keypresses by itself and toggle the hardware/LED automatically (with option ++autowlan=1). On Dritek type models this must be done by writing the desired ++value to one of the wireless files in the proc filesystem. In most ++cases this would be /proc/drivers/acerhk/wirelessled to control wlan ++hardware (blueled for Bluetooth hardware): ++ ++echo 1 > /proc/driver/acerhk/wirelessled ++ ++But you could use a hotkey manager to do that automatically when you press the ++button. In this case be aware that on some models the button generates ++different key events according to the actual state of the wireless hardware. ++ ++****************************************************************************** ++ ++Q: My keys do not work, I only get kernel messages of the form: ++atkbd.c: Unknown key pressed (translated set 2, code 0xf4 on isa0060/serio0). ++atkbd.c: Use 'setkeycodes e074 ' to make it known. ++ ++A: Press each of the buttons and note the mentioned ++code for it (e074 in this example). You should get a list like this: ++P1 e074 ++P2 e075 ++... ++If you are finished with it, look into /usr/include/linux/input.h, using ++your favourite text viewer/editor. Search for "KEY_STOP". You should see ++the following line in the file: ++ ++#define KEY_STOP 128 ++ ++After it many more lines with equal #defines should be visible. Look for ++key names which best match the names of your buttons, e.g. KEY_PROG1, ++KEY_WWW and so on. Note the numbers assigned to the names, for KEY_STOP ++this would be 128, for KEY_PROG1 148. ++Now you have a list with three items per entry, your button, a code ++from the kernel messages and a corresponding number from the file ++linux.h: ++P1 e074 148 ++P2 e075 149 ++... ++For each line in this list, issue the setkeycodes command as mentioned ++in the kernel message: ++setkeycodes e074 148 ++setkeycodes e075 149 ++... ++After doing that, the keys should be available for your hotkey manager. ++ ++****************************************************************************** ++ ++Q: My WLAN hardware gets activated through /proc/driver/acerhk/wirelessled, ++but the LED is not working. Why not? ++ ++A: Try if adding the option "led=1" to your wireless module helps. For the ++ipw2200 driver it works, as Didier CLERC found out: ++ ++ I have to load the module "ipw2200" with the option "led=1", then ++ the wifi button blinks until a network is detected. ++ ++****************************************************************************** ++ ++Q: I have an unsupported laptop, but the driver works when I force the series ++to a type like 610 or 2100. Only my buttons doesn't get recognized, why? ++ ++A: On models of the type TM_new (like TravelMate 600, 2100 and many other, see ++acerhk.c, function setup_model_features for details) the buttons use different ++codes on different models. Therefore the driver needs to know these codes. You ++can get them if you load the driver with verbose=4, press the buttons and key ++combinations (Fn+xx) you are interested in and look for kernel messages of the ++form "acerhk: translated acer key code 0xnn to ...". Write down the key code ++for each button/key combination and send them to me so I can patch the ++driver. I also need your model string to make autodetection work, so include ++/proc/driver/acerk/info. +\ Ingen nyrad vid filslut +diff -Nurp linux-2.6.37/3rdparty/acerhk/doc/IOCTL linux-2.6.37.3rdparty/3rdparty/acerhk/doc/IOCTL +--- linux-2.6.37/3rdparty/acerhk/doc/IOCTL 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/doc/IOCTL 2004-01-31 22:38:17.000000000 +0200 +@@ -0,0 +1,61 @@ ++Documentation of possible IOCTLs used by acerhk +++++++++++++++++++++++++++++++++++++++++++++++++ ++ ++ACERHK_GET_KEYCOUNT ++ Read the number of unread key presses in queue ++ Parameter: pointer to char ++ ++ACERHK_GET_KEYID ++ Read the code of the first key press (oldest) in queue ++ Parameter: pointer to char ++ ++ACERHK_CONNECT ++ Don't know what it does, used in windows driver ++ ++ACERHK_DISCONNECT ++ Don't know what it does, used in windows driver ++ ++ACERHK_GET_THERMAL_EVENT ++ Don't know what it does, used in windows driver ++ Parameter: pointer to short ++ ++ACERHK_MAIL_LED_OFF ++ Switch off the LED of the mail button(if available) ++ ++ACERHK_MAIL_LED_ON ++ Switch on the LED of the mail button (if available) ++ ++ACERHK_START_POLLING ++ Start polling (and translation to key events) in kernel ++ ++ACERHK_STOP_POLLING ++ Stop polling in kernel ++ ++ACERHK_GET_KEY_MAP ++ Get mapping of key names to key events ++ Parameter: pointer to t_map_name2event ++ ++ACERHK_SET_KEY_MAP ++ Set mapping of key names to key events ++ Parameter: pointer to t_map_name2event ++ ++IOCTLs used by windows driver +++++++++++++++++++++++++++++++ ++device name: ++\DosDevices\HOTKEY ++\Device\HOTKEY ++ ++ ++630 series: ++0x222404 ++ Get CMOS index ++0x222408 ++ ACERHK_GET_KEYCOUNT ++0x22240C ++ ACERHK_GET_KEYID ++0x222410 ++ ACERHK_MAIL_LED_OFF/ACERHK_MAIL_LED_ON ++0x222414 ++ ACERHK_CONNECT/ACERHK_DISCONNECT ++0x222418 ++ ACERHK_GET_THERMAL_EVENT +diff -Nurp linux-2.6.37/3rdparty/acerhk/doc/keycodes linux-2.6.37.3rdparty/3rdparty/acerhk/doc/keycodes +--- linux-2.6.37/3rdparty/acerhk/doc/keycodes 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/doc/keycodes 2004-04-18 20:42:59.000000000 +0300 +@@ -0,0 +1,26 @@ ++standard X keycodes with older (acerhk controlled) hardware from Acer ++********************************************************************* ++help (Fn+F1) 226 ++setup (Fn+F2) 129 ++p1 153 ++p2 144 ++p3 171 ++www 178 ++mail 236 ++wireless 147 ++power (Fn+F3) 222 ++mute (Fn+F8) 166 ++volup (Fn+Up) 158 ++voldn (Fn+Down) 165 ++ ++standard X keycodes with newer (acerhk activated) hardware from Dritek ++********************************************************************** ++help (Fn+F1) 226 ++setup (Fn+F2) 129 ++p1 153 ++p2 144 ++www 178 ++mail 236 ++volup (Fn+Up) 176 ++voldn (Fn+Down) 174 ++mute (Fn+F8) 160 +diff -Nurp linux-2.6.37/3rdparty/acerhk/doc/md95400.def linux-2.6.37.3rdparty/3rdparty/acerhk/doc/md95400.def +--- linux-2.6.37/3rdparty/acerhk/doc/md95400.def 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/doc/md95400.def 2005-03-01 22:46:53.000000000 +0200 +@@ -0,0 +1,14 @@ ++ ++ ++ ++Mail ++Web ++Play/Pause ++Stop ++Previous ++Next ++Leiser ++Lauter ++ ++ ++ +diff -Nurp linux-2.6.37/3rdparty/acerhk/INSTALL linux-2.6.37.3rdparty/3rdparty/acerhk/INSTALL +--- linux-2.6.37/3rdparty/acerhk/INSTALL 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/INSTALL 2005-12-07 14:27:16.000000000 +0200 +@@ -0,0 +1,109 @@ ++Installation ++************ ++ ++1. You need the kernel sources (or kernel headers for your kernel) ++installed to compile the driver. ++ ++2. Your kernel needs loadable module support with version information for ++modules enabled. Usage of procfs is highly recommended. ++If you want the driver to generate regular keyboard events using ++kernel version 2.4 you need the input system of the kernel enabled ++(Input core support AND keyboard support). In kernel version 2.6 all ++needed functionality should be available by default. ++ ++In most cases you can skip the next step, the Makefile tries do determine ++the correct directory on its own. Change KERNELSRC only if the autodetection ++does not work for you. Otherwise proceed directly with step 4. ++ ++3. Before you compile the driver, change KERNELSRC in the makefile to your ++path to the kernel build environment. If you are using a self compiled kernel, ++point it to the root of your sources. If you are using a packaged kernel of ++your distribution, install the package with kernel headers ++(Debian:kernel-headers) and point KERNELSRC to where the headers and config ++files are located. If you are using Debian, this ++would be "/lib/modules//build". ++ ++4. Do: ++ make ++to compile the driver. If you run into problems because of the makefile not ++recognizing your kernel version correctly, try this: ++ make acerhk.o - kernel version 2.4 ++ make acerhk.ko - kernel version 2.6 ++ ++5. Do: ++ make install ++to automatically copy the driver into the kernel module library. If you've ++done so, proceed directly with step 8. If you want to install the module ++binary yourself (because you want a different location), use steps 6 and 7 ++instead. ++ ++6. Copy the created file "acerhk.o" ("acerhk.ko" with version 2.6) to your ++kernel modules path. In Debian this could be ++"/lib/modules//kernel/drivers/extra/". ++ ++7. Update module dependencies: depmod -a ++ ++8. Try loading the module with: ++ insmod/modprobe acerhk ++If it succeeds - congratulations! If you have procfs enabled, you can try the ++following to test the driver: ++ ++Non-Dritek models: ++Press one of the special keys and after that: ++ cat /proc/driver/acerhk/key ++to read the (hexadezimal) code of the key pressed. It should ++be different from 0x00. ++(Note: You mustn't have the polling feature enabled for this to work, so load ++ the module with poll=0) ++ ++Dritek-models: ++Press one of the special keys and look for the generated key with "xev". If ++there is none, then you should see at least kernel messages about using ++setkeycodes. ++ ++If your notebook has a mail led you can try this: ++ echo on > /proc/driver/acerhk/led ++This should sete the mail led to blinking mode. ++ echo off > /proc/driver/acerhk/led ++turns it off again. ++See README for further usage information. ++ ++If the module didn't load look into your kernel messages what went wrong. If ++you see something like the following lines: ++ acerhk: could not find request handler ++ acerhk: can't find ROM area ++ acerhk: unloaded ++then your hardware is not recognized. See README for supported models. If it ++won't work on your notebook, please contact me and I will see if I can fix ++that. ++ ++Integrating the driver into kernel tree version 2.6 ++*************************************************** ++ ++If you want the driver to fully integrate into the kernel tree of version 2.6 ++proceed as follows: ++1. Copy the acerhk directory into the source tree, for instance ++ /usr/src/linux/drivers/misc/acerhk ++2. Include the driver directory in the config files. Add to the Kconfig ++file of the parent directory(/usr/src/linux/drivers/misc/Kconfig): ++ ++config ACERHK ++ tristate "Acerhk driver" ++ depends on EXPERIMENTAL ++ ---help--- ++ This is an experimental acer keyboard driver for ++ acer laptops ++ ++3. Include the acer directory in it's parents ++Makefile(/usr/src/linux/drivers/misc/Makefile): ++ ++obj-$(CONFIG_ACERHK) += acerhk/ ++ ++4. In this case you also need to activate the misc drivers first ++(/usr/src/linux/drivers/Kconfig): ++ ++source "drivers/misc/Kconfig" ++ ++If that's done, you should be able to select the driver from the configuration ++programm and build the module. ++ +diff -Nurp linux-2.6.37/3rdparty/acerhk/Makefile linux-2.6.37.3rdparty/3rdparty/acerhk/Makefile +--- linux-2.6.37/3rdparty/acerhk/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/Makefile 2006-08-16 19:11:08.000000000 +0300 +@@ -0,0 +1,65 @@ ++# change KERNELSRC to the location of your kernel build tree only if ++# autodetection does not work ++#KERNELSRC=/usr/src/linux ++KERNELSRC?=/lib/modules/`uname -r`/build ++# Starting with 2.6.18, the kernel version is in utsrelease.h instead of version.h, accomodate both cases ++KERNELVERSION=$(shell awk -F\" '/REL/ {print $$2}' $(shell grep -s -l REL $(KERNELSRC)/include/linux/version.h $(KERNELSRC)/include/linux/utsrelease.h)) ++KERNELMAJOR=$(shell echo $(KERNELVERSION)|head -c3) ++ ++# next line is for kernel 2.6, if you integrate the driver in the kernel tree ++# /usr/src/linux/drivers/acerhk - or something similar ++# don't forget to add the following line to the parent dir's Makefile: ++# (/usr/src/linux/drivers/Makefile) ++# obj-m += acerhk/ ++CONFIG_ACERHK?=m ++obj-$(CONFIG_ACERHK) += acerhk.o ++ ++CFLAGS+=-c -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fomit-frame-pointer -fno-strict-aliasing -fno-common -pipe ++INCLUDE=-I$(KERNELSRC)/include ++ ++ifeq ($(KERNELMAJOR), 2.6) ++TARGET := acerhk.ko ++else ++TARGET := acerhk.o ++endif ++ ++SOURCE := acerhk.c ++ ++all: $(TARGET) ++ ++help: ++ @echo Possible targets: ++ @echo -e all\\t- default target, builds kernel module ++ @echo -e install\\t- copies module binary to /lib/modules/$(KERNELVERSION)/extra/ ++ @echo -e clean\\t- removes all binaries and temporary files ++ ++# this target is only for me, don't use it yourself (Olaf) ++export: ++ sh export.sh ++ ++acerhk.ko: $(SOURCE) acerhk.h ++ $(MAKE) -C $(KERNELSRC) SUBDIRS=$(PWD) modules ++ ++acerhk.o: $(SOURCE) acerhk.h ++ $(CC) $(INCLUDE) $(CFLAGS) -DMODVERSIONS -DMODULE -D__KERNEL__ -o $(TARGET) $(SOURCE) ++ ++asm: $(SOURCE) ++ifeq ($(KERNELMAJOR), 2.6) ++ $(CC) $(INCLUDE) $(INCLUDE)/asm-i386/mach-default $(CFLAGS) -fverbose-asm -S -DMODVERSIONS -DMODULE -D__KERNEL__ $(SOURCE) ++else ++ $(CC) $(INCLUDE) $(CFLAGS) -fverbose-asm -S -DMODVERSIONS -DMODULE -D__KERNEL__ $(SOURCE) ++endif ++ ++clean: ++ rm -f *~ *.o *.s *.ko .acerhk* *.mod.c ++ ++load: $(TARGET) ++ insmod $(TARGET) ++ ++unload: ++ rmmod acerhk ++ ++install: $(TARGET) ++ mkdir -p /lib/modules/$(KERNELVERSION)/extra ++ cp -v $(TARGET) /lib/modules/$(KERNELVERSION)/extra/ ++ depmod -a +diff -Nurp linux-2.6.37/3rdparty/acerhk/NEWS linux-2.6.37.3rdparty/3rdparty/acerhk/NEWS +--- linux-2.6.37/3rdparty/acerhk/NEWS 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/NEWS 2003-02-28 02:47:18.000000000 +0200 +@@ -0,0 +1,16 @@ ++2003-02-28 Version 0.5.0 ++ completely changed key polling/translation ++ support for more series ++2002-07-06 Version 0.4.2 ++ added debug functionality ++ bugfix with 520/210 ++2002-06-24 Version 0.4.1 ++ added support for TM 210 series ++ removed nvram dependency ++2002-06-15 Version 0.4 ++ added model recognition ++ added kernel polling an key event generation ++ added support for 520 series ++ ++2002-04-29 Version 0.3 ++ Initial release +\ Ingen nyrad vid filslut +diff -Nurp linux-2.6.37/3rdparty/acerhk/README linux-2.6.37.3rdparty/3rdparty/acerhk/README +--- linux-2.6.37/3rdparty/acerhk/README 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/README 2006-11-10 00:01:46.000000000 +0200 +@@ -0,0 +1,215 @@ ++ ++What is this driver good for? ++***************************** ++ ++This driver will give access to the special keys on notebooks of the ++Acer Travelmate series, which are not handled by the keyboard ++driver. ++It also works on notebooks from other manufacturers (some Medion, ++Fujitsu-Siemens, ...). ++ ++It also has some other related functionality (depending on the model): ++- controlling LEDs (Mail, Wireless) ++- enable/disable wireless hardware ++ ++Usage ++***** ++ ++The driver provides a device /dev/misc/acerhk where you can access all ++functions through IOCTL's, look into acerhk.h for their definitions. ++I use devfs and don't care about the minor number. You may want to change ++ACERHK_MINOR in acerhk.h. ++If you don't use devfs you need to create the device node. The device uses ++major 10 (misc character devices), the minor is chosen by the kernel (if ++ACERHK_MINOR equals MISC_DYNAMIC_MINOR) or by yourself (any other value). ++Use something like ++ mknod /dev/acerhk c 10 123 ++to create the device node. ++You can also use most functions through procfs. You will find some files in ++/proc/driver/acerhk: ++ led - write "on" or "off" to set the mail led state ++ key - read it to get a key press, only useful on non-dritek models ++ and only if polling is disabled ++ This file exists only on non-dritek models ++ info - some information about the driver, including the number of ++ pending keys ++ wirelessled - write "on" or "off" to set the led state and enable ++ wlan hardware ++ On some laptops you need to load the ipw2200 (others ++ too?) with option "led=1" to make the led work. ++ blueled - write "on" or "off" to set the led state and enable ++ bluetooth hardware ++ write a value n >= 50 to let the led blink every n jiffies ++ Do not use blinking mode where not only the led but also the ++ bluetooth hardware is controlled! ++ ++Probably the best way to use the driver is to let it poll for the keys itself ++and generate real key events. this is the normal case when loading the module ++without an additional parameter : ++ ++ modprobe acerhk ++ ++or you can use the ioctl as specified in acerhk.h to control the polling. If ++your kernel has keyboard input support you will get real key events when ++pressing the special keys. ++You can then use whatever software you like to make use of those keys, ++i.e. 'hotkeys' or Linux Easy Access Keyboard 'lineakd'. I prefer hotkeys, just ++in case anyone is interested, you can find a sample configuration for this ++programm in doc/acertm.def. ++Gnome >= 2.4 has built in support for multimedia keys (acme), that's ++what I use now. ++ ++Have a look at ++ http://mmkc.sourceforge.net/ ++ ++Note: If you have one of the newer models using dritek hardware you don't need ++polling (nor the file /proc/driver/acerhk/key) to use your buttons. On this ++hardware the driver only needs to send a special command to the keyboard ++controller to make them work. The actual key presses are then handled by the ++normal keyboard driver of the kernel. You can switch of polling by ++loading the module with poll=0. It saves you precious cpu time. ++ ++ ++Module parameters ++***************** ++name values meaning ++autowlan 0,1 disable(default)/enable automatic switching of wlan hardware ++ on wireless keypress, only useful for older (no ++ dritek-hardware) models, works only will poll=1 ++poll 0,1 disable/enable(default) kernel polling of key events ++verbose 0-4 verbosity level, see below ++usedritek 0,1 disable/enable(default) use of dritek hardware on newer ++ series, needed to activate the keys on such models ++force_series set this to the laptop series number you want the driver to ++ assume, skip autodetection (look at function ++ setup_model_features() for possible values) ++ ++Debugging ++********* ++ ++You can make the the driver be more verbose. To do this, add the following ++parameter when loading the module: ++ ++ verbose= ++ ++n is an integer, 0 (default) means no additional information while increasing ++values provide an increasing amount of information. Currently 3 is maximum, ++bigger values will have the same effect as 3. The existing verbosity levels ++will generate information about: ++ Level Information ++ 1 state changes and variable initialization ++ 2 model probing ++ 3 key translation, only known keys ++ 4 key translation, also unknown keys ++ 5 misc. information (idle values) ++ ++If you have rather serious problems you can activate debugging functionality ++in the driver. To do this, uncomment the '#define ACERDEBUG' in acerhk.c. You ++will find a new file in /proc/driver/acerhk, named 'debug'. You cannot read ++from this file, but you can write commands consisting of up to 4 digits. The ++first one specifies the action, while the latter can give additional ++parameters. Implemented are: ++ 'd' decrement module usage counter ++ 'i' increment module usage counter ++ ++ 'p' call function pbutton_fct() ++ 't' call function get_thermal_event() ++ 'w1x' call function wbutton_fct_1() with parameter x (0-9) ++ 'w2x' call function wbutton_fct_2() with parameter x (0-9) ++ ++ 'vx' change verbosity level to x (0-9) ++ ++ 'mxyy' set mapping of key name x to key event yy (hex) ++ 'sxx' send key event xx (hex) to input system ++ 'Sxx' simulate acer key press with code xx (hex) ++ ++ 'e0' stop kernel polling ++ 'e1' start kernel polling ++ ++Example: ++ ++1) echo d > /proc/driver/acerhk/debug ++ ++will decrement the usage counter, very useful if a program using the driver ++segfaulted. This way you can still unload the driver. ++ ++2) echo v4 > /proc/driver/acerhk/debug ++ ++will set the verbosity level to maximum. ++ ++Keycodes ++******** ++ ++see doc/keycodes ++Also see http://bernd-wurst.de/linux/tm800.php#mmkeys (only in german) ++ ++If you have one of the newer models with the dritek hardware, use kernel 2.6 ++and get (after enabling it) kernel messages of the form: ++ ++ atkbd.c: Unknown key pressed (translated set 2, code 0xf4 on ++ isa0060/serio0). ++ atkbd.c: Use 'setkeycodes e074 ' to make it known. ++ ++then you should do exactly what your told. In this case you could do ++ ++ setkeycodes e074 158 ++ ++to map the button with scancode e074 (hex) to keycode 158 (decimal). To find ++out the scancodes of the buttons either look into the kernel log or into the ++file MMKEYBD.CFG of the windows launch manager package. There you should find ++lines like this: ++ ++Key 1 = 1,E0,74,E0,F4,F500,P1 ++ ** ** ** ++ ++The important information is marked in the example above. The numbers give the ++scancode produced by the button which's name is given last. ++The keycode you give as parameter to setkeycodes is one out of the header file ++linux/input.h, in the example above the one for KEY_BACK. ++Important note: I received mails from a number of people where setkeycodes ++rejected keycodes above a certain value. This is caused by an outdated version ++of setkeycodes, use a more recent one. ++To ease the setup of keymappings for the newer series I will try to include ++setup scripts for the different notebook series. If I have enough time to ++spare I will perhaps expand the driver itself do to that. ++ ++How does it work? ++***************** ++ ++The driver is based on the windows Me for series 610 driver and ++resembles its structure and functionality. ++Key presses are events, which are stored in a FIFO queue with 31 ++entries. You can access the event count via CMOS nvram, but the access to ++the actual queue (and other functionality like switching the mail led) is ++done through calling a system ROM function. ++Upon loading the driver looks for this function, if it cannot find it, ++loading aborts. ++Newer Dritek Hardware: ++Button handling is done entirely by the EC (embbedded/environment ++controller) which behaves like an extended keyboard controller. My ++driver only enables/disables this extension. ++ ++ ++Credits ++******* ++ ++Leif Jensen, whose driver inspired me to do the probing stuff ++http://www.math.columbia.edu/~jensen/linux/acertm/ ++ ++Thanks to all who contributed patches to this driver or who just tried it out ++on their laptops, without them it wouldn't support anything else but my ++TM 613. ++ ++Contact ++******* ++ ++If you have problems with the driver, please include the following information: ++1. name of your laptop (e.g. Acer TM 4001) ++2. content of /proc/driver/acerhk/info, if available ++3. kernel output after loading the module with verbose=2 ++ ++Email: Olaf Tauber ++ ++The latest version can be found here: ++ ++http://www.informatik.hu-berlin.de/~tauber/acerhk diff --git a/kernel/tools/perf/files/patches/mageia/3rd-acerhk-2.6.36-buildfix.patch b/kernel/tools/perf/files/patches/mageia/3rd-acerhk-2.6.36-buildfix.patch new file mode 100644 index 0000000000..47a71053a6 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-acerhk-2.6.36-buildfix.patch @@ -0,0 +1,20 @@ +--- linux-2.6.35/3rdparty/acerhk/acerhk.c.orig 2010-10-03 12:50:33.000000000 +0000 ++++ linux-2.6.35/3rdparty/acerhk/acerhk.c 2010-10-03 13:13:22.093868410 +0000 +@@ -2730,7 +2730,7 @@ static void acerhk_proc_cleanup(void) + + /* {{{ file operations */ + +-static int acerhk_ioctl( struct inode *inode, struct file *file, ++static long acerhk_ioctl( struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg ) + { + int retval; +@@ -2827,7 +2827,7 @@ static int acerhk_release( struct inode + + static struct file_operations acerhk_fops = { + owner: THIS_MODULE, +- ioctl: acerhk_ioctl, ++ unlocked_ioctl: acerhk_ioctl, + open: acerhk_open, + #ifdef ACERDEBUG + write: acerhk_write, diff --git a/kernel/tools/perf/files/patches/mageia/3rd-acerhk-extra-cflags.patch b/kernel/tools/perf/files/patches/mageia/3rd-acerhk-extra-cflags.patch new file mode 100644 index 0000000000..7971c6993f --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-acerhk-extra-cflags.patch @@ -0,0 +1,33 @@ +CFLAGS use isn't allowed anymore with 2.6.24, we must use EXTRA_CFLAGS +in its place + +Signed-off-by: Herton Ronaldo Krzesinski + +--- linux-2.6.23/3rdparty/acerhk/Makefile.orig 2007-11-08 21:32:43.000000000 -0200 ++++ linux-2.6.23/3rdparty/acerhk/Makefile 2007-11-08 21:33:28.000000000 -0200 +@@ -14,7 +14,7 @@ + CONFIG_ACERHK?=m + obj-$(CONFIG_ACERHK) += acerhk.o + +-CFLAGS+=-c -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fomit-frame-pointer -fno-strict-aliasing -fno-common -pipe ++EXTRA_CFLAGS+=-c -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fomit-frame-pointer -fno-strict-aliasing -fno-common -pipe + INCLUDE=-I$(KERNELSRC)/include + + ifeq ($(KERNELMAJOR), 2.6) +@@ -41,13 +41,13 @@ acerhk.ko: $(SOURCE) acerhk.h + $(MAKE) -C $(KERNELSRC) SUBDIRS=$(PWD) modules + + acerhk.o: $(SOURCE) acerhk.h +- $(CC) $(INCLUDE) $(CFLAGS) -DMODVERSIONS -DMODULE -D__KERNEL__ -o $(TARGET) $(SOURCE) ++ $(CC) $(INCLUDE) $(EXTRA_CFLAGS) -DMODVERSIONS -DMODULE -D__KERNEL__ -o $(TARGET) $(SOURCE) + + asm: $(SOURCE) + ifeq ($(KERNELMAJOR), 2.6) +- $(CC) $(INCLUDE) $(INCLUDE)/asm-i386/mach-default $(CFLAGS) -fverbose-asm -S -DMODVERSIONS -DMODULE -D__KERNEL__ $(SOURCE) ++ $(CC) $(INCLUDE) $(INCLUDE)/asm-i386/mach-default $(EXTRA_CFLAGS) -fverbose-asm -S -DMODVERSIONS -DMODULE -D__KERNEL__ $(SOURCE) + else +- $(CC) $(INCLUDE) $(CFLAGS) -fverbose-asm -S -DMODVERSIONS -DMODULE -D__KERNEL__ $(SOURCE) ++ $(CC) $(INCLUDE) $(EXTRA_CFLAGS) -fverbose-asm -S -DMODVERSIONS -DMODULE -D__KERNEL__ $(SOURCE) + endif + + clean: diff --git a/kernel/tools/perf/files/patches/mageia/3rd-acerhk-fix-build-with-function-tracer.patch b/kernel/tools/perf/files/patches/mageia/3rd-acerhk-fix-build-with-function-tracer.patch new file mode 100644 index 0000000000..c8d000b598 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-acerhk-fix-build-with-function-tracer.patch @@ -0,0 +1,22 @@ +Fix acerhk build with FUNCTION_TRACER enabled. + +Signed-off-by: Herton Ronaldo Krzesinski +--- + 3rdparty/acerhk/Makefile | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff -p -up linux-2.6.31/3rdparty/acerhk/Makefile.orig linux-2.6.31/3rdparty/acerhk/Makefile +--- linux-2.6.31/3rdparty/acerhk/Makefile.orig 2009-10-02 16:39:06.000000000 -0300 ++++ linux-2.6.31/3rdparty/acerhk/Makefile 2009-10-02 16:45:13.000000000 -0300 +@@ -14,7 +14,10 @@ + CONFIG_ACERHK?=m + obj-$(CONFIG_ACERHK) += acerhk.o + +-EXTRA_CFLAGS+=-c -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fomit-frame-pointer -fno-strict-aliasing -fno-common -pipe ++CFLAGS_acerhk.o += -c -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fomit-frame-pointer -fno-strict-aliasing -fno-common -pipe ++ifdef CONFIG_FUNCTION_TRACER ++CFLAGS_REMOVE_acerhk.o = -pg ++endif + INCLUDE=-I$(KERNELSRC)/include + + ifeq ($(KERNELMAJOR), 2.6) diff --git a/kernel/tools/perf/files/patches/mageia/3rd-acerhk-fix-include.patch b/kernel/tools/perf/files/patches/mageia/3rd-acerhk-fix-include.patch new file mode 100644 index 0000000000..cba269847d --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-acerhk-fix-include.patch @@ -0,0 +1,23 @@ + +AUTOCONF_INCLUDED is not defined anymore in 2.6.38, so old include got exposed. + +Fix by removing the offending bits. + +Signed-off-by: Thomas Backlund + + 3rdparty/acerhk/acerhk.c | 4 ---- + 1 file changed, 4 deletions(-) + +--- linux-2.6.38/3rdparty/acerhk/acerhk.c.orig 2011-03-20 13:57:32.000000000 +0200 ++++ linux-2.6.38/3rdparty/acerhk/acerhk.c 2011-03-20 15:00:45.768659568 +0200 +@@ -35,10 +35,6 @@ + * + */ + +-#ifndef AUTOCONF_INCLUDED +-#include +-#endif +- + /* This driver is heavily dependent on the architecture, don't let + * anyone without an X86 machine use it. On laptops with AMD64 + * architecture this driver is only useable in 32 bit mode. diff --git a/kernel/tools/perf/files/patches/mageia/3rd-acerhk-kbuild.patch b/kernel/tools/perf/files/patches/mageia/3rd-acerhk-kbuild.patch new file mode 100644 index 0000000000..f0c419add6 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-acerhk-kbuild.patch @@ -0,0 +1,37 @@ +Fix Makefile and add Kconfig for the acerhk driver +--- + 3rdparty/acerhk/Kconfig | 8 8 + 0 - 0 ! + 3rdparty/acerhk/Makefile | 6 3 + 3 - 0 ! + 2 files changed, 11 insertions(+), 3 deletions(-) + +Index: linux-2.6.21/3rdparty/acerhk/Makefile +=================================================================== +--- linux-2.6.21.orig/3rdparty/acerhk/Makefile 2007-05-15 15:34:48.000000000 +0200 ++++ linux-2.6.21/3rdparty/acerhk/Makefile 2007-05-15 15:37:17.000000000 +0200 +@@ -1,10 +1,10 @@ + # change KERNELSRC to the location of your kernel build tree only if + # autodetection does not work + #KERNELSRC=/usr/src/linux +-KERNELSRC?=/lib/modules/`uname -r`/build ++#KERNELSRC?=/lib/modules/`uname -r`/build + # Starting with 2.6.18, the kernel version is in utsrelease.h instead of version.h, accomodate both cases +-KERNELVERSION=$(shell awk -F\" '/REL/ {print $$2}' $(shell grep -s -l REL $(KERNELSRC)/include/linux/version.h $(KERNELSRC)/include/linux/utsrelease.h)) +-KERNELMAJOR=$(shell echo $(KERNELVERSION)|head -c3) ++#KERNELVERSION=$(shell awk -F\" '/REL/ {print $$2}' $(shell grep -s -l REL $(KERNELSRC)/include/linux/version.h $(KERNELSRC)/include/linux/utsrelease.h)) ++#KERNELMAJOR=$(shell echo $(KERNELVERSION)|head -c3) + + # next line is for kernel 2.6, if you integrate the driver in the kernel tree + # /usr/src/linux/drivers/acerhk - or something similar +Index: linux-2.6.21/3rdparty/acerhk/Kconfig +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.21/3rdparty/acerhk/Kconfig 2007-05-15 15:39:30.000000000 +0200 +@@ -0,0 +1,8 @@ ++config ACERHK ++ tristate "Acerhk driver" ++ depends on EXPERIMENTAL && X86 ++ ---help--- ++ This is an experimental acer keyboard driver for ++ acer laptops. If you have a notebook with a ipw2X00 ++ wireless card, it allows you to turn off the rf_kill ++ diff --git a/kernel/tools/perf/files/patches/mageia/3rd-acerhk-proc_dir_entry-owner.patch b/kernel/tools/perf/files/patches/mageia/3rd-acerhk-proc_dir_entry-owner.patch new file mode 100644 index 0000000000..e5821d462f --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-acerhk-proc_dir_entry-owner.patch @@ -0,0 +1,67 @@ +Updated for owner removal from struct proc_dir_entry (2.6.30) + +Signed-off-by: Herton Ronaldo Krzesinski + +--- + 3rdparty/acerhk/acerhk.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff -p -up linux-2.6.29/3rdparty/acerhk/acerhk.c.orig linux-2.6.29/3rdparty/acerhk/acerhk.c +--- linux-2.6.29/3rdparty/acerhk/acerhk.c.orig 2009-05-22 02:42:44.000000000 -0300 ++++ linux-2.6.29/3rdparty/acerhk/acerhk.c 2009-05-22 02:43:45.000000000 -0300 +@@ -2626,7 +2626,6 @@ static int acerhk_proc_init(void) + printk(KERN_INFO"acerhk: could not create /proc/driver/acerhk\n"); + } + else { +- proc_acer_dir->owner = THIS_MODULE; + /* now create several files, first general info ... */ + entry = create_proc_read_entry("info", + 0444, proc_acer_dir, acerhk_proc_info, NULL); +@@ -2635,7 +2634,6 @@ static int acerhk_proc_init(void) + remove_proc_entry("driver/acerhk", NULL); + retval = 0; + } else { +- entry->owner = THIS_MODULE; + /* ... last pressed key ... */ + entry = create_proc_read_entry("key", + 0444, proc_acer_dir, acerhk_proc_key, NULL); +@@ -2645,7 +2643,6 @@ static int acerhk_proc_init(void) + remove_proc_entry("driver/acerhk", NULL); + retval = 0; + } else { +- entry->owner = THIS_MODULE; + /* ... and led control file */ + entry = create_proc_entry("led", 0222, proc_acer_dir); + if (entry == NULL) { +@@ -2657,7 +2654,6 @@ static int acerhk_proc_init(void) + } + else { + entry->write_proc = acerhk_proc_led; +- entry->owner = THIS_MODULE; + /* ... and wireless led controll file */ + entry = create_proc_entry("wirelessled", 0222, proc_acer_dir); + if (entry == NULL) { +@@ -2670,7 +2666,6 @@ static int acerhk_proc_init(void) + } + else { + entry->write_proc = acerhk_proc_wirelessled; +- entry->owner = THIS_MODULE; + /* ... and bluetooth led controll file */ + entry = create_proc_entry("blueled", 0222, proc_acer_dir); + if (entry == NULL) { +@@ -2683,7 +2678,6 @@ static int acerhk_proc_init(void) + retval = 0; + } else { + entry->write_proc = acerhk_proc_blueled; +- entry->owner = THIS_MODULE; + retval = 1; + #ifdef ACERDEBUG + /* add extra file for debugging purposes */ +@@ -2700,7 +2694,6 @@ static int acerhk_proc_init(void) + } + else { + entry->write_proc = acerhk_proc_debug; +- entry->owner = THIS_MODULE; + retval = 1; + } + #endif diff --git a/kernel/tools/perf/files/patches/mageia/3rd-aes2501-kbuild.patch b/kernel/tools/perf/files/patches/mageia/3rd-aes2501-kbuild.patch new file mode 100644 index 0000000000..1dcf8fa061 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-aes2501-kbuild.patch @@ -0,0 +1,47 @@ +Fix Makefile and add Kconfig for the aes2501 driver. + +Signed-off-by: Herton Ronaldo Krzesinski + +--- + linux-2.6.23/3rdparty/aes2501/Kconfig | 10 ++++++++++ + linux-2.6.23/3rdparty/aes2501/Makefile | 19 +------------------ + 2 files changed, 11 insertions(+), 18 deletions(-) + +diff -p -up linux-2.6.23/3rdparty/aes2501/Kconfig.orig linux-2.6.23/3rdparty/aes2501/Kconfig +--- linux-2.6.23/3rdparty/aes2501/Kconfig.orig 2008-01-13 23:14:47.000000000 -0200 ++++ linux-2.6.23/3rdparty/aes2501/Kconfig 2008-01-13 23:35:21.000000000 -0200 +@@ -0,0 +1,10 @@ ++config AES2501 ++ tristate "AuthenTec AES2501 Fingerprint Sensor Driver" ++ depends on USB ++ default m ++ ---help--- ++ Say Y here if you have a AuthenTec AES2501 Fingerprint ++ Sensor device. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called aes2501. +diff -p -up linux-2.6.23/3rdparty/aes2501/Makefile.orig linux-2.6.23/3rdparty/aes2501/Makefile +--- linux-2.6.23/3rdparty/aes2501/Makefile.orig 2008-01-13 23:14:36.000000000 -0200 ++++ linux-2.6.23/3rdparty/aes2501/Makefile 2008-01-13 23:21:33.000000000 -0200 +@@ -1,19 +1,2 @@ +- +-obj-m := aes2501.o +- +-KERNELDIR ?= /lib/modules/$(shell uname -r)/build +- +-PWD := $(shell pwd) +- +-all: usertest +- $(MAKE) -C $(KERNELDIR) M=$(PWD) +- +-usertest: +- gcc -I. -o usertest usertest.c +- +-clean: +- rm -f *.o *~ aes2501.ko aes2501.mod.c Module.symvers usertest +- rm -rf .tmp_versions +- rm -f .*.cmd +- ++obj-$(CONFIG_AES2501) := aes2501.o + diff --git a/kernel/tools/perf/files/patches/mageia/3rd-aes2501-r19.patch b/kernel/tools/perf/files/patches/mageia/3rd-aes2501-r19.patch new file mode 100644 index 0000000000..a5f95e790f --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-aes2501-r19.patch @@ -0,0 +1,2356 @@ + 3rdparty/aes2501/ChangeLog | 95 ++ + 3rdparty/aes2501/Makefile | 19 + 3rdparty/aes2501/aes2501.c | 1629 ++++++++++++++++++++++++++++++++++++++++ + 3rdparty/aes2501/aes2501.h | 40 + 3rdparty/aes2501/aes2501_regs.h | 464 +++++++++++ + 3rdparty/aes2501/usertest.c | 78 + + 6 files changed, 2325 insertions(+) +diff -Nurp linux-2.6.37/3rdparty/aes2501/aes2501.c linux-2.6.37.3rdparty/3rdparty/aes2501/aes2501.c +--- linux-2.6.37/3rdparty/aes2501/aes2501.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/aes2501/aes2501.c 2008-01-14 03:07:30.000000000 +0200 +@@ -0,0 +1,1629 @@ ++ ++/* ++ * aes2501.c -- AuthenTec AES2501 Fingerprint Sensor Driver for Linux ++ * ++ * Maintainer: Cyrille Bagard ++ * ++ * Copyright (C) 2007 Cyrille Bagard ++ * ++ * This file is part of the AES2501 driver. ++ * ++ * the AES2501 driver 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. ++ * ++ * the AES2501 driver 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 the AES2501 driver; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include "aes2501.h" ++#include "aes2501_regs.h" ++ ++ ++static int major = 0; ++ ++module_param(major, int, 0); ++MODULE_PARM_DESC(major, "major number"); ++ ++ ++//#define DEBUG ++ ++ ++#define PRINTK_INFO(fmt, arg...) printk(KERN_INFO "aes2501: " fmt, ## arg) ++ ++#define PRINTK_CRIT(fmt, arg...) printk(KERN_CRIT "aes2501: " fmt, ## arg) ++ ++#define PRINTK_DBG(fmt, arg...) printk(KERN_DEBUG "aes2501: " fmt, ## arg) ++ ++ ++static struct workqueue_struct *comm_queue; ++ ++ ++static char *finger_print = NULL; ++static size_t finger_print_len; ++ ++ ++ ++static DECLARE_WAIT_QUEUE_HEAD(wq); ++static int flag = 0; ++ ++ ++ ++struct usb_aes2501 *_dev; ++ ++ ++ ++ ++ ++ ++struct aes2501 { ++ ++ struct usb_device *udev; ++ ++ int temp; ++ ++ unsigned char *int_in_buffer; ++ struct urb *int_in_urb; ++ ++}; ++ ++ ++/* ++#define VENDOR_ID 0x08f7 ++#define PRODUCT_ID 0x0002 ++*/ ++ ++#define VENDOR_ID 0x08ff ++#define PRODUCT_ID 0x2580 ++ ++ ++/* Table of devices that work with this driver */ ++ ++static struct usb_device_id id_table [] = { ++ { USB_DEVICE(VENDOR_ID, PRODUCT_ID) }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(usb, id_table); ++ ++ ++/* Get a minor range for your devices from the usb maintainer */ ++#define USB_AES2501_MINOR_BASE 192 ++ ++ ++ ++#define WRITES_IN_FLIGHT 8 /* ??? */ ++ ++ ++ ++enum AES2501_Status { ++ ++ AESS_INIT_DONE, ++ AESS_IS_SCANNING, ++ ++ AESS_COUNT ++ ++}; ++ ++ ++#define BULK_OUT_BUFFER_SIZE 32 ++ ++ ++/* Read a register value from a dump sent by the device. */ ++static int read_register_value(const uint8_t *, Aes2501Registers); ++ ++/* Tells if a finger motion is still detected. */ ++static int sum_histogram_values(const uint8_t *, uint8_t); ++ ++ ++/* Structure to hold all device specific stuff */ ++struct usb_aes2501 { ++ ++ struct usb_device *udev; /* the usb device for this device */ ++ struct usb_interface *interface; /* the interface for this device */ ++ struct semaphore limit_sem; /* limiting the number of writes in progress */ ++ unsigned char *bulk_in_buffer; /* the buffer to receive data */ ++ size_t bulk_in_size; /* the size of the receive buffer */ ++ __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ ++ uint8_t bulk_out_buffer[BULK_OUT_BUFFER_SIZE]; /* the buffer to send data (32 / 8 = 4) */ ++ size_t bulk_out_buffer_used; /* the quantity of buffered data to send */ ++ __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ ++ struct kref kref; ++ struct mutex io_mutex; /* synchronize I/O with disconnect */ ++ ++ DECLARE_BITMAP(status, AESS_COUNT); /* Information about what has been set / is running */ ++ ++ struct work_struct scan_work; ++ uint8_t stop_scan; /* Flag to stop finger detecting during module removal */ ++}; ++ ++ ++#define to_aes2501_dev(r) container_of(r, struct usb_aes2501, kref) ++ ++static struct usb_driver aes2501_driver; ++ ++static void aes2501_delete(struct kref *kref) ++{ ++ struct usb_aes2501 *dev; ++ ++ dev = to_aes2501_dev(kref); ++ ++ usb_put_dev(dev->udev); ++ kfree(dev->bulk_in_buffer); ++ kfree(dev); ++ ++} ++ ++ ++static int aes2501_open(struct inode *inode, struct file *file); ++/* ++struct usb_aes2501 *_dev; ++static int aes2501_open(struct inode *inode, struct file *file) ++{ ++ printk(KERN_INFO "Plop !\n"); ++ ++ ++ ++ return 0; ++} ++*/ ++ ++static ssize_t aes2501_read(struct file *file, char *buffer, size_t count, loff_t *ppos) ++{ ++ int read_len; ++ ++ //printk(KERN_INFO "aes2501_read ! got %d -> need (%d ; %d)\n", finger_print_len, *ppos, count); ++ ++ if (flag == 0) ++ printk(KERN_INFO "Process %i (%s) is going to sleep\n", current->pid, current->comm); ++ ++ wait_event_interruptible(wq, flag == 1); ++ ++ if (signal_pending(current)) ++ return -ERESTARTSYS; ++ ++ if (finger_print_len == 0) ++ return -ENODATA; ++ ++ if (unlikely((*ppos < 0) || (loff_t)(*ppos + count) < 0)) ++ return -EINVAL; ++ ++ if (*ppos + count > finger_print_len) ++ read_len = finger_print_len - *ppos; ++ else read_len = count; ++ ++ if (read_len > 0) ++ { ++ if (!access_ok(VERIFY_WRITE, buffer, read_len)) ++ return -EFAULT; ++ ++ read_len -= copy_to_user(buffer, finger_print + *ppos, read_len); ++ *ppos += read_len; ++ ++ } ++ ++ /* !!!! */ ++ else flag = 0; ++ ++ return read_len; ++ ++} ++ ++ ++ ++static int detect_finger_on_aes2501(struct usb_aes2501 *dev); ++ ++static void do_scanning(struct work_struct *work); ++ ++ ++// ioctl - I/O control ++static int aes2501_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ struct usb_aes2501 *dev; ++ int retval; ++ ++ dev = _dev; ++ ++ ++ printk(KERN_INFO "Get IOCtl :: cmd = %d vs %d\n", cmd, (AES2501_IOC_TEST)); ++ ++ switch (cmd) { ++ ++ case AES2501_IOC_TEST: ++ ++#if defined(_arch_um__) || !(LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) ++ INIT_WORK(&dev->scan_work, do_scanning); ++#else ++ INIT_WORK(&dev->scan_work, do_scanning, NULL); ++#endif ++ ++ retval = queue_work(comm_queue, &dev->scan_work); ++ ++ ++ } ++ ++ ++ ++ return 0; ++ ++ ++#if 0 ++ int retval = 0; ++ switch ( cmd ) { ++ case CASE1:/* for writing data to arg */ ++ if (copy_from_user(&data, (int *)arg, sizeof(int))) ++ return -EFAULT; ++ break; ++ case CASE2:/* for reading data from arg */ ++ if (copy_to_user((int *)arg, &data, sizeof(int))) ++ return -EFAULT; ++ break; ++ default: ++ retval = -EINVAL; ++ } ++ return retval; ++#endif ++} ++ ++ ++ ++static const struct file_operations aes2501_fops = { ++ .owner = THIS_MODULE, ++ .read = aes2501_read,/* ++ .write = aes2501_write,*/ ++ .open = aes2501_open,/* ++ .release = skel_release,*/ ++ .ioctl = aes2501_ioctl ++}; ++ ++ ++ ++/* ++static int send_data_to_aes2501(struct usb_aes2501 *dev, unsigned char *buffer, int len) ++{ ++#ifdef DEBUG ++ int i; ++#endif ++ int bytes_written; ++ int ret; ++ ++#ifdef DEBUG ++ printk(KERN_INFO "\n:: OUT :: len=%d\n", len); ++ ++ for (i = 0; i < len; i++) ++ { ++ if (i > 0 && i % 16 == 0) ++ printk("\n"); ++ if (i % 16 == 0) ++ printk(KERN_INFO " %05x: ", i); ++ ++ if (i % 8 == 0) ++ printk(" "); ++ ++ printk("%02x ", buffer[i]); ++ ++ } ++ ++ printk("\n"); ++#endif ++ ++ ret = usb_bulk_msg(dev->udev, ++ usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), ++ buffer, ++ len, ++ &bytes_written, 4000); ++ ++ if (ret < 0) ++ PRINTK_CRIT("error while sending data: %d\n", ret); ++ ++ if (bytes_written != len) ++ printk(KERN_INFO "did not write all ! %d vs %d\n", bytes_written, len); ++ ++ return ret; ++ ++} ++*/ ++ ++static int flush_aes2501_bulk_out(struct usb_aes2501 *dev) ++{ ++ int ret; ++ int bytes_written; ++ ++ ret = 0; ++ ++ if (dev->bulk_out_buffer_used > 0) { ++ ++ ret = usb_bulk_msg(dev->udev, ++ usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), ++ dev->bulk_out_buffer, ++ dev->bulk_out_buffer_used, ++ &bytes_written, 4000); ++ ++ if (ret < 0) ++ PRINTK_CRIT("error while sending data: %d\n", ret); ++ ++ else if (bytes_written != dev->bulk_out_buffer_used) ++ { ++ printk(KERN_INFO "did not write all ! %d vs %d\n", bytes_written, dev->bulk_out_buffer_used); ++ /*ret = ... */ ++ } ++ ++ dev->bulk_out_buffer_used = 0; ++ ++ } ++ ++ return ret; ++ ++} ++ ++ ++static int write_aes2501_register(struct usb_aes2501 *dev, uint8_t reg, uint8_t data) ++{ ++ int ret; ++ ++ if (dev->bulk_out_buffer_used == BULK_OUT_BUFFER_SIZE) ++ ret = flush_aes2501_bulk_out(dev); ++ else ++ ret = 0; ++ ++ dev->bulk_out_buffer[dev->bulk_out_buffer_used++] = reg; ++ dev->bulk_out_buffer[dev->bulk_out_buffer_used++] = data; ++ ++ return ret; ++ ++} ++ ++ ++static int recv_data_to_aes2501(struct usb_aes2501 *dev, unsigned char *buffer, int len) ++{ ++ int bytes_read; ++ int ret; ++#ifdef DEBUG ++ int i; ++#endif ++ ++ ret = usb_bulk_msg(dev->udev, ++ usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr), ++ buffer, ++ len, ++ &bytes_read, 4000); ++ ++ if (ret < 0) ++ PRINTK_CRIT("error while sending data: %d\n", ret); ++ ++ if (bytes_read != len) ++ printk(KERN_INFO "did not read all ! %d vs %d\n", bytes_read, len); ++ ++#ifdef DEBUG ++ if (ret == 0) ++ { ++ printk(KERN_INFO "\n:: IN :: len=%d\n", len); ++ ++ for (i = 0; i < len; i++) ++ { ++ if (i > 0 && i % 16 == 0) ++ printk("\n"); ++ if (i % 16 == 0) ++ printk(KERN_INFO " %05x: ", i); ++ ++ if (i % 8 == 0) ++ printk(" "); ++ ++ printk("%02x ", buffer[i]); ++ ++ } ++ ++ printk("\n"); ++ ++ } ++#endif ++ ++ return ret; ++ ++} ++ ++ ++ ++static int standby_aes2501(struct usb_aes2501 *dev) ++{ ++ ++ //unsigned char cmd[] = "\xac\x01\xad\x1a\x81\x02"; ++ ++ ++ unsigned char buffer[4]; ++ ++ ++ ++ ++ printk(KERN_INFO ">> Standby aes2501 !\n"); ++ ++ ++ //msleep(800); ++ ++ write_aes2501_register(dev, AES2501_REG_TREGC, AES2501_TREGC_ENABLE); ++ write_aes2501_register(dev, AES2501_REG_TREGD, 0x1a); ++ ++ flush_aes2501_bulk_out(dev); ++ ++ /** ++ * TODO: ++ * - lire ici les deux octets. ++ * - voir pour inverser les commandes. ++ */ ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL2, 0x02/* AES2501_CTRL2_READ_REGS ??? */); ++ flush_aes2501_bulk_out(dev); ++ ++ //send_data_to_aes2501(dev, cmd, 6); ++ recv_data_to_aes2501(dev, buffer, 2); ++ ++ ++ ++ printk(KERN_INFO " %02x %02x\n", buffer[0], buffer[1]); ++ ++ ++ if ((buffer[1] & AES2501_STAT_SCAN) == buffer[1]) ++ { ++ PRINTK_DBG("scan state: "); ++ ++ switch (buffer[1]) ++ { ++ case STATE_WAITING_FOR_FINGER: ++ printk("'Waiting for finger'\n"); ++ break; ++ case STATE_FINGER_SETTLING_DELAY: ++ printk("'In Finger settling delay'\n"); ++ break; ++ case STATE_POWER_UP_DELAY: ++ printk("'In power up delay'\n"); ++ break; ++ case STATE_WAITING_TO_START_SCAN: ++ printk("'Waiting to start image scan'\n"); ++ break; ++ case STATE_PRELOADING_SUBARRAY_0: ++ printk("'Pre-loading subarray 0'\n"); ++ break; ++ case STATE_SETUP_FOR_ROW_ADVANCE: ++ printk("'Setup for row advance'\n"); ++ break; ++ case STATE_WAITING_FOR_ROW_ADVANCE: ++ printk("'Waiting for row advance'\n"); ++ break; ++ case STATE_PRELOADING_COL_0: ++ printk("'Pre-loading column 0'\n"); ++ break; ++ case STATE_SETUP_FOR_COL_ADVANCE: ++ printk("'Setup for column advance'\n"); ++ break; ++ case STATE_WAITING_FOR_COL_ADVANCE: ++ printk("'Waiting for column advance'\n"); ++ break; ++ case STATE_WAITING_FOR_SCAN_START: ++ printk("'Waiting for scan start'\n"); ++ break; ++ case STATE_WAITING_FOR_SCAN_END: ++ printk("'Waiting for scan end'\n"); ++ break; ++ case STATE_WAITING_FOR_ROW_SETUP: ++ printk("'Waiting for row setup'\n"); ++ break; ++ case STATE_WAITING_FOR_COL_TIME: ++ printk("'Waiting for one column time (depends on scan rate)'\n"); ++ break; ++ case STATE_WAITING_FOR_QUEUED_DATA: ++ printk("'Waiting for queued data transmission to be completed'\n"); ++ break; ++ case STATE_WAIT_FOR_128_US: ++ printk("'Wait for 128 us'\n"); ++ break; ++ default: ++ printk("none (?!)\n"); ++ break; ++ ++ } ++ ++ } ++ ++ if (buffer[1] & AES2501_STAT_ERROR) ++ PRINTK_DBG("got serial interface framing error\n"); ++ ++ if (buffer[1] & AES2501_STAT_PAUSED) ++ PRINTK_DBG("scan was paused due to input buffer full\n"); ++ ++ if (buffer[1] & AES2501_STAT_RESET) ++ PRINTK_DBG("master reset input has been asserted\n"); ++ ++ ++ ++ ++ return 0; ++ ++ ++} ++ ++ ++ ++ ++static int setup_aes2501(struct usb_aes2501 *dev) ++{ ++ //unsigned char patch_msg[] = "\x80\x01"; ++ ++ ++ //unsigned char cmd[] = "\x80\x01\x81\x02"; ++ ++ //unsigned char cmd_00[] = "\xb0\x27"; ++ //unsigned char cmd_01[] = "\x80\x01\x82\x40"; ++ //unsigned char cmd_02[] = "\xff\x00"; ++ //unsigned char cmd_03[] = "\x80\x01\x82\x40\x83\x00\x88\x02\x89\x10\x8a\x05\x8c\x00\x8e\x13\x91\x44\x92\x34\x95\x16\x96\x16\x97\x18\xa1\x70\xa2\x02\xa7\x00\xac\x01\xad\x1a\x80\x04\x81\x04\xb4\x00";/*42*/ ++ //unsigned char cmd_04[] = "\x80\x01\x82\x40"; ++ ++ //unsigned char cmd2[] = "\x80\x01\xa8\x41\x82\x42\x83\x53\x80\x04\x81\x02";/*12*/ ++ ++ //unsigned char cmd3_00[] = "\xff\x00"; ++ //unsigned char cmd3_01[] = "\x80\x01\xa8\x41\x82\x42\x83\x53\x80\x04\x81\x02";/*12*/ ++ ++ //unsigned char cmd4[] = "\x80\x01\x82\x40\xb0\x27\x94\x0a\x80\x04\x83\x45\xa8\x41";/*14*/ ++ ++ //unsigned char cmd5_00[] = "\xb0\x27"; ++ //unsigned char cmd5_01[] = "\x80\x01\x82\x40"; ++ //unsigned char cmd5_02[] = "\xff\x00"; ++ //unsigned char cmd5_03[] = "\x80\x02"; ++ //unsigned char cmd5_04[] = "\x81\x02"; ++ ++ ++ int i; ++ ++ unsigned char buffer[128]; ++ ++ ++ /* To be sure the device will respond */ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ //send_data_to_aes2501(dev, patch_msg, 2); ++ flush_aes2501_bulk_out(dev);/* ... */ ++ ++ printk(KERN_INFO ">> Setting up aes2501 !\n"); ++ ++ /* Part 1 */ ++ ++ printk(KERN_INFO " -- part 1 --\n"); ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_READ_REGS); ++ flush_aes2501_bulk_out(dev); ++ ++ //send_data_to_aes2501(dev, cmd, 4); ++ recv_data_to_aes2501(dev, buffer, 126); ++ ++ ++ ++ //send_data_to_aes2501(dev, cmd_00, 2); ++ ++ write_aes2501_register(dev, 0xb0, 0x27);/* Reserved */ ++ ++ ++ ++ //send_data_to_aes2501(dev, cmd_01, 4); ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ ++ for (i = 0; i <= 10; i++) ++ { ++ //msleep(200); ++ //send_data_to_aes2501(dev, cmd_02, 2); ++ write_aes2501_register(dev, 0xff, 0x00);/* Reserved */ ++ } ++ ++ //msleep(100); ++ ++ ++ //send_data_to_aes2501(dev, cmd_03, 42); ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ write_aes2501_register(dev, AES2501_REG_DETCTRL, AES2501_DETCTRL_DRATE_CONTINUOUS | AES2501_DETCTRL_SDELAY_31_MS); ++ write_aes2501_register(dev, AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US); ++ write_aes2501_register(dev, AES2501_REG_MEASDRV, AES2501_MEASDRV_MDRIVE_0_325 | AES2501_MEASDRV_MEASURE_SQUARE); ++ write_aes2501_register(dev, AES2501_REG_MEASFREQ, AES2501_MEASFREQ_2M); ++ write_aes2501_register(dev, AES2501_REG_DEMODPHASE1, DEMODPHASE_NONE);/* Default */ ++ write_aes2501_register(dev, AES2501_REG_DEMODPHASE2, DEMODPHASE_NONE); ++ write_aes2501_register(dev, AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE2_4X | AES2501_CHANGAIN_STAGE1_16X); ++ write_aes2501_register(dev, AES2501_REG_ADREFHI, 0x44); ++ write_aes2501_register(dev, AES2501_REG_ADREFLO, 0x34); ++ write_aes2501_register(dev, AES2501_REG_STRTCOL, 0x16); ++ write_aes2501_register(dev, AES2501_REG_ENDCOL, 0x16); ++ write_aes2501_register(dev, AES2501_REG_DATFMT, AES2501_DATFMT_BIN_IMG | 0x08);/* ??? */ ++ write_aes2501_register(dev, AES2501_REG_TREG1, 0x70);/* Reserved + 0xXX */ ++ write_aes2501_register(dev, 0xa2, 0x02);/* Reserved */ ++ write_aes2501_register(dev, 0xa7, 0x00);/* Reserved */ ++ write_aes2501_register(dev, AES2501_REG_TREGC, AES2501_TREGC_ENABLE); ++ write_aes2501_register(dev, AES2501_REG_TREGD, 0x1a); ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE); ++ write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT); ++ write_aes2501_register(dev, AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE); ++ ++ ++ flush_aes2501_bulk_out(dev); ++ ++ recv_data_to_aes2501(dev, buffer, 20); ++ ++ ++ ++ //send_data_to_aes2501(dev, cmd_04, 4); ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ ++ /* Part 2 */ ++ ++ printk(KERN_INFO " -- part 2 --\n"); ++ ++ //msleep(100); ++ ++ //send_data_to_aes2501(dev, cmd2, 12); ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_AUTOCALOFFSET, 0x41); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x42);/* ??? */ ++ write_aes2501_register(dev, AES2501_REG_DETCTRL, 0x53);/* Cumul ??? */ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE); ++ write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_READ_REGS); ++ ++ ++ ++ ++ flush_aes2501_bulk_out(dev); ++ ++ ++ recv_data_to_aes2501(dev, buffer, 126); ++ ++ /* Part 3 */ ++ ++ printk(KERN_INFO " -- part 3 --\n"); ++ ++ i = 0; ++ ++ printk(KERN_INFO " reg 0xaf = 0x%x\n", buffer[0x5f]); ++ while (buffer[0x5f] == 0x6b) ++ { ++ //msleep(200); ++ ++ ++ //send_data_to_aes2501(dev, cmd3_00, 2); ++ write_aes2501_register(dev, 0xff, 0x00);/* Reserved */ ++ ++ //msleep(80); ++ ++ //send_data_to_aes2501(dev, cmd3_01, 12); ++ ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_AUTOCALOFFSET, 0x41); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x42);/* ??? */ ++ write_aes2501_register(dev, AES2501_REG_DETCTRL, 0x53);/* Cumul ??? */ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE); ++ write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_READ_REGS); ++ ++ flush_aes2501_bulk_out(dev); ++ ++ ++ ++ ++ recv_data_to_aes2501(dev, buffer, 126); ++ ++ printk(KERN_INFO " +reg 0xaf = 0x%x\n", buffer[0x5f]); ++ ++ if (++i == 13) break; ++ ++ } ++ ++ ++ ++ ++ ++ /* Part 4 */ ++ ++ printk(KERN_INFO " -- part 4 --\n"); ++ ++ //send_data_to_aes2501(dev, cmd4, 14); ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ write_aes2501_register(dev, 0xb0, 0x27);/* Reserved */ ++ write_aes2501_register(dev, AES2501_REG_ENDROW, 0x0a); ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE); ++ write_aes2501_register(dev, AES2501_REG_DETCTRL, 0x45);/* ???? */ ++ write_aes2501_register(dev, AES2501_REG_AUTOCALOFFSET, 0x41); ++ ++ ++ ++ ++ ++ ++ /* ... */ ++ ++ ++/* ++ for (i = 0; i < 126; i += 10) ++ { ++ printk(KERN_INFO " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", ++ buffer[i + 0], buffer[i + 1], buffer[i + 2], buffer[i + 3], buffer[i + 4], ++ buffer[i + 5], buffer[i + 6], buffer[i + 7], buffer[i + 8], buffer[i + 9]); ++ ++ if (i % 20 == 0) ++ printk(KERN_INFO "\n "); ++ ++ } ++ ++ printk(KERN_INFO "\n"); ++*/ ++ ++ ++ ++ /* Part 5 */ ++ ++ printk(KERN_INFO " -- part 5 --\n"); ++ ++ //send_data_to_aes2501(dev, cmd5_00, 2); ++ ++ write_aes2501_register(dev, 0xb0, 0x27);/* Reserved */ ++ ++ //send_data_to_aes2501(dev, cmd5_01, 4); ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ ++ //msleep(200); ++ ++ ++ //send_data_to_aes2501(dev, cmd5_02, 2); ++ //send_data_to_aes2501(dev, cmd5_01, 4); ++ //send_data_to_aes2501(dev, cmd5_01, 4); ++ ++ write_aes2501_register(dev, 0xff, 0x00);/* Reserved */ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ ++ ++ ++ //msleep(50); ++ ++ //send_data_to_aes2501(dev, cmd5_01, 4); ++ //send_data_to_aes2501(dev, cmd5_01, 4); ++ //send_data_to_aes2501(dev, cmd5_01, 4); ++ //send_data_to_aes2501(dev, cmd5_03, 2); ++ //send_data_to_aes2501(dev, cmd5_03, 2); ++ //send_data_to_aes2501(dev, cmd5_04, 2); ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_SCAN_RESET); ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_SCAN_RESET); ++ write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_READ_REGS); ++ flush_aes2501_bulk_out(dev); ++ ++ ++ recv_data_to_aes2501(dev, buffer, 126); ++ ++ ++ ++ ++ ++ return 0; ++ ++} ++ ++static int detect_finger_on_aes2501(struct usb_aes2501 *dev) ++{ ++ //uint8_t cmd1[] = "\x80\x01\x82\x40"; ++ //uint8_t cmd2[] = "\x80\x01\x82\x40\x83\x00\x88\x02\x89\x10\x8a\x05\x8c\x00\x8e\x13\x91\x44\x92\x34\x95\x16\x96\x16\x97\x18\xa1\x70\xa2\x02\xa7\x00\xac\x01\xad\x1a\x80\x04\x81\x04\xb4\x00";/*42*/ ++ ++ ++ unsigned char buffer[22]; ++ unsigned i, sum; ++ ++ //send_data_to_aes2501(dev, cmd1, 4); ++ ++ //msleep(30); ++ ++ ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* Reserved */ ++ write_aes2501_register(dev, AES2501_REG_DETCTRL, AES2501_DETCTRL_DRATE_CONTINUOUS | AES2501_DETCTRL_SDELAY_31_MS); ++ write_aes2501_register(dev, AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US);/* not the faster ??? */ ++ write_aes2501_register(dev, AES2501_REG_MEASDRV, AES2501_MEASDRV_MDRIVE_0_325 | AES2501_MEASDRV_MEASURE_SQUARE); ++ write_aes2501_register(dev, AES2501_REG_MEASFREQ, AES2501_MEASFREQ_2M); ++ write_aes2501_register(dev, AES2501_REG_DEMODPHASE1, DEMODPHASE_NONE);/* Default */ ++ write_aes2501_register(dev, AES2501_REG_DEMODPHASE2, DEMODPHASE_NONE); ++ write_aes2501_register(dev, AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE2_4X | AES2501_CHANGAIN_STAGE1_16X); ++ write_aes2501_register(dev, AES2501_REG_ADREFHI, 0x44); ++ write_aes2501_register(dev, AES2501_REG_ADREFLO, 0x34); ++ write_aes2501_register(dev, AES2501_REG_STRTCOL, 0x16); ++ write_aes2501_register(dev, AES2501_REG_ENDCOL, 0x16); ++ write_aes2501_register(dev, AES2501_REG_DATFMT, AES2501_DATFMT_BIN_IMG | 0x08); ++ write_aes2501_register(dev, AES2501_REG_TREG1, 0x70);/* Reserved + 0xXX */ ++ write_aes2501_register(dev, 0xa2, 0x02);/* Reserved */ ++ write_aes2501_register(dev, 0xa7, 0x00);/* Reserved */ ++ write_aes2501_register(dev, AES2501_REG_TREGC, AES2501_TREGC_ENABLE); ++ write_aes2501_register(dev, AES2501_REG_TREGD, 0x1a); ++ ++ flush_aes2501_bulk_out(dev); ++ ++ /** ++ * TODO: ++ * - lire ici les deux octets. ++ * - voir pour inverser les commandes. ++ */ ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE); ++ write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT); ++ write_aes2501_register(dev, AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE); ++ ++ flush_aes2501_bulk_out(dev); ++ ++ ++ //send_data_to_aes2501(dev, cmd2, 42); ++ ++ recv_data_to_aes2501(dev, buffer, 20); ++ ++ ++ /* One column is returned here but I don't know which one. ++ Maybe an average over the whole sensor area. */ ++ sum = 0; ++ for (i = 1; i != 9; i++) { ++ sum += (buffer[i] & 0xf) + (buffer[i] >> 4); ++ } ++ ++ ++ //printk(KERN_INFO "===finger=== sum = %d vs %d\n", sum, 20); ++ ++ ++ /* ++ return (sum > aes->fingerTh1); ++ */ ++ ++ return sum > 20; ++ ++} ++ ++ ++static unsigned read_fingerprint_on_aes2501(struct usb_aes2501 *dev, void *raw_, unsigned maxstrip) ++{ ++ //unsigned char patch_msg[] = "\x80\x01"; ++ ++ /* 8e xx = set gain */ ++ //uint8_t cmd1_00[] = "0x80\x01\x82\x40"; ++ //uint8_t cmd1_01[] = "0x80\x01\x82\x40\x83\x00\x88\x02\x8c\x7c\x89\x10\x8d\x24\x9b\x00\x9c\x6c\x9d\x09\x9e\x54\x9f\x78\xa2\x02\xa7\x00\xb6\x26\xb7\x1a\x80\x04\x98\x23\x95\x10\x96\x1f\x8e\x00\x91\x70\x92\x20\x81\x04\xb4\x00";/*50*/ ++ ++ //uint8_t cmd2[] = "\x98\x23\x95\x10\x96\x1f\x8e\x03\x91\x70\x92\x20\x81\x04";/*14*/ ++ ++ //uint8_t cmd3[] = "\x98\x22\x95\x00\x96\x2f\x8e\x03\x91\x5b\x92\x20\x81\x04";/*14*/ ++ ++ uint8_t buf[1705]; ++ uint8_t *raw = (uint8_t *) raw_; ++ unsigned nstrips; ++ ++ int threshold; ++ int sum; ++ ++ ++ //send_data_to_aes2501(dev, patch_msg, 2); ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ flush_aes2501_bulk_out(dev); ++ ++ ++ ++ //send_data_to_aes2501(dev, cmd1_00, 4); ++ ++ ++ //send_data_to_aes2501(dev, cmd1_01, 50); ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* Reserved */ ++ write_aes2501_register(dev, AES2501_REG_DETCTRL, AES2501_DETCTRL_SDELAY_31_MS | AES2501_DETCTRL_DRATE_CONTINUOUS); ++ write_aes2501_register(dev, AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US); ++ write_aes2501_register(dev, AES2501_REG_DEMODPHASE2, 0x7c);/* ... */ ++ write_aes2501_register(dev, AES2501_REG_MEASDRV, AES2501_MEASDRV_MEASURE_SQUARE | AES2501_MEASDRV_MDRIVE_0_325); ++ write_aes2501_register(dev, AES2501_REG_DEMODPHASE1, 0x24);/* ... */ ++ write_aes2501_register(dev, AES2501_REG_CHWORD1, 0x00);/* Challenge Word */ ++ write_aes2501_register(dev, AES2501_REG_CHWORD2, 0x6c);/* Challenge Word */ ++ write_aes2501_register(dev, AES2501_REG_CHWORD3, 0x09);/* Challenge Word */ ++ write_aes2501_register(dev, AES2501_REG_CHWORD4, 0x54);/* Challenge Word */ ++ write_aes2501_register(dev, AES2501_REG_CHWORD5, 0x78);/* Challenge Word */ ++ write_aes2501_register(dev, 0xa2, 0x02);/* Reserved */ ++ write_aes2501_register(dev, 0xa7, 0x00);/* Reserved */ ++ write_aes2501_register(dev, 0xb6, 0x26);/* Reserved */ ++ write_aes2501_register(dev, 0xb7, 0x1a);/* Reserved */ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE); ++ write_aes2501_register(dev, AES2501_REG_IMAGCTRL, AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE | AES2501_IMAGCTRL_IMG_DATA_DISABLE); ++ write_aes2501_register(dev, AES2501_REG_STRTCOL, 0x10); ++ write_aes2501_register(dev, AES2501_REG_ENDCOL, 0x1f); ++ write_aes2501_register(dev, AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE1_2X | AES2501_CHANGAIN_STAGE2_2X); ++ write_aes2501_register(dev, AES2501_REG_ADREFHI, 0x70); ++ write_aes2501_register(dev, AES2501_REG_ADREFLO, 0x20); ++ write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT); ++ write_aes2501_register(dev, AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE); ++ ++ ///////recv_data_to_aes2501(dev, buf, 159); ++ /* TODO: calibration e.g setting gain (0x8e xx) */ ++ ++ ++ ++ ++ //send_data_to_aes2501(dev, cmd2, 14); ++ ++ ++ ++ write_aes2501_register(dev, AES2501_REG_IMAGCTRL, AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE | AES2501_IMAGCTRL_IMG_DATA_DISABLE); ++ write_aes2501_register(dev, AES2501_REG_STRTCOL, 0x10); ++ write_aes2501_register(dev, AES2501_REG_ENDCOL, 0x1f); ++ write_aes2501_register(dev, AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE1_16X); ++ write_aes2501_register(dev, AES2501_REG_ADREFHI, 0x70); ++ write_aes2501_register(dev, AES2501_REG_ADREFLO, 0x20); ++ write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT); ++ ++ flush_aes2501_bulk_out(dev); ++ ++ ++ recv_data_to_aes2501(dev, buf, 159); ++ ++ nstrips = 0; ++ do { ++ printk(KERN_INFO "-start-\n"); ++ /* Timing in this loop is critical. It decides how fast you can move your finger. ++ If one loop takes tl second, the maximum speed is: ++ (16/500 * 25.4) / tl [mm per sec] ++ */ ++ //send_data_to_aes2501(dev, cmd3, 14); ++ ++ write_aes2501_register(dev, AES2501_REG_IMAGCTRL, AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE); ++ write_aes2501_register(dev, AES2501_REG_STRTCOL, 0x00); ++ write_aes2501_register(dev, AES2501_REG_ENDCOL, 0x2f); ++ write_aes2501_register(dev, AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE1_16X); ++ write_aes2501_register(dev, AES2501_REG_ADREFHI, 0x5b); ++ write_aes2501_register(dev, AES2501_REG_ADREFLO, 0x20); ++ write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT); ++ ++ flush_aes2501_bulk_out(dev); ++ ++ ++ ++ recv_data_to_aes2501(dev, buf, 1705); ++ memcpy(raw, buf+1, 192*8); ++ raw += 192*8; ++ ++ printk(KERN_INFO "-end of copy-\n"); ++ ++ ++ threshold = read_register_value((buf + 1 + 192*8 + 1 + 16*2 + 1 + 8), _AES2501_REG_DATFMT); ++ /*if (threshold < 0) ++ return threshold;*/ ++ ++ threshold &= 0x0f; ++ ++ sum = sum_histogram_values((buf + 1 + 192*8), threshold); ++ /*if (threshold < 0) ++ return threshold;*/ ++ ++ nstrips++; ++ printk(KERN_INFO "-end- %d vs %d\n", nstrips, maxstrip); ++ } while (sum > 0 && nstrips < maxstrip); ++ printk(KERN_INFO "nstrips = %u\n", nstrips); ++ if (nstrips == maxstrip) ++ printk(KERN_INFO "nstrips == %u, swiping the finger too slowly?\n", maxstrip); ++ return nstrips; ++} ++ ++ ++ ++/** ++ * Read a register value from a dump sent by the device. ++ * @data: list of couples . ++ * @target: index of the register to process. ++ * @return: -EILSEQ,-EINVAL if error, value > 0 if a finger is here. ++ */ ++int read_register_value(const uint8_t *data, Aes2501Registers target) ++{ ++ int result; ++ uint8_t offset; ++ ++ if (*data == FIRST_AES2501_REG) ++ { ++ offset = target; ++ ++ if (!(FIRST_AES2501_REG <= offset && offset <= LAST_AES2501_REG)) ++ result = -EINVAL; ++ ++ else ++ { ++ offset -= FIRST_AES2501_REG; ++ offset *= 2; ++ ++ result = data[++offset]; ++ ++ } ++ ++ } ++ else result = -EILSEQ; ++ ++ return result; ++ ++} ++ ++ ++/** ++ * Tells if a finger motion is still detected. ++ * @data: start point of data to handle, preceded by 0xde. ++ * @threshold: index of values set to 1 by the device. ++ * @return: -EILSEQ,-EINVAL if error, value > 0 if a finger is here. ++ * ++ * Histograms always are a 16-uint16_t long message, where ++ * histogram[i] = number of pixels of value i. ++ */ ++int sum_histogram_values(const uint8_t *data, uint8_t threshold) ++{ ++ int result; ++ uint16_t *histogram; ++ uint8_t i; ++ ++ if (*data == 0xde) ++ { ++ if (threshold > 0x0f) ++ result = -EINVAL; ++ ++ else ++ { ++ result = 0; ++ histogram = (uint16_t *)(data + 1); ++ ++ for (i = threshold; i < 16; i++) ++ result += histogram[i]; ++ ++ } ++ ++ } ++ else result = -EILSEQ; ++ ++ return result; ++ ++} ++ ++ ++ ++/********************************************************** ++ ** Image processing ++ **********************************************************/ ++ ++/* This function finds overlapping parts of two frames ++ * Based on calculating normalized hamming distance ++ * between two frames ++ */ ++ ++static unsigned find_overlap(const uint8_t *first_frame, ++ const uint8_t *second_frame, ++ uint32_t frame_height, ++ uint32_t frame_width, ++ uint32_t *min_error) ++{ ++ uint32_t dy, i; ++ uint32_t error, not_overlapped_height = 0; ++ *min_error = 255 * frame_height * frame_width; ++ for (dy = 0; dy < frame_height; dy++) { ++ /* Calculating difference (error) between parts of frames */ ++ error = 0; ++ for (i = 0; i < frame_width * (frame_height - dy); i++) { ++ /* Using ? operator to avoid abs function */ ++ error += first_frame[i] > second_frame[i] ? ++ (first_frame[i] - second_frame[i]) : ++ (second_frame[i] - first_frame[i]); ++ } ++ ++ /* Normalizing error */ ++ error *= 15; ++ error /= i; ++ if (error < *min_error) { ++ *min_error = error; ++ not_overlapped_height = dy; ++ } ++ first_frame += frame_width; ++ } ++ ++ return not_overlapped_height; ++} ++ ++ ++/* This function assembles frames to single image, returns image height ++ * TODO: add Doxygen comments ++ */ ++static unsigned assemble(const uint8_t *input, /* Raw data received from device */ ++ uint8_t *output, /* Output buffer */ ++ uint32_t frame_height, /* Height of each frame */ ++ uint32_t frame_width, /* Width of each frame */ ++ uint32_t frames_count, /* Frames count */ ++ /*int overlap, */ ++ uint8_t reversed, ++ uint32_t *errors_sum ++ ) ++{ ++ uint8_t *assembled = output; ++ uint32_t frame, column, row, image_height = frame_height; ++ uint32_t error, not_overlapped; ++ ++ *errors_sum = 0; ++ ++ if (frames_count < 1) return 0; ++ ++ /* Rotating given data by 90 degrees ++ * Taken from document describing aes2501 image format ++ * TODO: move reversing detection here */ ++ if (reversed) { ++ output += (frames_count - 1) * frame_width * frame_height; ++ } ++ ++ for (frame = 0; frame < frames_count; frame++) { ++ for (column = 0; column < frame_width; column++) { ++ for (row = 0; row < (frame_height / 2); row++) { ++ output[frame_width * ( 2 * row) + column] = *input & 0x0F; ++ output[frame_width * ( 2 * row + 1) + column] = *input >> 4; ++ input++; ++ } ++ } ++ ++ if (reversed) { ++ output -= frame_width * frame_height; ++ } ++ else { ++ output += frame_width * frame_height; ++ } ++ } ++ ++ /* Detecting where frames overlaped */ ++ output = assembled; ++ for (frame = 1; frame < frames_count; frame++) ++ { ++ output += frame_width * frame_height; ++ not_overlapped = find_overlap(assembled, output, frame_height, frame_width, &error); ++ *errors_sum += error; ++ image_height += not_overlapped; ++ assembled += frame_width * not_overlapped; ++ memcpy(assembled, output, frame_width * frame_height); ++ } ++ ++ return image_height; ++} ++ ++ ++ ++static void store_new_aes2501_pnm(const uint8_t *data, unsigned int width, unsigned int height) ++{ ++ char header[20]; ++ __kernel_size_t header_len; ++ int i; ++ char *iter; ++ ++ sprintf(header, "P5\n%u %u\n255\n", width, height); ++ header_len = strlen(header); ++ ++ finger_print_len = header_len + width * height; ++ finger_print = kzalloc(finger_print_len, GFP_KERNEL); ++ ++ memcpy(finger_print, header, header_len); ++ ++ for (i = 0, iter = &finger_print[header_len]; i < width * height; i++, iter++) ++ *iter = (data[i] << 4) + 0x0f; ++ ++} ++ ++ ++ ++static void do_scanning(struct work_struct *work) ++{ ++ struct usb_aes2501 *dev; ++ ++ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ ++ ++ uint8_t *raw, *cooked; ++ unsigned swidth = 192; ++ unsigned sheight = 16; ++ unsigned maxstrip = 150; ++ unsigned nstrips, height, mindiff_sum, mindiff_sum_r; ++ ++ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ ++ ++ dev = container_of(work, struct usb_aes2501, scan_work); ++ ++ ++ ++ ++ ++ ++ setup_aes2501(dev); ++ ++ while (!detect_finger_on_aes2501(dev)) ++ { ++ if (dev->stop_scan) ++ { ++ PRINTK_INFO("aborting scan due to module removal\n"); ++ return; ++ } ++ }; ++ ++ /* We don't need physical continuity of allocated memory */ ++ raw = (uint8_t *)vmalloc((3 * maxstrip * sheight * swidth) / 2); ++ if (raw == NULL) ++ { ++ PRINTK_CRIT("failed to allocate memory\n"); ++ return; ++ } ++ ++ cooked = raw + (maxstrip * sheight * swidth)/2; ++ ++ ++ ++ printk(KERN_INFO "Raw is 0x%p\n", raw); ++ ++ ++ printk(KERN_INFO "Scanning...\n"); ++ nstrips = read_fingerprint_on_aes2501(dev, raw, maxstrip); ++ ++ printk(KERN_INFO "Assembling...\n"); ++ ++ ++ height = assemble(raw, cooked, 16, 192, nstrips, 0, &mindiff_sum); ++ height = assemble(raw, cooked, 16, 192, nstrips, 1, &mindiff_sum_r); ++ ++ ++ printk(KERN_INFO "Mindiff normal: %d, mindiff reversed: %d\n", mindiff_sum, mindiff_sum_r); ++ ++ if (mindiff_sum_r < mindiff_sum) ++ { ++ PRINTK_INFO("reversed image detected\n"); ++ } ++ else ++ { ++ height = assemble(raw, cooked, 16, 192, nstrips, 0, &mindiff_sum); ++ } ++ ++ printk(KERN_INFO "First height :: %d\n", height); ++ ++#if 0 ++ if (height < 100) { ++ /* It was a "touch", not a finger scan. */ ++ printk(KERN_INFO "Was only a 'touch' ;( [%d]\n", height); ++ /*break;*/ ++ } ++ else ++ ++ { ++ //store_new_aes2501_pnm(cooked, swidth, height); ++ height = assemble(raw, cooked, nstrips, 1, sensor_reversed); ++ printk(KERN_INFO "Second height :: %d\n", height); ++ store_new_aes2501_pnm(cooked, swidth, height); ++ } ++#endif ++ store_new_aes2501_pnm(cooked, swidth, height); ++ standby_aes2501(dev); ++ ++ vfree(raw); ++ ++ flag = 1; ++ wake_up_interruptible(&wq); ++ ++ ++} ++ ++ ++static int aes2501_open(struct inode *inode, struct file *file) ++{ ++ struct usb_aes2501 *dev; ++ ++ //return 0; ++ ++ ++ dev = _dev; ++ ++ printk(KERN_INFO "Plop !\n"); ++ ++ ++ return 0; ++} ++ ++ ++ ++ ++ ++ ++/* ++ * usb class driver info in order to get a minor number from the usb core, ++ * and to have the device registered with the driver core ++ */ ++static struct usb_class_driver aes2501_class = { ++ .name = "aes2501%d", ++ .fops = &aes2501_fops, ++ .minor_base = USB_AES2501_MINOR_BASE, ++}; ++ ++static int aes2501_probe(struct usb_interface *interface, const struct usb_device_id *id) ++{ ++ int retval; ++ struct usb_aes2501 *dev; ++ struct usb_host_interface *iface_desc; ++ __u8 i; ++ struct usb_endpoint_descriptor *endpoint; ++ __u16 buffer_size; ++ ++ ++ ++#if 0 ++ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ ++ ++ uint8_t *raw, *cooked; ++ unsigned swidth = 192; ++ unsigned sheight = 16; ++ unsigned maxstrip = 150; ++ unsigned nstrips, height; ++ ++ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ ++ ++ ++ raw = (uint8_t *)__get_free_page(GFP_KERNEL);//kmalloc((3 * maxstrip * sheight * swidth) / 2, GFP_KERNEL); ++ cooked = raw + (maxstrip * sheight * swidth)/2; ++#endif ++ ++ printk(KERN_INFO "aes2501 probe !\n"); ++ ++ ++ retval = -ENOMEM; ++ ++ /* Allocate memory for our device state and initialize it */ ++ ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ if (dev == NULL) ++ { ++ PRINTK_CRIT("out of memory\n"); ++ goto error; ++ } ++ ++ _dev = dev; ++ ++ dev->stop_scan = 0; ++ ++ kref_init(&dev->kref); ++ sema_init(&dev->limit_sem, WRITES_IN_FLIGHT); ++ mutex_init(&dev->io_mutex); ++ ++ dev->udev = usb_get_dev(interface_to_usbdev(interface)); ++ dev->interface = interface; ++ ++ printk(KERN_INFO "num_altsetting == %d\n", interface->num_altsetting); ++ ++ /** ++ * Set up the endpoint information. ++ * Use only the first bulk-in and bulk-out endpoints. ++ */ ++ ++ iface_desc = interface->cur_altsetting; ++ ++ printk(KERN_INFO "BULK COUNT %d\n", iface_desc->desc.bNumEndpoints); ++ ++ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) ++ { ++ endpoint = &iface_desc->endpoint[i].desc; ++ ++ if (!dev->bulk_in_endpointAddr && /*usb_endpoint_is_bulk_in(endpoint))*/ ++ ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ++ == USB_DIR_IN) && ++ ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ++ == USB_ENDPOINT_XFER_BULK)) ++ { ++ /* We found a bulk in endpoint */ ++ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); ++ dev->bulk_in_size = buffer_size; ++ dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; ++ dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); ++ ++ printk(KERN_INFO "BULK IN %d ; size = %d\n", i, buffer_size); ++ ++ if (dev->bulk_in_buffer == NULL) ++ { ++ PRINTK_CRIT("could not allocate bulk_in_buffer\n"); ++ goto error; ++ } ++ ++ } ++ ++ if (!dev->bulk_out_endpointAddr && /*usb_endpoint_is_bulk_out(endpoint))*/ ++ ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ++ == USB_DIR_OUT) && ++ ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ++ == USB_ENDPOINT_XFER_BULK)) ++ { ++ printk(KERN_INFO "BULK OUT %d\n", i); ++ ++ /* We found a bulk out endpoint */ ++ dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; ++ } ++ ++ } ++ ++ if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) ++ { ++ PRINTK_CRIT("could not find both bulk-in and bulk-out endpoints\n"); ++ goto error; ++ } ++ ++/* ++ dev->once_tasklet = kzalloc(sizeof(*dev->once_tasklet), GFP_KERNEL); ++ if (dev->once_tasklet == NULL) ++ { ++ PRINTK_CRIT("out of memory\n"); ++ goto error; ++ } ++*/ ++ /* Save our data pointer in this interface device */ ++ usb_set_intfdata(interface, dev); ++ ++ /* We can register the device now, as it is ready */ ++ retval = usb_register_dev(interface, &aes2501_class); ++ if (retval) { ++ /* something prevented us from registering this driver */ ++ PRINTK_CRIT("not able to get a minor for this device\n"); ++ usb_set_intfdata(interface, NULL); ++ goto error; ++ } ++ ++ /* Let the user know what node this device is now attached to */ ++ PRINTK_INFO("device now attached to aes2501-%d\n", interface->minor); ++ ++#if 0 ++ setup_aes2501(dev); ++ ++ while (!detect_finger_on_aes2501(dev)); ++ ++ ++ printk(KERN_INFO "Raw is 0x%p\n", raw); ++ ++ ++ printk(KERN_INFO "Scanning...\n"); ++ nstrips = read_fingerprint_on_aes2501(dev, raw, maxstrip); ++ ++ printk(KERN_INFO "Assembling...\n"); ++ ++ height = assemble(raw, cooked, nstrips, 1); ++ if (height < 100) { ++ /* It was a "touch", not a finger scan. */ ++ printk(KERN_INFO "Was only a 'touch' ;(\n"); ++ /*break;*/ ++ } ++ else ++ { ++ store_new_aes2501_pnm(cooked, swidth, height); ++ height = assemble(raw, cooked, nstrips, 0); ++ store_new_aes2501_pnm(cooked, swidth, height); ++ } ++ ++ standby_aes2501(dev); ++#endif ++ ++ return 0; ++ ++error: ++ if (dev != NULL) ++ kref_put(&dev->kref, aes2501_delete); ++ ++ return retval; ++ ++} ++ ++ ++static void aes2501_disconnect(struct usb_interface *interface) ++{ ++ int minor; ++ struct usb_aes2501 *dev; ++ ++ minor = interface->minor; ++ ++ /* Prevent aes2501_open() from racing aes2501_disconnect() */ ++ lock_kernel(); ++ ++ dev = usb_get_intfdata(interface); ++ usb_set_intfdata(interface, NULL); ++ ++ /* Give back our minor */ ++ usb_deregister_dev(interface, &aes2501_class); ++ ++ /* Prevent more I/O from starting */ ++ mutex_lock(&dev->io_mutex); ++ dev->interface = NULL; ++ mutex_unlock(&dev->io_mutex); ++ ++ unlock_kernel(); ++ ++ /* Decrement our usage count */ ++ kref_put(&dev->kref, aes2501_delete); ++ ++ PRINTK_INFO("aes2501 device #%d now disconnected\n", minor); ++ ++ ++ ++ ++ printk(KERN_INFO "aes2501 disconnect !\n"); ++ ++ ++} ++ ++ ++static struct usb_driver aes2501_driver = { ++ .name = "aes2501", ++ .probe = aes2501_probe, ++ .disconnect = aes2501_disconnect, ++ .id_table = id_table, ++}; ++ ++ ++static int __init aes2501_init(void) ++{ ++ int retval; ++ ++ comm_queue = create_singlethread_workqueue("aes2501"); ++ if (comm_queue == NULL) { ++ PRINTK_CRIT("could not create work queue\n"); ++ return -ENOMEM; ++ } ++ ++ retval = usb_register(&aes2501_driver); ++ if (retval == -EINVAL) ++ { ++ printk(KERN_ERR "usb_register failed. Error number %d\n", retval); ++ destroy_workqueue(comm_queue); ++ return retval; ++ } ++ ++ return 0; ++ ++} ++ ++static void __exit aes2501_exit(void) ++{ ++ _dev->stop_scan = 1; ++ destroy_workqueue(comm_queue); ++ usb_deregister(&aes2501_driver); ++} ++ ++module_init(aes2501_init); ++module_exit(aes2501_exit); ++ ++MODULE_AUTHOR("Cyrille Bagard"); ++MODULE_DESCRIPTION("AES 2501 fingerprint scanner driver"); ++MODULE_LICENSE("GPL"); +diff -Nurp linux-2.6.37/3rdparty/aes2501/aes2501.h linux-2.6.37.3rdparty/3rdparty/aes2501/aes2501.h +--- linux-2.6.37/3rdparty/aes2501/aes2501.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/aes2501/aes2501.h 2008-01-14 03:07:30.000000000 +0200 +@@ -0,0 +1,40 @@ ++ ++/* ++ * aes2501.h -- AuthenTec AES2501 Fingerprint Sensor Driver for Linux ++ * ++ * Maintainer: Cyrille Bagard ++ * ++ * Copyright (C) 2007 Cyrille Bagard ++ * ++ * This file is part of the AES2501 driver. ++ * ++ * the AES2501 driver 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. ++ * ++ * the AES2501 driver 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 the AES2501 driver; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++ ++ ++#ifndef __AES2501_H ++#define __AES2501_H ++ ++ ++#define AES2501_IOC_MAGIC 'N' ++ ++ ++#define AES2501_IOC_TEST _IOW(AES2501_IOC_MAGIC, 1, int) ++ ++ ++ ++ ++#endif /* __AES2501_H */ +diff -Nurp linux-2.6.37/3rdparty/aes2501/aes2501_regs.h linux-2.6.37.3rdparty/3rdparty/aes2501/aes2501_regs.h +--- linux-2.6.37/3rdparty/aes2501/aes2501_regs.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/aes2501/aes2501_regs.h 2008-01-14 03:07:30.000000000 +0200 +@@ -0,0 +1,464 @@ ++ ++/* ++ * aes2501_regs.h -- AuthenTec AES2501 Fingerprint Sensor Driver for Linux ++ * ++ * Maintainer: Cyrille Bagard ++ * ++ * Copyright (C) 2007 Cyrille Bagard ++ * ++ * This file is part of the AES2501 driver. ++ * ++ * the AES2501 driver 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. ++ * ++ * the AES2501 driver 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 the AES2501 driver; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++ ++ ++#ifndef __AES2501_REGS_H ++#define __AES2501_REGS_H ++ ++ ++ ++/* ++ * AES2501 Control Register 1 (CTRL1) ++ */ ++ ++#define AES2501_REG_CTRL1 0x80 ++ ++#define AES2501_CTRL1_MASTER_RESET 0x01 /* Master reset, same as Power On Reset */ ++#define AES2501_CTRL1_SCAN_RESET 0x02 /* Scan reset: stop and restart the scan sequencer */ ++#define AES2501_CTRL1_REG_UPDATE 0x04 /* 1 = continuously updated, 0 = updated prior to starting a scan */ ++ ++ ++/* ++ * AES2501 Control Register 2 (CTRL2) ++ */ ++ ++#define AES2501_REG_CTRL2 0x81 ++ ++#define AES2501_CTRL2_CONTINUOUS 0x01 /* 1 = continuous scans, 0 = single scans */ ++#define AES2501_CTRL2_READ_REGS 0x02 /* Read the current state of the local registers in the Sensor IC */ ++#define AES2501_CTRL2_SET_ONE_SHOT 0x04 /* Set the one-shot flip-flop */ ++#define AES2501_CTRL2_CLR_ONE_SHOT 0x08 /* Clear the one-shot flip-flop */ ++#define AES2501_CTRL2_READ_ID 0x10 /* Read the ID register of the chip */ ++ ++ ++/* ++ * AES2501 Excitation Common Control Register (EXCITCTRL) ++ */ ++ ++#define AES2501_REG_EXCITCTRL 0x82 ++ ++#define AES2501_EXCITCTRL_LO_PWR 0x01 /* If set, enable detection in sleep/suspend mode */ ++#define AES2501_EXCITCTRL_AUTO_CAL 0x02 /* If set, perform finger detection calibration */ ++#define AES2501_EXCITCTRL_SGC_ENABLE 0x04 /* ??? */ ++#define AES2501_EXCITCTRL_SGC_RESTART 0x08 /* ??? */ ++ ++#define AES2501_EXCITCTRL_EXCIT_SQR 0x20 /* Select the (1=square | 0=sine) wave finger drive signal */ ++#define AES2501_EXCITCTRL_EXCIT_BOOST 0x10 /* TODO: understand this part */ ++ ++ ++/* ++ * AES2501 Detect Control Register (DETCTRL) ++ */ ++ ++#define AES2501_REG_DETCTRL 0x83 ++ ++enum aes2501_detection_rate { ++ ++ AES2501_DETCTRL_DRATE_CONTINUOUS = 0x00, /* Detection cycles occur continuously */ ++ AES2501_DETCTRL_DRATE_16_MS = 0x01, /* Detection cycles occur every 16.62 ms */ ++ AES2501_DETCTRL_DRATE_31_MS = 0x02, /* Detection cycles occur every 31.24 ms */ ++ AES2501_DETCTRL_DRATE_62_MS = 0x03, /* Detection cycles occur every 62.50 ms */ ++ AES2501_DETCTRL_DRATE_125_MS = 0x04, /* Detection cycles occur every 125.0 ms */ ++ AES2501_DETCTRL_DRATE_250_MS = 0x05, /* Detection cycles occur every 250.0 ms */ ++ AES2501_DETCTRL_DRATE_500_MS = 0x06, /* Detection cycles occur every 500.0 ms */ ++ AES2501_DETCTRL_DRATE_1_S = 0x07 /* Detection cycles occur every 1 s */ ++ ++}; ++ ++enum aes2501_settling_delay { ++ ++ AES2501_DETCTRL_SDELAY_31_MS = 0x00, /* 31.25 ms */ ++ AES2501_DETCTRL_SSDELAY_62_MS = 0x10, /* 62.5 ms */ ++ AES2501_DETCTRL_SSDELAY_125_MS = 0x20, /* 125 ms */ ++ AES2501_DETCTRL_SSDELAY_250_MS = 0x30 /* 250 ms */ ++ ++}; ++ ++ ++ ++ ++ ++/* ++ * AES2501 Column Scan Rate Register (COLSCAN) ++ */ ++ ++#define AES2501_REG_COLSCAN 0x88 ++ ++enum aes2501_col_scan_rate { ++ ++ AES2501_COLSCAN_SRATE_32_US = 0x00, /* 32 us */ ++ AES2501_COLSCAN_SRATE_64_US = 0x01, /* 64 us */ ++ AES2501_COLSCAN_SRATE_128_US = 0x02, /* 128 us */ ++ AES2501_COLSCAN_SRATE_256_US = 0x03, /* 256 us */ ++ AES2501_COLSCAN_SRATE_512_US = 0x04, /* 512 us */ ++ AES2501_COLSCAN_SRATE_1024_US = 0x05, /* 1024 us */ ++ AES2501_COLSCAN_SRATE_2048_US = 0x06, /* 2048 us */ ++ ++}; ++ ++ ++/* ++ * AES2501 Measure Drive Register (MEASDRV) ++ */ ++ ++#define AES2501_REG_MEASDRV 0x89 ++ ++enum aes2501_mesure_drive { ++ ++ AES2501_MEASDRV_MDRIVE_0_325 = 0x00, /* 0.325 Vpp */ ++ AES2501_MEASDRV_MDRIVE_0_65 = 0x01, /* 0.65 Vpp */ ++ AES2501_MEASDRV_MDRIVE_1_3 = 0x02, /* 1.3 Vpp */ ++ AES2501_MEASDRV_MDRIVE_2_6 = 0x03 /* 2.6 Vpp */ ++ ++}; ++ ++#define AES2501_MEASDRV_SQUARE 0x20 /* Select (1=square | 0=sine) wave drive during measure */ ++#define AES2501_MEASDRV_MEASURE_SQUARE 0x10 /* 0 = use mesure drive setting, 1 = when sine wave is selected */ ++ ++ ++/* ++ * AES2501 Measure Frequency Register (MEASFREQ) ++ */ ++ ++#define AES2501_REG_MEASFREQ 0x8a ++ ++enum aes2501_measure_freq { ++ ++ AES2501_MEASFREQ_125K = 0x01, /* 125 kHz */ ++ AES2501_MEASFREQ_250K = 0x02, /* 250 kHz */ ++ AES2501_MEASFREQ_500K = 0x03, /* 500 kHz */ ++ AES2501_MEASFREQ_1M = 0x04, /* 1 MHz */ ++ AES2501_MEASFREQ_2M = 0x05 /* 2 MHz */ ++ ++}; ++ ++ ++ ++ ++/* ++ * AES2501 Demod Phase 2 Register (DEMODPHASE2) ++ */ ++ ++#define AES2501_REG_DEMODPHASE2 0x8c ++ ++#define DEMODPHASE_NONE 0x00 ++ ++#define DEMODPHASE_180_00 0x40 /* 180 degrees */ ++#define DEMODPHASE_2_81 0x01 /* 2.8125 degrees */ ++ ++ ++/* ++ * AES2501 Demod Phase 1 Register (DEMODPHASE1) ++ */ ++ ++#define AES2501_REG_DEMODPHASE1 0x8d ++ ++#define DEMODPHASE_1_40 0x40 /* 1.40625 degrees */ ++#define DEMODPHASE_0_02 0x01 /* 0.02197256 degrees */ ++ ++ ++/* ++ * AES2501 Channel Gain Register (CHANGAIN) ++ */ ++ ++#define AES2501_REG_CHANGAIN 0x8e ++ ++enum aes2501_sensor_gain1 { ++ ++ AES2501_CHANGAIN_STAGE1_2X = 0x00, /* 2x */ ++ AES2501_CHANGAIN_STAGE1_4X = 0x01, /* 4x */ ++ AES2501_CHANGAIN_STAGE1_8X = 0x02, /* 8x */ ++ AES2501_CHANGAIN_STAGE1_16X = 0x03 /* 16x */ ++ ++}; ++ ++enum aes2501_sensor_gain2 { ++ ++ AES2501_CHANGAIN_STAGE2_2X = 0x00, /* 2x */ ++ AES2501_CHANGAIN_STAGE2_4X = 0x10, /* 4x */ ++ AES2501_CHANGAIN_STAGE2_8X = 0x20, /* 8x */ ++ AES2501_CHANGAIN_STAGE2_16X = 0x30 /* 16x */ ++ ++}; ++ ++ ++ ++/* ++ * AES2501 A/D Reference High Register (ADREFHI) ++ */ ++ ++#define AES2501_REG_ADREFHI 0x91 ++ ++ ++/* ++ * AES2501 A/D Reference Low Register (ADREFLO) ++ */ ++ ++#define AES2501_REG_ADREFLO 0x92 ++ ++ ++/* ++ * AES2501 Start Row Register (STRTROW) ++ */ ++ ++#define AES2501_REG_STRTROW 0x93 ++ ++ ++/* ++ * AES2501 End Row Register (ENDROW) ++ */ ++ ++#define AES2501_REG_ENDROW 0x94 ++ ++ ++/* ++ * AES2501 Start Column Register (STRTCOL) ++ */ ++ ++#define AES2501_REG_STRTCOL 0x95 ++ ++ ++/* ++ * AES2501 End Column Register (ENDCOL) ++ */ ++ ++#define AES2501_REG_ENDCOL 0x96 ++ ++ ++/* ++ * AES2501 Data Format Register (DATFMT) ++ */ ++ ++#define AES2501_REG_DATFMT 0x97 ++ ++#define AES2501_DATFMT_EIGHT 0x40 /* 1 = 8-bit data, 0 = 4-bit data */ ++#define AES2501_DATFMT_LOW_RES 0x20 /* TODO: understand this part */ ++#define AES2501_DATFMT_BIN_IMG 0x10 /* TODO: understand this part */ ++ ++/* TODO: Threshold */ ++ ++ ++/* ++ * AES2501 Image Data Control Register (IMAGCTRL) ++ */ ++ ++#define AES2501_REG_IMAGCTRL 0x98 ++ ++#define AES2501_IMAGCTRL_IMG_DATA_DISABLE 0x01 /* If set, image data message and authentication message are not returned when imaging */ ++#define AES2501_IMAGCTRL_HISTO_DATA_ENABLE 0x02 /* if set, send histogram message when imaging */ ++#define AES2501_IMAGCTRL_HISTO_EACH_ROW 0x04 /* A histo message is sent at the end of (1=each row | 0 = scanning) */ ++#define AES2501_IMAGCTRL_HISTO_FULL_ARRAY 0x08 /* 1 = full image array, 0 = 64x64 center */ ++#define AES2501_IMAGCTRL_REG_FIRST 0x10 /* Registers are returned (1=before | 0=after) image data */ ++#define AES2501_IMAGCTRL_TST_REG_ENABLE 0x20 /* If set, Test Registers are returned with register messages */ ++ ++ ++ ++ ++ ++ ++ ++ ++/* ++ * AES2501 Status Register (STAT) ++ */ ++ ++#define AES2501_REG_STAT 0x9a ++ ++#define AES2501_STAT_SCAN 0x0f /* Scan state */ ++#define AES2501_STAT_ERROR 0x10 /* Framing error */ ++#define AES2501_STAT_PAUSED 0x20 /* Scan paused */ ++#define AES2501_STAT_RESET 0x40 /* Reset occurred */ ++ ++enum aes2501_scan_state { ++ ++ STATE_WAITING_FOR_FINGER = 0x00, /* Waiting for finger */ ++ STATE_FINGER_SETTLING_DELAY = 0x01, /* In Finger settling delay */ ++ STATE_POWER_UP_DELAY = 0x02, /* In power up delay */ ++ STATE_WAITING_TO_START_SCAN = 0x03, /* Waiting to start image scan */ ++ STATE_PRELOADING_SUBARRAY_0 = 0x04, /* Pre-loading subarray 0 */ ++ STATE_SETUP_FOR_ROW_ADVANCE = 0x05, /* Setup for row advance */ ++ STATE_WAITING_FOR_ROW_ADVANCE = 0x06, /* Waiting for row advance */ ++ STATE_PRELOADING_COL_0 = 0x07, /* Pre-loading column 0 */ ++ STATE_SETUP_FOR_COL_ADVANCE = 0x08, /* Setup for column advance */ ++ STATE_WAITING_FOR_COL_ADVANCE = 0x09, /* Waiting for column advance */ ++ STATE_WAITING_FOR_SCAN_START = 0x0a, /* Waiting for scan start */ ++ STATE_WAITING_FOR_SCAN_END = 0x0b, /* Waiting for scan end */ ++ STATE_WAITING_FOR_ROW_SETUP = 0x0c, /* Waiting for row setup */ ++ STATE_WAITING_FOR_COL_TIME = 0x0d, /* Waiting for one column time (depends on scan rate) */ ++ STATE_WAITING_FOR_QUEUED_DATA = 0x0e, /* Waiting for queued data transmission to be completed */ ++ STATE_WAIT_FOR_128_US = 0x0f /* Wait for 128 us */ ++ ++}; ++ ++ ++/* ++ * AES2501 Challenge Word 1 Register (CHWORD1) ++ */ ++ ++#define AES2501_REG_CHWORD1 0x9b ++ ++#define AES2501_CHWORD1_IS_FINGER 0x01 /* If set, finger is present */ ++ ++ ++/* ++ * AES2501 Challenge Word 2 Register (CHWORD2) ++ */ ++ ++#define AES2501_REG_CHWORD2 0x9c ++ ++ ++/* ++ * AES2501 Challenge Word 3 Register (CHWORD3) ++ */ ++ ++#define AES2501_REG_CHWORD3 0x9d ++ ++ ++/* ++ * AES2501 Challenge Word 4 Register (CHWORD4) ++ */ ++ ++#define AES2501_REG_CHWORD4 0x9e ++ ++ ++/* ++ * AES2501 Challenge Word 5 Register (CHWORD5) ++ */ ++ ++#define AES2501_REG_CHWORD5 0x9f ++ ++ ++ ++ ++ ++/* ++ * AES2501 Test Register 1 (TREG1) ++ */ ++ ++#define AES2501_REG_TREG1 0xa1 ++ ++#define AES2501_TREG1_SBIAS_UNLCK 0x10 /* 1 = unlock the controlling of sense amp bias, 0 = sense amp bias changes */ ++ ++enum aes2501_sense_amp_bias { ++ ++ AES2501_TREG1_SAMP_BIAS_2_UA = 0x00, /* 2.5 uA */ ++ AES2501_TREG1_SAMP_BIAS_5_UA = 0x01, /* 5 uA */ ++ AES2501_TREG1_SAMP_BIAS_8_UA = 0x02, /* 8 uA */ ++ AES2501_TREG1_SAMP_BIAS_10_UA = 0x03 /* 10 uA */ ++ ++}; ++ ++ ++ ++ ++/* ++ * AES2501 Auto-Calibration Offset Register (AUTOCALOFFSET) ++ */ ++ ++#define AES2501_REG_AUTOCALOFFSET 0xa8 ++ ++ ++ ++ ++ ++/* ++ * AES2501 Test Register C (TREGC) ++ */ ++ ++#define AES2501_REG_TREGC 0xac ++ ++#define AES2501_TREGC_ENABLE 0x01 /* Enable the reading of the register in TREGD */ ++ ++ ++/* ++ * AES2501 Test Register D (TREGD) ++ */ ++ ++#define AES2501_REG_TREGD 0xad ++ ++ ++ ++ ++ ++/* ++ * AES2501 Low Power Oscillator On Time Register (LPONT) ++ */ ++ ++#define AES2501_REG_LPONT 0xb4 ++ ++/* ++ * This register sets the low power oscillator on time. ++ * Units are roughly equivalent to milliseconds. ++ */ ++ ++#define AES2501_LPONT_MIN_VALUE 0x00 /* 0 ms */ ++#define AES2501_LPONT_MAX_VALUE 0x1f /* About 16 ms */ ++ ++ ++ ++#define ENUM_REG(reg) _ ## reg = reg ++ ++typedef enum _Aes2501Registers ++{ ++ ENUM_REG(AES2501_REG_CTRL1), ++ ENUM_REG(AES2501_REG_CTRL2), ++ ENUM_REG(AES2501_REG_EXCITCTRL), ++ ENUM_REG(AES2501_REG_DETCTRL), ++ ENUM_REG(AES2501_REG_COLSCAN), ++ ENUM_REG(AES2501_REG_MEASDRV), ++ ENUM_REG(AES2501_REG_MEASFREQ), ++ ENUM_REG(AES2501_REG_DEMODPHASE2), ++ ENUM_REG(AES2501_REG_DEMODPHASE1), ++ ENUM_REG(AES2501_REG_CHANGAIN), ++ ENUM_REG(AES2501_REG_ADREFHI), ++ ENUM_REG(AES2501_REG_ADREFLO), ++ ENUM_REG(AES2501_REG_STRTROW), ++ ENUM_REG(AES2501_REG_ENDROW), ++ ENUM_REG(AES2501_REG_STRTCOL), ++ ENUM_REG(AES2501_REG_ENDCOL), ++ ENUM_REG(AES2501_REG_DATFMT), ++ ENUM_REG(AES2501_REG_IMAGCTRL), ++ ENUM_REG(AES2501_REG_STAT), ++ ENUM_REG(AES2501_REG_CHWORD1), ++ ENUM_REG(AES2501_REG_CHWORD2), ++ ENUM_REG(AES2501_REG_CHWORD3), ++ ENUM_REG(AES2501_REG_CHWORD4), ++ ENUM_REG(AES2501_REG_CHWORD5), ++ ENUM_REG(AES2501_REG_TREG1), ++ ENUM_REG(AES2501_REG_AUTOCALOFFSET), ++ ENUM_REG(AES2501_REG_TREGC), ++ ENUM_REG(AES2501_REG_TREGD), ++ ENUM_REG(AES2501_REG_LPONT) ++ ++} Aes2501Registers; ++ ++ ++#define FIRST_AES2501_REG 0x80 ++#define LAST_AES2501_REG 0x9f ++ ++ ++ ++#endif /* __AES2501_REGS_H */ +diff -Nurp linux-2.6.37/3rdparty/aes2501/ChangeLog linux-2.6.37.3rdparty/3rdparty/aes2501/ChangeLog +--- linux-2.6.37/3rdparty/aes2501/ChangeLog 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/aes2501/ChangeLog 2008-01-14 03:07:30.000000000 +0200 +@@ -0,0 +1,95 @@ ++2007-11-05 Cyrille Bagard ++ ++ * aes2501.c: ++ Apply Vasily Khoruzhick's new patch: rewrite image processing functions. ++ Thus, there should be no more significant common points with aes2501-wy. ++ ++2007-11-05 Cyrille Bagard ++ ++ * aes2501.c: ++ In order to respect the license of aes2501-wy, on which this driver is ++ based, begin to rewrite some functions. Thus, better handle histograms. ++ One more strip is often processed, but that is more logical like this. ++ ++ * aes2501_regs.h: ++ Enumerate all used registers for convenience. ++ ++2007-11-03 Cyrille Bagard ++ ++ * aes2501.c: ++ Clean the code. Take care of signals when processes are awaking. ++ Apply Vasily Khoruzhick's new patch: autodetect picture reversing needs ++ and fix kernel oops in case of module removal. ++ ++ * Makefile: ++ Remove hidden files and clean the rules. KERNELDIR has to be overrided ++ from the sheel if needed now. ++ ++2007-10-29 Cyrille Bagard ++ ++ * aes2501.c: ++ Apply Vasily Khoruzhick's patch and thus increase the resulting pictures ++ quality. Many thanks to him ! ++ ++ * Makefile: ++ Add two new rules: usertest and clean. ++ ++ * usertest.c: ++ Initial commit. ++ ++2007-08-27 Cyrille Bagard ++ ++ * aes2501.c: ++ Make INIT_WORK macro working with 2.6.20+ kernels. Many thanks to ++ Miguel Gea Milvaques for the patch ! ++ ++2007-06-13 Cyrille Bagard ++ ++ * aes2501.c: ++ * aes2501_regs.h: ++ Complete translation of all binary communications using well documented ++ registers and values (as often as possible). ++ ++2007-06-13 Cyrille Bagard ++ ++ * aes2501.c: ++ Increase communication speed by buffering bulk out. Output data ++ need to be flushed at the end now. ++ ++2007-06-13 Cyrille Bagard ++ ++ * aes2501.c: ++ * aes2501_regs.h: ++ Translate binary data used in finger detection. Some register values ++ still need to be understood. Note: some hex values are reserved bits ++ in registers. ++ ++2007-06-12 Cyrille Bagard ++ ++ * aes2501.c: ++ Begin the binary translation: the "standby" function now uses understood ++ instructions and prints debug status information if needed. CTRL2 register ++ value needs to be checked. ++ ++ * aes2501_regs.h: ++ Define the interesting hex values for the following registers: ++ CTRL2, STAT, TREGC and TREGD. ++ ++2007-06-12 Cyrille Bagard ++ ++ * aes2501.c: ++ Clean the driver a little bit by removing old piece of code to handle ++ a character device in the old way. ++ ++2007-06-12 Cyrille Bagard ++ ++ * aes2501.c: ++ Use an own work queue. Scanning now starts with the AES2501_IOC_TEST ++ ioctl command. Reading the /dev entry blocks until data is available. ++ ++2007-06-12 Cyrille Bagard ++ ++ * aes2501.c: ++ * aes2501.h: ++ * Makefile: ++ Initial [crappy] commit. +diff -Nurp linux-2.6.37/3rdparty/aes2501/Makefile linux-2.6.37.3rdparty/3rdparty/aes2501/Makefile +--- linux-2.6.37/3rdparty/aes2501/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/aes2501/Makefile 2008-01-14 03:07:30.000000000 +0200 +@@ -0,0 +1,19 @@ ++ ++obj-m := aes2501.o ++ ++KERNELDIR ?= /lib/modules/$(shell uname -r)/build ++ ++PWD := $(shell pwd) ++ ++all: usertest ++ $(MAKE) -C $(KERNELDIR) M=$(PWD) ++ ++usertest: ++ gcc -I. -o usertest usertest.c ++ ++clean: ++ rm -f *.o *~ aes2501.ko aes2501.mod.c Module.symvers usertest ++ rm -rf .tmp_versions ++ rm -f .*.cmd ++ ++ +diff -Nurp linux-2.6.37/3rdparty/aes2501/usertest.c linux-2.6.37.3rdparty/3rdparty/aes2501/usertest.c +--- linux-2.6.37/3rdparty/aes2501/usertest.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/aes2501/usertest.c 2008-01-14 03:07:30.000000000 +0200 +@@ -0,0 +1,78 @@ ++/** ++ * AES2501 Device Driver ++ * Userspace test program ++ * ++ * Compile with: ++ * gcc -I. -o usertest usertest.c ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define BUFFER_SIZE 256 ++ ++ ++int main(int argc, char *argv[]) ++{ ++ int fd_in; ++ int fd_out; ++ char buffer[BUFFER_SIZE]; ++ size_t len; ++ ++ fd_in = -1; ++ fd_out = -1; ++ ++ ++ int data, rdata; ++ ++ ++ ++ fd_in = open("/dev/aes2501", O_RDONLY); ++ if (fd_in == -1) { ++ perror("open() -- "); ++ goto err; ++ } ++ ++ fd_out = open("/root/pic.pnm", O_CREAT | O_WRONLY); ++ if (fd_out == -1) { ++ perror("open() -- "); ++ goto err; ++ } ++ ++ ++ ++ data = 0x55555555; ++ ioctl(fd_in, AES2501_IOC_TEST, data); ++ //ioctl(fd_in, CASE2, &rdata); ++ ++ printf("IOCTL test: written: '%x' - received: '%x'\n", data, rdata); ++ ++ ++ ++ ++ /* Write the fingerprint */ ++ while ((len = read(fd_in, buffer, BUFFER_SIZE)) > 0) ++ write(fd_out, buffer, len); ++ ++ close(fd_in); ++ close(fd_out); ++ ++ return EXIT_SUCCESS; ++ ++ err: ++ ++ if (fd_in != -1) ++ close(fd_in); ++ ++ if (fd_out != -1) ++ close(fd_out); ++ ++ return EXIT_FAILURE; ++ ++} diff --git a/kernel/tools/perf/files/patches/mageia/3rd-aes2501-rmmod-oops-fix.patch b/kernel/tools/perf/files/patches/mageia/3rd-aes2501-rmmod-oops-fix.patch new file mode 100644 index 0000000000..f11cc2e531 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-aes2501-rmmod-oops-fix.patch @@ -0,0 +1,21 @@ +Prevent oops on module removal when we don't have the device available. + +Signed-off-by: Herton Ronaldo Krzesinski + +--- + linux-2.6.23/3rdparty/aes2501/aes2501.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff -p -up linux-2.6.23/3rdparty/aes2501/aes2501.c.orig linux-2.6.23/3rdparty/aes2501/aes2501.c +--- linux-2.6.23/3rdparty/aes2501/aes2501.c.orig 2008-01-13 23:37:38.000000000 -0200 ++++ linux-2.6.23/3rdparty/aes2501/aes2501.c 2008-01-13 23:38:26.000000000 -0200 +@@ -1616,7 +1616,8 @@ static int __init aes2501_init(void) + + static void __exit aes2501_exit(void) + { +- _dev->stop_scan = 1; ++ if (_dev) ++ _dev->stop_scan = 1; + destroy_workqueue(comm_queue); + usb_deregister(&aes2501_driver); + } diff --git a/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-1.60.patch b/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-1.60.patch new file mode 100644 index 0000000000..b328f41a5f --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-1.60.patch @@ -0,0 +1,26410 @@ +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/crt.c linux-4.6-rc6-ndis/3rdparty/ndiswrapper/crt.c +--- linux-4.6-rc6/3rdparty/ndiswrapper/crt.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/crt.c 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,589 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include "ntoskernel.h" ++#include "crt_exports.h" ++ ++#ifdef CONFIG_X86_64 ++/* Windows long is 32-bit, so strip single 'l' in integer formats */ ++static void strip_l_modifier(char *str) ++{ ++ char *ptr = str; ++ int in_format = 0; ++ char *lptr = NULL; ++ char last = 0; ++ char *end_ptr; ++ char *wptr; ++ ++ /* Replace single 'l' inside integer formats with '\0' */ ++ for (ptr = str; *ptr; ptr++) { ++ if (!in_format) { ++ if (*ptr == '%') ++ in_format = 1; ++ last = *ptr; ++ continue; ++ } ++ switch (*ptr) { ++ case 'd': ++ case 'i': ++ case 'o': ++ case 'u': ++ case 'x': ++ case 'X': ++ case 'p': ++ case 'n': ++ case 'm': ++ if (lptr) { ++ *lptr = '\0'; ++ lptr = NULL; ++ } ++ in_format = 0; ++ break; ++ case 'c': ++ case 'C': ++ case 's': ++ case 'S': ++ case 'f': ++ case 'e': ++ case 'E': ++ case 'g': ++ case 'G': ++ case 'a': ++ case 'A': ++ lptr = NULL; ++ in_format = 0; ++ break; ++ case '%': ++ lptr = NULL; ++ if (last == '%') ++ in_format = 0; ++ else ++ in_format = 1; /* ignore previous junk */ ++ break; ++ case 'l': ++ if (last == 'l') ++ lptr = NULL; ++ else ++ lptr = ptr; ++ break; ++ default: ++ break; ++ } ++ last = *ptr; ++ } ++ ++ /* Purge zeroes from the resulting string */ ++ end_ptr = ptr; ++ wptr = str; ++ for (ptr = str; ptr < end_ptr; ptr++) ++ if (*ptr != 0) ++ *(wptr++) = *ptr; ++ *wptr = 0; ++} ++ ++/* ++ * va_list on x86_64 Linux is designed to allow passing arguments in registers ++ * even to variadic functions. va_list is a structure holding pointers to the ++ * register save area, which holds the arguments passed in registers, and to ++ * the stack, which may have the arguments that did not fit the registers. ++ * va_list also holds offsets in the register save area for the next general ++ * purpose and floating point registers that the next va_arg() would fetch. ++ * ++ * Unlike Linux, the Windows va_list is just a pointer to the stack. No ++ * arguments are passed in the registers. That's why we construct the Linux ++ * va_list so that the register save area is never used. For that goal, we set ++ * the offsets to the maximal allowed values, meaning that the arguments passed ++ * in the registers have been exhausted. The values are 48 for general purpose ++ * registers (6 registers, 8 bytes each) and 304 for floating point registers ++ * (16 registers, 16 bytes each, on top of general purpose register). ++ */ ++ ++struct x86_64_va_list { ++ int gp_offset; ++ int fp_offset; ++ void *overflow_arg_area; ++ void *reg_save_area; ++}; ++ ++#define VA_LIST_DECL(_args) \ ++ va_list _args##new; \ ++ struct x86_64_va_list *_args##x; ++#define VA_LIST_PREP(_args) \ ++do { \ ++ _args##x = (struct x86_64_va_list *)&_args##new; \ ++ _args##x->gp_offset = 6 * 8; /* GP registers exhausted */ \ ++ _args##x->fp_offset = 6 * 8 + 16 * 16; /* FP registers exhausted */ \ ++ _args##x->overflow_arg_area = (void *)_args; \ ++ _args##x->reg_save_area = NULL; \ ++} while (0) ++#define VA_LIST_CONV(_args) (_args##new) ++#define VA_LIST_FREE(_args) ++#define FMT_DECL(_fmt) \ ++ char *_fmt##copy; \ ++ int _fmt##len; ++#define FMT_PREP(_fmt) \ ++do { \ ++ _fmt##len = strlen(format) + 1; \ ++ _fmt##copy = kmalloc(_fmt##len, irql_gfp()); \ ++ if (_fmt##copy) { \ ++ memcpy(_fmt##copy, format, _fmt##len); \ ++ strip_l_modifier(_fmt##copy); \ ++ } \ ++} while (0) ++#define FMT_CONV(_fmt) (_fmt##copy ? _fmt##copy : format) ++#define FMT_FREE(_fmt) kfree(_fmt##copy) ++ ++#else /* !CONFIG_X86_64 */ ++ ++#define VA_LIST_DECL(_args) ++#define VA_LIST_PREP(_args) ++#define VA_LIST_CONV(_args) (_args) ++#define VA_LIST_FREE(_args) ++#define FMT_DECL(_fmt) ++#define FMT_PREP(_fmt) ++#define FMT_CONV(_fmt) (format) ++#define FMT_FREE(_fmt) ++ ++#endif /* !CONFIG_X86_64 */ ++ ++__attribute__((format(printf, 2, 3))) ++noregparm INT WIN_FUNC(_win_sprintf,12) ++ (char *buf, const char *format, ...) ++{ ++ va_list args; ++ int res; ++ FMT_DECL(format) ++ ++ FMT_PREP(format); ++ va_start(args, format); ++ res = vsprintf(buf, FMT_CONV(format), args); ++ va_end(args); ++ FMT_FREE(format); ++ ++ TRACE2("buf: %p: %s", buf, buf); ++ return res; ++} ++ ++noregparm INT WIN_FUNC(swprintf,12) ++ (wchar_t *buf, const wchar_t *format, ...) ++{ ++ TODO(); ++ EXIT2(return 0); ++} ++ ++noregparm INT WIN_FUNC(_win_vsprintf,3) ++ (char *str, const char *format, va_list ap) ++{ ++ INT i; ++ VA_LIST_DECL(ap) ++ FMT_DECL(format) ++ ++ VA_LIST_PREP(ap); ++ FMT_PREP(format); ++ ++ i = vsprintf(str, FMT_CONV(format), VA_LIST_CONV(ap)); ++ TRACE2("str: %p: %s", str, str); ++ ++ FMT_FREE(format); ++ VA_LIST_FREE(ap); ++ EXIT2(return i); ++} ++ ++__attribute__((format(printf, 3, 4))) ++noregparm INT WIN_FUNC(_win_snprintf,12) ++ (char *buf, SIZE_T count, const char *format, ...) ++{ ++ va_list args; ++ int res; ++ FMT_DECL(format) ++ ++ FMT_PREP(format); ++ va_start(args, format); ++ res = vsnprintf(buf, count, FMT_CONV(format), args); ++ va_end(args); ++ TRACE2("buf: %p: %s", buf, buf); ++ ++ FMT_FREE(format); ++ return res; ++} ++ ++__attribute__((format(printf, 3, 4))) ++noregparm INT WIN_FUNC(_win__snprintf,12) ++ (char *buf, SIZE_T count, const char *format, ...) ++{ ++ va_list args; ++ int res; ++ FMT_DECL(format) ++ ++ FMT_PREP(format); ++ va_start(args, format); ++ res = vsnprintf(buf, count, FMT_CONV(format), args); ++ va_end(args); ++ TRACE2("buf: %p: %s", buf, buf); ++ ++ FMT_FREE(format); ++ return res; ++} ++ ++noregparm INT WIN_FUNC(_win_vsnprintf,4) ++ (char *str, SIZE_T size, const char *format, va_list ap) ++{ ++ INT i; ++ VA_LIST_DECL(ap) ++ FMT_DECL(format) ++ ++ VA_LIST_PREP(ap); ++ FMT_PREP(format); ++ ++ i = vsnprintf(str, size, FMT_CONV(format), VA_LIST_CONV(ap)); ++ TRACE2("str: %p: %s", str, str); ++ ++ FMT_FREE(format); ++ VA_LIST_FREE(ap); ++ EXIT2(return i); ++} ++ ++noregparm INT WIN_FUNC(_win__vsnprintf,4) ++ (char *str, SIZE_T size, const char *format, va_list ap) ++{ ++ INT i; ++ VA_LIST_DECL(ap) ++ FMT_DECL(format) ++ ++ VA_LIST_PREP(ap); ++ FMT_PREP(format); ++ ++ i = vsnprintf(str, size, FMT_CONV(format), VA_LIST_CONV(ap)); ++ TRACE2("str: %p: %s", str, str); ++ ++ FMT_FREE(format); ++ VA_LIST_FREE(ap); ++ EXIT2(return i); ++} ++ ++noregparm INT WIN_FUNC(_win__vsnwprintf,4) ++ (wchar_t *str, SIZE_T size, const wchar_t *format, va_list ap) ++{ ++ int ret; ++ ++ TODO(); /* format expansion not implemented */ ++ _win_wcsncpy(str, format, size); ++ ret = _win_wcslen(format); ++ if (ret >= size) ++ ret = -1; ++ return ret; ++} ++ ++noregparm char *WIN_FUNC(_win_strncpy,3) ++ (char *dst, char *src, SIZE_T n) ++{ ++ return strncpy(dst, src, n); ++} ++ ++noregparm SIZE_T WIN_FUNC(_win_strlen,1) ++ (const char *s) ++{ ++ return strlen(s); ++} ++ ++noregparm INT WIN_FUNC(_win_strncmp,3) ++ (const char *s1, const char *s2, SIZE_T n) ++{ ++ return strncmp(s1, s2, n); ++} ++ ++noregparm INT WIN_FUNC(_win_strcmp,2) ++ (const char *s1, const char *s2) ++{ ++ return strcmp(s1, s2); ++} ++ ++noregparm INT WIN_FUNC(_win_stricmp,2) ++ (const char *s1, const char *s2) ++{ ++ return stricmp(s1, s2); ++} ++ ++noregparm char *WIN_FUNC(_win_strncat,3) ++ (char *dest, const char *src, SIZE_T n) ++{ ++ return strncat(dest, src, n); ++} ++ ++noregparm INT WIN_FUNC(_win_wcscmp,2) ++ (const wchar_t *s1, const wchar_t *s2) ++{ ++ while (*s1 && *s1 == *s2) { ++ s1++; ++ s2++; ++ } ++ return *s1 - *s2; ++} ++ ++noregparm INT WIN_FUNC(_win_wcsicmp,2) ++ (const wchar_t *s1, const wchar_t *s2) ++{ ++ while (*s1 && tolower((char)*s1) == tolower((char)*s2)) { ++ s1++; ++ s2++; ++ } ++ return tolower((char)*s1) - tolower((char)*s2); ++} ++ ++noregparm SIZE_T WIN_FUNC(_win_wcslen,1) ++ (const wchar_t *s) ++{ ++ const wchar_t *t = s; ++ while (*t) ++ t++; ++ return t - s; ++} ++ ++noregparm wchar_t *WIN_FUNC(_win_wcsncpy,3) ++ (wchar_t *dest, const wchar_t *src, SIZE_T n) ++{ ++ const wchar_t *s; ++ wchar_t *d; ++ s = src + n; ++ d = dest; ++ while (src < s && (*d++ = *src++)) ++ ; ++ if (s > src) ++ memset(d, 0, (s - src) * sizeof(wchar_t)); ++ return dest; ++} ++ ++noregparm wchar_t *WIN_FUNC(_win_wcscpy,2) ++ (wchar_t *dest, const wchar_t *src) ++{ ++ wchar_t *d = dest; ++ while ((*d++ = *src++)) ++ ; ++ return dest; ++} ++ ++noregparm wchar_t *WIN_FUNC(_win_wcscat,2) ++ (wchar_t *dest, const wchar_t *src) ++{ ++ wchar_t *d; ++ d = dest; ++ while (*d) ++ d++; ++ while ((*d++ = *src++)) ++ ; ++ return dest; ++} ++ ++noregparm INT WIN_FUNC(_win_towupper,1) ++ (wchar_t c) ++{ ++ return toupper(c); ++} ++ ++noregparm INT WIN_FUNC(_win_towlower,1) ++ (wchar_t c) ++{ ++ return tolower(c); ++} ++ ++noregparm INT WIN_FUNC(_win_tolower,1) ++ (INT c) ++{ ++ return tolower(c); ++} ++ ++noregparm INT WIN_FUNC(_win_toupper,1) ++ (INT c) ++{ ++ return toupper(c); ++} ++ ++noregparm void *WIN_FUNC(_win_strcpy,2) ++ (void *to, const void *from) ++{ ++ return strcpy(to, from); ++} ++ ++noregparm char *WIN_FUNC(_win_strstr,2) ++ (const char *s1, const char *s2) ++{ ++ return strstr(s1, s2); ++} ++ ++noregparm char *WIN_FUNC(_win_strchr,2) ++ (const char *s, int c) ++{ ++ return strchr(s, c); ++} ++ ++noregparm char *WIN_FUNC(_win_strrchr,2) ++ (const char *s, int c) ++{ ++ return strrchr(s, c); ++} ++ ++noregparm void *WIN_FUNC(_win_memmove,3) ++ (void *to, void *from, SIZE_T count) ++{ ++ return memmove(to, from, count); ++} ++ ++noregparm void *WIN_FUNC(_win_memchr,3) ++ (const void *s, INT c, SIZE_T n) ++{ ++ return memchr(s, c, n); ++} ++ ++noregparm void *WIN_FUNC(_win_memcpy,3) ++ (void *to, const void *from, SIZE_T n) ++{ ++ return memcpy(to, from, n); ++} ++ ++noregparm void *WIN_FUNC(_win_memset,3) ++ (void *s, char c, SIZE_T count) ++{ ++ return memset(s, c, count); ++} ++ ++noregparm int WIN_FUNC(_win_memcmp,3) ++ (void *s1, void *s2, SIZE_T n) ++{ ++ return memcmp(s1, s2, n); ++} ++ ++noregparm void WIN_FUNC(_win_srand,1) ++ (UINT seed) ++{ ++ prandom_seed(seed); ++} ++ ++noregparm int WIN_FUNC(rand,0) ++ (void) ++{ ++ char buf[6]; ++ int i, n; ++ ++ get_random_bytes(buf, sizeof(buf)); ++ for (n = i = 0; i < sizeof(buf); i++) ++ n += buf[i]; ++ return n; ++} ++ ++noregparm int WIN_FUNC(_win_atoi,1) ++ (const char *ptr) ++{ ++ int i = simple_strtol(ptr, NULL, 10); ++ return i; ++} ++ ++noregparm int WIN_FUNC(_win_isdigit,1) ++ (int c) ++{ ++ return isdigit(c); ++} ++ ++noregparm int WIN_FUNC(_win_isprint,1) ++ (int c) ++{ ++ return isprint(c); ++} ++ ++wstdcall s64 WIN_FUNC(_alldiv,2) ++ (s64 a, s64 b) ++{ ++ return a / b; ++} ++ ++wstdcall u64 WIN_FUNC(_aulldiv,2) ++ (u64 a, u64 b) ++{ ++ return a / b; ++} ++ ++wstdcall s64 WIN_FUNC(_allmul,2) ++ (s64 a, s64 b) ++{ ++ return a * b; ++} ++ ++wstdcall u64 WIN_FUNC(_aullmul,2) ++ (u64 a, u64 b) ++{ ++ return a * b; ++} ++ ++wstdcall s64 WIN_FUNC(_allrem,2) ++ (s64 a, s64 b) ++{ ++ return a % b; ++} ++ ++wstdcall u64 WIN_FUNC(_aullrem,2) ++ (u64 a, u64 b) ++{ ++ return a % b; ++} ++ ++regparm3 s64 WIN_FUNC(_allshl,2) ++ (s64 a, u8 b) ++{ ++ return a << b; ++} ++ ++regparm3 u64 WIN_FUNC(_aullshl,2) ++ (u64 a, u8 b) ++{ ++ return a << b; ++} ++ ++regparm3 s64 WIN_FUNC(_allshr,2) ++ (s64 a, u8 b) ++{ ++ return a >> b; ++} ++ ++regparm3 u64 WIN_FUNC(_aullshr,2) ++ (u64 a, u8 b) ++{ ++ return a >> b; ++} ++ ++int stricmp(const char *s1, const char *s2) ++{ ++ while (*s1 && tolower(*s1) == tolower(*s2)) { ++ s1++; ++ s2++; ++ } ++ return *s1 - *s2; ++} ++ ++void dump_bytes(const char *ctx, const u8 *from, int len) ++{ ++ int i, j; ++ u8 *buf; ++ ++ buf = kmalloc(len * 3 + 1, irql_gfp()); ++ if (!buf) { ++ ERROR("couldn't allocate memory"); ++ return; ++ } ++ for (i = j = 0; i < len; i++, j += 3) { ++ sprintf(&buf[j], "%02x ", from[i]); ++ } ++ buf[j] = 0; ++ printk(KERN_DEBUG "%s: %p: %s\n", ctx, from, buf); ++ kfree(buf); ++} +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/divdi3.c linux-4.6-rc6-ndis/3rdparty/ndiswrapper/divdi3.c +--- linux-4.6-rc6/3rdparty/ndiswrapper/divdi3.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/divdi3.c 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,329 @@ ++/* 64-bit multiplication and division ++ Copyright (C) 1989, 1992-1999, 2000, 2001, 2002, 2003 ++ Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, write to the Free ++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ 02111-1307 USA. */ ++ ++#include ++#include ++ ++#if BITS_PER_LONG != 32 ++#error This is for 32-bit targets only ++#endif ++ ++typedef unsigned int UQItype __attribute__ ((mode (QI))); ++typedef int SItype __attribute__ ((mode (SI))); ++typedef unsigned int USItype __attribute__ ((mode (SI))); ++typedef int DItype __attribute__ ((mode (DI))); ++typedef unsigned int UDItype __attribute__ ((mode (DI))); ++#define Wtype SItype ++#define HWtype SItype ++#define DWtype DItype ++#define UWtype USItype ++#define UHWtype USItype ++#define UDWtype UDItype ++#define W_TYPE_SIZE 32 ++ ++#include "longlong.h" ++ ++#if defined(__BIG_ENDIAN) ++struct DWstruct { Wtype high, low;}; ++#elif defined(__LITTLE_ENDIAN) ++struct DWstruct { Wtype low, high;}; ++#else ++#error Unhandled endianity ++#endif ++typedef union { struct DWstruct s; DWtype ll; } DWunion; ++ ++/* Prototypes of exported functions. */ ++extern DWtype __divdi3 (DWtype u, DWtype v); ++extern DWtype __moddi3 (DWtype u, DWtype v); ++extern UDWtype __udivdi3 (UDWtype u, UDWtype v); ++extern UDWtype __umoddi3 (UDWtype u, UDWtype v); ++ ++static UDWtype ++__udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp) ++{ ++ DWunion ww; ++ DWunion nn, dd; ++ DWunion rr; ++ UWtype d0, d1, n0, n1, n2; ++ UWtype q0, q1; ++ UWtype b, bm; ++ ++ nn.ll = n; ++ dd.ll = d; ++ ++ d0 = dd.s.low; ++ d1 = dd.s.high; ++ n0 = nn.s.low; ++ n1 = nn.s.high; ++ ++#if !UDIV_NEEDS_NORMALIZATION ++ if (d1 == 0) ++ { ++ if (d0 > n1) ++ { ++ /* 0q = nn / 0D */ ++ ++ udiv_qrnnd (q0, n0, n1, n0, d0); ++ q1 = 0; ++ ++ /* Remainder in n0. */ ++ } ++ else ++ { ++ /* qq = NN / 0d */ ++ ++ if (d0 == 0) ++ d0 = 1 / d0; /* Divide intentionally by zero. */ ++ ++ udiv_qrnnd (q1, n1, 0, n1, d0); ++ udiv_qrnnd (q0, n0, n1, n0, d0); ++ ++ /* Remainder in n0. */ ++ } ++ ++ if (rp != NULL) ++ { ++ rr.s.low = n0; ++ rr.s.high = 0; ++ *rp = rr.ll; ++ } ++ } ++ ++#else /* UDIV_NEEDS_NORMALIZATION */ ++ ++ if (d1 == 0) ++ { ++ if (d0 > n1) ++ { ++ /* 0q = nn / 0D */ ++ ++ count_leading_zeros (bm, d0); ++ ++ if (bm != 0) ++ { ++ /* Normalize, i.e. make the most significant bit of the ++ denominator set. */ ++ ++ d0 = d0 << bm; ++ n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); ++ n0 = n0 << bm; ++ } ++ ++ udiv_qrnnd (q0, n0, n1, n0, d0); ++ q1 = 0; ++ ++ /* Remainder in n0 >> bm. */ ++ } ++ else ++ { ++ /* qq = NN / 0d */ ++ ++ if (d0 == 0) ++ d0 = 1 / d0; /* Divide intentionally by zero. */ ++ ++ count_leading_zeros (bm, d0); ++ ++ if (bm == 0) ++ { ++ /* From (n1 >= d0) /\ (the most significant bit of d0 is set), ++ conclude (the most significant bit of n1 is set) /\ (the ++ leading quotient digit q1 = 1). ++ ++ This special case is necessary, not an optimization. ++ (Shifts counts of W_TYPE_SIZE are undefined.) */ ++ ++ n1 -= d0; ++ q1 = 1; ++ } ++ else ++ { ++ /* Normalize. */ ++ ++ b = W_TYPE_SIZE - bm; ++ ++ d0 = d0 << bm; ++ n2 = n1 >> b; ++ n1 = (n1 << bm) | (n0 >> b); ++ n0 = n0 << bm; ++ ++ udiv_qrnnd (q1, n1, n2, n1, d0); ++ } ++ ++ /* n1 != d0... */ ++ ++ udiv_qrnnd (q0, n0, n1, n0, d0); ++ ++ /* Remainder in n0 >> bm. */ ++ } ++ ++ if (rp != NULL) ++ { ++ rr.s.low = n0 >> bm; ++ rr.s.high = 0; ++ *rp = rr.ll; ++ } ++ } ++#endif /* UDIV_NEEDS_NORMALIZATION */ ++ ++ else ++ { ++ if (d1 > n1) ++ { ++ /* 00 = nn / DD */ ++ ++ q0 = 0; ++ q1 = 0; ++ ++ /* Remainder in n1n0. */ ++ if (rp != NULL) ++ { ++ rr.s.low = n0; ++ rr.s.high = n1; ++ *rp = rr.ll; ++ } ++ } ++ else ++ { ++ /* 0q = NN / dd */ ++ ++ count_leading_zeros (bm, d1); ++ if (bm == 0) ++ { ++ /* From (n1 >= d1) /\ (the most significant bit of d1 is set), ++ conclude (the most significant bit of n1 is set) /\ (the ++ quotient digit q0 = 0 or 1). ++ ++ This special case is necessary, not an optimization. */ ++ ++ /* The condition on the next line takes advantage of that ++ n1 >= d1 (true due to program flow). */ ++ if (n1 > d1 || n0 >= d0) ++ { ++ q0 = 1; ++ sub_ddmmss (n1, n0, n1, n0, d1, d0); ++ } ++ else ++ q0 = 0; ++ ++ q1 = 0; ++ ++ if (rp != NULL) ++ { ++ rr.s.low = n0; ++ rr.s.high = n1; ++ *rp = rr.ll; ++ } ++ } ++ else ++ { ++ UWtype m1, m0; ++ /* Normalize. */ ++ ++ b = W_TYPE_SIZE - bm; ++ ++ d1 = (d1 << bm) | (d0 >> b); ++ d0 = d0 << bm; ++ n2 = n1 >> b; ++ n1 = (n1 << bm) | (n0 >> b); ++ n0 = n0 << bm; ++ ++ udiv_qrnnd (q0, n1, n2, n1, d1); ++ umul_ppmm (m1, m0, q0, d0); ++ ++ if (m1 > n1 || (m1 == n1 && m0 > n0)) ++ { ++ q0--; ++ sub_ddmmss (m1, m0, m1, m0, d1, d0); ++ } ++ ++ q1 = 0; ++ ++ /* Remainder in (n1n0 - m1m0) >> bm. */ ++ if (rp != NULL) ++ { ++ sub_ddmmss (n1, n0, n1, n0, m1, m0); ++ rr.s.low = (n1 << b) | (n0 >> bm); ++ rr.s.high = n1 >> bm; ++ *rp = rr.ll; ++ } ++ } ++ } ++ } ++ ++ ww.s.low = q0; ++ ww.s.high = q1; ++ return ww.ll; ++} ++ ++DWtype ++__divdi3 (DWtype u, DWtype v) ++{ ++ Wtype c = 0; ++ DWtype w; ++ ++ if (u < 0) ++ { ++ c = ~c; ++ u = -u; ++ } ++ if (v < 0) ++ { ++ c = ~c; ++ v = -v; ++ } ++ w = __udivmoddi4 (u, v, NULL); ++ if (c) ++ w = -w; ++ return w; ++} ++ ++DWtype ++__moddi3 (DWtype u, DWtype v) ++{ ++ Wtype c = 0; ++ DWtype w; ++ ++ if (u < 0) ++ { ++ c = ~c; ++ u = -u; ++ } ++ if (v < 0) ++ v = -v; ++ __udivmoddi4 (u, v, &w); ++ if (c) ++ w = -w; ++ return w; ++} ++ ++UDWtype ++__udivdi3 (UDWtype u, UDWtype v) ++{ ++ return __udivmoddi4 (u, v, NULL); ++} ++ ++UDWtype ++__umoddi3 (UDWtype u, UDWtype v) ++{ ++ UDWtype w; ++ ++ __udivmoddi4 (u, v, &w); ++ return w; ++} +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/hal.c linux-4.6-rc6-ndis/3rdparty/ndiswrapper/hal.c +--- linux-4.6-rc6/3rdparty/ndiswrapper/hal.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/hal.c 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,157 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include "ntoskernel.h" ++#include "hal_exports.h" ++ ++wstdcall void WIN_FUNC(WRITE_PORT_ULONG,2) ++ (ULONG_PTR port, ULONG value) ++{ ++ outl(value, port); ++} ++ ++wstdcall ULONG WIN_FUNC(READ_PORT_ULONG,1) ++ (ULONG_PTR port) ++{ ++ return inl(port); ++} ++ ++wstdcall void WIN_FUNC(WRITE_PORT_USHORT,2) ++ (ULONG_PTR port, USHORT value) ++{ ++ outw(value, port); ++} ++ ++wstdcall USHORT WIN_FUNC(READ_PORT_USHORT,1) ++ (ULONG_PTR port) ++{ ++ return inw(port); ++} ++ ++wstdcall void WIN_FUNC(WRITE_PORT_UCHAR,2) ++ (ULONG_PTR port, UCHAR value) ++{ ++ outb(value, port); ++} ++ ++wstdcall UCHAR WIN_FUNC(READ_PORT_UCHAR,1) ++ (ULONG_PTR port) ++{ ++ return inb(port); ++} ++ ++wstdcall void WIN_FUNC(WRITE_PORT_BUFFER_USHORT,3) ++ (ULONG_PTR port, USHORT *buf, ULONG count) ++{ ++ outsw(port, buf, count); ++} ++ ++wstdcall void WIN_FUNC(READ_PORT_BUFFER_USHORT,3) ++ (ULONG_PTR port, USHORT *buf, ULONG count) ++{ ++ insw(port, buf, count); ++} ++ ++wstdcall void WIN_FUNC(WRITE_PORT_BUFFER_ULONG,3) ++ (ULONG_PTR port, ULONG *buf, ULONG count) ++{ ++ outsl(port, buf, count); ++} ++ ++wstdcall void WIN_FUNC(READ_PORT_BUFFER_ULONG,3) ++ (ULONG_PTR port, ULONG *buf, ULONG count) ++{ ++ insl(port, buf, count); ++} ++ ++wstdcall USHORT WIN_FUNC(READ_REGISTER_USHORT,1) ++ (void __iomem *reg) ++{ ++ return readw(reg); ++} ++ ++wstdcall void WIN_FUNC(WRITE_REGISTER_ULONG,2) ++ (void __iomem *reg, UINT val) ++{ ++ writel(val, reg); ++} ++ ++wstdcall void WIN_FUNC(WRITE_REGISTER_USHORT,2) ++ (void __iomem *reg, USHORT val) ++{ ++ writew(val, reg); ++} ++ ++wstdcall void WIN_FUNC(WRITE_REGISTER_UCHAR,2) ++ (void __iomem *reg, UCHAR val) ++{ ++ writeb(val, reg); ++} ++ ++wstdcall void WIN_FUNC(KeStallExecutionProcessor,1) ++ (ULONG usecs) ++{ ++ udelay(usecs); ++} ++ ++wstdcall KIRQL WIN_FUNC(KeGetCurrentIrql,0) ++ (void) ++{ ++ return current_irql(); ++} ++ ++wfastcall KIRQL WIN_FUNC(KfRaiseIrql,1) ++ (KIRQL newirql) ++{ ++ return raise_irql(newirql); ++} ++ ++wfastcall void WIN_FUNC(KfLowerIrql,1) ++ (KIRQL oldirql) ++{ ++ lower_irql(oldirql); ++} ++ ++wfastcall KIRQL WIN_FUNC(KfAcquireSpinLock,1) ++ (NT_SPIN_LOCK *lock) ++{ ++ return nt_spin_lock_irql(lock, DISPATCH_LEVEL); ++} ++ ++wfastcall void WIN_FUNC(KfReleaseSpinLock,2) ++ (NT_SPIN_LOCK *lock, KIRQL oldirql) ++{ ++ nt_spin_unlock_irql(lock, oldirql); ++} ++ ++wfastcall void WIN_FUNC(KefAcquireSpinLockAtDpcLevel,1) ++ (NT_SPIN_LOCK *lock) ++{ ++#ifdef DEBUG_IRQL ++ if (current_irql() != DISPATCH_LEVEL) ++ ERROR("irql != DISPATCH_LEVEL"); ++#endif ++ nt_spin_lock(lock); ++} ++ ++wfastcall void WIN_FUNC(KefReleaseSpinLockFromDpcLevel,1) ++ (NT_SPIN_LOCK *lock) ++{ ++#ifdef DEBUG_IRQL ++ if (current_irql() != DISPATCH_LEVEL) ++ ERROR("irql != DISPATCH_LEVEL"); ++#endif ++ nt_spin_unlock(lock); ++} +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/iw_ndis.c linux-4.6-rc6-ndis/3rdparty/ndiswrapper/iw_ndis.c +--- linux-4.6-rc6/3rdparty/ndiswrapper/iw_ndis.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/iw_ndis.c 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,2001 @@ ++ /* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "iw_ndis.h" ++#include "wrapndis.h" ++ ++#ifdef CONFIG_WIRELESS_EXT ++ ++static int freq_chan[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, ++ 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; ++ ++static const char *network_names[] = {"IEEE 802.11FH", "IEEE 802.11b", ++ "IEEE 802.11a", "IEEE 802.11g", "Auto"}; ++ ++static int set_essid(struct ndis_device *wnd, const char *ssid, int ssid_len) ++{ ++ NDIS_STATUS res; ++ struct ndis_essid req; ++ ++ if (ssid_len > NDIS_ESSID_MAX_SIZE) ++ return -EINVAL; ++ ++ memset(&req, 0, sizeof(req)); ++ req.length = ssid_len; ++ if (ssid_len) ++ memcpy(&req.essid, ssid, ssid_len); ++ ++ res = mp_set(wnd, OID_802_11_SSID, &req, sizeof(req)); ++ if (res) { ++ WARNING("setting essid failed (%08X)", res); ++ EXIT2(return -EINVAL); ++ } ++ memcpy(&wnd->essid, &req, sizeof(req)); ++ EXIT2(return 0); ++} ++ ++static int set_iw_auth_mode(struct ndis_device *wnd, int wpa_version, ++ int auth_80211_alg) ++{ ++ NDIS_STATUS res; ++ ULONG auth_mode; ++ ++ ENTER2("%d, %d", wpa_version, auth_80211_alg); ++ if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) { ++ if (wnd->iw_auth_key_mgmt & IW_AUTH_KEY_MGMT_802_1X) ++ auth_mode = Ndis802_11AuthModeWPA2; ++ else ++ auth_mode = Ndis802_11AuthModeWPA2PSK; ++ } else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) { ++ if (wnd->iw_auth_key_mgmt & IW_AUTH_KEY_MGMT_802_1X) ++ auth_mode = Ndis802_11AuthModeWPA; ++ else if (wnd->iw_auth_key_mgmt & IW_AUTH_KEY_MGMT_PSK) ++ auth_mode = Ndis802_11AuthModeWPAPSK; ++ else ++ auth_mode = Ndis802_11AuthModeWPANone; ++ } else if (auth_80211_alg & IW_AUTH_ALG_SHARED_KEY) { ++ if (auth_80211_alg & IW_AUTH_ALG_OPEN_SYSTEM) ++ auth_mode = Ndis802_11AuthModeAutoSwitch; ++ else ++ auth_mode = Ndis802_11AuthModeShared; ++ } else ++ auth_mode = Ndis802_11AuthModeOpen; ++ ++ res = mp_set_int(wnd, OID_802_11_AUTHENTICATION_MODE, auth_mode); ++ if (res) { ++ WARNING("setting auth mode to %u failed (%08X)", ++ auth_mode, res); ++ if (res == NDIS_STATUS_INVALID_DATA) ++ EXIT2(return -EINVAL); ++ return -EOPNOTSUPP; ++ } ++ wnd->iw_auth_wpa_version = wpa_version; ++ wnd->iw_auth_80211_alg = auth_80211_alg; ++ EXIT2(return 0); ++} ++ ++static int set_auth_mode(struct ndis_device *wnd) ++{ ++ return set_iw_auth_mode(wnd, wnd->iw_auth_wpa_version, ++ wnd->iw_auth_80211_alg); ++} ++ ++static enum ndis_priv_filter ndis_priv_mode(struct ndis_device *wnd) ++{ ++ if (wnd->iw_auth_wpa_version & IW_AUTH_WPA_VERSION_WPA2 || ++ wnd->iw_auth_wpa_version & IW_AUTH_WPA_VERSION_WPA) ++ return Ndis802_11PrivFilter8021xWEP; ++ else ++ return Ndis802_11PrivFilterAcceptAll; ++} ++ ++static int set_priv_filter(struct ndis_device *wnd) ++{ ++ NDIS_STATUS res; ++ ULONG flags; ++ ++ flags = ndis_priv_mode(wnd); ++ ENTER2("filter: %d", flags); ++ res = mp_set_int(wnd, OID_802_11_PRIVACY_FILTER, flags); ++ if (res) ++ TRACE2("setting privacy filter to %d failed (%08X)", ++ flags, res); ++ EXIT2(return 0); ++} ++ ++static int set_encr_mode(struct ndis_device *wnd) ++{ ++ return set_iw_encr_mode(wnd, wnd->iw_auth_cipher_pairwise, ++ wnd->iw_auth_cipher_group); ++} ++ ++static int set_assoc_params(struct ndis_device *wnd) ++{ ++ TRACE2("wpa_version=0x%x auth_alg=0x%x key_mgmt=0x%x " ++ "cipher_pairwise=0x%x cipher_group=0x%x", ++ wnd->iw_auth_wpa_version, wnd->iw_auth_80211_alg, ++ wnd->iw_auth_key_mgmt, wnd->iw_auth_cipher_pairwise, ++ wnd->iw_auth_cipher_group); ++ set_auth_mode(wnd); ++ set_priv_filter(wnd); ++ set_encr_mode(wnd); ++ return 0; ++} ++ ++static int iw_set_essid(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ int length; ++ ++ ENTER2(""); ++ /* there is no way to turn off essid other than to set to ++ * random bytes; instead, we use off to mean any */ ++ if (wrqu->essid.flags) { ++ length = wrqu->essid.length; ++ /* Strip '\0' appended by wireless extensions 19 and older */ ++ if (length > 0 && extra[length - 1] == '\0') ++ length--; ++ TRACE2("%d", length); ++ if (length <= 0 || length > NDIS_ESSID_MAX_SIZE) ++ EXIT2(return -EINVAL); ++ } else ++ length = 0; ++ ++ set_assoc_params(wnd); ++ ++ if (set_essid(wnd, extra, length)) ++ EXIT2(return -EINVAL); ++ ++ EXIT2(return 0); ++} ++ ++static int iw_get_essid(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ struct ndis_essid req; ++ ++ ENTER2(""); ++ memset(&req, 0, sizeof(req)); ++ res = mp_query(wnd, OID_802_11_SSID, &req, sizeof(req)); ++ if (res) { ++ WARNING("getting essid failed (%08X)", res); ++ EXIT2(return -EOPNOTSUPP); ++ } ++ memcpy(extra, req.essid, req.length); ++ if (req.length > 0) ++ wrqu->essid.flags = 1; ++ else ++ wrqu->essid.flags = 0; ++ wrqu->essid.length = req.length; ++ EXIT2(return 0); ++} ++ ++/* index must be 0 - N, as per NDIS */ ++static int add_wep_key(struct ndis_device *wnd, char *key, int key_len, ++ int index) ++{ ++ struct ndis_encr_key ndis_key; ++ NDIS_STATUS res; ++ ++ ENTER2("key index: %d, length: %d", index, key_len); ++ if (key_len <= 0 || key_len > NDIS_ENCODING_TOKEN_MAX) { ++ WARNING("invalid key length (%d)", key_len); ++ EXIT2(return -EINVAL); ++ } ++ if (index < 0 || index >= MAX_ENCR_KEYS) { ++ WARNING("invalid key index (%d)", index); ++ EXIT2(return -EINVAL); ++ } ++ ndis_key.struct_size = sizeof(ndis_key); ++ ndis_key.length = key_len; ++ memcpy(&ndis_key.key, key, key_len); ++ ndis_key.index = index; ++ ++ if (index == wnd->encr_info.tx_key_index) { ++ ndis_key.index |= (1 << 31); ++ res = set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104, ++ IW_AUTH_CIPHER_NONE); ++ if (res) ++ WARNING("encryption couldn't be enabled (%08X)", res); ++ } ++ TRACE2("key %d: " MACSTRSEP, index, MAC2STR(key)); ++ res = mp_set(wnd, OID_802_11_ADD_WEP, &ndis_key, sizeof(ndis_key)); ++ if (res) { ++ WARNING("adding encryption key %d failed (%08X)", ++ index+1, res); ++ EXIT2(return -EINVAL); ++ } ++ ++ /* Atheros driver messes up ndis_key during ADD_WEP, so ++ * don't rely on that; instead use info in key and key_len */ ++ wnd->encr_info.keys[index].length = key_len; ++ memcpy(&wnd->encr_info.keys[index].key, key, key_len); ++ ++ EXIT2(return 0); ++} ++ ++static int set_infra_mode(struct ndis_device *wnd, ++ enum ndis_infrastructure_mode mode) ++{ ++ NDIS_STATUS res; ++ unsigned int i; ++ ++ ENTER2("%d", mode); ++ res = mp_query_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, ++ &wnd->infrastructure_mode); ++ if (res != NDIS_STATUS_SUCCESS) { ++ WARNING("getting operating mode failed (%08X)", res); ++ EXIT2(return -EINVAL); ++ } ++ if (wnd->infrastructure_mode == mode) ++ EXIT2(return 0); ++ res = mp_set_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, mode); ++ if (res) { ++ WARNING("setting operating mode to %d failed (%08X)", ++ mode, res); ++ EXIT2(return -EINVAL); ++ } ++ /* NDIS drivers clear keys when infrastructure mode is ++ * changed. But Linux tools assume otherwise. So set the ++ * keys */ ++ if (wnd->iw_auth_key_mgmt == 0 || ++ wnd->iw_auth_key_mgmt == IW_AUTH_KEY_MGMT_802_1X) { ++ for (i = 0; i < MAX_ENCR_KEYS; i++) { ++ if (wnd->encr_info.keys[i].length > 0) ++ add_wep_key(wnd, wnd->encr_info.keys[i].key, ++ wnd->encr_info.keys[i].length, i); ++ } ++ } ++ wnd->infrastructure_mode = mode; ++ EXIT2(return 0); ++} ++ ++static int iw_set_infra_mode(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ enum ndis_infrastructure_mode ndis_mode; ++ ++ ENTER2("%d", wrqu->mode); ++ switch (wrqu->mode) { ++ case IW_MODE_ADHOC: ++ ndis_mode = Ndis802_11IBSS; ++ break; ++ case IW_MODE_INFRA: ++ ndis_mode = Ndis802_11Infrastructure; ++ break; ++ case IW_MODE_AUTO: ++ ndis_mode = Ndis802_11AutoUnknown; ++ break; ++ default: ++ EXIT2(return -EINVAL); ++ } ++ ++ if (set_infra_mode(wnd, ndis_mode)) ++ EXIT2(return -EINVAL); ++ ++ EXIT2(return 0); ++} ++ ++static int iw_get_infra_mode(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ int ndis_mode, iw_mode; ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ res = mp_query_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, &ndis_mode); ++ if (res) { ++ WARNING("getting operating mode failed (%08X)", res); ++ EXIT2(return -EOPNOTSUPP); ++ } ++ ++ switch (ndis_mode) { ++ case Ndis802_11IBSS: ++ iw_mode = IW_MODE_ADHOC; ++ break; ++ case Ndis802_11Infrastructure: ++ iw_mode = IW_MODE_INFRA; ++ break; ++ case Ndis802_11AutoUnknown: ++ iw_mode = IW_MODE_AUTO; ++ break; ++ default: ++ ERROR("invalid operating mode (%u)", ndis_mode); ++ EXIT2(return -EINVAL); ++ } ++ wrqu->mode = iw_mode; ++ EXIT2(return 0); ++} ++ ++static const char *network_type_to_name(int net_type) ++{ ++ if (net_type >= 0 && net_type < ARRAY_SIZE(network_names)) ++ return network_names[net_type]; ++ else ++ return network_names[ARRAY_SIZE(network_names) - 1]; ++} ++ ++static int iw_get_network_type(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ unsigned int network_type; ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ res = mp_query_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE, ++ &network_type); ++ if (res) { ++ WARNING("getting network type failed: %08X", res); ++ network_type = -1; ++ } ++ strncpy(wrqu->name, network_type_to_name(network_type), ++ sizeof(wrqu->name) - 1); ++ wrqu->name[sizeof(wrqu->name)-1] = 0; ++ return 0; ++} ++ ++static int iw_get_freq(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ struct ndis_configuration req; ++ ++ ENTER2(""); ++ memset(&req, 0, sizeof(req)); ++ res = mp_query(wnd, OID_802_11_CONFIGURATION, &req, sizeof(req)); ++ if (res) { ++ WARNING("getting configuration failed (%08X)", res); ++ EXIT2(return -EOPNOTSUPP); ++ } ++ ++ memset(&(wrqu->freq), 0, sizeof(struct iw_freq)); ++ ++ /* see comment in wireless.h above the "struct iw_freq" ++ definition for an explanation of this if ++ NOTE: 1000000 is due to the kHz ++ */ ++ if (req.ds_config > 1000000) { ++ wrqu->freq.m = req.ds_config / 10; ++ wrqu->freq.e = 1; ++ } ++ else ++ wrqu->freq.m = req.ds_config; ++ ++ /* convert from kHz to Hz */ ++ wrqu->freq.e += 3; ++ ++ return 0; ++} ++ ++static int iw_set_freq(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ struct ndis_configuration req; ++ ++ ENTER2(""); ++ /* this OID is valid only when not associated */ ++ if (netif_carrier_ok(wnd->net_dev)) ++ EXIT2(return 0); ++ memset(&req, 0, sizeof(req)); ++ res = mp_query(wnd, OID_802_11_CONFIGURATION, &req, sizeof(req)); ++ if (res) { ++ WARNING("getting configuration failed (%08X)", res); ++ EXIT2(return 0); ++ } ++ ++ if (wrqu->freq.m < 1000 && wrqu->freq.e == 0) { ++ if (wrqu->freq.m >= 1 && wrqu->freq.m <= ARRAY_SIZE(freq_chan)) ++ req.ds_config = freq_chan[wrqu->freq.m - 1] * 1000; ++ else ++ return -EINVAL; ++ } else { ++ int i; ++ req.ds_config = wrqu->freq.m; ++ for (i = wrqu->freq.e; i > 0; i--) ++ req.ds_config *= 10; ++ req.ds_config /= 1000; ++ } ++ res = mp_set(wnd, OID_802_11_CONFIGURATION, &req, sizeof(req)); ++ if (res) ++ WARNING("setting configuration failed (%08X)", res); ++ return 0; ++} ++ ++static int iw_get_tx_power(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ndis_tx_power_level ndis_power; ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ res = mp_query(wnd, OID_802_11_TX_POWER_LEVEL, ++ &ndis_power, sizeof(ndis_power)); ++ if (res) ++ return -EOPNOTSUPP; ++ wrqu->txpower.flags = IW_TXPOW_MWATT; ++ wrqu->txpower.disabled = 0; ++ wrqu->txpower.fixed = 0; ++ wrqu->txpower.value = ndis_power; ++ return 0; ++} ++ ++static int iw_set_tx_power(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ndis_tx_power_level ndis_power; ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ if (wrqu->txpower.disabled) ++ ndis_power = 0; ++ else { ++ if (wrqu->txpower.flags == IW_TXPOW_MWATT) ++ ndis_power = wrqu->txpower.value; ++ else { // wrqu->txpower.flags == IW_TXPOW_DBM ++ if (wrqu->txpower.value > 20) ++ ndis_power = 128; ++ else if (wrqu->txpower.value < -43) ++ ndis_power = 127; ++ else { ++ signed char tmp; ++ tmp = wrqu->txpower.value; ++ tmp = -12 - tmp; ++ tmp <<= 2; ++ ndis_power = (unsigned char)tmp; ++ } ++ } ++ } ++ TRACE2("%d", ndis_power); ++ res = mp_set(wnd, OID_802_11_TX_POWER_LEVEL, ++ &ndis_power, sizeof(ndis_power)); ++ if (res) ++ EXIT2(return -EOPNOTSUPP); ++ if (ndis_power == 0) ++ res = disassociate(wnd, 0); ++ EXIT2(return 0); ++} ++ ++static int iw_get_bitrate(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ULONG ndis_rate; ++ int res; ++ ++ ENTER2(""); ++ res = mp_query(wnd, OID_GEN_LINK_SPEED, &ndis_rate, sizeof(ndis_rate)); ++ if (res) { ++ WARNING("getting bitrate failed (%08X)", res); ++ ndis_rate = 0; ++ } ++ ++ wrqu->bitrate.value = ndis_rate * 100; ++ return 0; ++} ++ ++static int iw_set_bitrate(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ int i, n; ++ NDIS_STATUS res; ++ UCHAR rates[NDIS_MAX_RATES_EX]; ++ ++ ENTER2(""); ++ if (wrqu->bitrate.fixed == 0) ++ EXIT2(return 0); ++ ++ res = mp_query_info(wnd, OID_802_11_SUPPORTED_RATES, &rates, ++ sizeof(rates), &n, NULL); ++ if (res) { ++ WARNING("getting bit rate failed (%08X)", res); ++ EXIT2(return 0); ++ } ++ for (i = 0; i < n; i++) { ++ if (rates[i] & 0x80) ++ continue; ++ if ((rates[i] & 0x7f) * 500000 > wrqu->bitrate.value) { ++ TRACE2("setting rate %d to 0", ++ (rates[i] & 0x7f) * 500000); ++ rates[i] = 0; ++ } ++ } ++ ++ res = mp_set(wnd, OID_802_11_DESIRED_RATES, &rates, n); ++ if (res) { ++ WARNING("setting bit rate failed (%08X)", res); ++ EXIT2(return 0); ++ } ++ ++ return 0; ++} ++ ++static int iw_set_dummy(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ /* Do nothing. Used for ioctls that are not implemented. */ ++ return 0; ++} ++ ++static int iw_get_rts_threshold(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ndis_rts_threshold threshold; ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ res = mp_query(wnd, OID_802_11_RTS_THRESHOLD, ++ &threshold, sizeof(threshold)); ++ if (res) ++ return -EOPNOTSUPP; ++ ++ wrqu->rts.value = threshold; ++ return 0; ++} ++ ++static int iw_set_rts_threshold(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ndis_rts_threshold threshold; ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ threshold = wrqu->rts.value; ++ res = mp_set(wnd, OID_802_11_RTS_THRESHOLD, ++ &threshold, sizeof(threshold)); ++ if (res == NDIS_STATUS_INVALID_DATA) ++ return -EINVAL; ++ if (res) ++ return -EOPNOTSUPP; ++ ++ return 0; ++} ++ ++static int iw_get_frag_threshold(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ndis_fragmentation_threshold frag_threshold; ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ res = mp_query(wnd, OID_802_11_FRAGMENTATION_THRESHOLD, ++ &frag_threshold, sizeof(frag_threshold)); ++ if (res) ++ return -ENOTSUPP; ++ ++ wrqu->frag.value = frag_threshold; ++ return 0; ++} ++ ++static int iw_set_frag_threshold(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ndis_rts_threshold threshold; ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ threshold = wrqu->frag.value; ++ res = mp_set(wnd, OID_802_11_FRAGMENTATION_THRESHOLD, ++ &threshold, sizeof(threshold)); ++ if (res == NDIS_STATUS_INVALID_DATA) ++ return -EINVAL; ++ if (res) ++ return -EOPNOTSUPP; ++ return 0; ++} ++ ++int get_ap_address(struct ndis_device *wnd, mac_address ap_addr) ++{ ++ NDIS_STATUS res; ++ ++ res = mp_query(wnd, OID_802_11_BSSID, ap_addr, ETH_ALEN); ++ TRACE2(MACSTRSEP, MAC2STR(ap_addr)); ++ if (res) { ++ TRACE2("res: %08X", res); ++ memset(ap_addr, 0x0, ETH_ALEN); ++ EXIT2(return -EOPNOTSUPP); ++ } ++ EXIT2(return 0); ++} ++ ++static int iw_get_ap_address(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ mac_address ap_addr; ++ ++ ENTER2(""); ++ get_ap_address(wnd, ap_addr); ++ memcpy(wrqu->ap_addr.sa_data, ap_addr, ETH_ALEN); ++ wrqu->ap_addr.sa_family = ARPHRD_ETHER; ++ EXIT2(return 0); ++} ++ ++static int iw_set_ap_address(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ mac_address ap_addr; ++ ++ ENTER2(""); ++ memcpy(ap_addr, wrqu->ap_addr.sa_data, ETH_ALEN); ++ TRACE2(MACSTRSEP, MAC2STR(ap_addr)); ++ res = mp_set(wnd, OID_802_11_BSSID, ap_addr, ETH_ALEN); ++ /* user apps may set ap's mac address, which is not required; ++ * they may fail to work if this function fails, so return ++ * success */ ++ if (res) ++ WARNING("setting AP mac address failed (%08X)", res); ++ ++ EXIT2(return 0); ++} ++ ++int set_ndis_auth_mode(struct ndis_device *wnd, ULONG auth_mode) ++{ ++ NDIS_STATUS res; ++ ++ ENTER2("%d", auth_mode); ++ res = mp_set_int(wnd, OID_802_11_AUTHENTICATION_MODE, auth_mode); ++ if (res) { ++ WARNING("setting auth mode to %u failed (%08X)", ++ auth_mode, res); ++ if (res == NDIS_STATUS_INVALID_DATA) ++ EXIT2(return -EINVAL); ++ return -EOPNOTSUPP; ++ } ++ switch (auth_mode) { ++ case Ndis802_11AuthModeWPA: ++ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA; ++ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_802_1X; ++ break; ++ case Ndis802_11AuthModeWPAPSK: ++ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA; ++ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_PSK; ++ case Ndis802_11AuthModeWPANone: ++ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED; ++ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_PSK; ++ break; ++ case Ndis802_11AuthModeWPA2: ++ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA2; ++ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_802_1X; ++ break; ++ case Ndis802_11AuthModeWPA2PSK: ++ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA2; ++ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_PSK; ++ break; ++ case Ndis802_11AuthModeOpen: ++ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED; ++ wnd->iw_auth_80211_alg = IW_AUTH_ALG_OPEN_SYSTEM; ++ break; ++ case Ndis802_11AuthModeShared: ++ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED; ++ wnd->iw_auth_80211_alg = IW_AUTH_ALG_SHARED_KEY; ++ break; ++ case Ndis802_11AuthModeAutoSwitch: ++ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED; ++ wnd->iw_auth_80211_alg = IW_AUTH_ALG_SHARED_KEY; ++ wnd->iw_auth_80211_alg |= IW_AUTH_ALG_OPEN_SYSTEM; ++ break; ++ default: ++ WARNING("invalid authentication algorithm: %d", auth_mode); ++ break; ++ } ++ EXIT2(return 0); ++} ++ ++int get_ndis_auth_mode(struct ndis_device *wnd) ++{ ++ ULONG mode; ++ NDIS_STATUS res; ++ ++ res = mp_query_int(wnd, OID_802_11_AUTHENTICATION_MODE, &mode); ++ if (res) { ++ WARNING("getting authentication mode failed (%08X)", res); ++ EXIT2(return -EOPNOTSUPP); ++ } ++ TRACE2("%d", mode); ++ return mode; ++} ++ ++int set_iw_encr_mode(struct ndis_device *wnd, int cipher_pairwise, ++ int cipher_groupwise) ++{ ++ NDIS_STATUS res; ++ ULONG ndis_mode; ++ ++ ENTER2("%d, %d", cipher_pairwise, cipher_groupwise); ++ if (cipher_pairwise & IW_AUTH_CIPHER_CCMP) ++ ndis_mode = Ndis802_11Encryption3Enabled; ++ else if (cipher_pairwise & IW_AUTH_CIPHER_TKIP) ++ ndis_mode = Ndis802_11Encryption2Enabled; ++ else if (cipher_pairwise & ++ (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) ++ ndis_mode = Ndis802_11Encryption1Enabled; ++ else if (cipher_groupwise & IW_AUTH_CIPHER_CCMP) ++ ndis_mode = Ndis802_11Encryption3Enabled; ++ else if (cipher_groupwise & IW_AUTH_CIPHER_TKIP) ++ ndis_mode = Ndis802_11Encryption2Enabled; ++ else ++ ndis_mode = Ndis802_11EncryptionDisabled; ++ ++ res = mp_set_int(wnd, OID_802_11_ENCRYPTION_STATUS, ndis_mode); ++ if (res) { ++ WARNING("setting encryption mode to %u failed (%08X)", ++ ndis_mode, res); ++ if (res == NDIS_STATUS_INVALID_DATA) ++ EXIT2(return -EINVAL); ++ return -EOPNOTSUPP; ++ } ++ wnd->iw_auth_cipher_pairwise = cipher_pairwise; ++ wnd->iw_auth_cipher_group = cipher_groupwise; ++ EXIT2(return 0); ++} ++ ++int get_ndis_encr_mode(struct ndis_device *wnd) ++{ ++ ULONG mode; ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ res = mp_query_int(wnd, OID_802_11_ENCRYPTION_STATUS, &mode); ++ if (res) { ++ WARNING("getting encryption status failed (%08X)", res); ++ EXIT2(return -EOPNOTSUPP); ++ } else ++ EXIT2(return mode); ++} ++ ++static int iw_get_encr(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ int index, mode; ++ struct encr_info *encr_info = &wnd->encr_info; ++ ++ ENTER2("wnd = %p", wnd); ++ wrqu->data.length = 0; ++ extra[0] = 0; ++ ++ index = (wrqu->encoding.flags & IW_ENCODE_INDEX); ++ TRACE2("index = %u", index); ++ if (index > 0) ++ index--; ++ else ++ index = encr_info->tx_key_index; ++ ++ if (index < 0 || index >= MAX_ENCR_KEYS) { ++ WARNING("encryption index out of range (%u)", index); ++ EXIT2(return -EINVAL); ++ } ++ ++ if (index != encr_info->tx_key_index) { ++ if (encr_info->keys[index].length > 0) { ++ wrqu->data.flags |= IW_ENCODE_ENABLED; ++ wrqu->data.length = encr_info->keys[index].length; ++ memcpy(extra, encr_info->keys[index].key, ++ encr_info->keys[index].length); ++ } ++ else ++ wrqu->data.flags |= IW_ENCODE_DISABLED; ++ ++ EXIT2(return 0); ++ } ++ ++ /* transmit key */ ++ mode = get_ndis_encr_mode(wnd); ++ if (mode < 0) ++ EXIT2(return -EOPNOTSUPP); ++ ++ if (mode == Ndis802_11EncryptionDisabled || ++ mode == Ndis802_11EncryptionNotSupported) ++ wrqu->data.flags |= IW_ENCODE_DISABLED; ++ else { ++ if (mode == Ndis802_11Encryption1KeyAbsent || ++ mode == Ndis802_11Encryption2KeyAbsent || ++ mode == Ndis802_11Encryption3KeyAbsent) ++ wrqu->data.flags |= IW_ENCODE_NOKEY; ++ else { ++ wrqu->data.flags |= IW_ENCODE_ENABLED; ++ wrqu->encoding.flags |= index+1; ++ wrqu->data.length = encr_info->keys[index].length; ++ memcpy(extra, encr_info->keys[index].key, ++ encr_info->keys[index].length); ++ } ++ } ++ mode = get_ndis_auth_mode(wnd); ++ if (mode < 0) ++ EXIT2(return -EOPNOTSUPP); ++ ++ if (mode == Ndis802_11AuthModeOpen) ++ wrqu->data.flags |= IW_ENCODE_OPEN; ++ else if (mode == Ndis802_11AuthModeAutoSwitch) ++ wrqu->data.flags |= IW_ENCODE_RESTRICTED; ++ else // Ndis802_11AuthModeAutoSwitch, Ndis802_11AuthModeWPA etc. ++ wrqu->data.flags |= IW_ENCODE_RESTRICTED; ++ ++ EXIT2(return 0); ++} ++ ++/* remove_key is for both wep and wpa */ ++static int remove_key(struct ndis_device *wnd, int index, ++ mac_address bssid) ++{ ++ NDIS_STATUS res; ++ if (wnd->encr_info.keys[index].length == 0) ++ EXIT2(return 0); ++ wnd->encr_info.keys[index].length = 0; ++ memset(&wnd->encr_info.keys[index].key, 0, ++ sizeof(wnd->encr_info.keys[index].length)); ++ if (wnd->iw_auth_cipher_pairwise == IW_AUTH_CIPHER_TKIP || ++ wnd->iw_auth_cipher_pairwise == IW_AUTH_CIPHER_CCMP || ++ wnd->iw_auth_cipher_group == IW_AUTH_CIPHER_TKIP || ++ wnd->iw_auth_cipher_group == IW_AUTH_CIPHER_CCMP) { ++ struct ndis_remove_key rmkey; ++ rmkey.struct_size = sizeof(rmkey); ++ rmkey.index = index; ++ if (bssid) { ++ /* pairwise key */ ++ if (memcmp(bssid, "\xff\xff\xff\xff\xff\xff", ++ ETH_ALEN) != 0) ++ rmkey.index |= (1 << 30); ++ memcpy(rmkey.bssid, bssid, sizeof(rmkey.bssid)); ++ } else ++ memset(rmkey.bssid, 0xff, sizeof(rmkey.bssid)); ++ if (mp_set(wnd, OID_802_11_REMOVE_KEY, &rmkey, sizeof(rmkey))) ++ EXIT2(return -EINVAL); ++ } else { ++ ndis_key_index keyindex = index; ++ res = mp_set_int(wnd, OID_802_11_REMOVE_WEP, keyindex); ++ if (res) { ++ WARNING("removing encryption key %d failed (%08X)", ++ keyindex, res); ++ EXIT2(return -EINVAL); ++ } ++ } ++ /* if it is transmit key, disable encryption */ ++ if (index == wnd->encr_info.tx_key_index) { ++ res = set_iw_encr_mode(wnd, IW_AUTH_CIPHER_NONE, ++ IW_AUTH_CIPHER_NONE); ++ if (res) ++ WARNING("changing encr status failed (%08X)", res); ++ } ++ TRACE2("key %d removed", index); ++ EXIT2(return 0); ++} ++ ++static int iw_set_wep(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ unsigned int index, key_len; ++ struct encr_info *encr_info = &wnd->encr_info; ++ unsigned char *key; ++ ++ ENTER2(""); ++ index = (wrqu->encoding.flags & IW_ENCODE_INDEX); ++ TRACE2("index = %u", index); ++ ++ /* iwconfig gives index as 1 - N */ ++ if (index > 0) ++ index--; ++ else ++ index = encr_info->tx_key_index; ++ ++ if (index >= MAX_ENCR_KEYS) { ++ WARNING("encryption index out of range (%u)", index); ++ EXIT2(return -EINVAL); ++ } ++ ++ /* remove key if disabled */ ++ if (wrqu->data.flags & IW_ENCODE_DISABLED) { ++ if (remove_key(wnd, index, NULL)) ++ EXIT2(return -EINVAL); ++ else ++ EXIT2(return 0); ++ } ++ ++ /* global encryption state (for all keys) */ ++ if (wrqu->data.flags & IW_ENCODE_OPEN) ++ res = set_ndis_auth_mode(wnd, Ndis802_11AuthModeOpen); ++ else // if (wrqu->data.flags & IW_ENCODE_RESTRICTED) ++ res = set_ndis_auth_mode(wnd, Ndis802_11AuthModeShared); ++ if (res) { ++ WARNING("setting authentication mode failed (%08X)", res); ++ EXIT2(return -EINVAL); ++ } ++ ++ TRACE2("key length: %d", wrqu->data.length); ++ ++ if (wrqu->data.length > 0) { ++ key_len = wrqu->data.length; ++ key = extra; ++ } else { // must be set as tx key ++ if (encr_info->keys[index].length == 0) { ++ WARNING("key %d is not set", index+1); ++ EXIT2(return -EINVAL); ++ } ++ key_len = encr_info->keys[index].length; ++ key = encr_info->keys[index].key; ++ encr_info->tx_key_index = index; ++ } ++ ++ if (add_wep_key(wnd, key, key_len, index)) ++ EXIT2(return -EINVAL); ++ ++ if (index == encr_info->tx_key_index) { ++ /* if transmit key is at index other than 0, some ++ * drivers, at least Atheros and TI, want another ++ * (global) non-transmit key to be set; don't know why */ ++ if (index != 0) { ++ int i; ++ for (i = 0; i < MAX_ENCR_KEYS; i++) ++ if (i != index && ++ encr_info->keys[i].length != 0) ++ break; ++ if (i == MAX_ENCR_KEYS) { ++ if (index == 0) ++ i = index + 1; ++ else ++ i = index - 1; ++ if (add_wep_key(wnd, key, key_len, i)) ++ WARNING("couldn't add broadcast key" ++ " at %d", i); ++ } ++ } ++ /* ndis drivers want essid to be set after setting encr */ ++ set_essid(wnd, wnd->essid.essid, wnd->essid.length); ++ } ++ EXIT2(return 0); ++} ++ ++static int iw_set_nick(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ++ if (wrqu->data.length >= sizeof(wnd->nick)) ++ return -EINVAL; ++ memcpy(wnd->nick, extra, wrqu->data.length); ++ wnd->nick[wrqu->data.length] = 0; ++ return 0; ++} ++ ++static int iw_get_nick(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ++ wrqu->data.length = strlen(wnd->nick); ++ memcpy(extra, wnd->nick, wrqu->data.length); ++ return 0; ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) && !defined(IW_REQUEST_FLAG_COMPAT) ++#define iwe_stream_add_event(a, b, c, d, e) iwe_stream_add_event(b, c, d, e) ++#define iwe_stream_add_point(a, b, c, d, e) iwe_stream_add_point(b, c, d, e) ++#define iwe_stream_add_value(a, b, c, d, e, f) \ ++ iwe_stream_add_value(b, c, d, e, f) ++#define iwe_stream_lcp_len(a) IW_EV_LCP_LEN ++#endif ++ ++static char *ndis_translate_scan(struct net_device *dev, ++ struct iw_request_info *info, char *event, ++ char *end_buf, void *item) ++{ ++ struct iw_event iwe; ++ char *current_val; ++ char *ret; ++ int i, nrates; ++ unsigned char custom_str[64]; ++ struct ndis_wlan_bssid *bssid; ++ struct ndis_wlan_bssid_ex *bssid_ex; ++ int extended; ++ ++ ENTER2("%p, %p", event, item); ++ bssid = item; ++ bssid_ex = item; ++ extended = (bssid->length > offsetof(struct ndis_wlan_bssid_ex, var)); ++ ++ /* add mac address */ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ iwe.len = IW_EV_ADDR_LEN; ++ memcpy(iwe.u.ap_addr.sa_data, bssid->mac, ETH_ALEN); ++ ret = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_ADDR_LEN); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ ++ /* add essid */ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.length = bssid->ssid.length; ++ if (iwe.u.data.length > IW_ESSID_MAX_SIZE) ++ iwe.u.data.length = IW_ESSID_MAX_SIZE; ++ iwe.u.data.flags = 1; ++ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; ++ ret = iwe_stream_add_point(info, event, end_buf, &iwe, ++ bssid->ssid.essid); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ ++ /* add protocol name */ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWNAME; ++ strncpy(iwe.u.name, network_type_to_name(bssid->net_type), IFNAMSIZ); ++ ret = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_CHAR_LEN); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ ++ /* add mode */ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWMODE; ++ if (bssid->mode == Ndis802_11IBSS) ++ iwe.u.mode = IW_MODE_ADHOC; ++ else if (bssid->mode == Ndis802_11Infrastructure) ++ iwe.u.mode = IW_MODE_MASTER; ++ else // if (bssid->mode == Ndis802_11AutoUnknown) ++ iwe.u.mode = IW_MODE_AUTO; ++ ret = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_UINT_LEN); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ ++ /* add freq */ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWFREQ; ++ iwe.u.freq.m = bssid->config.ds_config; ++ if (bssid->config.ds_config > 1000000) { ++ iwe.u.freq.m = bssid->config.ds_config / 10; ++ iwe.u.freq.e = 1; ++ } ++ else ++ iwe.u.freq.m = bssid->config.ds_config; ++ /* convert from kHz to Hz */ ++ iwe.u.freq.e += 3; ++ iwe.len = IW_EV_FREQ_LEN; ++ ret = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_FREQ_LEN); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ ++ /* add qual */ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVQUAL; ++ i = 100 * (bssid->rssi - WL_NOISE) / (WL_SIGMAX - WL_NOISE); ++ if (i < 0) ++ i = 0; ++ else if (i > 100) ++ i = 100; ++ iwe.u.qual.level = bssid->rssi; ++ iwe.u.qual.noise = WL_NOISE; ++ iwe.u.qual.qual = i; ++ iwe.len = IW_EV_QUAL_LEN; ++ ret = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_QUAL_LEN); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ ++ /* add key info */ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWENCODE; ++ if (bssid->privacy == Ndis802_11PrivFilterAcceptAll) ++ iwe.u.data.flags = IW_ENCODE_DISABLED; ++ else ++ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ iwe.u.data.length = 0; ++ iwe.len = IW_EV_POINT_LEN; ++ ret = iwe_stream_add_point(info, event, end_buf, &iwe, ++ bssid->ssid.essid); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ ++ /* add rate */ ++ memset(&iwe, 0, sizeof(iwe)); ++ current_val = event + iwe_stream_lcp_len(info); ++ iwe.cmd = SIOCGIWRATE; ++ if (extended) ++ nrates = ARRAY_SIZE(bssid->rates); ++ else ++ nrates = ARRAY_SIZE(bssid_ex->rates_ex); ++ for (i = 0; i < nrates; i++) { ++ if (bssid_ex->rates_ex[i] & 0x7f) { ++ iwe.u.bitrate.value = ((bssid->rates[i] & 0x7f) * ++ 500000); ++ ret = iwe_stream_add_value(info, event, current_val, ++ end_buf, &iwe, ++ IW_EV_PARAM_LEN); ++ if (ret == current_val) ++ return NULL; ++ current_val = ret; ++ } ++ } ++ ++ if ((current_val - event) > iwe_stream_lcp_len(info)) ++ event = current_val; ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ sprintf(custom_str, "bcn_int=%d", bssid->config.beacon_period); ++ iwe.u.data.length = strlen(custom_str); ++ ret = iwe_stream_add_point(info, event, end_buf, &iwe, custom_str); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ sprintf(custom_str, "atim=%u", bssid->config.atim_window); ++ iwe.u.data.length = strlen(custom_str); ++ ret = iwe_stream_add_point(info, event, end_buf, &iwe, custom_str); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ ++ TRACE2("%d, %zu", bssid->length, sizeof(*bssid)); ++ if (extended) { ++ struct ndis_variable_ies *iep = bssid_ex->var; ++ unsigned char *end = (unsigned char *)&bssid_ex->fixed + ++ bssid_ex->ie_length; ++ ++ while (&iep->length < end && &iep->data[iep->length] <= end) { ++ unsigned char ielen = iep->length + 2; ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = ielen; ++ ret = iwe_stream_add_point(info, event, end_buf, &iwe, ++ (char *)iep); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ iep = (typeof(iep))&iep->data[iep->length]; ++ } ++ } ++ TRACE2("event = %p, current_val = %p", event, current_val); ++ EXIT2(return event); ++} ++ ++static int set_scan(struct ndis_device *wnd) ++{ ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ res = mp_set(wnd, OID_802_11_BSSID_LIST_SCAN, NULL, 0); ++ if (res) { ++ WARNING("scanning failed (%08X)", res); ++ EXIT2(return -EOPNOTSUPP); ++ } ++ wnd->scan_timestamp = jiffies; ++ EXIT2(return 0); ++} ++ ++static int iw_set_scan(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ return set_scan(wnd); ++} ++ ++static int iw_get_scan(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ unsigned int i, buf_len, needed, data_len; ++ NDIS_STATUS res; ++ struct ndis_bssid_list *bssid_list = NULL; ++ char *event = extra; ++ struct ndis_wlan_bssid *cur_item; ++ ++ ENTER2(""); ++ if (time_before(jiffies, wnd->scan_timestamp + 3 * HZ)) ++ return -EAGAIN; ++ /* try with space for a few scan items */ ++ buf_len = sizeof(ULONG) + offsetof(struct ndis_wlan_bssid_ex, var) * 8; ++ ++ /* Try many times, as the needed space may grow between queries */ ++ for (i = 0; i < 10; i++) { ++ bssid_list = kzalloc(buf_len, GFP_KERNEL); ++ if (!bssid_list) { ++ ERROR("couldn't allocate %u bytes for scan results", ++ buf_len); ++ return -ENOMEM; ++ } ++ ++ needed = 0; ++ data_len = 0; ++ res = mp_query_info(wnd, OID_802_11_BSSID_LIST, bssid_list, ++ buf_len, &data_len, &needed); ++ TRACE2("try %d: given %d bytes, needed %d, written %d", ++ i, buf_len, needed, data_len); ++ if (needed <= buf_len) ++ break; ++ kfree(bssid_list); ++ buf_len = needed; ++ } ++ if (res) { ++ WARNING("getting BSSID list failed (%08X)", res); ++ kfree(bssid_list); ++ EXIT2(return -EOPNOTSUPP); ++ } ++ ++ /* some drivers don't set bssid_list->num_items to 0 if ++ OID_802_11_BSSID_LIST returns no items (prism54 driver, e.g.,) */ ++ TRACE2("items: %d", bssid_list->num_items); ++ cur_item = &bssid_list->bssid[0]; ++ for (i = 0; i < bssid_list->num_items; i++) { ++ TRACE2("item %d: len %d, remaining data %d", ++ i, cur_item->length, data_len); ++ /* drop truncated items */ ++ if (cur_item->length > data_len) ++ break; ++ event = ndis_translate_scan(dev, info, event, ++ extra + wrqu->data.length, ++ cur_item); ++ if (!event) { ++ kfree(bssid_list); ++ return -E2BIG; ++ } ++ data_len -= cur_item->length; ++ cur_item = (struct ndis_wlan_bssid *)((char *)cur_item + ++ cur_item->length); ++ } ++ wrqu->data.length = event - extra; ++ wrqu->data.flags = 0; ++ kfree(bssid_list); ++ EXIT2(return 0); ++} ++ ++static int iw_set_power_mode(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ enum ndis_power power_mode; ++ ++ if (wrqu->power.disabled == 1) ++ power_mode = NDIS_POWER_OFF; ++ else if (wrqu->power.flags & IW_POWER_MIN) ++ power_mode = NDIS_POWER_MIN; ++ else // if (wrqu->power.flags & IW_POWER_MAX) ++ power_mode = NDIS_POWER_MAX; ++ ++ TRACE2("%d", power_mode); ++ res = mp_set(wnd, OID_802_11_POWER_MODE, ++ &power_mode, sizeof(power_mode)); ++ if (res) ++ WARNING("setting power mode failed (%08X)", res); ++ return 0; ++} ++ ++static int iw_get_power_mode(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ enum ndis_power power_mode; ++ ++ ENTER2(""); ++ res = mp_query(wnd, OID_802_11_POWER_MODE, ++ &power_mode, sizeof(power_mode)); ++ if (res) ++ return -ENOTSUPP; ++ ++ if (power_mode == NDIS_POWER_OFF) ++ wrqu->power.disabled = 1; ++ else { ++ if (wrqu->power.flags != 0) ++ return 0; ++ wrqu->power.flags |= IW_POWER_ALL_R; ++ wrqu->power.flags |= IW_POWER_TIMEOUT; ++ wrqu->power.value = 0; ++ wrqu->power.disabled = 0; ++ ++ if (power_mode == NDIS_POWER_MIN) ++ wrqu->power.flags |= IW_POWER_MIN; ++ else // if (power_mode == NDIS_POWER_MAX) ++ wrqu->power.flags |= IW_POWER_MAX; ++ } ++ return 0; ++} ++ ++static int iw_get_sensitivity(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ ndis_rssi rssi_trigger; ++ ++ ENTER2(""); ++ res = mp_query(wnd, OID_802_11_RSSI_TRIGGER, ++ &rssi_trigger, sizeof(rssi_trigger)); ++ if (res) ++ return -EOPNOTSUPP; ++ wrqu->param.value = rssi_trigger; ++ wrqu->param.disabled = (rssi_trigger == 0); ++ wrqu->param.fixed = 1; ++ return 0; ++} ++ ++static int iw_set_sensitivity(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ ndis_rssi rssi_trigger; ++ ++ ENTER2(""); ++ if (wrqu->param.disabled) ++ rssi_trigger = 0; ++ else ++ rssi_trigger = wrqu->param.value; ++ res = mp_set(wnd, OID_802_11_RSSI_TRIGGER, ++ &rssi_trigger, sizeof(rssi_trigger)); ++ if (res == NDIS_STATUS_INVALID_DATA) ++ return -EINVAL; ++ if (res) ++ return -EOPNOTSUPP; ++ return 0; ++} ++ ++static int iw_get_ndis_stats(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ struct iw_statistics *stats = &wnd->iw_stats; ++ memcpy(&wrqu->qual, &stats->qual, sizeof(stats->qual)); ++ return 0; ++} ++ ++static int iw_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 iw_point *data = &wrqu->data; ++ struct ndis_device *wnd = netdev_priv(dev); ++ unsigned int i, n; ++ NDIS_STATUS res; ++ UCHAR rates[NDIS_MAX_RATES_EX]; ++ ndis_tx_power_level tx_power; ++ ++ ENTER2(""); ++ data->length = sizeof(struct iw_range); ++ memset(range, 0, sizeof(struct iw_range)); ++ ++ range->txpower_capa = IW_TXPOW_MWATT; ++ range->num_txpower = 0; ++ ++ res = mp_query(wnd, OID_802_11_TX_POWER_LEVEL, ++ &tx_power, sizeof(tx_power)); ++ if (!res) { ++ range->num_txpower = 1; ++ range->txpower[0] = tx_power; ++ } ++ ++ range->we_version_compiled = WIRELESS_EXT; ++ range->we_version_source = 19; ++ ++ range->retry_capa = IW_RETRY_LIMIT; ++ range->retry_flags = IW_RETRY_LIMIT; ++ range->min_retry = 0; ++ range->max_retry = 255; ++ ++ range->num_channels = 1; ++ ++ range->max_qual.qual = 100; ++ range->max_qual.level = 154; ++ range->max_qual.noise = 154; ++ range->sensitivity = 3; ++ ++ range->max_encoding_tokens = 4; ++ range->num_encoding_sizes = 2; ++ range->encoding_size[0] = 5; ++ range->encoding_size[1] = 13; ++ ++ range->num_bitrates = 0; ++ memset(&rates, 0, sizeof(rates)); ++ res = mp_query_info(wnd, OID_802_11_SUPPORTED_RATES, ++ &rates, sizeof(rates), &n, NULL); ++ if (res) ++ WARNING("getting bit rates failed: %08X", res); ++ else { ++ for (i = 0; i < n && range->num_bitrates < IW_MAX_BITRATES; i++) ++ if (rates[i] & 0x80) ++ continue; ++ else if (rates[i] & 0x7f) { ++ range->bitrate[range->num_bitrates] = ++ (rates[i] & 0x7f) * 500000; ++ range->num_bitrates++; ++ } ++ } ++ ++ range->num_channels = ARRAY_SIZE(freq_chan); ++ ++ for (i = 0; i < ARRAY_SIZE(freq_chan) && i < IW_MAX_FREQUENCIES; i++) { ++ range->freq[i].i = i + 1; ++ range->freq[i].m = freq_chan[i] * 100000; ++ range->freq[i].e = 1; ++ } ++ range->num_frequency = i; ++ ++ range->min_rts = 0; ++ range->max_rts = 2347; ++ range->min_frag = 256; ++ range->max_frag = 2346; ++ ++ /* Event capability (kernel + driver) */ ++ range->event_capa[0] = (IW_EVENT_CAPA_K_0 | ++ IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | ++ IW_EVENT_CAPA_MASK(SIOCGIWAP) | ++ IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); ++ range->event_capa[1] = IW_EVENT_CAPA_K_1; ++ range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVTXDROP) | ++ IW_EVENT_CAPA_MASK(IWEVCUSTOM) | ++ IW_EVENT_CAPA_MASK(IWEVREGISTERED) | ++ IW_EVENT_CAPA_MASK(IWEVEXPIRED)); ++ ++ range->enc_capa = 0; ++ ++ if (test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr)) ++ range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP; ++ if (test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr)) ++ range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP; ++ ++ if (test_bit(Ndis802_11AuthModeWPA, &wnd->capa.auth) || ++ test_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.auth)) ++ range->enc_capa |= IW_ENC_CAPA_WPA; ++ if (test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) || ++ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth)) ++ range->enc_capa |= IW_ENC_CAPA_WPA2; ++ ++ return 0; ++} ++ ++void set_default_iw_params(struct ndis_device *wnd) ++{ ++ wnd->iw_auth_key_mgmt = 0; ++ wnd->iw_auth_wpa_version = 0; ++ set_infra_mode(wnd, Ndis802_11Infrastructure); ++ set_ndis_auth_mode(wnd, Ndis802_11AuthModeOpen); ++ set_priv_filter(wnd); ++ set_iw_encr_mode(wnd, IW_AUTH_CIPHER_NONE, IW_AUTH_CIPHER_NONE); ++} ++ ++static int deauthenticate(struct ndis_device *wnd) ++{ ++ int ret; ++ ++ ENTER2(""); ++ ret = disassociate(wnd, 1); ++ set_default_iw_params(wnd); ++ EXIT2(return ret); ++} ++ ++NDIS_STATUS disassociate(struct ndis_device *wnd, int reset_ssid) ++{ ++ NDIS_STATUS res; ++ u8 buf[NDIS_ESSID_MAX_SIZE]; ++ int i; ++ ++ TRACE2(""); ++ res = mp_set(wnd, OID_802_11_DISASSOCIATE, NULL, 0); ++ /* disassociate causes radio to be turned off; if reset_ssid ++ * is given, set ssid to random to enable radio */ ++ if (reset_ssid) { ++ get_random_bytes(buf, sizeof(buf)); ++ for (i = 0; i < sizeof(buf); i++) ++ buf[i] = 'a' + (buf[i] % 26); ++ set_essid(wnd, buf, sizeof(buf)); ++ } ++ return res; ++} ++ ++static int iw_set_mlme(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ struct iw_mlme *mlme = (struct iw_mlme *)extra; ++ ++ ENTER2(""); ++ switch (mlme->cmd) { ++ case IW_MLME_DEAUTH: ++ return deauthenticate(wnd); ++ case IW_MLME_DISASSOC: ++ TRACE2("cmd=%d reason_code=%d", mlme->cmd, mlme->reason_code); ++ return disassociate(wnd, 1); ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++static int iw_set_genie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ /* ++ * NDIS drivers do not allow IEs to be configured; this is ++ * done by the driver based on other configuration. Return 0 ++ * to avoid causing issues with user space programs that ++ * expect this function to succeed. ++ */ ++ return 0; ++} ++ ++static int iw_set_auth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ TRACE2("index=%d value=%d", wrqu->param.flags & IW_AUTH_INDEX, ++ wrqu->param.value); ++ switch (wrqu->param.flags & IW_AUTH_INDEX) { ++ case IW_AUTH_WPA_VERSION: ++ wnd->iw_auth_wpa_version = wrqu->param.value; ++ break; ++ case IW_AUTH_CIPHER_PAIRWISE: ++ wnd->iw_auth_cipher_pairwise = wrqu->param.value; ++ break; ++ case IW_AUTH_CIPHER_GROUP: ++ wnd->iw_auth_cipher_group = wrqu->param.value; ++ break; ++ case IW_AUTH_KEY_MGMT: ++ wnd->iw_auth_key_mgmt = wrqu->param.value; ++ break; ++ case IW_AUTH_80211_AUTH_ALG: ++ wnd->iw_auth_80211_alg = wrqu->param.value; ++ break; ++ case IW_AUTH_WPA_ENABLED: ++ if (wrqu->param.value) ++ deauthenticate(wnd); ++ break; ++#ifdef IW_AUTH_MFP ++ case IW_AUTH_MFP: ++ if (wrqu->param.value == IW_AUTH_MFP_DISABLED || ++ wrqu->param.value == IW_AUTH_MFP_OPTIONAL) ++ break; ++ WARNING("MFP not implemented"); ++ return -EOPNOTSUPP; ++#endif ++ case IW_AUTH_TKIP_COUNTERMEASURES: ++ case IW_AUTH_DROP_UNENCRYPTED: ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ case IW_AUTH_PRIVACY_INVOKED: ++ TRACE2("%d not implemented: %d", ++ wrqu->param.flags & IW_AUTH_INDEX, wrqu->param.value); ++ break; ++ default: ++ WARNING("invalid cmd %d", wrqu->param.flags & IW_AUTH_INDEX); ++ return -EOPNOTSUPP; ++ } ++ return 0; ++} ++ ++static int iw_get_auth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ++ ENTER2("index=%d", wrqu->param.flags & IW_AUTH_INDEX); ++ switch (wrqu->param.flags & IW_AUTH_INDEX) { ++ case IW_AUTH_WPA_VERSION: ++ wrqu->param.value = wnd->iw_auth_wpa_version; ++ break; ++ case IW_AUTH_CIPHER_PAIRWISE: ++ wrqu->param.value = wnd->iw_auth_cipher_pairwise; ++ break; ++ case IW_AUTH_CIPHER_GROUP: ++ wrqu->param.value = wnd->iw_auth_cipher_group; ++ break; ++ case IW_AUTH_KEY_MGMT: ++ wrqu->param.value = wnd->iw_auth_key_mgmt; ++ break; ++ case IW_AUTH_80211_AUTH_ALG: ++ wrqu->param.value = wnd->iw_auth_80211_alg; ++ break; ++ default: ++ WARNING("invalid cmd %d", wrqu->param.flags & IW_AUTH_INDEX); ++ return -EOPNOTSUPP; ++ } ++ return 0; ++} ++ ++static int iw_set_encodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ struct ndis_device *wnd = netdev_priv(dev); ++ struct ndis_add_key ndis_key; ++ int i, keyidx; ++ NDIS_STATUS res; ++ u8 *addr; ++ ++ keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; ++ ENTER2("%d", keyidx); ++ if (keyidx) ++ keyidx--; ++ else ++ keyidx = wnd->encr_info.tx_key_index; ++ ++ if (keyidx < 0 || keyidx >= MAX_ENCR_KEYS) ++ return -EINVAL; ++ ++ if (ext->alg == WPA_ALG_WEP) { ++ if (!test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr)) ++ EXIT2(return -1); ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ wnd->encr_info.tx_key_index = keyidx; ++ if (add_wep_key(wnd, ext->key, ext->key_len, keyidx)) ++ EXIT2(return -1); ++ else ++ EXIT2(return 0); ++ } ++ if ((wrqu->encoding.flags & IW_ENCODE_DISABLED) || ++ ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0) ++ EXIT2(return remove_key(wnd, keyidx, ndis_key.bssid)); ++ ++ if (ext->key_len > sizeof(ndis_key.key)) { ++ TRACE2("incorrect key length (%u)", ext->key_len); ++ EXIT2(return -1); ++ } ++ ++ memset(&ndis_key, 0, sizeof(ndis_key)); ++ ++ ndis_key.struct_size = ++ sizeof(ndis_key) - sizeof(ndis_key.key) + ext->key_len; ++ ndis_key.length = ext->key_len; ++ ndis_key.index = keyidx; ++ ++ if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { ++ for (i = 0; i < 6; i++) ++ ndis_key.rsc |= (((u64)ext->rx_seq[i]) << (i * 8)); ++ TRACE2("0x%llx", ndis_key.rsc); ++ ndis_key.index |= 1 << 29; ++ } ++ ++ addr = ext->addr.sa_data; ++ if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { ++ /* group key */ ++ if (wnd->infrastructure_mode == Ndis802_11IBSS) ++ memset(ndis_key.bssid, 0xff, ETH_ALEN); ++ else ++ get_ap_address(wnd, ndis_key.bssid); ++ } else { ++ /* pairwise key */ ++ ndis_key.index |= (1 << 30); ++ memcpy(ndis_key.bssid, addr, ETH_ALEN); ++ } ++ TRACE2(MACSTRSEP, MAC2STR(ndis_key.bssid)); ++ ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ ndis_key.index |= (1 << 31); ++ ++ if (ext->alg == IW_ENCODE_ALG_TKIP && ext->key_len == 32) { ++ /* wpa_supplicant gives us the Michael MIC RX/TX keys in ++ * different order than NDIS spec, so swap the order here. */ ++ memcpy(ndis_key.key, ext->key, 16); ++ memcpy(ndis_key.key + 16, ext->key + 24, 8); ++ memcpy(ndis_key.key + 24, ext->key + 16, 8); ++ } else ++ memcpy(ndis_key.key, ext->key, ext->key_len); ++ ++ res = mp_set(wnd, OID_802_11_ADD_KEY, &ndis_key, ndis_key.struct_size); ++ if (res) { ++ TRACE2("adding key failed (%08X), %u", ++ res, ndis_key.struct_size); ++ EXIT2(return -1); ++ } ++ wnd->encr_info.keys[keyidx].length = ext->key_len; ++ memcpy(&wnd->encr_info.keys[keyidx].key, ndis_key.key, ext->key_len); ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ wnd->encr_info.tx_key_index = keyidx; ++ TRACE2("key %d added", keyidx); ++ ++ EXIT2(return 0); ++} ++ ++static int iw_get_encodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ /* struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; */ ++ /* TODO */ ++ ENTER2(""); ++ return 0; ++} ++ ++static int iw_set_pmksa(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct iw_pmksa *pmksa = (struct iw_pmksa *)extra; ++ struct ndis_pmkid pmkid; ++ NDIS_STATUS res; ++ struct ndis_device *wnd = netdev_priv(dev); ++ ++ /* TODO: must keep local list of PMKIDs since NDIS drivers ++ * expect that all PMKID entries are included whenever a new ++ * one is added. */ ++ ++ ENTER2("%d", pmksa->cmd); ++ if ((pmksa->cmd == IW_PMKSA_ADD || pmksa->cmd == IW_PMKSA_REMOVE) && ++ (!(wnd->iw_auth_wpa_version & IW_AUTH_WPA_VERSION_WPA2))) ++ EXIT2(return -EOPNOTSUPP); ++ ++ memset(&pmkid, 0, sizeof(pmkid)); ++ if (pmksa->cmd == IW_PMKSA_ADD) { ++ pmkid.bssid_info_count = 1; ++ memcpy(pmkid.bssid_info[0].bssid, pmksa->bssid.sa_data, ++ ETH_ALEN); ++ memcpy(pmkid.bssid_info[0].pmkid, pmksa->pmkid, IW_PMKID_LEN); ++ } ++ pmkid.length = sizeof(pmkid); ++ ++ res = mp_set(wnd, OID_802_11_PMKID, &pmkid, pmkid.length); ++ if (res == NDIS_STATUS_FAILURE) ++ EXIT2(return -EOPNOTSUPP); ++ TRACE2("OID_802_11_PMKID -> %d", res); ++ if (res) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++#define WEXT(id) [id - SIOCIWFIRST] ++ ++static const iw_handler ndis_handler[] = { ++ WEXT(SIOCGIWNAME) = iw_get_network_type, ++ WEXT(SIOCSIWESSID) = iw_set_essid, ++ WEXT(SIOCGIWESSID) = iw_get_essid, ++ WEXT(SIOCSIWMODE) = iw_set_infra_mode, ++ WEXT(SIOCGIWMODE) = iw_get_infra_mode, ++ WEXT(SIOCGIWFREQ) = iw_get_freq, ++ WEXT(SIOCSIWFREQ) = iw_set_freq, ++ WEXT(SIOCGIWTXPOW) = iw_get_tx_power, ++ WEXT(SIOCSIWTXPOW) = iw_set_tx_power, ++ WEXT(SIOCGIWRATE) = iw_get_bitrate, ++ WEXT(SIOCSIWRATE) = iw_set_bitrate, ++ WEXT(SIOCGIWRTS) = iw_get_rts_threshold, ++ WEXT(SIOCSIWRTS) = iw_set_rts_threshold, ++ WEXT(SIOCGIWFRAG) = iw_get_frag_threshold, ++ WEXT(SIOCSIWFRAG) = iw_set_frag_threshold, ++ WEXT(SIOCGIWAP) = iw_get_ap_address, ++ WEXT(SIOCSIWAP) = iw_set_ap_address, ++ WEXT(SIOCSIWENCODE) = iw_set_wep, ++ WEXT(SIOCGIWENCODE) = iw_get_encr, ++ WEXT(SIOCSIWSCAN) = iw_set_scan, ++ WEXT(SIOCGIWSCAN) = iw_get_scan, ++ WEXT(SIOCGIWPOWER) = iw_get_power_mode, ++ WEXT(SIOCSIWPOWER) = iw_set_power_mode, ++ WEXT(SIOCGIWRANGE) = iw_get_range, ++ WEXT(SIOCGIWSTATS) = iw_get_ndis_stats, ++ WEXT(SIOCGIWSENS) = iw_get_sensitivity, ++ WEXT(SIOCSIWSENS) = iw_set_sensitivity, ++ WEXT(SIOCGIWNICKN) = iw_get_nick, ++ WEXT(SIOCSIWNICKN) = iw_set_nick, ++ WEXT(SIOCSIWCOMMIT) = iw_set_dummy, ++ WEXT(SIOCSIWMLME) = iw_set_mlme, ++ WEXT(SIOCSIWGENIE) = iw_set_genie, ++ WEXT(SIOCSIWAUTH) = iw_set_auth, ++ WEXT(SIOCGIWAUTH) = iw_get_auth, ++ WEXT(SIOCSIWENCODEEXT) = iw_set_encodeext, ++ WEXT(SIOCGIWENCODEEXT) = iw_get_encodeext, ++ WEXT(SIOCSIWPMKSA) = iw_set_pmksa, ++}; ++ ++/* private ioctl's */ ++ ++static int priv_reset(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int res; ++ ENTER2(""); ++ res = mp_reset(netdev_priv(dev)); ++ if (res) { ++ WARNING("reset failed: %08X", res); ++ return -EOPNOTSUPP; ++ } ++ return 0; ++} ++ ++static int priv_deauthenticate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int res; ++ ENTER2(""); ++ res = deauthenticate(netdev_priv(dev)); ++ return res; ++} ++ ++static int priv_power_profile(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ struct miniport *mp; ++ ULONG profile_inf; ++ ++ ENTER2(""); ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ if (!mp->pnp_event_notify) ++ EXIT2(return -EOPNOTSUPP); ++ ++ /* 1 for AC and 0 for Battery */ ++ if (wrqu->param.value) ++ profile_inf = NdisPowerProfileAcOnLine; ++ else ++ profile_inf = NdisPowerProfileBattery; ++ ++ LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx, ++ NdisDevicePnPEventPowerProfileChanged, ++ &profile_inf, sizeof(profile_inf)); ++ EXIT2(return 0); ++} ++ ++static int priv_network_type(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ enum network_type network_type; ++ NDIS_STATUS res; ++ char type; ++ ++ ENTER2(""); ++ type = wrqu->param.value; ++ if (type == 'f') ++ network_type = Ndis802_11FH; ++ else if (type == 'b') ++ network_type = Ndis802_11DS; ++ else if (type == 'a') ++ network_type = Ndis802_11OFDM5; ++ else if (type == 'g' || type == 'n') ++ network_type = Ndis802_11OFDM24; ++ else ++ network_type = Ndis802_11Automode; ++ ++ res = mp_set_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE, network_type); ++ if (res) { ++ WARNING("setting network type to %d failed (%08X)", ++ network_type, res); ++ EXIT2(return -EINVAL); ++ } ++ ++ EXIT2(return 0); ++} ++ ++static int priv_media_stream_mode(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ int mode; ++ ++ ENTER2(""); ++ if (wrqu->param.value > 0) ++ mode = Ndis802_11MediaStreamOn; ++ else ++ mode = Ndis802_11MediaStreamOff; ++ res = mp_set_int(wnd, OID_802_11_MEDIA_STREAM_MODE, mode); ++ if (res) { ++ WARNING("oid failed (%08X)", res); ++ EXIT2(return -EINVAL); ++ } ++ EXIT2(return 0); ++} ++ ++static int priv_reload_defaults(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ int res; ++ ENTER2(""); ++ res = mp_set_int(wnd, OID_802_11_RELOAD_DEFAULTS, ++ Ndis802_11ReloadWEPKeys); ++ if (res) { ++ WARNING("reloading defaults failed: %08X", res); ++ return -EOPNOTSUPP; ++ } ++ return 0; ++} ++ ++static const struct iw_priv_args priv_args[] = { ++ {PRIV_RESET, 0, 0, "ndis_reset"}, ++ {PRIV_POWER_PROFILE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ++ "power_profile"}, ++ {PRIV_DEAUTHENTICATE, 0, 0, "deauthenticate"}, ++ {PRIV_NETWORK_TYPE, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, ++ "network_type"}, ++ {PRIV_MEDIA_STREAM_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ++ "media_stream"}, ++ ++ {PRIV_RELOAD_DEFAULTS, 0, 0, "reload_defaults"}, ++}; ++ ++#define WEPRIV(id) [id - SIOCIWFIRSTPRIV] ++ ++static const iw_handler priv_handler[] = { ++ WEPRIV(PRIV_RESET) = priv_reset, ++ WEPRIV(PRIV_POWER_PROFILE) = priv_power_profile, ++ WEPRIV(PRIV_DEAUTHENTICATE) = priv_deauthenticate, ++ WEPRIV(PRIV_NETWORK_TYPE) = priv_network_type, ++ WEPRIV(PRIV_MEDIA_STREAM_MODE) = priv_media_stream_mode, ++ WEPRIV(PRIV_RELOAD_DEFAULTS) = priv_reload_defaults, ++}; ++ ++const struct iw_handler_def ndis_handler_def = { ++ .num_standard = ARRAY_SIZE(ndis_handler), ++ .num_private = ARRAY_SIZE(priv_handler), ++ .num_private_args = ARRAY_SIZE(priv_args), ++ ++ .standard = (iw_handler *)ndis_handler, ++ .private = (iw_handler *)priv_handler, ++ .private_args = (struct iw_priv_args *)priv_args, ++ .get_wireless_stats = get_iw_stats, ++}; ++ ++#endif +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/iw_ndis.h linux-4.6-rc6-ndis/3rdparty/ndiswrapper/iw_ndis.h +--- linux-4.6-rc6/3rdparty/ndiswrapper/iw_ndis.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/iw_ndis.h 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,194 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _IW_NDIS_H_ ++#define _IW_NDIS_H_ ++ ++#include "ndis.h" ++ ++#define WL_NOISE -96 /* typical noise level in dBm */ ++#define WL_SIGMAX -32 /* typical maximum signal level in dBm */ ++ ++struct ndis_encr_key { ++ ULONG struct_size; ++ ULONG index; ++ ULONG length; ++ UCHAR key[NDIS_ENCODING_TOKEN_MAX]; ++}; ++ ++struct ndis_add_key { ++ ULONG struct_size; ++ ndis_key_index index; ++ ULONG length; ++ mac_address bssid; ++ UCHAR pad[6]; ++ ndis_key_rsc rsc; ++ UCHAR key[NDIS_ENCODING_TOKEN_MAX]; ++}; ++ ++struct ndis_remove_key { ++ ULONG struct_size; ++ ndis_key_index index; ++ mac_address bssid; ++}; ++ ++struct ndis_fixed_ies { ++ UCHAR time_stamp[8]; ++ USHORT beacon_interval; ++ USHORT capa; ++}; ++ ++struct ndis_variable_ies { ++ UCHAR elem_id; ++ UCHAR length; ++ UCHAR data[]; ++}; ++ ++enum ndis_reload_defaults { Ndis802_11ReloadWEPKeys }; ++ ++struct ndis_assoc_info { ++ ULONG length; ++ USHORT req_ies; ++ struct req_ie { ++ USHORT capa; ++ USHORT listen_interval; ++ mac_address cur_ap_address; ++ } req_ie; ++ ULONG req_ie_length; ++ ULONG offset_req_ies; ++ USHORT resp_ies; ++ struct resp_ie { ++ USHORT capa; ++ USHORT status_code; ++ USHORT assoc_id; ++ } resp_ie; ++ ULONG resp_ie_length; ++ ULONG offset_resp_ies; ++}; ++ ++struct ndis_configuration_fh { ++ ULONG length; ++ ULONG hop_pattern; ++ ULONG hop_set; ++ ULONG dwell_time; ++}; ++ ++struct ndis_configuration { ++ ULONG length; ++ ULONG beacon_period; ++ ULONG atim_window; ++ ULONG ds_config; ++ struct ndis_configuration_fh fh_config; ++}; ++ ++struct ndis_wlan_bssid { ++ ULONG length; ++ mac_address mac; ++ UCHAR reserved[2]; ++ struct ndis_essid ssid; ++ ULONG privacy; ++ ndis_rssi rssi; ++ UINT net_type; ++ struct ndis_configuration config; ++ UINT mode; ++ UCHAR rates[NDIS_MAX_RATES]; ++}; ++ ++struct ndis_wlan_bssid_ex { ++ ULONG length; ++ mac_address mac; ++ UCHAR reserved[2]; ++ struct ndis_essid ssid; ++ ULONG privacy; ++ ndis_rssi rssi; ++ UINT net_type; ++ struct ndis_configuration config; ++ UINT mode; ++ UCHAR rates_ex[NDIS_MAX_RATES_EX]; ++ ULONG ie_length; ++ struct ndis_fixed_ies fixed; ++ struct ndis_variable_ies var[]; ++}; ++ ++/* we use bssid_list as bssid_list_ex also */ ++struct ndis_bssid_list { ++ ULONG num_items; ++ struct ndis_wlan_bssid bssid[1]; ++}; ++ ++enum ndis_priv_filter { ++ Ndis802_11PrivFilterAcceptAll, Ndis802_11PrivFilter8021xWEP ++}; ++ ++enum network_type { ++ Ndis802_11FH, Ndis802_11DS, Ndis802_11OFDM5, Ndis802_11OFDM24, ++ /* MSDN site uses Ndis802_11Automode, which is not mentioned ++ * in DDK, so add one and assign it to ++ * Ndis802_11NetworkTypeMax */ ++ Ndis802_11Automode, Ndis802_11NetworkTypeMax = Ndis802_11Automode ++}; ++ ++struct network_type_list { ++ ULONG num; ++ enum network_type types[1]; ++}; ++ ++enum ndis_power { ++ NDIS_POWER_OFF = 0, NDIS_POWER_MAX, NDIS_POWER_MIN, ++}; ++ ++struct ndis_auth_req { ++ ULONG length; ++ mac_address bssid; ++ ULONG flags; ++}; ++ ++struct ndis_bssid_info { ++ mac_address bssid; ++ UCHAR pmkid[IW_PMKID_LEN]; ++}; ++ ++struct ndis_pmkid { ++ ULONG length; ++ ULONG bssid_info_count; ++ struct ndis_bssid_info bssid_info[1]; ++}; ++ ++int get_ap_address(struct ndis_device *wnd, mac_address mac); ++int set_ndis_auth_mode(struct ndis_device *wnd, ULONG auth_mode); ++int get_ndis_encr_mode(struct ndis_device *wnd); ++int set_iw_encr_mode(struct ndis_device *wnd, int cipher_pairwise, ++ int cipher_groupwise); ++int get_ndis_auth_mode(struct ndis_device *wnd); ++NDIS_STATUS disassociate(struct ndis_device *wnd, int reset_ssid); ++void set_default_iw_params(struct ndis_device *wnd); ++extern const struct iw_handler_def ndis_handler_def; ++ ++#define PRIV_RESET SIOCIWFIRSTPRIV+16 ++#define PRIV_POWER_PROFILE SIOCIWFIRSTPRIV+17 ++#define PRIV_NETWORK_TYPE SIOCIWFIRSTPRIV+18 ++#define PRIV_DEAUTHENTICATE SIOCIWFIRSTPRIV+19 ++#define PRIV_MEDIA_STREAM_MODE SIOCIWFIRSTPRIV+20 ++#define PRIV_RELOAD_DEFAULTS SIOCIWFIRSTPRIV+23 ++ ++/* these have to match what is in wpa_supplicant */ ++ ++enum wpa_alg { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP }; ++enum wpa_cipher { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP, ++ CIPHER_WEP104 }; ++enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, ++ KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE }; ++ ++#endif // IW_NDIS_H +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/lin2win.h linux-4.6-rc6-ndis/3rdparty/ndiswrapper/lin2win.h +--- linux-4.6-rc6/3rdparty/ndiswrapper/lin2win.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/lin2win.h 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,111 @@ ++/* ++ * Copyright (C) 2006 Giridhar Pemmasani ++ * ++ * 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. ++ * ++ */ ++ ++#ifdef CONFIG_X86_64 ++ ++u64 lin2win0(void *func); ++u64 lin2win1(void *func, u64 arg1); ++u64 lin2win2(void *func, u64 arg1, u64 arg2); ++u64 lin2win3(void *func, u64 arg1, u64 arg2, u64 arg3); ++u64 lin2win4(void *func, u64 arg1, u64 arg2, u64 arg3, u64 arg4); ++u64 lin2win5(void *func, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5); ++u64 lin2win6(void *func, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, ++ u64 arg6); ++ ++#define LIN2WIN0(func) \ ++({ \ ++ if (0) \ ++ func(); \ ++ lin2win0(func); \ ++}) ++ ++#define LIN2WIN1(func, arg1) \ ++({ \ ++ if (0) \ ++ func(arg1); \ ++ lin2win1(func, (u64)arg1); \ ++}) ++ ++#define LIN2WIN2(func, arg1, arg2) \ ++({ \ ++ if (0) \ ++ func(arg1, arg2); \ ++ lin2win2(func, (u64)arg1, (u64)arg2); \ ++}) ++ ++#define LIN2WIN3(func, arg1, arg2, arg3) \ ++({ \ ++ if (0) \ ++ func(arg1, arg2, arg3); \ ++ lin2win3(func, (u64)arg1, (u64)arg2, (u64)arg3); \ ++}) ++ ++#define LIN2WIN4(func, arg1, arg2, arg3, arg4) \ ++({ \ ++ if (0) \ ++ func(arg1, arg2, arg3, arg4); \ ++ lin2win4(func, (u64)arg1, (u64)arg2, (u64)arg3, (u64)arg4); \ ++}) ++ ++#define LIN2WIN5(func, arg1, arg2, arg3, arg4, arg5) \ ++({ \ ++ if (0) \ ++ func(arg1, arg2, arg3, arg4, arg5); \ ++ lin2win5(func, (u64)arg1, (u64)arg2, (u64)arg3, (u64)arg4, \ ++ (u64)arg5); \ ++}) ++ ++#define LIN2WIN6(func, arg1, arg2, arg3, arg4, arg5, arg6) \ ++({ \ ++ if (0) \ ++ func(arg1, arg2, arg3, arg4, arg5, arg6); \ ++ lin2win6(func, (u64)arg1, (u64)arg2, (u64)arg3, (u64)arg4, \ ++ (u64)arg5, (u64)arg6); \ ++}) ++ ++#else // CONFIG_X86_64 ++ ++#define LIN2WIN1(func, arg1) \ ++({ \ ++ TRACE6("calling %p", func); \ ++ func(arg1); \ ++}) ++#define LIN2WIN2(func, arg1, arg2) \ ++({ \ ++ TRACE6("calling %p", func); \ ++ func(arg1, arg2); \ ++}) ++#define LIN2WIN3(func, arg1, arg2, arg3) \ ++({ \ ++ TRACE6("calling %p", func); \ ++ func(arg1, arg2, arg3); \ ++}) ++#define LIN2WIN4(func, arg1, arg2, arg3, arg4) \ ++({ \ ++ TRACE6("calling %p", func); \ ++ func(arg1, arg2, arg3, arg4); \ ++}) ++#define LIN2WIN5(func, arg1, arg2, arg3, arg4, arg5) \ ++({ \ ++ TRACE6("calling %p", func); \ ++ func(arg1, arg2, arg3, arg4, arg5); \ ++}) ++#define LIN2WIN6(func, arg1, arg2, arg3, arg4, arg5, arg6) \ ++({ \ ++ TRACE6("calling %p", func); \ ++ func(arg1, arg2, arg3, arg4, arg5, arg6); \ ++}) ++ ++#endif // CONFIG_X86_64 +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/lin2win.S linux-4.6-rc6-ndis/3rdparty/ndiswrapper/lin2win.S +--- linux-4.6-rc6/3rdparty/ndiswrapper/lin2win.S 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/lin2win.S 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,138 @@ ++/* ++ * Copyright (C) 2011 Pavel Roskin ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include ++ ++ .text ++ ++#define WORD_BYTES 8 ++#define LINUX_REG_ARGS 6 ++#define WINDOWS_REG_ARGS 4 ++ ++/* %rbp is saved to create a stack frame, which can help with debugging */ ++#define SAVED_REGS 1 ++ ++/* ++ * When calling a Windows function, stack space is allocated for at least 4 ++ * arguments even if the number of arguments is less than 4. The value of ++ * true is -1 in assembler, so we multiply it by another true value. ++ */ ++#define stack_args(argc) \ ++ (WINDOWS_REG_ARGS + \ ++ (0 < 1) * (argc > WINDOWS_REG_ARGS) * (argc - WINDOWS_REG_ARGS)) ++ ++/* Full required change of stack pointer, in words */ ++#define stack_words_raw(argc) (stack_args(argc) + SAVED_REGS + 1) ++ ++/* Full actual change of stack pointer, in words (must be even) */ ++#define stack_words_aligned(argc) ((stack_words_raw(argc) + 1) & ~1) ++ ++/* Space allocated for Linux arguments on stack */ ++#define stack_space(argc) \ ++ ((stack_words_aligned(argc) - SAVED_REGS - 1) * WORD_BYTES) ++ ++/* ++ * lin2win_win_arg(N) gives the address of the Nth Windows argument on our ++ * stack frame. %rsp points to the first argument. The Nth argument is ++ * therefore at ((N - 1) * 8)(%rsp). ++ * ++ * Don't call with N less than 5! ++ */ ++#define lin2win_win_arg(n) ((n - 1) * WORD_BYTES)(%rsp) ++ ++/* ++ * lin2win_lin_arg(N, ARGC) gives the address of the Nth Linux argument after ++ * the stack has been prepared for a Windows function call with ARGC arguments. ++ * ++ * When called from Linux, the Nth argument is at ((N - 6) * 8)(%rsp). We add ++ * the allocated stack space and saved registers to compensate for %rsp change. ++ * ++ * Don't call with N less than 7! ++ */ ++#define lin2win_lin_arg(n, argc) \ ++ (stack_space(argc) + \ ++ (SAVED_REGS + n - LINUX_REG_ARGS) * WORD_BYTES)(%rsp) ++ ++/* ++ * lin2win(func, winarg1, winarg2, ...) ++ * Call Windows FUNC function with ARGC arguments WINARG1, WINARG2, ... ++ * We get (ARGC + 1) arguments. ++ */ ++.macro lin2win name, argc ++ .type \name, @function ++ ENTRY(\name) ++ ++ /* Create a call frame - it's optional, but good for debugging */ ++ .cfi_startproc ++ push %rbp ++ .cfi_def_cfa %rsp, 2 * WORD_BYTES ++ .cfi_offset %rbp, -2 * WORD_BYTES ++ mov %rsp, %rbp ++ .cfi_def_cfa %rbp, 2 * WORD_BYTES ++ ++ /* Allocate space for Windows arguments */ ++ sub $stack_space(\argc), %rsp ++ ++ /* arg7 to winarg6 */ ++ .if (\argc >= 6) ++ mov lin2win_lin_arg(7, \argc), %r11 ++ mov %r11, lin2win_win_arg(6) ++ .endif ++ ++ /* arg6 to winarg5 */ ++ .if (\argc >= 5) ++ mov %r9, lin2win_win_arg(5) ++ .endif ++ ++ /* arg5 to winarg4 */ ++ .if (\argc >= 4) ++ mov %r8, %r9 ++ .endif ++ ++ /* arg4 to winarg3 */ ++ .if (\argc >= 3) ++ mov %rcx, %r8 ++ .endif ++ ++ /* arg3 to winarg2 - nothing needed, both are in %rdx */ ++ ++ /* arg2 to winarg1 */ ++ .if (\argc >= 1) ++ mov %rsi, %rcx ++ .endif ++ ++ /* Call function (arg1) */ ++ call *%rdi ++ ++ /* Reclaim space for Windows arguments */ ++ add $stack_space(\argc), %rsp ++ ++ /* Return to the caller */ ++ leave ++ .cfi_def_cfa %rsp, WORD_BYTES ++ .cfi_restore %rbp ++ ret ++ .cfi_endproc ++ .size \name, (. - \name) ++.endm ++ ++/* Define lin2winN functions */ ++lin2win lin2win0, 0 ++lin2win lin2win1, 1 ++lin2win lin2win2, 2 ++lin2win lin2win3, 3 ++lin2win lin2win4, 4 ++lin2win lin2win5, 5 ++lin2win lin2win6, 6 +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/loader.c linux-4.6-rc6-ndis/3rdparty/ndiswrapper/loader.c +--- linux-4.6-rc6/3rdparty/ndiswrapper/loader.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/loader.c 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,967 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include "ndis.h" ++#include "loader.h" ++#include "wrapndis.h" ++#include "pnp.h" ++ ++#include ++#include ++#include ++#include ++ ++/* ++ Network adapter: ClassGuid = {4d36e972-e325-11ce-bfc1-08002be10318} ++ Network client: ClassGuid = {4d36e973-e325-11ce-bfc1-08002be10318} ++ PCMCIA adapter: ClassGuid = {4d36e977-e325-11ce-bfc1-08002be10318} ++ USB: ClassGuid = {36fc9e60-c465-11cf-8056-444553540000} ++*/ ++ ++/* the indices used here must match macros WRAP_NDIS_DEVICE etc. */ ++static struct guid class_guids[] = { ++ /* Network */ ++ { .data1 = 0x4d36e972, .data2 = 0xe325, .data3 = 0x11ce }, ++ /* USB WDM */ ++ { .data1 = 0x36fc9e60, .data2 = 0xc465, .data3 = 0x11cf }, ++ /* Bluetooth */ ++ { .data1 = 0xe0cbf06c, .data2 = 0xcd8b, .data3 = 0x4647 }, ++ /* ivtcorporation.com's bluetooth device claims this is ++ * bluetooth guid */ ++ { .data1 = 0xf12d3cf8, .data2 = 0xb11d, .data3 = 0x457e}, ++}; ++ ++struct mutex loader_mutex; ++static struct completion loader_complete; ++ ++static struct nt_list wrap_devices; ++static struct nt_list wrap_drivers; ++ ++static int wrap_device_type(int data1) ++{ ++ int i; ++ for (i = 0; i < ARRAY_SIZE(class_guids); i++) ++ if (data1 == class_guids[i].data1) ++ return i; ++ ERROR("unknown device: 0x%x\n", data1); ++ return -1; ++} ++ ++/* load driver for given device, if not already loaded */ ++struct wrap_driver *load_wrap_driver(struct wrap_device *wd) ++{ ++ int ret; ++ struct nt_list *cur; ++ struct wrap_driver *wrap_driver; ++ ++ ENTER1("device: %04X:%04X:%04X:%04X", wd->vendor, wd->device, ++ wd->subvendor, wd->subdevice); ++ mutex_lock(&loader_mutex); ++ wrap_driver = NULL; ++ nt_list_for_each(cur, &wrap_drivers) { ++ wrap_driver = container_of(cur, struct wrap_driver, list); ++ if (!stricmp(wrap_driver->name, wd->driver_name)) { ++ TRACE1("driver %s already loaded", wrap_driver->name); ++ break; ++ } else ++ wrap_driver = NULL; ++ } ++ mutex_unlock(&loader_mutex); ++ ++ if (!wrap_driver) { ++ char *argv[] = {"loadndisdriver", WRAP_CMD_LOAD_DRIVER, ++#if DEBUG >= 1 ++ "1", ++#else ++ "0", ++#endif ++ UTILS_VERSION, wd->driver_name, ++ wd->conf_file_name, NULL}; ++ char *env[] = {NULL}; ++ ++ TRACE1("loading driver %s", wd->driver_name); ++ mutex_lock(&loader_mutex); ++ reinit_completion(&loader_complete); ++ ret = call_usermodehelper("/sbin/loadndisdriver", argv, env, ++ UMH_WAIT_PROC); ++ if (ret) { ++ mutex_unlock(&loader_mutex); ++ ERROR("couldn't load driver %s; check system log " ++ "for messages from 'loadndisdriver'", ++ wd->driver_name); ++ EXIT1(return NULL); ++ } ++ wait_for_completion(&loader_complete); ++ TRACE1("%s", wd->driver_name); ++ wrap_driver = NULL; ++ nt_list_for_each(cur, &wrap_drivers) { ++ wrap_driver = container_of(cur, struct wrap_driver, ++ list); ++ if (!stricmp(wrap_driver->name, wd->driver_name)) { ++ wd->driver = wrap_driver; ++ break; ++ } else ++ wrap_driver = NULL; ++ } ++ mutex_unlock(&loader_mutex); ++ if (wrap_driver) ++ TRACE1("driver %s is loaded", wrap_driver->name); ++ else ++ ERROR("couldn't load driver '%s'", wd->driver_name); ++ } ++ EXIT1(return wrap_driver); ++} ++ ++/* load the driver files from userspace. */ ++static int load_sys_files(struct wrap_driver *driver, ++ struct load_driver *load_driver) ++{ ++ int i, err; ++ ++ TRACE1("num_pe_images = %d", load_driver->num_sys_files); ++ TRACE1("loading driver: %s", load_driver->name); ++ strncpy(driver->name, load_driver->name, sizeof(driver->name)); ++ driver->name[sizeof(driver->name)-1] = 0; ++ TRACE1("driver: %s", driver->name); ++ err = 0; ++ driver->num_pe_images = 0; ++ for (i = 0; i < load_driver->num_sys_files; i++) { ++ struct pe_image *pe_image; ++ pe_image = &driver->pe_images[driver->num_pe_images]; ++ ++ strncpy(pe_image->name, load_driver->sys_files[i].name, ++ sizeof(pe_image->name)); ++ pe_image->name[sizeof(pe_image->name)-1] = 0; ++ TRACE1("image size: %zu bytes", load_driver->sys_files[i].size); ++ ++#ifdef CONFIG_X86_64 ++#ifdef PAGE_KERNEL_EXECUTABLE ++ pe_image->image = ++ __vmalloc(load_driver->sys_files[i].size, ++ GFP_KERNEL | __GFP_HIGHMEM, ++ PAGE_KERNEL_EXECUTABLE); ++#elif defined PAGE_KERNEL_EXEC ++ pe_image->image = ++ __vmalloc(load_driver->sys_files[i].size, ++ GFP_KERNEL | __GFP_HIGHMEM, ++ PAGE_KERNEL_EXEC); ++#else ++#error x86_64 should have either PAGE_KERNEL_EXECUTABLE or PAGE_KERNEL_EXEC ++#endif ++#else ++ /* hate to play with kernel macros, but PAGE_KERNEL_EXEC is ++ * not available to modules! */ ++#ifdef cpu_has_nx ++ if (cpu_has_nx) ++ pe_image->image = ++ __vmalloc(load_driver->sys_files[i].size, ++ GFP_KERNEL | __GFP_HIGHMEM, ++ __pgprot(__PAGE_KERNEL & ~_PAGE_NX)); ++ else ++ pe_image->image = ++ vmalloc(load_driver->sys_files[i].size); ++#else ++ pe_image->image = ++ vmalloc(load_driver->sys_files[i].size); ++#endif ++#endif ++ if (!pe_image->image) { ++ ERROR("couldn't allocate memory"); ++ err = -ENOMEM; ++ break; ++ } ++ TRACE1("image is at %p", pe_image->image); ++ ++ if (copy_from_user(pe_image->image, ++ load_driver->sys_files[i].data, ++ load_driver->sys_files[i].size)) { ++ ERROR("couldn't load file %s", ++ load_driver->sys_files[i].name); ++ err = -EFAULT; ++ break; ++ } ++ pe_image->size = load_driver->sys_files[i].size; ++ driver->num_pe_images++; ++ } ++ ++ if (!err && link_pe_images(driver->pe_images, driver->num_pe_images)) { ++ ERROR("couldn't prepare driver '%s'", load_driver->name); ++ err = -EINVAL; ++ } ++ ++ if (driver->num_pe_images < load_driver->num_sys_files || err) { ++ for (i = 0; i < driver->num_pe_images; i++) ++ if (driver->pe_images[i].image) ++ vfree(driver->pe_images[i].image); ++ driver->num_pe_images = 0; ++ EXIT1(return err); ++ } else ++ EXIT1(return 0); ++} ++ ++struct wrap_bin_file *get_bin_file(char *bin_file_name) ++{ ++ int i = 0; ++ struct wrap_driver *driver, *cur; ++ ++ ENTER1("%s", bin_file_name); ++ mutex_lock(&loader_mutex); ++ driver = NULL; ++ nt_list_for_each_entry(cur, &wrap_drivers, list) { ++ for (i = 0; i < cur->num_bin_files; i++) ++ if (!stricmp(cur->bin_files[i].name, bin_file_name)) { ++ driver = cur; ++ break; ++ } ++ if (driver) ++ break; ++ } ++ mutex_unlock(&loader_mutex); ++ if (!driver) { ++ TRACE1("couldn't find bin file '%s'", bin_file_name); ++ return NULL; ++ } ++ ++ if (!driver->bin_files[i].data) { ++ char *argv[] = {"loadndisdriver", WRAP_CMD_LOAD_BIN_FILE, ++#if DEBUG >= 1 ++ "1", ++#else ++ "0", ++#endif ++ UTILS_VERSION, driver->name, ++ driver->bin_files[i].name, NULL}; ++ char *env[] = {NULL}; ++ int ret; ++ ++ TRACE1("loading bin file %s/%s", driver->name, ++ driver->bin_files[i].name); ++ mutex_lock(&loader_mutex); ++ reinit_completion(&loader_complete); ++ ret = call_usermodehelper("/sbin/loadndisdriver", argv, env, ++ UMH_WAIT_PROC); ++ if (ret) { ++ mutex_unlock(&loader_mutex); ++ ERROR("couldn't load file %s/%s; check system log " ++ "for messages from 'loadndisdriver' (%d)", ++ driver->name, driver->bin_files[i].name, ret); ++ EXIT1(return NULL); ++ } ++ wait_for_completion(&loader_complete); ++ mutex_unlock(&loader_mutex); ++ if (!driver->bin_files[i].data) { ++ WARNING("couldn't load binary file %s", ++ driver->bin_files[i].name); ++ EXIT1(return NULL); ++ } ++ } ++ EXIT2(return &(driver->bin_files[i])); ++} ++ ++/* called with loader_mutex down */ ++static int add_bin_file(struct load_driver_file *driver_file) ++{ ++ struct wrap_driver *driver, *cur; ++ struct wrap_bin_file *bin_file; ++ int i = 0; ++ ++ driver = NULL; ++ nt_list_for_each_entry(cur, &wrap_drivers, list) { ++ for (i = 0; i < cur->num_bin_files; i++) ++ if (!stricmp(cur->bin_files[i].name, ++ driver_file->name)) { ++ driver = cur; ++ break; ++ } ++ if (driver) ++ break; ++ } ++ if (!driver) { ++ ERROR("couldn't find %s", driver_file->name); ++ return -EINVAL; ++ } ++ bin_file = &driver->bin_files[i]; ++ strncpy(bin_file->name, driver_file->name, sizeof(bin_file->name)); ++ bin_file->name[sizeof(bin_file->name)-1] = 0; ++ bin_file->data = vmalloc(driver_file->size); ++ if (!bin_file->data) { ++ ERROR("couldn't allocate memory"); ++ return -ENOMEM; ++ } ++ bin_file->size = driver_file->size; ++ if (copy_from_user(bin_file->data, driver_file->data, bin_file->size)) { ++ ERROR("couldn't copy data"); ++ free_bin_file(bin_file); ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++void free_bin_file(struct wrap_bin_file *bin_file) ++{ ++ TRACE2("unloading %s", bin_file->name); ++ if (bin_file->data) ++ vfree(bin_file->data); ++ bin_file->data = NULL; ++ bin_file->size = 0; ++ EXIT2(return); ++} ++ ++/* load firmware files from userspace */ ++static int load_bin_files_info(struct wrap_driver *driver, ++ struct load_driver *load_driver) ++{ ++ struct wrap_bin_file *bin_files; ++ int i; ++ ++ ENTER1("%s, %d", load_driver->name, load_driver->num_bin_files); ++ driver->num_bin_files = 0; ++ driver->bin_files = NULL; ++ if (load_driver->num_bin_files == 0) ++ EXIT1(return 0); ++ bin_files = kzalloc(load_driver->num_bin_files * sizeof(*bin_files), ++ GFP_KERNEL); ++ if (!bin_files) { ++ ERROR("couldn't allocate memory"); ++ EXIT1(return -ENOMEM); ++ } ++ ++ for (i = 0; i < load_driver->num_bin_files; i++) { ++ strncpy(bin_files[i].name, load_driver->bin_files[i].name, ++ sizeof(bin_files[i].name)); ++ bin_files[i].name[sizeof(bin_files[i].name)-1] = 0; ++ TRACE2("loaded bin file %s", bin_files[i].name); ++ } ++ driver->num_bin_files = load_driver->num_bin_files; ++ driver->bin_files = bin_files; ++ EXIT1(return 0); ++} ++ ++/* load settings for a device. called with loader_mutex down */ ++static int load_settings(struct wrap_driver *wrap_driver, ++ struct load_driver *load_driver) ++{ ++ int i, num_settings; ++ ++ ENTER1("%p, %p", wrap_driver, load_driver); ++ ++ num_settings = 0; ++ for (i = 0; i < load_driver->num_settings; i++) { ++ struct load_device_setting *load_setting = ++ &load_driver->settings[i]; ++ struct wrap_device_setting *setting; ++ ULONG data1; ++ ++ setting = kzalloc(sizeof(*setting), GFP_KERNEL); ++ if (!setting) { ++ ERROR("couldn't allocate memory"); ++ break; ++ } ++ strncpy(setting->name, load_setting->name, ++ sizeof(setting->name)); ++ setting->name[sizeof(setting->name)-1] = 0; ++ strncpy(setting->value, load_setting->value, ++ sizeof(setting->value)); ++ setting->value[sizeof(setting->value)-1] = 0; ++ TRACE2("%p: %s=%s", setting, setting->name, setting->value); ++ ++ if (strcmp(setting->name, "driver_version") == 0) { ++ strncpy(wrap_driver->version, setting->value, ++ sizeof(wrap_driver->version)); ++ wrap_driver->version[sizeof(wrap_driver->version)-1] = 0; ++ } else if (strcmp(setting->name, "class_guid") == 0 && ++ sscanf(setting->value, "%x", &data1) == 1) { ++ wrap_driver->dev_type = wrap_device_type(data1); ++ if (wrap_driver->dev_type < 0) { ++ WARNING("unknown guid: %x", data1); ++ wrap_driver->dev_type = 0; ++ } ++ } ++ InsertTailList(&wrap_driver->settings, &setting->list); ++ num_settings++; ++ } ++ /* it is not a fatal error if some settings couldn't be loaded */ ++ if (num_settings > 0) ++ EXIT1(return 0); ++ else ++ EXIT1(return -EINVAL); ++} ++ ++void unload_wrap_device(struct wrap_device *wd) ++{ ++ struct nt_list *cur; ++ ENTER1("unloading device %p (%04X:%04X:%04X:%04X), driver %s", wd, ++ wd->vendor, wd->device, wd->subvendor, wd->subdevice, ++ wd->driver_name); ++ mutex_lock(&loader_mutex); ++ while ((cur = RemoveHeadList(&wd->settings))) { ++ struct wrap_device_setting *setting; ++ setting = container_of(cur, struct wrap_device_setting, list); ++ kfree(setting); ++ } ++ RemoveEntryList(&wd->list); ++ mutex_unlock(&loader_mutex); ++ kfree(wd); ++ EXIT1(return); ++} ++ ++/* should be called with loader_mutex down */ ++void unload_wrap_driver(struct wrap_driver *driver) ++{ ++ int i; ++ struct driver_object *drv_obj; ++ struct nt_list *cur, *next; ++ ++ ENTER1("unloading driver: %s (%p)", driver->name, driver); ++ TRACE1("freeing %d images", driver->num_pe_images); ++ drv_obj = driver->drv_obj; ++ for (i = 0; i < driver->num_pe_images; i++) ++ if (driver->pe_images[i].image) { ++ TRACE1("freeing image at %p", ++ driver->pe_images[i].image); ++ vfree(driver->pe_images[i].image); ++ } ++ ++ TRACE1("freeing %d bin files", driver->num_bin_files); ++ for (i = 0; i < driver->num_bin_files; i++) { ++ TRACE1("freeing image at %p", driver->bin_files[i].data); ++ if (driver->bin_files[i].data) ++ vfree(driver->bin_files[i].data); ++ } ++ kfree(driver->bin_files); ++ RtlFreeUnicodeString(&drv_obj->name); ++ RemoveEntryList(&driver->list); ++ nt_list_for_each_safe(cur, next, &driver->settings) { ++ struct wrap_device_setting *setting; ++ struct ndis_configuration_parameter *param; ++ ++ setting = container_of(cur, struct wrap_device_setting, list); ++ TRACE2("%p", setting); ++ param = setting->encoded; ++ if (param) { ++ TRACE2("%p", param); ++ if (param->type == NdisParameterString) ++ RtlFreeUnicodeString(¶m->data.string); ++ ExFreePool(param); ++ } ++ kfree(setting); ++ } ++ /* this frees driver */ ++ free_custom_extensions(drv_obj->drv_ext); ++ kfree(drv_obj->drv_ext); ++ TRACE1("drv_obj: %p", drv_obj); ++ ++ EXIT1(return); ++} ++ ++/* call the entry point of the driver */ ++static int start_wrap_driver(struct wrap_driver *driver) ++{ ++ int i; ++ NTSTATUS ret, res; ++ struct driver_object *drv_obj; ++ typeof(driver->pe_images[0].entry) entry; ++ ++ ENTER1("%s", driver->name); ++ drv_obj = driver->drv_obj; ++ for (ret = res = 0, i = 0; i < driver->num_pe_images; i++) ++ /* dlls are already started by loader */ ++ if (driver->pe_images[i].type == IMAGE_FILE_EXECUTABLE_IMAGE) { ++ entry = driver->pe_images[i].entry; ++ drv_obj->start = driver->pe_images[i].entry; ++ drv_obj->driver_size = driver->pe_images[i].size; ++ TRACE1("entry: %p, %p, drv_obj: %p", ++ entry, *entry, drv_obj); ++ res = LIN2WIN2(entry, drv_obj, &drv_obj->name); ++ ret |= res; ++ TRACE1("entry returns %08X", res); ++ break; ++ } ++ if (ret) { ++ ERROR("driver initialization failed: %08X", ret); ++ RtlFreeUnicodeString(&drv_obj->name); ++ /* this frees ndis_driver */ ++ free_custom_extensions(drv_obj->drv_ext); ++ kfree(drv_obj->drv_ext); ++ TRACE1("drv_obj: %p", drv_obj); ++ ObDereferenceObject(drv_obj); ++ EXIT1(return -EINVAL); ++ } ++ EXIT1(return 0); ++} ++ ++/* ++ * add driver to list of loaded driver but make sure this driver is ++ * not loaded before. called with loader_mutex down ++ */ ++static int add_wrap_driver(struct wrap_driver *driver) ++{ ++ struct wrap_driver *tmp; ++ ++ ENTER1("name: %s", driver->name); ++ nt_list_for_each_entry(tmp, &wrap_drivers, list) { ++ if (stricmp(tmp->name, driver->name) == 0) { ++ ERROR("cannot add duplicate driver"); ++ EXIT1(return -EBUSY); ++ } ++ } ++ InsertHeadList(&wrap_drivers, &driver->list); ++ EXIT1(return 0); ++} ++ ++/* load a driver from userspace and initialize it. called with ++ * loader_mutex down */ ++static int load_user_space_driver(struct load_driver *load_driver) ++{ ++ struct driver_object *drv_obj; ++ struct ansi_string ansi_reg; ++ struct wrap_driver *wrap_driver = NULL; ++ ++ ENTER1("%p", load_driver); ++ drv_obj = allocate_object(sizeof(*drv_obj), OBJECT_TYPE_DRIVER, NULL); ++ if (!drv_obj) { ++ ERROR("couldn't allocate memory"); ++ EXIT1(return -ENOMEM); ++ } ++ TRACE1("drv_obj: %p", drv_obj); ++ drv_obj->drv_ext = kzalloc(sizeof(*(drv_obj->drv_ext)), GFP_KERNEL); ++ if (!drv_obj->drv_ext) { ++ ERROR("couldn't allocate memory"); ++ ObDereferenceObject(drv_obj); ++ EXIT1(return -ENOMEM); ++ } ++ InitializeListHead(&drv_obj->drv_ext->custom_ext); ++ if (IoAllocateDriverObjectExtension(drv_obj, ++ (void *)WRAP_DRIVER_CLIENT_ID, ++ sizeof(*wrap_driver), ++ (void **)&wrap_driver) != ++ STATUS_SUCCESS) ++ EXIT1(return -ENOMEM); ++ TRACE1("driver: %p", wrap_driver); ++ memset(wrap_driver, 0, sizeof(*wrap_driver)); ++ InitializeListHead(&wrap_driver->list); ++ InitializeListHead(&wrap_driver->settings); ++ wrap_driver->drv_obj = drv_obj; ++ RtlInitAnsiString(&ansi_reg, "/tmp"); ++ if (RtlAnsiStringToUnicodeString(&drv_obj->name, &ansi_reg, TRUE) != ++ STATUS_SUCCESS) { ++ ERROR("couldn't initialize registry path"); ++ free_custom_extensions(drv_obj->drv_ext); ++ kfree(drv_obj->drv_ext); ++ TRACE1("drv_obj: %p", drv_obj); ++ ObDereferenceObject(drv_obj); ++ EXIT1(return -EINVAL); ++ } ++ strncpy(wrap_driver->name, load_driver->name, sizeof(wrap_driver->name)); ++ wrap_driver->name[sizeof(wrap_driver->name)-1] = 0; ++ if (load_sys_files(wrap_driver, load_driver) || ++ load_bin_files_info(wrap_driver, load_driver) || ++ load_settings(wrap_driver, load_driver) || ++ start_wrap_driver(wrap_driver) || ++ add_wrap_driver(wrap_driver)) { ++ unload_wrap_driver(wrap_driver); ++ ObDereferenceObject(drv_obj); ++ EXIT1(return -EINVAL); ++ } else { ++ printk(KERN_INFO "%s: driver %s (%s) loaded\n", ++ DRIVER_NAME, wrap_driver->name, wrap_driver->version); ++ add_taint(TAINT_PROPRIETARY_MODULE, LOCKDEP_NOW_UNRELIABLE); ++ EXIT1(return 0); ++ } ++} ++ ++static struct pci_device_id wrap_pci_id_table[] = { ++ { ++ .vendor = PCI_ANY_ID, ++ .device = PCI_ANY_ID, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .class = 0, ++ .class_mask = 0, ++ .driver_data = 0 ++ } ++}; ++ ++static struct pci_driver wrap_pci_driver = { ++ .name = DRIVER_NAME, ++ .id_table = wrap_pci_id_table, ++ .probe = wrap_pnp_start_pci_device, ++ .remove = wrap_pnp_remove_pci_device, ++ .suspend = wrap_pnp_suspend_pci_device, ++ .resume = wrap_pnp_resume_pci_device, ++}; ++ ++#ifdef ENABLE_USB ++static struct usb_device_id wrap_usb_id_table[] = { ++ { ++ .driver_info = 1 ++ }, ++}; ++ ++static struct usb_driver wrap_usb_driver = { ++ .name = DRIVER_NAME, ++ .id_table = wrap_usb_id_table, ++ .probe = wrap_pnp_start_usb_device, ++ .disconnect = wrap_pnp_remove_usb_device, ++ .suspend = wrap_pnp_suspend_usb_device, ++ .resume = wrap_pnp_resume_usb_device, ++}; ++#endif ++ ++/* register drivers for pci and usb */ ++static void register_devices(void) ++{ ++ int res; ++ ++ res = pci_register_driver(&wrap_pci_driver); ++ if (res < 0) { ++ ERROR("couldn't register pci driver: %d", res); ++ wrap_pci_driver.name = NULL; ++ } ++ ++#ifdef ENABLE_USB ++ res = usb_register(&wrap_usb_driver); ++ if (res < 0) { ++ ERROR("couldn't register usb driver: %d", res); ++ wrap_usb_driver.name = NULL; ++ } ++#endif ++ EXIT1(return); ++} ++ ++static void unregister_devices(void) ++{ ++ struct nt_list *cur, *next; ++ ++ mutex_lock(&loader_mutex); ++ nt_list_for_each_safe(cur, next, &wrap_devices) { ++ struct wrap_device *wd; ++ wd = container_of(cur, struct wrap_device, list); ++ set_bit(HW_DISABLED, &wd->hw_status); ++ } ++ mutex_unlock(&loader_mutex); ++ ++ if (wrap_pci_driver.name) ++ pci_unregister_driver(&wrap_pci_driver); ++#ifdef ENABLE_USB ++ if (wrap_usb_driver.name) ++ usb_deregister(&wrap_usb_driver); ++#endif ++} ++ ++struct wrap_device *load_wrap_device(struct load_device *load_device) ++{ ++ int ret; ++ struct nt_list *cur; ++ struct wrap_device *wd = NULL; ++ char vendor[5], device[5], subvendor[5], subdevice[5], bus[5]; ++ ++ ENTER1("%04x, %04x, %04x, %04x", load_device->vendor, ++ load_device->device, load_device->subvendor, ++ load_device->subdevice); ++ if (sprintf(vendor, "%04x", load_device->vendor) == 4 && ++ sprintf(device, "%04x", load_device->device) == 4 && ++ sprintf(subvendor, "%04x", load_device->subvendor) == 4 && ++ sprintf(subdevice, "%04x", load_device->subdevice) == 4 && ++ sprintf(bus, "%04x", load_device->bus) == 4) { ++ char *argv[] = {"loadndisdriver", WRAP_CMD_LOAD_DEVICE, ++#if DEBUG >= 1 ++ "1", ++#else ++ "0", ++#endif ++ UTILS_VERSION, vendor, device, ++ subvendor, subdevice, bus, NULL}; ++ char *env[] = {NULL}; ++ TRACE2("%s, %s, %s, %s, %s", vendor, device, ++ subvendor, subdevice, bus); ++ mutex_lock(&loader_mutex); ++ reinit_completion(&loader_complete); ++ ret = call_usermodehelper("/sbin/loadndisdriver", argv, env, ++ UMH_WAIT_PROC); ++ if (ret) { ++ mutex_unlock(&loader_mutex); ++ TRACE1("couldn't load device %04x:%04x; check system " ++ "log for messages from 'loadndisdriver'", ++ load_device->vendor, load_device->device); ++ EXIT1(return NULL); ++ } ++ wait_for_completion(&loader_complete); ++ wd = NULL; ++ nt_list_for_each(cur, &wrap_devices) { ++ wd = container_of(cur, struct wrap_device, list); ++ TRACE2("%p, %04x, %04x, %04x, %04x", wd, wd->vendor, ++ wd->device, wd->subvendor, wd->subdevice); ++ if (wd->vendor == load_device->vendor && ++ wd->device == load_device->device) ++ break; ++ else ++ wd = NULL; ++ } ++ mutex_unlock(&loader_mutex); ++ } else ++ wd = NULL; ++ EXIT1(return wd); ++} ++ ++struct wrap_device *get_wrap_device(void *dev, int bus) ++{ ++ struct nt_list *cur; ++ struct wrap_device *wd; ++ ++ mutex_lock(&loader_mutex); ++ wd = NULL; ++ nt_list_for_each(cur, &wrap_devices) { ++ wd = container_of(cur, struct wrap_device, list); ++ if (bus == WRAP_PCI_BUS && ++ wrap_is_pci_bus(wd->dev_bus) && wd->pci.pdev == dev) ++ break; ++ else if (bus == WRAP_USB_BUS && ++ wrap_is_usb_bus(wd->dev_bus) && wd->usb.udev == dev) ++ break; ++ else ++ wd = NULL; ++ } ++ mutex_unlock(&loader_mutex); ++ return wd; ++} ++ ++/* called with loader_mutex is down */ ++static long wrapper_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ struct load_driver *load_driver; ++ struct load_device load_device; ++ struct load_driver_file load_bin_file; ++ int ret; ++ void __user *addr = (void __user *)arg; ++ ++ ENTER1("cmd: 0x%x", cmd); ++ ++ ret = 0; ++ switch (cmd) { ++ case WRAP_IOCTL_LOAD_DEVICE: ++ if (copy_from_user(&load_device, addr, sizeof(load_device))) { ++ ret = -EFAULT; ++ break; ++ } ++ TRACE2("%04x, %04x, %04x, %04x", load_device.vendor, ++ load_device.device, load_device.subvendor, ++ load_device.subdevice); ++ if (load_device.vendor) { ++ struct wrap_device *wd; ++ wd = kzalloc(sizeof(*wd), GFP_KERNEL); ++ if (!wd) { ++ ret = -ENOMEM; ++ break; ++ } ++ InitializeListHead(&wd->settings); ++ wd->dev_bus = WRAP_BUS(load_device.bus); ++ wd->vendor = load_device.vendor; ++ wd->device = load_device.device; ++ wd->subvendor = load_device.subvendor; ++ wd->subdevice = load_device.subdevice; ++ strncpy(wd->conf_file_name, load_device.conf_file_name, ++ sizeof(wd->conf_file_name)); ++ wd->conf_file_name[sizeof(wd->conf_file_name)-1] = 0; ++ strncpy(wd->driver_name, load_device.driver_name, ++ sizeof(wd->driver_name)); ++ wd->driver_name[sizeof(wd->driver_name)-1] = 0; ++ InsertHeadList(&wrap_devices, &wd->list); ++ ret = 0; ++ } else ++ ret = -EINVAL; ++ break; ++ case WRAP_IOCTL_LOAD_DRIVER: ++ TRACE1("loading driver at %p", addr); ++ load_driver = vmalloc(sizeof(*load_driver)); ++ if (!load_driver) { ++ ret = -ENOMEM; ++ break; ++ } ++ if (copy_from_user(load_driver, addr, sizeof(*load_driver))) ++ ret = -EFAULT; ++ else ++ ret = load_user_space_driver(load_driver); ++ vfree(load_driver); ++ break; ++ case WRAP_IOCTL_LOAD_BIN_FILE: ++ if (copy_from_user(&load_bin_file, addr, sizeof(load_bin_file))) ++ ret = -EFAULT; ++ else ++ ret = add_bin_file(&load_bin_file); ++ break; ++ default: ++ ERROR("unknown ioctl 0x%x", cmd); ++ ret = -EINVAL; ++ break; ++ } ++ complete(&loader_complete); ++ EXIT1(return ret); ++} ++ ++#ifdef CONFIG_COMPAT ++static int copy_load_driver_file32(struct load_driver_file *k, ++ struct load_driver_file32 __user *u) ++{ ++ u32 data; ++ ++ if (copy_from_user(&k->driver_name, &u->driver_name, ++ sizeof(u->driver_name) + sizeof(u->name))) ++ return -EFAULT; ++ ++ if (get_user(k->size, &u->size)) ++ return -EFAULT; ++ if (get_user(data, &u->data)) ++ return -EFAULT; ++ ++ k->data = (void __user *)(unsigned long)data; ++ return 0; ++} ++ ++static int copy_load_driver32(struct load_driver *k, ++ struct load_driver32 __user *u) ++{ ++ int i; ++ ++ if (copy_from_user(&k->name, &u->name, ++ sizeof(u->name) + sizeof(u->conf_file_name))) ++ return -EFAULT; ++ ++ if (get_user(k->num_sys_files, &u->num_sys_files)) ++ return -EFAULT; ++ ++ for (i = 0; i < k->num_sys_files; i++) ++ if (copy_load_driver_file32(&k->sys_files[i], &u->sys_files[i])) ++ return -EFAULT; ++ ++ if (get_user(k->num_settings, &u->num_settings)) ++ return -EFAULT; ++ ++ if (copy_from_user(&k->settings, &u->settings, ++ sizeof(u->settings[0]) * k->num_settings)) ++ return -EFAULT; ++ ++ if (get_user(k->num_bin_files, &u->num_bin_files)) ++ return -EFAULT; ++ ++ for (i = 0; i < k->num_bin_files; i++) ++ if (copy_load_driver_file32(&k->bin_files[i], &u->bin_files[i])) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++static long wrapper_ioctl_compat(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ int ret = 0; ++ void __user *addr = (void __user *)arg; ++ struct load_driver *kdriver; ++ struct load_driver32 __user *udriver = addr; ++ struct load_driver_file kfile; ++ struct load_driver_file32 __user *ufile = addr; ++ ++ ENTER1("cmd: 0x%x", cmd); ++ ++ switch (cmd) { ++ case WRAP_IOCTL_LOAD_DEVICE32: ++ return wrapper_ioctl(file, WRAP_IOCTL_LOAD_DEVICE, arg); ++ case WRAP_IOCTL_LOAD_DRIVER32: ++ TRACE1("loading driver at %p", addr); ++ kdriver = vmalloc(sizeof(*kdriver)); ++ if (!kdriver) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ ret = copy_load_driver32(kdriver, udriver); ++ if (!ret) ++ ret = load_user_space_driver(kdriver); ++ ++ vfree(kdriver); ++ break; ++ case WRAP_IOCTL_LOAD_BIN_FILE32: ++ ret = copy_load_driver_file32(&kfile, ufile); ++ if (ret) ++ break; ++ ++ ret = add_bin_file(&kfile); ++ break; ++ default: ++ ERROR("unknown ioctl 0x%x", cmd); ++ ret = -EINVAL; ++ break; ++ } ++ complete(&loader_complete); ++ EXIT1(return ret); ++} ++#endif ++ ++static int wrapper_ioctl_release(struct inode *inode, struct file *file) ++{ ++ ENTER1(""); ++ complete(&loader_complete); ++ return 0; ++} ++ ++static struct file_operations wrapper_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = wrapper_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = wrapper_ioctl_compat, ++#endif ++ .release = wrapper_ioctl_release, ++}; ++ ++static struct miscdevice wrapper_misc = { ++ .name = DRIVER_NAME, ++ .minor = MISC_DYNAMIC_MINOR, ++ .fops = &wrapper_fops ++}; ++ ++int loader_init(void) ++{ ++ int err; ++ ++ InitializeListHead(&wrap_drivers); ++ InitializeListHead(&wrap_devices); ++ mutex_init(&loader_mutex); ++ init_completion(&loader_complete); ++ if ((err = misc_register(&wrapper_misc)) < 0) { ++ ERROR("couldn't register module (%d)", err); ++ unregister_devices(); ++ EXIT1(return err); ++ } ++ register_devices(); ++ EXIT1(return 0); ++} ++ ++void loader_exit(void) ++{ ++ struct nt_list *cur, *next; ++ ++ ENTER1(""); ++ misc_deregister(&wrapper_misc); ++ unregister_devices(); ++ mutex_lock(&loader_mutex); ++ nt_list_for_each_safe(cur, next, &wrap_drivers) { ++ struct wrap_driver *driver; ++ driver = container_of(cur, struct wrap_driver, list); ++ unload_wrap_driver(driver); ++ } ++ mutex_unlock(&loader_mutex); ++ EXIT1(return); ++} +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/loader.h linux-4.6-rc6-ndis/3rdparty/ndiswrapper/loader.h +--- linux-4.6-rc6/3rdparty/ndiswrapper/loader.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/loader.h 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,112 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _LOADER_H_ ++#define _LOADER_H_ ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(4,0,0) ++#include ++#endif ++ ++#include "ndiswrapper.h" ++ ++#ifndef __KERNEL__ ++#define __user ++#endif ++ ++struct load_driver_file { ++ char driver_name[MAX_DRIVER_NAME_LEN]; ++ char name[MAX_DRIVER_NAME_LEN]; ++ size_t size; ++ void __user *data; ++}; ++ ++struct load_device_setting { ++ char name[MAX_SETTING_NAME_LEN]; ++ char value[MAX_SETTING_VALUE_LEN]; ++}; ++ ++struct load_device { ++ int bus; ++ int vendor; ++ int device; ++ int subvendor; ++ int subdevice; ++ char conf_file_name[MAX_DRIVER_NAME_LEN]; ++ char driver_name[MAX_DRIVER_NAME_LEN]; ++}; ++ ++struct load_driver { ++ char name[MAX_DRIVER_NAME_LEN]; ++ char conf_file_name[MAX_DRIVER_NAME_LEN]; ++ unsigned int num_sys_files; ++ struct load_driver_file sys_files[MAX_DRIVER_PE_IMAGES]; ++ unsigned int num_settings; ++ struct load_device_setting settings[MAX_DEVICE_SETTINGS]; ++ unsigned int num_bin_files; ++ struct load_driver_file bin_files[MAX_DRIVER_BIN_FILES]; ++}; ++ ++#define WRAP_IOCTL_LOAD_DEVICE _IOW(('N' + 'd' + 'i' + 'S'), 0, \ ++ struct load_device *) ++#define WRAP_IOCTL_LOAD_DRIVER _IOW(('N' + 'd' + 'i' + 'S'), 1, \ ++ struct load_driver *) ++#define WRAP_IOCTL_LOAD_BIN_FILE _IOW(('N' + 'd' + 'i' + 'S'), 2, \ ++ struct load_driver_file *) ++ ++#ifdef CONFIG_COMPAT ++struct load_driver_file32 { ++ char driver_name[MAX_DRIVER_NAME_LEN]; ++ char name[MAX_DRIVER_NAME_LEN]; ++ u32 size; ++ u32 data; ++}; ++ ++struct load_driver32 { ++ char name[MAX_DRIVER_NAME_LEN]; ++ char conf_file_name[MAX_DRIVER_NAME_LEN]; ++ u32 num_sys_files; ++ struct load_driver_file32 sys_files[MAX_DRIVER_PE_IMAGES]; ++ u32 num_settings; ++ struct load_device_setting settings[MAX_DEVICE_SETTINGS]; ++ u32 num_bin_files; ++ struct load_driver_file32 bin_files[MAX_DRIVER_BIN_FILES]; ++} __packed; ++ ++#define WRAP_IOCTL_LOAD_DEVICE32 _IOW(('N' + 'd' + 'i' + 'S'), 0, u32) ++#define WRAP_IOCTL_LOAD_DRIVER32 _IOW(('N' + 'd' + 'i' + 'S'), 1, u32) ++#define WRAP_IOCTL_LOAD_BIN_FILE32 _IOW(('N' + 'd' + 'i' + 'S'), 2, u32) ++#endif ++ ++#define WRAP_CMD_LOAD_DEVICE "load_device" ++#define WRAP_CMD_LOAD_DRIVER "load_driver" ++#define WRAP_CMD_LOAD_BIN_FILE "load_bin_file" ++ ++int loader_init(void); ++void loader_exit(void); ++ ++#ifdef __KERNEL__ ++struct wrap_device *load_wrap_device(struct load_device *load_device); ++struct wrap_driver *load_wrap_driver(struct wrap_device *device); ++struct wrap_bin_file *get_bin_file(char *bin_file_name); ++void free_bin_file(struct wrap_bin_file *bin_file); ++void unload_wrap_driver(struct wrap_driver *driver); ++void unload_wrap_device(struct wrap_device *wd); ++struct wrap_device *get_wrap_device(void *dev, int bus_type); ++ ++extern struct mutex loader_mutex; ++#endif ++ ++#endif /* LOADER_H */ +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/longlong.h linux-4.6-rc6-ndis/3rdparty/ndiswrapper/longlong.h +--- linux-4.6-rc6/3rdparty/ndiswrapper/longlong.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/longlong.h 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,1333 @@ ++/* longlong.h -- definitions for mixed size 32/64 bit arithmetic. ++ Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000 ++ Free Software Foundation, Inc. ++ ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, write to the Free ++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ 02111-1307 USA. */ ++ ++/* You have to define the following before including this file: ++ ++ UWtype -- An unsigned type, default type for operations (typically a "word") ++ UHWtype -- An unsigned type, at least half the size of UWtype. ++ UDWtype -- An unsigned type, at least twice as large a UWtype ++ W_TYPE_SIZE -- size in bits of UWtype ++ ++ UQItype -- Unsigned 8 bit type. ++ SItype, USItype -- Signed and unsigned 32 bit types. ++ DItype, UDItype -- Signed and unsigned 64 bit types. ++ ++ On a 32 bit machine UWtype should typically be USItype; ++ on a 64 bit machine, UWtype should typically be UDItype. ++*/ ++ ++#define __BITS4 (W_TYPE_SIZE / 4) ++#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) ++#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) ++#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) ++ ++#ifndef W_TYPE_SIZE ++#define W_TYPE_SIZE 32 ++#define UWtype USItype ++#define UHWtype USItype ++#define UDWtype UDItype ++#endif ++ ++/* Define auxiliary asm macros. ++ ++ 1) umul_ppmm(high_prod, low_prod, multipler, multiplicand) multiplies two ++ UWtype integers MULTIPLER and MULTIPLICAND, and generates a two UWtype ++ word product in HIGH_PROD and LOW_PROD. ++ ++ 2) __umulsidi3(a,b) multiplies two UWtype integers A and B, and returns a ++ UDWtype product. This is just a variant of umul_ppmm. ++ ++ 3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator, ++ denominator) divides a UDWtype, composed by the UWtype integers ++ HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient ++ in QUOTIENT and the remainder in REMAINDER. HIGH_NUMERATOR must be less ++ than DENOMINATOR for correct operation. If, in addition, the most ++ significant bit of DENOMINATOR must be 1, then the pre-processor symbol ++ UDIV_NEEDS_NORMALIZATION is defined to 1. ++ ++ 4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator, ++ denominator). Like udiv_qrnnd but the numbers are signed. The quotient ++ is rounded towards 0. ++ ++ 5) count_leading_zeros(count, x) counts the number of zero-bits from the ++ msb to the first nonzero bit in the UWtype X. This is the number of ++ steps X needs to be shifted left to set the msb. Undefined for X == 0, ++ unless the symbol COUNT_LEADING_ZEROS_0 is defined to some value. ++ ++ 6) count_trailing_zeros(count, x) like count_leading_zeros, but counts ++ from the least significant end. ++ ++ 7) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1, ++ high_addend_2, low_addend_2) adds two UWtype integers, composed by ++ HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2 ++ respectively. The result is placed in HIGH_SUM and LOW_SUM. Overflow ++ (i.e. carry out) is not stored anywhere, and is lost. ++ ++ 8) sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend, ++ high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers, ++ composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and ++ LOW_SUBTRAHEND_2 respectively. The result is placed in HIGH_DIFFERENCE ++ and LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere, ++ and is lost. ++ ++ If any of these macros are left undefined for a particular CPU, ++ C macros are used. */ ++ ++/* The CPUs come in alphabetical order below. ++ ++ Please add support for more CPUs here, or improve the current support ++ for the CPUs below! ++ (E.g. WE32100, IBM360.) */ ++ ++#if defined (__GNUC__) && !defined (NO_ASM) ++ ++/* We sometimes need to clobber "cc" with gcc2, but that would not be ++ understood by gcc1. Use cpp to avoid major code duplication. */ ++#if __GNUC__ < 2 ++#define __CLOBBER_CC ++#define __AND_CLOBBER_CC ++#else /* __GNUC__ >= 2 */ ++#define __CLOBBER_CC : "cc" ++#define __AND_CLOBBER_CC , "cc" ++#endif /* __GNUC__ < 2 */ ++ ++#if defined (__alpha) && W_TYPE_SIZE == 64 ++#define umul_ppmm(ph, pl, m0, m1) \ ++ do { \ ++ UDItype __m0 = (m0), __m1 = (m1); \ ++ __asm__ ("umulh %r1,%2,%0" \ ++ : "=r" ((UDItype) ph) \ ++ : "%rJ" (__m0), \ ++ "rI" (__m1)); \ ++ (pl) = __m0 * __m1; \ ++ } while (0) ++#define UMUL_TIME 46 ++#ifndef LONGLONG_STANDALONE ++#define udiv_qrnnd(q, r, n1, n0, d) \ ++ do { UDItype __r; \ ++ (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \ ++ (r) = __r; \ ++ } while (0) ++extern UDItype __udiv_qrnnd (UDItype *, UDItype, UDItype, UDItype); ++#define UDIV_TIME 220 ++#endif /* LONGLONG_STANDALONE */ ++#ifdef __alpha_cix__ ++#define count_leading_zeros(COUNT,X) \ ++ __asm__("ctlz %1,%0" : "=r"(COUNT) : "r"(X)) ++#define count_trailing_zeros(COUNT,X) \ ++ __asm__("cttz %1,%0" : "=r"(COUNT) : "r"(X)) ++#define COUNT_LEADING_ZEROS_0 64 ++#else ++extern const UQItype __clz_tab[]; ++#define count_leading_zeros(COUNT,X) \ ++ do { \ ++ UDItype __xr = (X), __t, __a; \ ++ __asm__("cmpbge $31,%1,%0" : "=r"(__t) : "r"(__xr)); \ ++ __a = __clz_tab[__t ^ 0xff] - 1; \ ++ __asm__("extbl %1,%2,%0" : "=r"(__t) : "r"(__xr), "r"(__a)); \ ++ (COUNT) = 64 - (__clz_tab[__t] + __a*8); \ ++ } while (0) ++#define count_trailing_zeros(COUNT,X) \ ++ do { \ ++ UDItype __xr = (X), __t, __a; \ ++ __asm__("cmpbge $31,%1,%0" : "=r"(__t) : "r"(__xr)); \ ++ __t = ~__t & -~__t; \ ++ __a = ((__t & 0xCC) != 0) * 2; \ ++ __a += ((__t & 0xF0) != 0) * 4; \ ++ __a += ((__t & 0xAA) != 0); \ ++ __asm__("extbl %1,%2,%0" : "=r"(__t) : "r"(__xr), "r"(__a)); \ ++ __a <<= 3; \ ++ __t &= -__t; \ ++ __a += ((__t & 0xCC) != 0) * 2; \ ++ __a += ((__t & 0xF0) != 0) * 4; \ ++ __a += ((__t & 0xAA) != 0); \ ++ (COUNT) = __a; \ ++ } while (0) ++#endif /* __alpha_cix__ */ ++#endif /* __alpha */ ++ ++#if defined (__arc__) && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("add.f %1, %4, %5\n\tadc %0, %2, %3" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "%r" ((USItype) (ah)), \ ++ "rIJ" ((USItype) (bh)), \ ++ "%r" ((USItype) (al)), \ ++ "rIJ" ((USItype) (bl))) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("sub.f %1, %4, %5\n\tsbc %0, %2, %3" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "r" ((USItype) (ah)), \ ++ "rIJ" ((USItype) (bh)), \ ++ "r" ((USItype) (al)), \ ++ "rIJ" ((USItype) (bl))) ++/* Call libgcc routine. */ ++#define umul_ppmm(w1, w0, u, v) \ ++do { \ ++ DWunion __w; \ ++ __w.ll = __umulsidi3 (u, v); \ ++ w1 = __w.s.high; \ ++ w0 = __w.s.low; \ ++} while (0) ++#define __umulsidi3 __umulsidi3 ++UDItype __umulsidi3 (USItype, USItype); ++#endif ++ ++#if defined (__arm__) && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("adds %1, %4, %5\n\tadc %0, %2, %3" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "%r" ((USItype) (ah)), \ ++ "rI" ((USItype) (bh)), \ ++ "%r" ((USItype) (al)), \ ++ "rI" ((USItype) (bl))) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("subs %1, %4, %5\n\tsbc %0, %2, %3" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "r" ((USItype) (ah)), \ ++ "rI" ((USItype) (bh)), \ ++ "r" ((USItype) (al)), \ ++ "rI" ((USItype) (bl))) ++#define umul_ppmm(xh, xl, a, b) \ ++{register USItype __t0, __t1, __t2; \ ++ __asm__ ("%@ Inlined umul_ppmm\n" \ ++ " mov %2, %5, lsr #16\n" \ ++ " mov %0, %6, lsr #16\n" \ ++ " bic %3, %5, %2, lsl #16\n" \ ++ " bic %4, %6, %0, lsl #16\n" \ ++ " mul %1, %3, %4\n" \ ++ " mul %4, %2, %4\n" \ ++ " mul %3, %0, %3\n" \ ++ " mul %0, %2, %0\n" \ ++ " adds %3, %4, %3\n" \ ++ " addcs %0, %0, #65536\n" \ ++ " adds %1, %1, %3, lsl #16\n" \ ++ " adc %0, %0, %3, lsr #16" \ ++ : "=&r" ((USItype) (xh)), \ ++ "=r" ((USItype) (xl)), \ ++ "=&r" (__t0), "=&r" (__t1), "=r" (__t2) \ ++ : "r" ((USItype) (a)), \ ++ "r" ((USItype) (b)));} ++#define UMUL_TIME 20 ++#define UDIV_TIME 100 ++#endif /* __arm__ */ ++ ++#if defined (__hppa) && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("add %4,%5,%1\n\taddc %2,%3,%0" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "%rM" ((USItype) (ah)), \ ++ "rM" ((USItype) (bh)), \ ++ "%rM" ((USItype) (al)), \ ++ "rM" ((USItype) (bl))) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("sub %4,%5,%1\n\tsubb %2,%3,%0" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "rM" ((USItype) (ah)), \ ++ "rM" ((USItype) (bh)), \ ++ "rM" ((USItype) (al)), \ ++ "rM" ((USItype) (bl))) ++#if defined (_PA_RISC1_1) ++#define umul_ppmm(w1, w0, u, v) \ ++ do { \ ++ union \ ++ { \ ++ UDItype __f; \ ++ struct {USItype __w1, __w0;} __w1w0; \ ++ } __t; \ ++ __asm__ ("xmpyu %1,%2,%0" \ ++ : "=x" (__t.__f) \ ++ : "x" ((USItype) (u)), \ ++ "x" ((USItype) (v))); \ ++ (w1) = __t.__w1w0.__w1; \ ++ (w0) = __t.__w1w0.__w0; \ ++ } while (0) ++#define UMUL_TIME 8 ++#else ++#define UMUL_TIME 30 ++#endif ++#define UDIV_TIME 40 ++#define count_leading_zeros(count, x) \ ++ do { \ ++ USItype __tmp; \ ++ __asm__ ( \ ++ "ldi 1,%0\n" \ ++" extru,= %1,15,16,%%r0 ; Bits 31..16 zero?\n" \ ++" extru,tr %1,15,16,%1 ; No. Shift down, skip add.\n"\ ++" ldo 16(%0),%0 ; Yes. Perform add.\n" \ ++" extru,= %1,23,8,%%r0 ; Bits 15..8 zero?\n" \ ++" extru,tr %1,23,8,%1 ; No. Shift down, skip add.\n"\ ++" ldo 8(%0),%0 ; Yes. Perform add.\n" \ ++" extru,= %1,27,4,%%r0 ; Bits 7..4 zero?\n" \ ++" extru,tr %1,27,4,%1 ; No. Shift down, skip add.\n"\ ++" ldo 4(%0),%0 ; Yes. Perform add.\n" \ ++" extru,= %1,29,2,%%r0 ; Bits 3..2 zero?\n" \ ++" extru,tr %1,29,2,%1 ; No. Shift down, skip add.\n"\ ++" ldo 2(%0),%0 ; Yes. Perform add.\n" \ ++" extru %1,30,1,%1 ; Extract bit 1.\n" \ ++" sub %0,%1,%0 ; Subtract it.\n" \ ++ : "=r" (count), "=r" (__tmp) : "1" (x)); \ ++ } while (0) ++#endif ++ ++#if (defined (__i370__) || defined (__mvs__)) && W_TYPE_SIZE == 32 ++#define umul_ppmm(xh, xl, m0, m1) \ ++ do { \ ++ union {UDItype __ll; \ ++ struct {USItype __h, __l;} __i; \ ++ } __xx; \ ++ USItype __m0 = (m0), __m1 = (m1); \ ++ __asm__ ("mr %0,%3" \ ++ : "=r" (__xx.__i.__h), \ ++ "=r" (__xx.__i.__l) \ ++ : "%1" (__m0), \ ++ "r" (__m1)); \ ++ (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ ++ (xh) += ((((SItype) __m0 >> 31) & __m1) \ ++ + (((SItype) __m1 >> 31) & __m0)); \ ++ } while (0) ++#define smul_ppmm(xh, xl, m0, m1) \ ++ do { \ ++ union {DItype __ll; \ ++ struct {USItype __h, __l;} __i; \ ++ } __xx; \ ++ __asm__ ("mr %0,%3" \ ++ : "=r" (__xx.__i.__h), \ ++ "=r" (__xx.__i.__l) \ ++ : "%1" (m0), \ ++ "r" (m1)); \ ++ (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ ++ } while (0) ++#define sdiv_qrnnd(q, r, n1, n0, d) \ ++ do { \ ++ union {DItype __ll; \ ++ struct {USItype __h, __l;} __i; \ ++ } __xx; \ ++ __xx.__i.__h = n1; __xx.__i.__l = n0; \ ++ __asm__ ("dr %0,%2" \ ++ : "=r" (__xx.__ll) \ ++ : "0" (__xx.__ll), "r" (d)); \ ++ (q) = __xx.__i.__l; (r) = __xx.__i.__h; \ ++ } while (0) ++#endif ++ ++#if (defined (__i386__) || defined (__i486__)) && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("addl %5,%1\n\tadcl %3,%0" \ ++ : "=r" (sh), \ ++ "=&r" (sl) \ ++ : "%0" ((USItype) (ah)), \ ++ "g" ((USItype) (bh)), \ ++ "%1" ((USItype) (al)), \ ++ "g" ((USItype) (bl))) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("subl %5,%1\n\tsbbl %3,%0" \ ++ : "=r" (sh), \ ++ "=&r" (sl) \ ++ : "0" ((USItype) (ah)), \ ++ "g" ((USItype) (bh)), \ ++ "1" ((USItype) (al)), \ ++ "g" ((USItype) (bl))) ++#define umul_ppmm(w1, w0, u, v) \ ++ __asm__ ("mull %3" \ ++ : "=a" (w0), \ ++ "=d" (w1) \ ++ : "%0" ((USItype) (u)), \ ++ "rm" ((USItype) (v))) ++#define udiv_qrnnd(q, r, n1, n0, dv) \ ++ __asm__ ("divl %4" \ ++ : "=a" (q), \ ++ "=d" (r) \ ++ : "0" ((USItype) (n0)), \ ++ "1" ((USItype) (n1)), \ ++ "rm" ((USItype) (dv))) ++#define count_leading_zeros(count, x) \ ++ do { \ ++ USItype __cbtmp; \ ++ __asm__ ("bsrl %1,%0" \ ++ : "=r" (__cbtmp) : "rm" ((USItype) (x))); \ ++ (count) = __cbtmp ^ 31; \ ++ } while (0) ++#define count_trailing_zeros(count, x) \ ++ __asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x))) ++#define UMUL_TIME 40 ++#define UDIV_TIME 40 ++#endif /* 80x86 */ ++ ++#if defined (__i960__) && W_TYPE_SIZE == 32 ++#define umul_ppmm(w1, w0, u, v) \ ++ ({union {UDItype __ll; \ ++ struct {USItype __l, __h;} __i; \ ++ } __xx; \ ++ __asm__ ("emul %2,%1,%0" \ ++ : "=d" (__xx.__ll) \ ++ : "%dI" ((USItype) (u)), \ ++ "dI" ((USItype) (v))); \ ++ (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) ++#define __umulsidi3(u, v) \ ++ ({UDItype __w; \ ++ __asm__ ("emul %2,%1,%0" \ ++ : "=d" (__w) \ ++ : "%dI" ((USItype) (u)), \ ++ "dI" ((USItype) (v))); \ ++ __w; }) ++#endif /* __i960__ */ ++ ++#if defined (__M32R__) && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ /* The cmp clears the condition bit. */ \ ++ __asm__ ("cmp %0,%0\n\taddx %%5,%1\n\taddx %%3,%0" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "%0" ((USItype) (ah)), \ ++ "r" ((USItype) (bh)), \ ++ "%1" ((USItype) (al)), \ ++ "r" ((USItype) (bl)) \ ++ : "cbit") ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ /* The cmp clears the condition bit. */ \ ++ __asm__ ("cmp %0,%0\n\tsubx %5,%1\n\tsubx %3,%0" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "0" ((USItype) (ah)), \ ++ "r" ((USItype) (bh)), \ ++ "1" ((USItype) (al)), \ ++ "r" ((USItype) (bl)) \ ++ : "cbit") ++#endif /* __M32R__ */ ++ ++#if defined (__mc68000__) && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("add%.l %5,%1\n\taddx%.l %3,%0" \ ++ : "=d" ((USItype) (sh)), \ ++ "=&d" ((USItype) (sl)) \ ++ : "%0" ((USItype) (ah)), \ ++ "d" ((USItype) (bh)), \ ++ "%1" ((USItype) (al)), \ ++ "g" ((USItype) (bl))) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("sub%.l %5,%1\n\tsubx%.l %3,%0" \ ++ : "=d" ((USItype) (sh)), \ ++ "=&d" ((USItype) (sl)) \ ++ : "0" ((USItype) (ah)), \ ++ "d" ((USItype) (bh)), \ ++ "1" ((USItype) (al)), \ ++ "g" ((USItype) (bl))) ++ ++/* The '020, '030, '040 and CPU32 have 32x32->64 and 64/32->32q-32r. */ ++#if defined (__mc68020__) || defined(mc68020) \ ++ || defined(__mc68030__) || defined(mc68030) \ ++ || defined(__mc68040__) || defined(mc68040) \ ++ || defined(__mcpu32__) || defined(mcpu32) ++#define umul_ppmm(w1, w0, u, v) \ ++ __asm__ ("mulu%.l %3,%1:%0" \ ++ : "=d" ((USItype) (w0)), \ ++ "=d" ((USItype) (w1)) \ ++ : "%0" ((USItype) (u)), \ ++ "dmi" ((USItype) (v))) ++#define UMUL_TIME 45 ++#define udiv_qrnnd(q, r, n1, n0, d) \ ++ __asm__ ("divu%.l %4,%1:%0" \ ++ : "=d" ((USItype) (q)), \ ++ "=d" ((USItype) (r)) \ ++ : "0" ((USItype) (n0)), \ ++ "1" ((USItype) (n1)), \ ++ "dmi" ((USItype) (d))) ++#define UDIV_TIME 90 ++#define sdiv_qrnnd(q, r, n1, n0, d) \ ++ __asm__ ("divs%.l %4,%1:%0" \ ++ : "=d" ((USItype) (q)), \ ++ "=d" ((USItype) (r)) \ ++ : "0" ((USItype) (n0)), \ ++ "1" ((USItype) (n1)), \ ++ "dmi" ((USItype) (d))) ++ ++#else /* not mc68020 */ ++#if !defined(__mcf5200__) ++/* %/ inserts REGISTER_PREFIX, %# inserts IMMEDIATE_PREFIX. */ ++#define umul_ppmm(xh, xl, a, b) \ ++ __asm__ ("| Inlined umul_ppmm\n" \ ++ " move%.l %2,%/d0\n" \ ++ " move%.l %3,%/d1\n" \ ++ " move%.l %/d0,%/d2\n" \ ++ " swap %/d0\n" \ ++ " move%.l %/d1,%/d3\n" \ ++ " swap %/d1\n" \ ++ " move%.w %/d2,%/d4\n" \ ++ " mulu %/d3,%/d4\n" \ ++ " mulu %/d1,%/d2\n" \ ++ " mulu %/d0,%/d3\n" \ ++ " mulu %/d0,%/d1\n" \ ++ " move%.l %/d4,%/d0\n" \ ++ " eor%.w %/d0,%/d0\n" \ ++ " swap %/d0\n" \ ++ " add%.l %/d0,%/d2\n" \ ++ " add%.l %/d3,%/d2\n" \ ++ " jcc 1f\n" \ ++ " add%.l %#65536,%/d1\n" \ ++ "1: swap %/d2\n" \ ++ " moveq %#0,%/d0\n" \ ++ " move%.w %/d2,%/d0\n" \ ++ " move%.w %/d4,%/d2\n" \ ++ " move%.l %/d2,%1\n" \ ++ " add%.l %/d1,%/d0\n" \ ++ " move%.l %/d0,%0" \ ++ : "=g" ((USItype) (xh)), \ ++ "=g" ((USItype) (xl)) \ ++ : "g" ((USItype) (a)), \ ++ "g" ((USItype) (b)) \ ++ : "d0", "d1", "d2", "d3", "d4") ++#define UMUL_TIME 100 ++#define UDIV_TIME 400 ++#endif /* not mcf5200 */ ++#endif /* not mc68020 */ ++ ++/* The '020, '030, '040 and '060 have bitfield insns. */ ++#if defined (__mc68020__) || defined(mc68020) \ ++ || defined(__mc68030__) || defined(mc68030) \ ++ || defined(__mc68040__) || defined(mc68040) \ ++ || defined(__mc68060__) || defined(mc68060) ++#define count_leading_zeros(count, x) \ ++ __asm__ ("bfffo %1{%b2:%b2},%0" \ ++ : "=d" ((USItype) (count)) \ ++ : "od" ((USItype) (x)), "n" (0)) ++#endif ++#endif /* mc68000 */ ++ ++#if defined (__m88000__) && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("addu.co %1,%r4,%r5\n\taddu.ci %0,%r2,%r3" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "%rJ" ((USItype) (ah)), \ ++ "rJ" ((USItype) (bh)), \ ++ "%rJ" ((USItype) (al)), \ ++ "rJ" ((USItype) (bl))) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("subu.co %1,%r4,%r5\n\tsubu.ci %0,%r2,%r3" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "rJ" ((USItype) (ah)), \ ++ "rJ" ((USItype) (bh)), \ ++ "rJ" ((USItype) (al)), \ ++ "rJ" ((USItype) (bl))) ++#define count_leading_zeros(count, x) \ ++ do { \ ++ USItype __cbtmp; \ ++ __asm__ ("ff1 %0,%1" \ ++ : "=r" (__cbtmp) \ ++ : "r" ((USItype) (x))); \ ++ (count) = __cbtmp ^ 31; \ ++ } while (0) ++#define COUNT_LEADING_ZEROS_0 63 /* sic */ ++#if defined (__mc88110__) ++#define umul_ppmm(wh, wl, u, v) \ ++ do { \ ++ union {UDItype __ll; \ ++ struct {USItype __h, __l;} __i; \ ++ } __xx; \ ++ __asm__ ("mulu.d %0,%1,%2" \ ++ : "=r" (__xx.__ll) \ ++ : "r" ((USItype) (u)), \ ++ "r" ((USItype) (v))); \ ++ (wh) = __xx.__i.__h; \ ++ (wl) = __xx.__i.__l; \ ++ } while (0) ++#define udiv_qrnnd(q, r, n1, n0, d) \ ++ ({union {UDItype __ll; \ ++ struct {USItype __h, __l;} __i; \ ++ } __xx; \ ++ USItype __q; \ ++ __xx.__i.__h = (n1); __xx.__i.__l = (n0); \ ++ __asm__ ("divu.d %0,%1,%2" \ ++ : "=r" (__q) \ ++ : "r" (__xx.__ll), \ ++ "r" ((USItype) (d))); \ ++ (r) = (n0) - __q * (d); (q) = __q; }) ++#define UMUL_TIME 5 ++#define UDIV_TIME 25 ++#else ++#define UMUL_TIME 17 ++#define UDIV_TIME 150 ++#endif /* __mc88110__ */ ++#endif /* __m88000__ */ ++ ++#if defined (__mips__) && W_TYPE_SIZE == 32 ++#define umul_ppmm(w1, w0, u, v) \ ++ __asm__ ("multu %2,%3" \ ++ : "=l" ((USItype) (w0)), \ ++ "=h" ((USItype) (w1)) \ ++ : "d" ((USItype) (u)), \ ++ "d" ((USItype) (v))) ++#define UMUL_TIME 10 ++#define UDIV_TIME 100 ++#endif /* __mips__ */ ++ ++#if defined (__ns32000__) && W_TYPE_SIZE == 32 ++#define umul_ppmm(w1, w0, u, v) \ ++ ({union {UDItype __ll; \ ++ struct {USItype __l, __h;} __i; \ ++ } __xx; \ ++ __asm__ ("meid %2,%0" \ ++ : "=g" (__xx.__ll) \ ++ : "%0" ((USItype) (u)), \ ++ "g" ((USItype) (v))); \ ++ (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) ++#define __umulsidi3(u, v) \ ++ ({UDItype __w; \ ++ __asm__ ("meid %2,%0" \ ++ : "=g" (__w) \ ++ : "%0" ((USItype) (u)), \ ++ "g" ((USItype) (v))); \ ++ __w; }) ++#define udiv_qrnnd(q, r, n1, n0, d) \ ++ ({union {UDItype __ll; \ ++ struct {USItype __l, __h;} __i; \ ++ } __xx; \ ++ __xx.__i.__h = (n1); __xx.__i.__l = (n0); \ ++ __asm__ ("deid %2,%0" \ ++ : "=g" (__xx.__ll) \ ++ : "0" (__xx.__ll), \ ++ "g" ((USItype) (d))); \ ++ (r) = __xx.__i.__l; (q) = __xx.__i.__h; }) ++#define count_trailing_zeros(count,x) \ ++ do { \ ++ __asm__ ("ffsd %2,%0" \ ++ : "=r" ((USItype) (count)) \ ++ : "0" ((USItype) 0), \ ++ "r" ((USItype) (x))); \ ++ } while (0) ++#endif /* __ns32000__ */ ++ ++/* FIXME: We should test _IBMR2 here when we add assembly support for the ++ system vendor compilers. ++ FIXME: What's needed for gcc PowerPC VxWorks? __vxworks__ is not good ++ enough, since that hits ARM and m68k too. */ ++#if (defined (_ARCH_PPC) /* AIX */ \ ++ || defined (_ARCH_PWR) /* AIX */ \ ++ || defined (_ARCH_COM) /* AIX */ \ ++ || defined (__powerpc__) /* gcc */ \ ++ || defined (__POWERPC__) /* BEOS */ \ ++ || defined (__ppc__) /* Darwin */ \ ++ || defined (PPC) /* GNU/Linux, SysV */ \ ++ ) && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ do { \ ++ if (__builtin_constant_p (bh) && (bh) == 0) \ ++ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ ++ else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0) \ ++ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ ++ else \ ++ __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ ++ : "=r" (sh), "=&r" (sl) \ ++ : "%r" (ah), "r" (bh), "%r" (al), "rI" (bl)); \ ++ } while (0) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ do { \ ++ if (__builtin_constant_p (ah) && (ah) == 0) \ ++ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ ++ else if (__builtin_constant_p (ah) && (ah) == ~(USItype) 0) \ ++ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ ++ else if (__builtin_constant_p (bh) && (bh) == 0) \ ++ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ ++ else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0) \ ++ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ ++ else \ ++ __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ ++ : "=r" (sh), "=&r" (sl) \ ++ : "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \ ++ } while (0) ++#define count_leading_zeros(count, x) \ ++ __asm__ ("{cntlz|cntlzw} %0,%1" : "=r" (count) : "r" (x)) ++#define COUNT_LEADING_ZEROS_0 32 ++#if defined (_ARCH_PPC) || defined (__powerpc__) || defined (__POWERPC__) \ ++ || defined (__ppc__) || defined (PPC) || defined (__vxworks__) ++#define umul_ppmm(ph, pl, m0, m1) \ ++ do { \ ++ USItype __m0 = (m0), __m1 = (m1); \ ++ __asm__ ("mulhwu %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ ++ (pl) = __m0 * __m1; \ ++ } while (0) ++#define UMUL_TIME 15 ++#define smul_ppmm(ph, pl, m0, m1) \ ++ do { \ ++ SItype __m0 = (m0), __m1 = (m1); \ ++ __asm__ ("mulhw %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ ++ (pl) = __m0 * __m1; \ ++ } while (0) ++#define SMUL_TIME 14 ++#define UDIV_TIME 120 ++#elif defined (_ARCH_PWR) ++#define UMUL_TIME 8 ++#define smul_ppmm(xh, xl, m0, m1) \ ++ __asm__ ("mul %0,%2,%3" : "=r" (xh), "=q" (xl) : "r" (m0), "r" (m1)) ++#define SMUL_TIME 4 ++#define sdiv_qrnnd(q, r, nh, nl, d) \ ++ __asm__ ("div %0,%2,%4" : "=r" (q), "=q" (r) : "r" (nh), "1" (nl), "r" (d)) ++#define UDIV_TIME 100 ++#endif ++#endif /* 32-bit POWER architecture variants. */ ++ ++/* We should test _IBMR2 here when we add assembly support for the system ++ vendor compilers. */ ++#if (defined (_ARCH_PPC64) || defined (__powerpc64__)) && W_TYPE_SIZE == 64 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ do { \ ++ if (__builtin_constant_p (bh) && (bh) == 0) \ ++ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ ++ else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \ ++ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ ++ else \ ++ __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ ++ : "=r" (sh), "=&r" (sl) \ ++ : "%r" (ah), "r" (bh), "%r" (al), "rI" (bl)); \ ++ } while (0) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ do { \ ++ if (__builtin_constant_p (ah) && (ah) == 0) \ ++ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ ++ else if (__builtin_constant_p (ah) && (ah) == ~(UDItype) 0) \ ++ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ ++ else if (__builtin_constant_p (bh) && (bh) == 0) \ ++ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ ++ else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \ ++ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ ++ else \ ++ __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ ++ : "=r" (sh), "=&r" (sl) \ ++ : "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \ ++ } while (0) ++#define count_leading_zeros(count, x) \ ++ __asm__ ("cntlzd %0,%1" : "=r" (count) : "r" (x)) ++#define COUNT_LEADING_ZEROS_0 64 ++#define umul_ppmm(ph, pl, m0, m1) \ ++ do { \ ++ UDItype __m0 = (m0), __m1 = (m1); \ ++ __asm__ ("mulhdu %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ ++ (pl) = __m0 * __m1; \ ++ } while (0) ++#define UMUL_TIME 15 ++#define smul_ppmm(ph, pl, m0, m1) \ ++ do { \ ++ DItype __m0 = (m0), __m1 = (m1); \ ++ __asm__ ("mulhd %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ ++ (pl) = __m0 * __m1; \ ++ } while (0) ++#define SMUL_TIME 14 /* ??? */ ++#define UDIV_TIME 120 /* ??? */ ++#endif /* 64-bit PowerPC. */ ++ ++#if defined (__ibm032__) /* RT/ROMP */ && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("a %1,%5\n\tae %0,%3" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "%0" ((USItype) (ah)), \ ++ "r" ((USItype) (bh)), \ ++ "%1" ((USItype) (al)), \ ++ "r" ((USItype) (bl))) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("s %1,%5\n\tse %0,%3" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "0" ((USItype) (ah)), \ ++ "r" ((USItype) (bh)), \ ++ "1" ((USItype) (al)), \ ++ "r" ((USItype) (bl))) ++#define umul_ppmm(ph, pl, m0, m1) \ ++ do { \ ++ USItype __m0 = (m0), __m1 = (m1); \ ++ __asm__ ( \ ++ "s r2,r2\n" \ ++" mts r10,%2\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" cas %0,r2,r0\n" \ ++" mfs r10,%1" \ ++ : "=r" ((USItype) (ph)), \ ++ "=r" ((USItype) (pl)) \ ++ : "%r" (__m0), \ ++ "r" (__m1) \ ++ : "r2"); \ ++ (ph) += ((((SItype) __m0 >> 31) & __m1) \ ++ + (((SItype) __m1 >> 31) & __m0)); \ ++ } while (0) ++#define UMUL_TIME 20 ++#define UDIV_TIME 200 ++#define count_leading_zeros(count, x) \ ++ do { \ ++ if ((x) >= 0x10000) \ ++ __asm__ ("clz %0,%1" \ ++ : "=r" ((USItype) (count)) \ ++ : "r" ((USItype) (x) >> 16)); \ ++ else \ ++ { \ ++ __asm__ ("clz %0,%1" \ ++ : "=r" ((USItype) (count)) \ ++ : "r" ((USItype) (x))); \ ++ (count) += 16; \ ++ } \ ++ } while (0) ++#endif ++ ++#if defined (__sh2__) && W_TYPE_SIZE == 32 ++#define umul_ppmm(w1, w0, u, v) \ ++ __asm__ ( \ ++ "dmulu.l %2,%3\n\tsts macl,%1\n\tsts mach,%0" \ ++ : "=r" ((USItype)(w1)), \ ++ "=r" ((USItype)(w0)) \ ++ : "r" ((USItype)(u)), \ ++ "r" ((USItype)(v)) \ ++ : "macl", "mach") ++#define UMUL_TIME 5 ++#endif ++ ++#if defined (__SH5__) && __SHMEDIA__ && W_TYPE_SIZE == 32 ++#define __umulsidi3(u,v) ((UDItype)(USItype)u*(USItype)v) ++#define count_leading_zeros(count, x) \ ++ do \ ++ { \ ++ UDItype x_ = (USItype)(x); \ ++ SItype c_; \ ++ \ ++ __asm__ ("nsb %1, %0" : "=r" (c_) : "r" (x_)); \ ++ (count) = c_ - 31; \ ++ } \ ++ while (0) ++#define COUNT_LEADING_ZEROS_0 32 ++#endif ++ ++#if defined (__sparc__) && !defined (__arch64__) && !defined (__sparcv9) \ ++ && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("addcc %r4,%5,%1\n\taddx %r2,%3,%0" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "%rJ" ((USItype) (ah)), \ ++ "rI" ((USItype) (bh)), \ ++ "%rJ" ((USItype) (al)), \ ++ "rI" ((USItype) (bl)) \ ++ __CLOBBER_CC) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("subcc %r4,%5,%1\n\tsubx %r2,%3,%0" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "rJ" ((USItype) (ah)), \ ++ "rI" ((USItype) (bh)), \ ++ "rJ" ((USItype) (al)), \ ++ "rI" ((USItype) (bl)) \ ++ __CLOBBER_CC) ++#if defined (__sparc_v8__) ++#define umul_ppmm(w1, w0, u, v) \ ++ __asm__ ("umul %2,%3,%1;rd %%y,%0" \ ++ : "=r" ((USItype) (w1)), \ ++ "=r" ((USItype) (w0)) \ ++ : "r" ((USItype) (u)), \ ++ "r" ((USItype) (v))) ++#define udiv_qrnnd(__q, __r, __n1, __n0, __d) \ ++ __asm__ ("mov %2,%%y;nop;nop;nop;udiv %3,%4,%0;umul %0,%4,%1;sub %3,%1,%1"\ ++ : "=&r" ((USItype) (__q)), \ ++ "=&r" ((USItype) (__r)) \ ++ : "r" ((USItype) (__n1)), \ ++ "r" ((USItype) (__n0)), \ ++ "r" ((USItype) (__d))) ++#else ++#if defined (__sparclite__) ++/* This has hardware multiply but not divide. It also has two additional ++ instructions scan (ffs from high bit) and divscc. */ ++#define umul_ppmm(w1, w0, u, v) \ ++ __asm__ ("umul %2,%3,%1;rd %%y,%0" \ ++ : "=r" ((USItype) (w1)), \ ++ "=r" ((USItype) (w0)) \ ++ : "r" ((USItype) (u)), \ ++ "r" ((USItype) (v))) ++#define udiv_qrnnd(q, r, n1, n0, d) \ ++ __asm__ ("! Inlined udiv_qrnnd\n" \ ++" wr %%g0,%2,%%y ! Not a delayed write for sparclite\n" \ ++" tst %%g0\n" \ ++" divscc %3,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%0\n" \ ++" rd %%y,%1\n" \ ++" bl,a 1f\n" \ ++" add %1,%4,%1\n" \ ++"1: ! End of inline udiv_qrnnd" \ ++ : "=r" ((USItype) (q)), \ ++ "=r" ((USItype) (r)) \ ++ : "r" ((USItype) (n1)), \ ++ "r" ((USItype) (n0)), \ ++ "rI" ((USItype) (d)) \ ++ : "g1" __AND_CLOBBER_CC) ++#define UDIV_TIME 37 ++#define count_leading_zeros(count, x) \ ++ do { \ ++ __asm__ ("scan %1,1,%0" \ ++ : "=r" ((USItype) (count)) \ ++ : "r" ((USItype) (x))); \ ++ } while (0) ++/* Early sparclites return 63 for an argument of 0, but they warn that future ++ implementations might change this. Therefore, leave COUNT_LEADING_ZEROS_0 ++ undefined. */ ++#else ++/* SPARC without integer multiplication and divide instructions. ++ (i.e. at least Sun4/20,40,60,65,75,110,260,280,330,360,380,470,490) */ ++#define umul_ppmm(w1, w0, u, v) \ ++ __asm__ ("! Inlined umul_ppmm\n" \ ++" wr %%g0,%2,%%y ! SPARC has 0-3 delay insn after a wr\n"\ ++" sra %3,31,%%o5 ! Don't move this insn\n" \ ++" and %2,%%o5,%%o5 ! Don't move this insn\n" \ ++" andcc %%g0,0,%%g1 ! Don't move this insn\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,0,%%g1\n" \ ++" add %%g1,%%o5,%0\n" \ ++" rd %%y,%1" \ ++ : "=r" ((USItype) (w1)), \ ++ "=r" ((USItype) (w0)) \ ++ : "%rI" ((USItype) (u)), \ ++ "r" ((USItype) (v)) \ ++ : "g1", "o5" __AND_CLOBBER_CC) ++#define UMUL_TIME 39 /* 39 instructions */ ++/* It's quite necessary to add this much assembler for the sparc. ++ The default udiv_qrnnd (in C) is more than 10 times slower! */ ++#define udiv_qrnnd(__q, __r, __n1, __n0, __d) \ ++ __asm__ ("! Inlined udiv_qrnnd\n" \ ++" mov 32,%%g1\n" \ ++" subcc %1,%2,%%g0\n" \ ++"1: bcs 5f\n" \ ++" addxcc %0,%0,%0 ! shift n1n0 and a q-bit in lsb\n" \ ++" sub %1,%2,%1 ! this kills msb of n\n" \ ++" addx %1,%1,%1 ! so this can't give carry\n" \ ++" subcc %%g1,1,%%g1\n" \ ++"2: bne 1b\n" \ ++" subcc %1,%2,%%g0\n" \ ++" bcs 3f\n" \ ++" addxcc %0,%0,%0 ! shift n1n0 and a q-bit in lsb\n" \ ++" b 3f\n" \ ++" sub %1,%2,%1 ! this kills msb of n\n" \ ++"4: sub %1,%2,%1\n" \ ++"5: addxcc %1,%1,%1\n" \ ++" bcc 2b\n" \ ++" subcc %%g1,1,%%g1\n" \ ++"! Got carry from n. Subtract next step to cancel this carry.\n" \ ++" bne 4b\n" \ ++" addcc %0,%0,%0 ! shift n1n0 and a 0-bit in lsb\n" \ ++" sub %1,%2,%1\n" \ ++"3: xnor %0,0,%0\n" \ ++" ! End of inline udiv_qrnnd" \ ++ : "=&r" ((USItype) (__q)), \ ++ "=&r" ((USItype) (__r)) \ ++ : "r" ((USItype) (__d)), \ ++ "1" ((USItype) (__n1)), \ ++ "0" ((USItype) (__n0)) : "g1" __AND_CLOBBER_CC) ++#define UDIV_TIME (3+7*32) /* 7 instructions/iteration. 32 iterations. */ ++#endif /* __sparclite__ */ ++#endif /* __sparc_v8__ */ ++#endif /* sparc32 */ ++ ++#if ((defined (__sparc__) && defined (__arch64__)) || defined (__sparcv9)) \ ++ && W_TYPE_SIZE == 64 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("addcc %r4,%5,%1\n\t" \ ++ "add %r2,%3,%0\n\t" \ ++ "bcs,a,pn %%xcc, 1f\n\t" \ ++ "add %0, 1, %0\n" \ ++ "1:" \ ++ : "=r" ((UDItype)(sh)), \ ++ "=&r" ((UDItype)(sl)) \ ++ : "%rJ" ((UDItype)(ah)), \ ++ "rI" ((UDItype)(bh)), \ ++ "%rJ" ((UDItype)(al)), \ ++ "rI" ((UDItype)(bl)) \ ++ __CLOBBER_CC) ++ ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("subcc %r4,%5,%1\n\t" \ ++ "sub %r2,%3,%0\n\t" \ ++ "bcs,a,pn %%xcc, 1f\n\t" \ ++ "sub %0, 1, %0\n\t" \ ++ "1:" \ ++ : "=r" ((UDItype)(sh)), \ ++ "=&r" ((UDItype)(sl)) \ ++ : "rJ" ((UDItype)(ah)), \ ++ "rI" ((UDItype)(bh)), \ ++ "rJ" ((UDItype)(al)), \ ++ "rI" ((UDItype)(bl)) \ ++ __CLOBBER_CC) ++ ++#define umul_ppmm(wh, wl, u, v) \ ++ do { \ ++ UDItype tmp1, tmp2, tmp3, tmp4; \ ++ __asm__ __volatile__ ( \ ++ "srl %7,0,%3\n\t" \ ++ "mulx %3,%6,%1\n\t" \ ++ "srlx %6,32,%2\n\t" \ ++ "mulx %2,%3,%4\n\t" \ ++ "sllx %4,32,%5\n\t" \ ++ "srl %6,0,%3\n\t" \ ++ "sub %1,%5,%5\n\t" \ ++ "srlx %5,32,%5\n\t" \ ++ "addcc %4,%5,%4\n\t" \ ++ "srlx %7,32,%5\n\t" \ ++ "mulx %3,%5,%3\n\t" \ ++ "mulx %2,%5,%5\n\t" \ ++ "sethi %%hi(0x80000000),%2\n\t" \ ++ "addcc %4,%3,%4\n\t" \ ++ "srlx %4,32,%4\n\t" \ ++ "add %2,%2,%2\n\t" \ ++ "movcc %%xcc,%%g0,%2\n\t" \ ++ "addcc %5,%4,%5\n\t" \ ++ "sllx %3,32,%3\n\t" \ ++ "add %1,%3,%1\n\t" \ ++ "add %5,%2,%0" \ ++ : "=r" ((UDItype)(wh)), \ ++ "=&r" ((UDItype)(wl)), \ ++ "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4) \ ++ : "r" ((UDItype)(u)), \ ++ "r" ((UDItype)(v)) \ ++ __CLOBBER_CC); \ ++ } while (0) ++#define UMUL_TIME 96 ++#define UDIV_TIME 230 ++#endif /* sparc64 */ ++ ++#if defined (__vax__) && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("addl2 %5,%1\n\tadwc %3,%0" \ ++ : "=g" ((USItype) (sh)), \ ++ "=&g" ((USItype) (sl)) \ ++ : "%0" ((USItype) (ah)), \ ++ "g" ((USItype) (bh)), \ ++ "%1" ((USItype) (al)), \ ++ "g" ((USItype) (bl))) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("subl2 %5,%1\n\tsbwc %3,%0" \ ++ : "=g" ((USItype) (sh)), \ ++ "=&g" ((USItype) (sl)) \ ++ : "0" ((USItype) (ah)), \ ++ "g" ((USItype) (bh)), \ ++ "1" ((USItype) (al)), \ ++ "g" ((USItype) (bl))) ++#define umul_ppmm(xh, xl, m0, m1) \ ++ do { \ ++ union { \ ++ UDItype __ll; \ ++ struct {USItype __l, __h;} __i; \ ++ } __xx; \ ++ USItype __m0 = (m0), __m1 = (m1); \ ++ __asm__ ("emul %1,%2,$0,%0" \ ++ : "=r" (__xx.__ll) \ ++ : "g" (__m0), \ ++ "g" (__m1)); \ ++ (xh) = __xx.__i.__h; \ ++ (xl) = __xx.__i.__l; \ ++ (xh) += ((((SItype) __m0 >> 31) & __m1) \ ++ + (((SItype) __m1 >> 31) & __m0)); \ ++ } while (0) ++#define sdiv_qrnnd(q, r, n1, n0, d) \ ++ do { \ ++ union {DItype __ll; \ ++ struct {SItype __l, __h;} __i; \ ++ } __xx; \ ++ __xx.__i.__h = n1; __xx.__i.__l = n0; \ ++ __asm__ ("ediv %3,%2,%0,%1" \ ++ : "=g" (q), "=g" (r) \ ++ : "g" (__xx.__ll), "g" (d)); \ ++ } while (0) ++#endif /* __vax__ */ ++ ++#if defined (__z8000__) && W_TYPE_SIZE == 16 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("add %H1,%H5\n\tadc %H0,%H3" \ ++ : "=r" ((unsigned int)(sh)), \ ++ "=&r" ((unsigned int)(sl)) \ ++ : "%0" ((unsigned int)(ah)), \ ++ "r" ((unsigned int)(bh)), \ ++ "%1" ((unsigned int)(al)), \ ++ "rQR" ((unsigned int)(bl))) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("sub %H1,%H5\n\tsbc %H0,%H3" \ ++ : "=r" ((unsigned int)(sh)), \ ++ "=&r" ((unsigned int)(sl)) \ ++ : "0" ((unsigned int)(ah)), \ ++ "r" ((unsigned int)(bh)), \ ++ "1" ((unsigned int)(al)), \ ++ "rQR" ((unsigned int)(bl))) ++#define umul_ppmm(xh, xl, m0, m1) \ ++ do { \ ++ union {long int __ll; \ ++ struct {unsigned int __h, __l;} __i; \ ++ } __xx; \ ++ unsigned int __m0 = (m0), __m1 = (m1); \ ++ __asm__ ("mult %S0,%H3" \ ++ : "=r" (__xx.__i.__h), \ ++ "=r" (__xx.__i.__l) \ ++ : "%1" (__m0), \ ++ "rQR" (__m1)); \ ++ (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ ++ (xh) += ((((signed int) __m0 >> 15) & __m1) \ ++ + (((signed int) __m1 >> 15) & __m0)); \ ++ } while (0) ++#endif /* __z8000__ */ ++ ++#endif /* __GNUC__ */ ++ ++/* If this machine has no inline assembler, use C macros. */ ++ ++#if !defined (add_ssaaaa) ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ do { \ ++ UWtype __x; \ ++ __x = (al) + (bl); \ ++ (sh) = (ah) + (bh) + (__x < (al)); \ ++ (sl) = __x; \ ++ } while (0) ++#endif ++ ++#if !defined (sub_ddmmss) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ do { \ ++ UWtype __x; \ ++ __x = (al) - (bl); \ ++ (sh) = (ah) - (bh) - (__x > (al)); \ ++ (sl) = __x; \ ++ } while (0) ++#endif ++ ++#if !defined (umul_ppmm) ++#define umul_ppmm(w1, w0, u, v) \ ++ do { \ ++ UWtype __x0, __x1, __x2, __x3; \ ++ UHWtype __ul, __vl, __uh, __vh; \ ++ \ ++ __ul = __ll_lowpart (u); \ ++ __uh = __ll_highpart (u); \ ++ __vl = __ll_lowpart (v); \ ++ __vh = __ll_highpart (v); \ ++ \ ++ __x0 = (UWtype) __ul * __vl; \ ++ __x1 = (UWtype) __ul * __vh; \ ++ __x2 = (UWtype) __uh * __vl; \ ++ __x3 = (UWtype) __uh * __vh; \ ++ \ ++ __x1 += __ll_highpart (__x0);/* this can't give carry */ \ ++ __x1 += __x2; /* but this indeed can */ \ ++ if (__x1 < __x2) /* did we get it? */ \ ++ __x3 += __ll_B; /* yes, add it in the proper pos. */ \ ++ \ ++ (w1) = __x3 + __ll_highpart (__x1); \ ++ (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \ ++ } while (0) ++#endif ++ ++#if !defined (__umulsidi3) ++#define __umulsidi3(u, v) \ ++ ({DWunion __w; \ ++ umul_ppmm (__w.s.high, __w.s.low, u, v); \ ++ __w.ll; }) ++#endif ++ ++/* Define this unconditionally, so it can be used for debugging. */ ++#define __udiv_qrnnd_c(q, r, n1, n0, d) \ ++ do { \ ++ UWtype __d1, __d0, __q1, __q0; \ ++ UWtype __r1, __r0, __m; \ ++ __d1 = __ll_highpart (d); \ ++ __d0 = __ll_lowpart (d); \ ++ \ ++ __r1 = (n1) % __d1; \ ++ __q1 = (n1) / __d1; \ ++ __m = (UWtype) __q1 * __d0; \ ++ __r1 = __r1 * __ll_B | __ll_highpart (n0); \ ++ if (__r1 < __m) \ ++ { \ ++ __q1--, __r1 += (d); \ ++ if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\ ++ if (__r1 < __m) \ ++ __q1--, __r1 += (d); \ ++ } \ ++ __r1 -= __m; \ ++ \ ++ __r0 = __r1 % __d1; \ ++ __q0 = __r1 / __d1; \ ++ __m = (UWtype) __q0 * __d0; \ ++ __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ ++ if (__r0 < __m) \ ++ { \ ++ __q0--, __r0 += (d); \ ++ if (__r0 >= (d)) \ ++ if (__r0 < __m) \ ++ __q0--, __r0 += (d); \ ++ } \ ++ __r0 -= __m; \ ++ \ ++ (q) = (UWtype) __q1 * __ll_B | __q0; \ ++ (r) = __r0; \ ++ } while (0) ++ ++/* If the processor has no udiv_qrnnd but sdiv_qrnnd, go through ++ __udiv_w_sdiv (defined in libgcc or elsewhere). */ ++#if !defined (udiv_qrnnd) && defined (sdiv_qrnnd) ++#define udiv_qrnnd(q, r, nh, nl, d) \ ++ do { \ ++ USItype __r; \ ++ (q) = __udiv_w_sdiv (&__r, nh, nl, d); \ ++ (r) = __r; \ ++ } while (0) ++#endif ++ ++/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c. */ ++#if !defined (udiv_qrnnd) ++#define UDIV_NEEDS_NORMALIZATION 1 ++#define udiv_qrnnd __udiv_qrnnd_c ++#endif ++ ++#if !defined (count_leading_zeros) ++extern const UQItype __clz_tab[]; ++#define count_leading_zeros(count, x) \ ++ do { \ ++ UWtype __xr = (x); \ ++ UWtype __a; \ ++ \ ++ if (W_TYPE_SIZE <= 32) \ ++ { \ ++ __a = __xr < ((UWtype)1<<2*__BITS4) \ ++ ? (__xr < ((UWtype)1<<__BITS4) ? 0 : __BITS4) \ ++ : (__xr < ((UWtype)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ ++ } \ ++ else \ ++ { \ ++ for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \ ++ if (((__xr >> __a) & 0xff) != 0) \ ++ break; \ ++ } \ ++ \ ++ (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \ ++ } while (0) ++#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE ++#endif ++ ++#if !defined (count_trailing_zeros) ++/* Define count_trailing_zeros using count_leading_zeros. The latter might be ++ defined in asm, but if it is not, the C version above is good enough. */ ++#define count_trailing_zeros(count, x) \ ++ do { \ ++ UWtype __ctz_x = (x); \ ++ UWtype __ctz_c; \ ++ count_leading_zeros (__ctz_c, __ctz_x & -__ctz_x); \ ++ (count) = W_TYPE_SIZE - 1 - __ctz_c; \ ++ } while (0) ++#endif ++ ++#ifndef UDIV_NEEDS_NORMALIZATION ++#define UDIV_NEEDS_NORMALIZATION 0 ++#endif +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/Makefile linux-4.6-rc6-ndis/3rdparty/ndiswrapper/Makefile +--- linux-4.6-rc6/3rdparty/ndiswrapper/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/Makefile 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,213 @@ ++# Name of the module ++MODNAME = ndiswrapper ++ ++DISTFILES = \ ++ Makefile crt.c divdi3.c hal.c iw_ndis.c iw_ndis.h lin2win.S lin2win.h \ ++ loader.c loader.h longlong.h mkexport.sh mkstubs.sh ndis.c ndis.h \ ++ ndiswrapper.h ntoskernel.c ntoskernel.h ntoskernel_io.c pe_linker.c \ ++ pe_linker.h pnp.c pnp.h proc.c rtl.c usb.c usb.h win2lin_stubs.S \ ++ winnt_types.h workqueue.c wrapmem.c wrapmem.h wrapndis.c wrapndis.h \ ++ wrapper.c wrapper.h ++ ++# By default, we try to compile the modules for the currently running ++# kernel. But it's the first approximation, as we will re-read the ++# version from the kernel sources. ++KVERS_UNAME ?= $(shell uname -r) ++ ++# KBUILD is the path to the Linux kernel build tree. It is usually the ++# same as the kernel source tree, except when the kernel was compiled in ++# a separate directory. ++KBUILD ?= $(shell readlink -f /lib/modules/$(KVERS_UNAME)/build) ++ ++ifeq (,$(KBUILD)) ++$(error Kernel build tree not found - please set KBUILD to configured kernel) ++endif ++ ++KCONFIG := $(KBUILD)/.config ++ifeq (,$(wildcard $(KCONFIG))) ++$(error No .config found in $(KBUILD), please set KBUILD to configured kernel) ++endif ++ ++ifneq (,$(wildcard $(KBUILD)/include/linux/version.h)) ++ifneq (,$(wildcard $(KBUILD)/include/generated/uapi/linux/version.h)) ++$(error Multiple copies of version.h found, please clean your build tree) ++endif ++endif ++ ++# Kernel Makefile doesn't always know the exact kernel version, so we ++# get it from the kernel headers instead and pass it to make. ++VERSION_H := $(KBUILD)/include/generated/utsrelease.h ++ifeq (,$(wildcard $(VERSION_H))) ++VERSION_H := $(KBUILD)/include/linux/utsrelease.h ++endif ++ifeq (,$(wildcard $(VERSION_H))) ++VERSION_H := $(KBUILD)/include/linux/version.h ++endif ++ifeq (,$(wildcard $(VERSION_H))) ++$(error Please run 'make modules_prepare' in $(KBUILD)) ++endif ++ ++KVERS := $(shell sed -ne 's/"//g;s/^\#define UTS_RELEASE //p' $(VERSION_H)) ++ ++ifeq (,$(KVERS)) ++$(error Cannot find UTS_RELEASE in $(VERSION_H), please report) ++endif ++ ++INST_DIR = /lib/modules/$(KVERS)/misc ++ ++SRC_DIR=$(shell pwd) ++ ++include $(KCONFIG) ++ ++# returns of structs and unions in registers when possible, like Windows ++EXTRA_CFLAGS += -freg-struct-return ++ ++# to produce debug trace, add option "DEBUG=" where is 1 to 6 ++ifdef DEBUG ++EXTRA_CFLAGS += -DDEBUG=$(DEBUG) -g ++endif ++ ++# to debug timers, add option "TIMER_DEBUG=1" ++ifdef TIMER_DEBUG ++EXTRA_CFLAGS += -DTIMER_DEBUG ++endif ++ ++# to debug event layer, add option "EVENT_DEBUG=1" ++ifdef EVENT_DEBUG ++EXTRA_CFLAGS += -DEVENT_DEBUG ++endif ++ ++# to debug USB layer, add option "USB_DEBUG=1" ++ifdef USB_DEBUG ++EXTRA_CFLAGS += -DUSB_DEBUG ++endif ++ ++# to debug I/O layer, add option "IO_DEBUG=1" ++ifdef IO_DEBUG ++EXTRA_CFLAGS += -DIO_DEBUG ++endif ++ ++# to debug worker threads, add option "WORK_DEBUG=1" ++ifdef WORK_DEBUG ++EXTRA_CFLAGS += -DWORK_DEBUG ++endif ++ ++# to debug memory allocation, add option "ALLOC_DEBUG=" where is 1 or 2 ++ifdef ALLOC_DEBUG ++EXTRA_CFLAGS += -DALLOC_DEBUG=$(ALLOC_DEBUG) ++endif ++ ++OBJS = crt.o hal.o iw_ndis.o loader.o ndis.o ntoskernel.o ntoskernel_io.o \ ++ pe_linker.o pnp.o proc.o rtl.o wrapmem.o wrapndis.o wrapper.o ++ ++EXPORT_SRCS = crt.c hal.c ndis.c ntoskernel.c ntoskernel_io.c rtl.c ++ ++STUB_SRCS = crt.c hal.c ndis.c ntoskernel.c ntoskernel_io.c \ ++ pnp.c rtl.c wrapndis.c ++ ++ ++# By default, USB layer is compiled in if USB support is in kernel; ++# to disable USB support in ndiswrapper even if USB support is in kernel, ++# add option "DISABLE_USB=1" ++ifndef DISABLE_USB ++ifeq ($(CONFIG_USB),y) ++ENABLE_USB = 1 ++endif ++ifeq ($(CONFIG_USB),m) ++ENABLE_USB = 1 ++endif ++endif ++ ++ifdef ENABLE_USB ++EXPORT_SRCS += usb.c ++STUB_SRCS += usb.c ++OBJS += usb.o ++EXTRA_CFLAGS += -DENABLE_USB ++endif ++ ++ifdef WRAP_WQ ++EXTRA_CFLAGS += -DWRAP_WQ ++OBJS += workqueue.o ++endif ++ ++ ++all: config_check modules ++ ++# generate exports symbol table from C files ++quiet_cmd_mkexport = MKEXPORT $@ ++cmd_mkexport = $(SHELL) $(obj)/mkexport.sh $< $@ ++ ++extra-y += $(EXPORT_SRCS:.c=_exports.h) ++%_exports.h: %.c $(obj)/mkexport.sh FORCE ++ $(call if_changed,mkexport) ++ ++$(addprefix $(obj)/,$(EXPORT_SRCS:.c=.o)): %.o: %_exports.h ++ ++ifeq ($(CONFIG_X86_64),y) ++quiet_cmd_mkstubs = MKSTUBS $@ ++cmd_mkstubs = $(SHELL) $(obj)/mkstubs.sh $(addprefix $(src)/,$(STUB_SRCS)) >$@ ++ ++extra-y += win2lin_stubs.h ++$(obj)/win2lin_stubs.h: $(addprefix $(src)/,$(STUB_SRCS)) FORCE ++ $(call if_changed,mkstubs) ++ ++$(obj)/win2lin_stubs.o: $(obj)/win2lin_stubs.h ++OBJS += win2lin_stubs.o lin2win.o ++else ++OBJS += divdi3.o ++endif ++ ++MODULE := $(MODNAME).ko ++obj-m := $(MODNAME).o ++ ++$(MODNAME)-objs := $(OBJS) ++ ++ ++config_check: ++ @if [ -z "$(CONFIG_WIRELESS_EXT)$(CONFIG_NET_RADIO)" ]; then \ ++ echo; echo; \ ++ echo "*** WARNING: This kernel lacks wireless extensions."; \ ++ echo "Wireless drivers will not work properly."; \ ++ echo; echo; \ ++ fi ++ @if [ -z "$(CONFIG_X86_64)" ] && [ -n "$(CONFIG_4KSTACKS)" ]; then \ ++ echo; echo; \ ++ echo "*** WARNING: This kernel uses 4K stack size option"; \ ++ echo "(CONFIG_4KSTACKS); many Windows drivers will not work"; \ ++ echo "with this option enabled. Disable CONFIG_4KSTACKS"; \ ++ echo "in kernel's .config file, recompile and install kernel"; \ ++ echo; echo; \ ++ fi ++ ++modules: ++ $(MAKE) -C $(KBUILD) M=$(SRC_DIR) ++ ++$(MODULE): ++ $(MAKE) modules ++ ++clean: ++ rm -f *.o *.ko .*.cmd *.mod.c *.symvers modules.order *~ .\#* ++ rm -f *_exports.h win2lin_stubs.h ++ rm -rf .tmp_versions ++ ++install: config_check $(MODULE) ++ @/sbin/modinfo $(MODULE) | grep -q "^vermagic: *$(KVERS) " || \ ++ { echo "$(MODULE)" is not for Linux $(KVERS); exit 1; } ++ mkdir -p -m 755 $(DESTDIR)$(INST_DIR) ++ install -m 0644 $(MODULE) $(DESTDIR)$(INST_DIR) ++ifndef DESTDIR ++ -/sbin/depmod -a $(KVERS) ++endif ++ ++uninstall: ++ rm -f $(DESTDIR)$(INST_DIR)/$(MODULE) ++ifndef DESTDIR ++ -/sbin/depmod -a $(KVERS) ++endif ++ ++dist: ++ @for file in $(DISTFILES); do \ ++ cp $$file $(distdir)/$$file || exit 1; \ ++ done ++ ++.PHONY: all modules clean install config_check dist +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/mkexport.sh linux-4.6-rc6-ndis/3rdparty/ndiswrapper/mkexport.sh +--- linux-4.6-rc6/3rdparty/ndiswrapper/mkexport.sh 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/mkexport.sh 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,42 @@ ++#! /bin/sh ++ ++# Generate exports symbol table from C files ++ ++input="$1" ++output="$2" ++exports=$(basename "$output" .h) ++exec >"$output" ++ ++echo "/* automatically generated from src */"; ++ ++sed -n -e '/^\(wstdcall\|wfastcall\|noregparm\|regparm3\|__attribute__\)/{ ++:more ++N ++s/\([^{]\)$/\1/ ++t more ++s/\n{$/;/ ++p ++}' $input ++ ++echo "#ifdef CONFIG_X86_64"; ++ ++sed -n \ ++ -e 's/.*WIN_FUNC(\([^\,]\+\) *\, *\([0-9]\+\)).*/'\ ++'WIN_FUNC_DECL(\1, \2)/p' \ ++ -e 's/.*WIN_FUNC_PTR(\([^\,]\+\) *\, *\([0-9]\+\)).*/'\ ++'WIN_FUNC_DECL(\1, \2)/p' $input | sort -u ++ ++echo "#endif" ++echo "extern struct wrap_export $exports[];" ++echo "struct wrap_export $exports[] = {" ++ ++sed -n \ ++ -e 's/.*WIN_FUNC(_win_\([^\,]\+\) *\, *\([0-9]\+\)).*/'\ ++' WIN_WIN_SYMBOL(\1, \2),/p' \ ++ -e 's/.*WIN_FUNC(\([^\,]\+\) *\, *\([0-9]\+\)).*/'\ ++' WIN_SYMBOL(\1, \2),/p' \ ++ -e 's/.*WIN_SYMBOL_MAP(\("[^"]\+"\)[ ,\n]\+\([^)]\+\)).*/'\ ++' {\1, (generic_func)\2},/p' $input | sort -u ++ ++echo " {NULL, NULL}" ++echo "};" +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/mkstubs.sh linux-4.6-rc6-ndis/3rdparty/ndiswrapper/mkstubs.sh +--- linux-4.6-rc6/3rdparty/ndiswrapper/mkstubs.sh 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/mkstubs.sh 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,12 @@ ++#! /bin/sh ++ ++for file in "$@"; do ++ echo ++ echo "# automatically generated from $file" ++ sed -n \ ++ -e 's/.*WIN_FUNC(\([^\,]\+\) *\, *\([0-9]\+\)).*/\ ++ win2lin(\1, \2)/p' \ ++ -e 's/.*WIN_FUNC_PTR(\([^\,]\+\) *\, *\([0-9]\+\)).*/\ ++ win2lin(\1, \2)/p' \ ++ $file | sed -e 's/[ \t ]\+//' | sort -u; \ ++done +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/ndis.c linux-4.6-rc6-ndis/3rdparty/ndiswrapper/ndis.c +--- linux-4.6-rc6/3rdparty/ndiswrapper/ndis.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/ndis.c 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,3025 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include "ndis.h" ++#include "iw_ndis.h" ++#include "wrapndis.h" ++#include "pnp.h" ++#include "loader.h" ++#include ++#include ++#include "ndis_exports.h" ++ ++#define MAX_ALLOCATED_NDIS_PACKETS TX_RING_SIZE ++#define MAX_ALLOCATED_NDIS_BUFFERS TX_RING_SIZE ++ ++static struct work_struct ndis_work; ++static struct nt_list ndis_work_list; ++static spinlock_t ndis_work_list_lock; ++ ++struct workqueue_struct *ndis_wq; ++ ++static void *ndis_get_routine_address(char *name); ++ ++wstdcall void WIN_FUNC(NdisInitializeWrapper,4) ++ (void **driver_handle, struct driver_object *driver, ++ struct unicode_string *reg_path, void *unused) ++{ ++ ENTER1("handle: %p, driver: %p", driver_handle, driver); ++ *driver_handle = driver; ++ EXIT1(return); ++} ++ ++wstdcall void WIN_FUNC(NdisTerminateWrapper,2) ++ (struct device_object *dev_obj, void *system_specific) ++{ ++ EXIT1(return); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterMiniport,3) ++ (struct driver_object *drv_obj, struct miniport *mp, UINT length) ++{ ++ int min_length; ++ struct wrap_driver *wrap_driver; ++ struct ndis_driver *ndis_driver; ++ ++ min_length = ((char *)&mp->co_create_vc) - ((char *)mp); ++ ++ ENTER1("%p %p %d", drv_obj, mp, length); ++ ++ if (mp->major_version < 4) { ++ ERROR("Driver is using ndis version %d which is too old.", ++ mp->major_version); ++ EXIT1(return NDIS_STATUS_BAD_VERSION); ++ } ++ ++ if (length < min_length) { ++ ERROR("Characteristics length %d is too small", length); ++ EXIT1(return NDIS_STATUS_BAD_CHARACTERISTICS); ++ } ++ ++ TRACE1("%d.%d, %d, %u", mp->major_version, mp->minor_version, length, ++ (u32)sizeof(struct miniport)); ++ wrap_driver = IoGetDriverObjectExtension(drv_obj, ++ (void *)WRAP_DRIVER_CLIENT_ID); ++ if (!wrap_driver) { ++ ERROR("couldn't get wrap_driver"); ++ EXIT1(return NDIS_STATUS_RESOURCES); ++ } ++ if (IoAllocateDriverObjectExtension( ++ drv_obj, (void *)NDIS_DRIVER_CLIENT_ID, ++ sizeof(*ndis_driver), (void **)&ndis_driver) != ++ STATUS_SUCCESS) ++ EXIT1(return NDIS_STATUS_RESOURCES); ++ wrap_driver->ndis_driver = ndis_driver; ++ TRACE1("driver: %p", ndis_driver); ++ memcpy(&ndis_driver->mp, mp, min_t(int, sizeof(*mp), length)); ++ ++ DBG_BLOCK(2) { ++ int i; ++ void **func; ++ char *mp_funcs[] = { ++ "queryinfo", "reconfig", "reset", "send", "setinfo", ++ "tx_data", "return_packet", "send_packets", ++ "alloc_complete", "co_create_vc", "co_delete_vc", ++ "co_activate_vc", "co_deactivate_vc", ++ "co_send_packets", "co_request", "cancel_send_packets", ++ "pnp_event_notify", "shutdown", ++ }; ++ func = (void **)&ndis_driver->mp.queryinfo; ++ for (i = 0; i < ARRAY_SIZE(mp_funcs); i++) ++ TRACE0("function '%s' is at %p", mp_funcs[i], func[i]); ++ } ++ EXIT1(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterDevice,6) ++ (struct driver_object *drv_obj, struct unicode_string *dev_name, ++ struct unicode_string *link, void **funcs, ++ struct device_object **dev_obj, void **dev_obj_handle) ++{ ++ NTSTATUS status; ++ struct device_object *tmp; ++ int i; ++ ++ ENTER1("%p, %p, %p", drv_obj, dev_name, link); ++ status = IoCreateDevice(drv_obj, 0, dev_name, FILE_DEVICE_NETWORK, 0, ++ FALSE, &tmp); ++ ++ if (status != STATUS_SUCCESS) ++ EXIT1(return NDIS_STATUS_RESOURCES); ++ if (link) ++ status = IoCreateSymbolicLink(link, dev_name); ++ if (status != STATUS_SUCCESS) { ++ IoDeleteDevice(tmp); ++ EXIT1(return NDIS_STATUS_RESOURCES); ++ } ++ ++ *dev_obj = tmp; ++ *dev_obj_handle = *dev_obj; ++ for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) ++ if (funcs[i] && i != IRP_MJ_PNP && i != IRP_MJ_POWER) { ++ drv_obj->major_func[i] = funcs[i]; ++ TRACE1("mj_fn for 0x%x is at %p", i, funcs[i]); ++ } ++ EXIT1(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMDeregisterDevice,1) ++ (struct device_object *dev_obj) ++{ ++ ENTER2("%p", dev_obj); ++ IoDeleteDevice(dev_obj); ++ return NDIS_STATUS_SUCCESS; ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisAllocateMemoryWithTag,3) ++ (void **dest, UINT length, ULONG tag) ++{ ++ void *addr; ++ ++ assert_irql(_irql_ <= DISPATCH_LEVEL); ++ addr = ExAllocatePoolWithTag(NonPagedPool, length, tag); ++ TRACE4("%p", addr); ++ if (addr) { ++ *dest = addr; ++ EXIT4(return NDIS_STATUS_SUCCESS); ++ } else ++ EXIT4(return NDIS_STATUS_FAILURE); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisAllocateMemory,4) ++ (void **dest, UINT length, UINT flags, NDIS_PHY_ADDRESS highest_address) ++{ ++ return NdisAllocateMemoryWithTag(dest, length, 0); ++} ++ ++/* length_tag is either length or tag, depending on if ++ * NdisAllocateMemory or NdisAllocateMemoryTag is used to allocate ++ * memory */ ++wstdcall void WIN_FUNC(NdisFreeMemory,3) ++ (void *addr, UINT length_tag, UINT flags) ++{ ++ TRACE4("%p", addr); ++ ExFreePool(addr); ++} ++ ++noregparm void WIN_FUNC(NdisWriteErrorLogEntry,12) ++ (struct driver_object *drv_obj, ULONG error, ULONG count, ...) ++{ ++ va_list args; ++ int i; ++ ULONG code; ++ ++ va_start(args, count); ++ ERROR("log: %08X, count: %d, return_address: %p", ++ error, count, __builtin_return_address(0)); ++ for (i = 0; i < count; i++) { ++ code = va_arg(args, ULONG); ++ ERROR("code: 0x%x", code); ++ } ++ va_end(args); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisOpenConfiguration,3) ++ (NDIS_STATUS *status, struct ndis_mp_block **conf_handle, ++ struct ndis_mp_block *handle) ++{ ++ ENTER2("%p", conf_handle); ++ *conf_handle = handle; ++ *status = NDIS_STATUS_SUCCESS; ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisOpenProtocolConfiguration,3) ++ (NDIS_STATUS *status, void **confhandle, ++ struct unicode_string *section) ++{ ++ ENTER2("%p", confhandle); ++ *status = NDIS_STATUS_SUCCESS; ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisOpenConfigurationKeyByName,4) ++ (NDIS_STATUS *status, void *handle, ++ struct unicode_string *key, void **subkeyhandle) ++{ ++ struct ansi_string ansi; ++ ENTER2(""); ++ if (RtlUnicodeStringToAnsiString(&ansi, key, TRUE) == STATUS_SUCCESS) { ++ TRACE2("%s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ *subkeyhandle = handle; ++ *status = NDIS_STATUS_SUCCESS; ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisOpenConfigurationKeyByIndex,5) ++ (NDIS_STATUS *status, void *handle, ULONG index, ++ struct unicode_string *key, void **subkeyhandle) ++{ ++ ENTER2("%u", index); ++// *subkeyhandle = handle; ++ *status = NDIS_STATUS_FAILURE; ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisCloseConfiguration,1) ++ (void *handle) ++{ ++ /* instead of freeing all configuration parameters as we are ++ * supposed to do here, we free them when the device is ++ * removed */ ++ ENTER2("%p", handle); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisOpenFile,5) ++ (NDIS_STATUS *status, struct wrap_bin_file **file, ++ UINT *filelength, struct unicode_string *filename, ++ NDIS_PHY_ADDRESS highest_address) ++{ ++ struct ansi_string ansi; ++ struct wrap_bin_file *bin_file; ++ ++ ENTER2("%p, %d, %llx, %p", status, *filelength, highest_address, *file); ++ if (RtlUnicodeStringToAnsiString(&ansi, filename, TRUE) != ++ STATUS_SUCCESS) { ++ *status = NDIS_STATUS_RESOURCES; ++ EXIT2(return); ++ } ++ TRACE2("%s", ansi.buf); ++ bin_file = get_bin_file(ansi.buf); ++ if (bin_file) { ++ *file = bin_file; ++ *filelength = bin_file->size; ++ *status = NDIS_STATUS_SUCCESS; ++ } else ++ *status = NDIS_STATUS_FILE_NOT_FOUND; ++ ++ RtlFreeAnsiString(&ansi); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisMapFile,3) ++ (NDIS_STATUS *status, void **mappedbuffer, struct wrap_bin_file *file) ++{ ++ ENTER2("%p", file); ++ ++ if (!file) { ++ *status = NDIS_STATUS_ALREADY_MAPPED; ++ EXIT2(return); ++ } ++ ++ *status = NDIS_STATUS_SUCCESS; ++ *mappedbuffer = file->data; ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisUnmapFile,1) ++ (struct wrap_bin_file *file) ++{ ++ ENTER2("%p", file); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisCloseFile,1) ++ (struct wrap_bin_file *file) ++{ ++ ENTER2("%p", file); ++ free_bin_file(file); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisGetSystemUpTime,1) ++ (ULONG *ms) ++{ ++ *ms = 1000 * jiffies / HZ; ++ EXIT5(return); ++} ++ ++wstdcall ULONG WIN_FUNC(NDIS_BUFFER_TO_SPAN_PAGES,1) ++ (ndis_buffer *buffer) ++{ ++ ULONG n, length; ++ ++ if (buffer == NULL) ++ EXIT2(return 0); ++ if (MmGetMdlByteCount(buffer) == 0) ++ EXIT2(return 1); ++ ++ length = MmGetMdlByteCount(buffer); ++ n = SPAN_PAGES(MmGetMdlVirtualAddress(buffer), length); ++ TRACE4("%p, %p, %d, %d", buffer->startva, buffer->mappedsystemva, ++ length, n); ++ EXIT3(return n); ++} ++ ++wstdcall void WIN_FUNC(NdisGetBufferPhysicalArraySize,2) ++ (ndis_buffer *buffer, UINT *arraysize) ++{ ++ ENTER3("%p", buffer); ++ *arraysize = NDIS_BUFFER_TO_SPAN_PAGES(buffer); ++ EXIT3(return); ++} ++ ++static struct ndis_configuration_parameter * ++ndis_encode_setting(struct wrap_device_setting *setting, ++ enum ndis_parameter_type type) ++{ ++ struct ansi_string ansi; ++ struct ndis_configuration_parameter *param; ++ ++ param = setting->encoded; ++ if (param) { ++ if (param->type == type) ++ EXIT2(return param); ++ if (param->type == NdisParameterString) ++ RtlFreeUnicodeString(¶m->data.string); ++ setting->encoded = NULL; ++ } else ++ param = ExAllocatePoolWithTag(NonPagedPool, sizeof(*param), 0); ++ if (!param) { ++ ERROR("couldn't allocate memory"); ++ return NULL; ++ } ++ switch (type) { ++ case NdisParameterInteger: ++ param->data.integer = simple_strtol(setting->value, NULL, 0); ++ TRACE2("0x%x", param->data.integer); ++ break; ++ case NdisParameterHexInteger: ++ param->data.integer = simple_strtol(setting->value, NULL, 16); ++ TRACE2("0x%x", param->data.integer); ++ break; ++ case NdisParameterString: ++ RtlInitAnsiString(&ansi, setting->value); ++ TRACE2("'%s'", ansi.buf); ++ if (RtlAnsiStringToUnicodeString(¶m->data.string, ++ &ansi, TRUE)) { ++ ExFreePool(param); ++ EXIT2(return NULL); ++ } ++ break; ++ case NdisParameterBinary: ++ param->data.integer = simple_strtol(setting->value, NULL, 2); ++ TRACE2("0x%x", param->data.integer); ++ break; ++ default: ++ ERROR("unknown type: %d", type); ++ ExFreePool(param); ++ return NULL; ++ } ++ param->type = type; ++ setting->encoded = param; ++ EXIT2(return param); ++} ++ ++static int ndis_decode_setting(struct wrap_device_setting *setting, ++ struct ndis_configuration_parameter *param) ++{ ++ struct ansi_string ansi; ++ struct ndis_configuration_parameter *prev; ++ ++ ENTER2("%p, %p", setting, param); ++ prev = setting->encoded; ++ if (prev && prev->type == NdisParameterString) { ++ RtlFreeUnicodeString(&prev->data.string); ++ setting->encoded = NULL; ++ } ++ switch (param->type) { ++ case NdisParameterInteger: ++ snprintf(setting->value, MAX_SETTING_VALUE_LEN, "%u", ++ param->data.integer); ++ break; ++ case NdisParameterHexInteger: ++ snprintf(setting->value, MAX_SETTING_VALUE_LEN, "%x", ++ param->data.integer); ++ break; ++ case NdisParameterString: ++ ansi.buf = setting->value; ++ ansi.max_length = MAX_SETTING_VALUE_LEN; ++ if ((RtlUnicodeStringToAnsiString(&ansi, ¶m->data.string, ++ FALSE) != STATUS_SUCCESS) ++ || ansi.length >= MAX_SETTING_VALUE_LEN) { ++ EXIT1(return -1); ++ } ++ if (ansi.length == ansi.max_length) ++ ansi.length--; ++ setting->value[ansi.length] = 0; ++ break; ++ default: ++ TRACE2("unknown setting type: %d", param->type); ++ return -1; ++ } ++ TRACE2("setting changed %s='%s', %d", setting->name, setting->value, ++ ansi.length); ++ return 0; ++} ++ ++static int read_setting(struct nt_list *setting_list, char *keyname, int length, ++ struct ndis_configuration_parameter **param, ++ enum ndis_parameter_type type) ++{ ++ struct wrap_device_setting *setting; ++ mutex_lock(&loader_mutex); ++ nt_list_for_each_entry(setting, setting_list, list) { ++ if (strncasecmp(keyname, setting->name, length) == 0) { ++ TRACE2("setting %s='%s'", keyname, setting->value); ++ mutex_unlock(&loader_mutex); ++ *param = ndis_encode_setting(setting, type); ++ if (*param) ++ EXIT2(return 0); ++ else ++ EXIT2(return -1); ++ } ++ } ++ mutex_unlock(&loader_mutex); ++ EXIT2(return -1); ++} ++ ++wstdcall void WIN_FUNC(NdisReadConfiguration,5) ++ (NDIS_STATUS *status, struct ndis_configuration_parameter **param, ++ struct ndis_mp_block *nmb, struct unicode_string *key, ++ enum ndis_parameter_type type) ++{ ++ struct ansi_string ansi; ++ int ret; ++ ++ ENTER2("nmb: %p", nmb); ++ ret = RtlUnicodeStringToAnsiString(&ansi, key, TRUE); ++ if (ret != STATUS_SUCCESS || ansi.buf == NULL) { ++ *param = NULL; ++ *status = NDIS_STATUS_FAILURE; ++ RtlFreeAnsiString(&ansi); ++ EXIT2(return); ++ } ++ TRACE2("%d, %s", type, ansi.buf); ++ ++ if (read_setting(&nmb->wnd->wd->settings, ansi.buf, ++ ansi.length, param, type) == 0 || ++ read_setting(&nmb->wnd->wd->driver->settings, ansi.buf, ++ ansi.length, param, type) == 0) ++ *status = NDIS_STATUS_SUCCESS; ++ else { ++ TRACE2("setting %s not found (type:%d)", ansi.buf, type); ++ *status = NDIS_STATUS_FAILURE; ++ } ++ RtlFreeAnsiString(&ansi); ++ EXIT2(return); ++ ++} ++ ++wstdcall void WIN_FUNC(NdisWriteConfiguration,4) ++ (NDIS_STATUS *status, struct ndis_mp_block *nmb, ++ struct unicode_string *key, struct ndis_configuration_parameter *param) ++{ ++ struct ansi_string ansi; ++ char *keyname; ++ struct wrap_device_setting *setting; ++ ++ ENTER2("nmb: %p", nmb); ++ if (RtlUnicodeStringToAnsiString(&ansi, key, TRUE)) { ++ *status = NDIS_STATUS_FAILURE; ++ EXIT2(return); ++ } ++ keyname = ansi.buf; ++ TRACE2("%s", keyname); ++ ++ mutex_lock(&loader_mutex); ++ nt_list_for_each_entry(setting, &nmb->wnd->wd->settings, list) { ++ if (strncasecmp(keyname, setting->name, ansi.length) == 0) { ++ mutex_unlock(&loader_mutex); ++ if (ndis_decode_setting(setting, param)) ++ *status = NDIS_STATUS_FAILURE; ++ else ++ *status = NDIS_STATUS_SUCCESS; ++ RtlFreeAnsiString(&ansi); ++ EXIT2(return); ++ } ++ } ++ mutex_unlock(&loader_mutex); ++ setting = kzalloc(sizeof(*setting), GFP_KERNEL); ++ if (setting) { ++ if (ansi.length == ansi.max_length) ++ ansi.length--; ++ memcpy(setting->name, keyname, ansi.length); ++ setting->name[ansi.length] = 0; ++ if (ndis_decode_setting(setting, param)) ++ *status = NDIS_STATUS_FAILURE; ++ else { ++ *status = NDIS_STATUS_SUCCESS; ++ mutex_lock(&loader_mutex); ++ InsertTailList(&nmb->wnd->wd->settings, &setting->list); ++ mutex_unlock(&loader_mutex); ++ } ++ } else ++ *status = NDIS_STATUS_RESOURCES; ++ ++ RtlFreeAnsiString(&ansi); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisReadNetworkAddress,4) ++ (NDIS_STATUS *status, void **addr, UINT *len, ++ struct ndis_mp_block *nmb) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ struct ndis_configuration_parameter *param; ++ struct unicode_string key; ++ struct ansi_string ansi; ++ typeof(wnd->mac) mac; ++ int i, ret; ++ ++ ENTER2("%p", nmb); ++ RtlInitAnsiString(&ansi, "NetworkAddress"); ++ *status = NDIS_STATUS_FAILURE; ++ if (RtlAnsiStringToUnicodeString(&key, &ansi, TRUE) != STATUS_SUCCESS) ++ EXIT1(return); ++ ++ NdisReadConfiguration(&ret, ¶m, nmb, &key, NdisParameterString); ++ RtlFreeUnicodeString(&key); ++ if (ret != NDIS_STATUS_SUCCESS) ++ EXIT1(return); ++ ret = RtlUnicodeStringToAnsiString(&ansi, ¶m->data.string, TRUE); ++ if (ret != STATUS_SUCCESS) ++ EXIT1(return); ++ ++ i = 0; ++ if (ansi.length >= 2 * sizeof(mac)) { ++ for (i = 0; i < sizeof(mac); i++) { ++ char c[3]; ++ int x; ++ c[0] = ansi.buf[i*2]; ++ c[1] = ansi.buf[i*2+1]; ++ c[2] = 0; ++ ret = sscanf(c, "%x", &x); ++ if (ret != 1) ++ break; ++ mac[i] = x; ++ } ++ } ++ TRACE2("%s, %d, " MACSTR, ansi.buf, i, MAC2STR(mac)); ++ RtlFreeAnsiString(&ansi); ++ if (i == sizeof(mac)) { ++ memcpy(wnd->mac, mac, sizeof(wnd->mac)); ++ *len = sizeof(mac); ++ *addr = wnd->mac; ++ *status = NDIS_STATUS_SUCCESS; ++ } ++ EXIT1(return); ++} ++ ++wstdcall void WIN_FUNC(NdisInitializeString,2) ++ (struct unicode_string *dest, UCHAR *src) ++{ ++ struct ansi_string ansi; ++ ++ ENTER2(""); ++ if (src == NULL) { ++ dest->length = dest->max_length = 0; ++ dest->buf = NULL; ++ } else { ++ RtlInitAnsiString(&ansi, src); ++ /* the string is freed with NdisFreeMemory */ ++ RtlAnsiStringToUnicodeString(dest, &ansi, TRUE); ++ } ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisInitAnsiString,2) ++ (struct ansi_string *dst, CHAR *src) ++{ ++ RtlInitAnsiString(dst, src); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisInitUnicodeString,2) ++ (struct unicode_string *dest, const wchar_t *src) ++{ ++ RtlInitUnicodeString(dest, src); ++ return; ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisAnsiStringToUnicodeString,2) ++ (struct unicode_string *dst, struct ansi_string *src) ++{ ++ ENTER2(""); ++ if (dst == NULL || src == NULL) ++ EXIT2(return NDIS_STATUS_FAILURE); ++ if (RtlAnsiStringToUnicodeString(dst, src, FALSE) == STATUS_SUCCESS) ++ return NDIS_STATUS_SUCCESS; ++ else ++ return NDIS_STATUS_FAILURE; ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisUnicodeStringToAnsiString,2) ++ (struct ansi_string *dst, struct unicode_string *src) ++{ ++ ENTER2(""); ++ if (dst == NULL || src == NULL) ++ EXIT2(return NDIS_STATUS_FAILURE); ++ if (RtlUnicodeStringToAnsiString(dst, src, FALSE) == STATUS_SUCCESS) ++ return NDIS_STATUS_SUCCESS; ++ else ++ return NDIS_STATUS_FAILURE; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(NdisUpcaseUnicodeString,2) ++ (struct unicode_string *dst, struct unicode_string *src) ++{ ++ EXIT2(return RtlUpcaseUnicodeString(dst, src, FALSE)); ++} ++ ++wstdcall void WIN_FUNC(NdisMSetAttributesEx,5) ++ (struct ndis_mp_block *nmb, void *mp_ctx, ++ UINT hangcheck_interval, UINT attributes, ULONG adaptertype) ++{ ++ struct ndis_device *wnd; ++ ++ ENTER1("%p, %p, %d, %08x, %d", nmb, mp_ctx, hangcheck_interval, ++ attributes, adaptertype); ++ wnd = nmb->wnd; ++ nmb->mp_ctx = mp_ctx; ++ wnd->attributes = attributes; ++ ++ if ((attributes & NDIS_ATTRIBUTE_BUS_MASTER) && ++ wrap_is_pci_bus(wnd->wd->dev_bus)) ++ pci_set_master(wnd->wd->pci.pdev); ++ ++ if (hangcheck_interval > 0) ++ wnd->hangcheck_interval = 2 * hangcheck_interval * HZ; ++ else ++ wnd->hangcheck_interval = 2 * HZ; ++ ++ EXIT1(return); ++} ++ ++wstdcall ULONG WIN_FUNC(NdisReadPciSlotInformation,5) ++ (struct ndis_mp_block *nmb, ULONG slot, ++ ULONG offset, char *buf, ULONG len) ++{ ++ struct wrap_device *wd = nmb->wnd->wd; ++ ULONG i; ++ if (!wrap_is_pci_bus(wd->dev_bus)) { ++ ERROR("used on a non-PCI device"); ++ return 0; ++ } ++ for (i = 0; i < len; i++) ++ if (pci_read_config_byte(wd->pci.pdev, offset + i, &buf[i]) != ++ PCIBIOS_SUCCESSFUL) ++ break; ++ DBG_BLOCK(2) { ++ if (i != len) ++ WARNING("%u, %u", i, len); ++ } ++ return i; ++} ++ ++wstdcall ULONG WIN_FUNC(NdisImmediateReadPciSlotInformation,5) ++ (struct ndis_mp_block *nmb, ULONG slot, ++ ULONG offset, char *buf, ULONG len) ++{ ++ return NdisReadPciSlotInformation(nmb, slot, offset, buf, len); ++} ++ ++wstdcall ULONG WIN_FUNC(NdisWritePciSlotInformation,5) ++ (struct ndis_mp_block *nmb, ULONG slot, ++ ULONG offset, char *buf, ULONG len) ++{ ++ struct wrap_device *wd = nmb->wnd->wd; ++ ULONG i; ++ if (!wrap_is_pci_bus(wd->dev_bus)) { ++ ERROR("used on a non-PCI device"); ++ return 0; ++ } ++ for (i = 0; i < len; i++) ++ if (pci_write_config_byte(wd->pci.pdev, offset + i, buf[i]) != ++ PCIBIOS_SUCCESSFUL) ++ break; ++ DBG_BLOCK(2) { ++ if (i != len) ++ WARNING("%u, %u", i, len); ++ } ++ return i; ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterIoPortRange,4) ++ (void **virt, struct ndis_mp_block *nmb, UINT start, UINT len) ++{ ++ ENTER3("%08x %08x", start, len); ++ *virt = (void *)(ULONG_PTR)start; ++ return NDIS_STATUS_SUCCESS; ++} ++ ++wstdcall void WIN_FUNC(NdisMDeregisterIoPortRange,4) ++ (struct ndis_mp_block *nmb, UINT start, UINT len, void* virt) ++{ ++ ENTER1("%08x %08x", start, len); ++} ++ ++wstdcall void WIN_FUNC(NdisReadPortUchar,3) ++ (struct ndis_mp_block *nmb, ULONG port, char *data) ++{ ++ *data = inb(port); ++} ++ ++wstdcall void WIN_FUNC(NdisImmediateReadPortUchar,3) ++ (struct ndis_mp_block *nmb, ULONG port, char *data) ++{ ++ *data = inb(port); ++} ++ ++wstdcall void WIN_FUNC(NdisWritePortUchar,3) ++ (struct ndis_mp_block *nmb, ULONG port, char data) ++{ ++ outb(data, port); ++} ++ ++wstdcall void WIN_FUNC(NdisImmediateWritePortUchar,3) ++ (struct ndis_mp_block *nmb, ULONG port, char data) ++{ ++ outb(data, port); ++} ++ ++wstdcall void WIN_FUNC(NdisMQueryAdapterResources,4) ++ (NDIS_STATUS *status, struct ndis_mp_block *nmb, ++ NDIS_RESOURCE_LIST *resource_list, UINT *size) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ NDIS_RESOURCE_LIST *list; ++ UINT resource_length; ++ ++ list = &wnd->wd->resource_list->list->partial_resource_list; ++ resource_length = sizeof(struct cm_partial_resource_list) + ++ sizeof(struct cm_partial_resource_descriptor) * ++ (list->count - 1); ++ TRACE2("%p, %p,%d (%d), %p %d %d", wnd, resource_list, *size, ++ resource_length, &list->partial_descriptors[list->count-1], ++ list->partial_descriptors[list->count-1].u.interrupt.level, ++ list->partial_descriptors[list->count-1].u.interrupt.vector); ++ if (*size < sizeof(*list)) { ++ *size = resource_length; ++ *status = NDIS_STATUS_BUFFER_TOO_SHORT; ++ } else { ++ ULONG count; ++ if (*size >= resource_length) { ++ *size = resource_length; ++ count = list->count; ++ } else { ++ UINT n = sizeof(*list); ++ count = 1; ++ while (count++ < list->count && n < *size) ++ n += sizeof(list->partial_descriptors); ++ *size = n; ++ } ++ memcpy(resource_list, list, *size); ++ resource_list->count = count; ++ *status = NDIS_STATUS_SUCCESS; ++ } ++ EXIT2(return); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMPciAssignResources,3) ++ (struct ndis_mp_block *nmb, ULONG slot_number, ++ NDIS_RESOURCE_LIST **resources) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ++ ENTER2("%p, %p", wnd, wnd->wd->resource_list); ++ *resources = &wnd->wd->resource_list->list->partial_resource_list; ++ EXIT2(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMMapIoSpace,4) ++ (void __iomem **virt, struct ndis_mp_block *nmb, ++ NDIS_PHY_ADDRESS phy_addr, UINT len) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ++ ENTER2("%llx, %d", phy_addr, len); ++ *virt = MmMapIoSpace(phy_addr, len, MmCached); ++ if (*virt == NULL) { ++ ERROR("ioremap failed"); ++ EXIT2(return NDIS_STATUS_FAILURE); ++ } ++ wnd->mem_start = phy_addr; ++ wnd->mem_end = phy_addr + len; ++ TRACE2("%p", *virt); ++ EXIT2(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(NdisMUnmapIoSpace,3) ++ (struct ndis_mp_block *nmb, void __iomem *virt, UINT len) ++{ ++ ENTER2("%p, %d", virt, len); ++ MmUnmapIoSpace(virt, len); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisAllocateSpinLock,1) ++ (struct ndis_spinlock *lock) ++{ ++ TRACE4("lock %p, %p", lock, &lock->klock); ++ KeInitializeSpinLock(&lock->klock); ++ lock->irql = PASSIVE_LEVEL; ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisFreeSpinLock,1) ++ (struct ndis_spinlock *lock) ++{ ++ TRACE4("lock %p, %p", lock, &lock->klock); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisAcquireSpinLock,1) ++ (struct ndis_spinlock *lock) ++{ ++ ENTER6("lock %p, %p", lock, &lock->klock); ++// assert_irql(_irql_ <= DISPATCH_LEVEL); ++ lock->irql = nt_spin_lock_irql(&lock->klock, DISPATCH_LEVEL); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisReleaseSpinLock,1) ++ (struct ndis_spinlock *lock) ++{ ++ ENTER6("lock %p, %p", lock, &lock->klock); ++// assert_irql(_irql_ == DISPATCH_LEVEL); ++ nt_spin_unlock_irql(&lock->klock, lock->irql); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisDprAcquireSpinLock,1) ++ (struct ndis_spinlock *lock) ++{ ++ ENTER6("lock %p", &lock->klock); ++// assert_irql(_irql_ == DISPATCH_LEVEL); ++ nt_spin_lock(&lock->klock); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisDprReleaseSpinLock,1) ++ (struct ndis_spinlock *lock) ++{ ++ ENTER6("lock %p", &lock->klock); ++// assert_irql(_irql_ == DISPATCH_LEVEL); ++ nt_spin_unlock(&lock->klock); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisInitializeReadWriteLock,1) ++ (struct ndis_rw_lock *rw_lock) ++{ ++ ENTER3("%p", rw_lock); ++ memset(rw_lock, 0, sizeof(*rw_lock)); ++ KeInitializeSpinLock(&rw_lock->klock); ++ return; ++} ++ ++/* read/write locks are implemented in a rather simplistic way - we ++ * should probably use Linux's rw_lock implementation */ ++ ++wstdcall void WIN_FUNC(NdisAcquireReadWriteLock,3) ++ (struct ndis_rw_lock *rw_lock, BOOLEAN write, ++ struct lock_state *lock_state) ++{ ++ if (write) { ++ while (1) { ++ if (cmpxchg(&rw_lock->count, 0, -1) == 0) ++ return; ++ while (rw_lock->count) ++ cpu_relax(); ++ } ++ return; ++ } ++ while (1) { ++ typeof(rw_lock->count) count; ++ while ((count = rw_lock->count) < 0) ++ cpu_relax(); ++ if (cmpxchg(&rw_lock->count, count, count + 1) == count) ++ return; ++ } ++} ++ ++wstdcall void WIN_FUNC(NdisReleaseReadWriteLock,2) ++ (struct ndis_rw_lock *rw_lock, struct lock_state *lock_state) ++{ ++ if (rw_lock->count > 0) ++ pre_atomic_add(rw_lock->count, -1); ++ else if (rw_lock->count == -1) ++ rw_lock->count = 0; ++ else ++ WARNING("invalid state: %d", rw_lock->count); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMAllocateMapRegisters,5) ++ (struct ndis_mp_block *nmb, UINT dmachan, ++ NDIS_DMA_SIZE dmasize, ULONG basemap, ULONG max_buf_size) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ++ ENTER2("%p, %d %d %d %d", wnd, dmachan, dmasize, basemap, max_buf_size); ++ if (!wrap_is_pci_bus(wnd->wd->dev_bus)) { ++ ERROR("used on a non-PCI device"); ++ return NDIS_STATUS_NOT_SUPPORTED; ++ } ++ if (wnd->dma_map_count > 0) { ++ WARNING("%s: map registers already allocated: %u", ++ wnd->net_dev->name, wnd->dma_map_count); ++ EXIT2(return NDIS_STATUS_RESOURCES); ++ } ++ if (dmasize == NDIS_DMA_24BITS) { ++ if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(24)) || ++ pci_set_consistent_dma_mask(wnd->wd->pci.pdev, ++ DMA_BIT_MASK(24))) ++ WARNING("setting dma mask failed"); ++ } else if (dmasize == NDIS_DMA_32BITS) { ++ /* consistent dma is in low 32-bits by default */ ++ if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(32))) ++ WARNING("setting dma mask failed"); ++#ifdef CONFIG_X86_64 ++ } else if (dmasize == NDIS_DMA_64BITS) { ++ if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(64)) || ++ pci_set_consistent_dma_mask(wnd->wd->pci.pdev, ++ DMA_BIT_MASK(64))) ++ WARNING("setting dma mask failed"); ++ else ++ wnd->net_dev->features |= NETIF_F_HIGHDMA; ++#endif ++ } else { ++ ERROR("dmasize %d not supported", dmasize); ++ EXIT2(return NDIS_STATUS_NOT_SUPPORTED); ++ } ++ /* since memory for buffer is allocated with kmalloc, buffer ++ * is physically contiguous, so entire map will fit in one ++ * register */ ++ if (basemap > 64) { ++ WARNING("Windows driver %s requesting too many (%u) " ++ "map registers", wnd->wd->driver->name, basemap); ++ /* As per NDIS, NDIS_STATUS_RESOURCES should be ++ * returned, but with that Atheros PCI driver fails - ++ * for now tolerate it */ ++// EXIT2(return NDIS_STATUS_RESOURCES); ++ } ++ ++ wnd->dma_map_addr = kzalloc(basemap * sizeof(*(wnd->dma_map_addr)), ++ GFP_KERNEL); ++ if (!wnd->dma_map_addr) ++ EXIT2(return NDIS_STATUS_RESOURCES); ++ wnd->dma_map_count = basemap; ++ TRACE2("%u", wnd->dma_map_count); ++ EXIT2(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(NdisMFreeMapRegisters,1) ++ (struct ndis_mp_block *nmb) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ int i; ++ ++ ENTER2("wnd: %p", wnd); ++ if (wnd->dma_map_addr) { ++ for (i = 0; i < wnd->dma_map_count; i++) { ++ if (wnd->dma_map_addr[i]) ++ WARNING("%s: dma addr 0x%llx not freed by " ++ "Windows driver", wnd->net_dev->name, ++ (unsigned long long)wnd->dma_map_addr[i]); ++ } ++ kfree(wnd->dma_map_addr); ++ wnd->dma_map_addr = NULL; ++ } else ++ WARNING("map registers already freed?"); ++ wnd->dma_map_count = 0; ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisMStartBufferPhysicalMapping,6) ++ (struct ndis_mp_block *nmb, ndis_buffer *buf, ++ ULONG index, BOOLEAN write_to_dev, ++ struct ndis_phy_addr_unit *phy_addr_array, UINT *array_size) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ++ ENTER3("%p, %p, %u, %u", wnd, buf, index, wnd->dma_map_count); ++ if (!wrap_is_pci_bus(wnd->wd->dev_bus)) { ++ ERROR("used on a non-PCI device"); ++ return; ++ } ++ if (unlikely(wnd->sg_dma_size || !write_to_dev || ++ index >= wnd->dma_map_count)) { ++ WARNING("invalid request: %d, %d, %d, %d", wnd->sg_dma_size, ++ write_to_dev, index, wnd->dma_map_count); ++ phy_addr_array[0].phy_addr = 0; ++ phy_addr_array[0].length = 0; ++ *array_size = 0; ++ return; ++ } ++ if (wnd->dma_map_addr[index]) { ++ TRACE2("buffer %p at %d is already mapped: %llx", buf, index, ++ (unsigned long long)wnd->dma_map_addr[index]); ++// *array_size = 1; ++ return; ++ } ++ TRACE3("%p, %p, %u", buf, MmGetSystemAddressForMdl(buf), ++ MmGetMdlByteCount(buf)); ++ DBG_BLOCK(4) { ++ dump_bytes(__func__, MmGetSystemAddressForMdl(buf), ++ MmGetMdlByteCount(buf)); ++ } ++ wnd->dma_map_addr[index] = ++ PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, ++ MmGetSystemAddressForMdl(buf), ++ MmGetMdlByteCount(buf), PCI_DMA_TODEVICE); ++ phy_addr_array[0].phy_addr = wnd->dma_map_addr[index]; ++ phy_addr_array[0].length = MmGetMdlByteCount(buf); ++ TRACE4("%llx, %d, %d", phy_addr_array[0].phy_addr, ++ phy_addr_array[0].length, index); ++ *array_size = 1; ++} ++ ++wstdcall void WIN_FUNC(NdisMCompleteBufferPhysicalMapping,3) ++ (struct ndis_mp_block *nmb, ndis_buffer *buf, ULONG index) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ++ ENTER3("%p, %p %u (%u)", wnd, buf, index, wnd->dma_map_count); ++ ++ if (!wrap_is_pci_bus(wnd->wd->dev_bus)) { ++ ERROR("used on a non-PCI device"); ++ return; ++ } ++ if (unlikely(wnd->sg_dma_size)) ++ WARNING("buffer %p may have been unmapped already", buf); ++ if (index >= wnd->dma_map_count) { ++ ERROR("invalid map register (%u >= %u)", ++ index, wnd->dma_map_count); ++ return; ++ } ++ TRACE4("%llx", (unsigned long long)wnd->dma_map_addr[index]); ++ if (wnd->dma_map_addr[index]) { ++ PCI_DMA_UNMAP_SINGLE(wnd->wd->pci.pdev, wnd->dma_map_addr[index], ++ MmGetMdlByteCount(buf), PCI_DMA_TODEVICE); ++ wnd->dma_map_addr[index] = 0; ++ } else ++ WARNING("map registers at %u not used", index); ++} ++ ++wstdcall void WIN_FUNC(NdisMAllocateSharedMemory,5) ++ (struct ndis_mp_block *nmb, ULONG size, ++ BOOLEAN cached, void **virt, NDIS_PHY_ADDRESS *phys) ++{ ++ dma_addr_t dma_addr; ++ struct wrap_device *wd = nmb->wnd->wd; ++ ++ ENTER3("size: %u, cached: %d", size, cached); ++ if (!wrap_is_pci_bus(wd->dev_bus)) { ++ ERROR("used on a non-PCI device"); ++ return; ++ } ++ *virt = PCI_DMA_ALLOC_COHERENT(wd->pci.pdev, size, &dma_addr); ++ if (*virt) ++ *phys = dma_addr; ++ else ++ WARNING("couldn't allocate %d bytes of %scached DMA memory", ++ size, cached ? "" : "un-"); ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(NdisMFreeSharedMemory,5) ++ (struct ndis_mp_block *nmb, ULONG size, BOOLEAN cached, ++ void *virt, NDIS_PHY_ADDRESS addr) ++{ ++ struct wrap_device *wd = nmb->wnd->wd; ++ ENTER3("%p, %llx, %u", virt, addr, size); ++ if (!wrap_is_pci_bus(wd->dev_bus)) { ++ ERROR("used on a non-PCI device"); ++ return; ++ } ++ PCI_DMA_FREE_COHERENT(wd->pci.pdev, size, virt, addr); ++ EXIT3(return); ++} ++ ++wstdcall void alloc_shared_memory_async(void *arg1, void *arg2) ++{ ++ struct ndis_device *wnd; ++ struct alloc_shared_mem *alloc_shared_mem; ++ struct miniport *mp; ++ void *virt; ++ NDIS_PHY_ADDRESS phys; ++ KIRQL irql; ++ ++ wnd = arg1; ++ alloc_shared_mem = arg2; ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ NdisMAllocateSharedMemory(wnd->nmb, alloc_shared_mem->size, ++ alloc_shared_mem->cached, &virt, &phys); ++ irql = serialize_lock_irql(wnd); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ LIN2WIN5(mp->alloc_complete, wnd->nmb, virt, ++ &phys, alloc_shared_mem->size, alloc_shared_mem->ctx); ++ serialize_unlock_irql(wnd, irql); ++ kfree(alloc_shared_mem); ++} ++WIN_FUNC_DECL(alloc_shared_memory_async,2) ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMAllocateSharedMemoryAsync,4) ++ (struct ndis_mp_block *nmb, ULONG size, BOOLEAN cached, void *ctx) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ struct alloc_shared_mem *alloc_shared_mem; ++ ++ ENTER3("wnd: %p", wnd); ++ alloc_shared_mem = kmalloc(sizeof(*alloc_shared_mem), irql_gfp()); ++ if (!alloc_shared_mem) { ++ WARNING("couldn't allocate memory"); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ alloc_shared_mem->size = size; ++ alloc_shared_mem->cached = cached; ++ alloc_shared_mem->ctx = ctx; ++ if (schedule_ntos_work_item(WIN_FUNC_PTR(alloc_shared_memory_async,2), ++ wnd, alloc_shared_mem)) ++ EXIT3(return NDIS_STATUS_FAILURE); ++ EXIT3(return NDIS_STATUS_PENDING); ++} ++ ++/* Some drivers allocate NDIS_BUFFER (aka MDL) very often; instead of ++ * allocating and freeing with kernel functions, we chain them into ++ * ndis_buffer_pool. When an MDL is freed, it is added to the list of ++ * free MDLs. When allocated, we first check if there is one in free ++ * list and if so just return it; otherwise, we allocate a new one and ++ * return that. This reduces memory fragmentation. Windows DDK says ++ * that the driver itself shouldn't check what is returned in ++ * pool_handle, presumably because buffer pools are not used in ++ * XP. However, as long as driver follows rest of the semantics - that ++ * it should indicate maximum number of MDLs used with num_descr and ++ * pass the same pool_handle in other buffer functions, this should ++ * work. Sadly, though, NdisFreeBuffer doesn't pass the pool_handle, ++ * so we use 'process' field of MDL to store pool_handle. */ ++ ++wstdcall void WIN_FUNC(NdisAllocateBufferPool,3) ++ (NDIS_STATUS *status, struct ndis_buffer_pool **pool_handle, ++ UINT num_descr) ++{ ++ struct ndis_buffer_pool *pool; ++ ++ ENTER1("buffers: %d", num_descr); ++ pool = kmalloc(sizeof(*pool), irql_gfp()); ++ if (!pool) { ++ *status = NDIS_STATUS_RESOURCES; ++ EXIT3(return); ++ } ++ spin_lock_init(&pool->lock); ++ pool->max_descr = num_descr; ++ pool->num_allocated_descr = 0; ++ pool->free_descr = NULL; ++ *pool_handle = pool; ++ *status = NDIS_STATUS_SUCCESS; ++ TRACE1("pool: %p, num_descr: %d", pool, num_descr); ++ EXIT1(return); ++} ++ ++wstdcall void WIN_FUNC(NdisAllocateBuffer,5) ++ (NDIS_STATUS *status, ndis_buffer **buffer, ++ struct ndis_buffer_pool *pool, void *virt, UINT length) ++{ ++ ndis_buffer *descr; ++ ++ ENTER4("pool: %p (%d)", pool, pool->num_allocated_descr); ++ /* NDIS drivers should call this at DISPATCH_LEVEL, but ++ * alloc_tx_packet calls at SOFT_IRQL */ ++ assert_irql(_irql_ <= SOFT_LEVEL); ++ if (!pool) { ++ *status = NDIS_STATUS_FAILURE; ++ *buffer = NULL; ++ EXIT4(return); ++ } ++ spin_lock_bh(&pool->lock); ++ if ((descr = pool->free_descr)) ++ pool->free_descr = descr->next; ++ spin_unlock_bh(&pool->lock); ++ if (descr) { ++ typeof(descr->flags) flags; ++ flags = descr->flags; ++ memset(descr, 0, sizeof(*descr)); ++ MmInitializeMdl(descr, virt, length); ++ if (flags & MDL_CACHE_ALLOCATED) ++ descr->flags |= MDL_CACHE_ALLOCATED; ++ } else { ++ if (pool->num_allocated_descr > pool->max_descr) { ++ TRACE2("pool %p is full: %d(%d)", pool, ++ pool->num_allocated_descr, pool->max_descr); ++#ifndef ALLOW_POOL_OVERFLOW ++ *status = NDIS_STATUS_FAILURE; ++ *buffer = NULL; ++ return; ++#endif ++ } ++ descr = allocate_init_mdl(virt, length); ++ if (!descr) { ++ WARNING("couldn't allocate buffer"); ++ *status = NDIS_STATUS_FAILURE; ++ *buffer = NULL; ++ EXIT4(return); ++ } ++ TRACE4("buffer %p for %p, %d", descr, virt, length); ++ atomic_inc_var(pool->num_allocated_descr); ++ } ++ /* TODO: make sure this mdl can map given buffer */ ++ MmBuildMdlForNonPagedPool(descr); ++// descr->flags |= MDL_ALLOCATED_FIXED_SIZE | ++// MDL_MAPPED_TO_SYSTEM_VA | MDL_PAGES_LOCKED; ++ descr->pool = pool; ++ *buffer = descr; ++ *status = NDIS_STATUS_SUCCESS; ++ TRACE4("buffer: %p", descr); ++ EXIT4(return); ++} ++ ++wstdcall void WIN_FUNC(NdisFreeBuffer,1) ++ (ndis_buffer *buffer) ++{ ++ struct ndis_buffer_pool *pool; ++ ++ ENTER4("%p", buffer); ++ if (!buffer || !buffer->pool) { ++ ERROR("invalid buffer"); ++ EXIT4(return); ++ } ++ pool = buffer->pool; ++ if (pool->num_allocated_descr > MAX_ALLOCATED_NDIS_BUFFERS) { ++ /* NB NB NB: set mdl's 'pool' field to NULL before ++ * calling free_mdl; otherwise free_mdl calls ++ * NdisFreeBuffer back */ ++ atomic_dec_var(pool->num_allocated_descr); ++ buffer->pool = NULL; ++ free_mdl(buffer); ++ } else { ++ spin_lock_bh(&pool->lock); ++ buffer->next = pool->free_descr; ++ pool->free_descr = buffer; ++ spin_unlock_bh(&pool->lock); ++ } ++ EXIT4(return); ++} ++ ++wstdcall void WIN_FUNC(NdisFreeBufferPool,1) ++ (struct ndis_buffer_pool *pool) ++{ ++ ndis_buffer *cur, *next; ++ ++ TRACE3("pool: %p", pool); ++ if (!pool) { ++ WARNING("invalid pool"); ++ EXIT3(return); ++ } ++ spin_lock_bh(&pool->lock); ++ cur = pool->free_descr; ++ while (cur) { ++ next = cur->next; ++ cur->pool = NULL; ++ free_mdl(cur); ++ cur = next; ++ } ++ spin_unlock_bh(&pool->lock); ++ kfree(pool); ++ pool = NULL; ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(NdisAdjustBufferLength,2) ++ (ndis_buffer *buffer, UINT length) ++{ ++ ENTER4("%p, %d", buffer, length); ++ buffer->bytecount = length; ++} ++ ++wstdcall void WIN_FUNC(NdisQueryBuffer,3) ++ (ndis_buffer *buffer, void **virt, UINT *length) ++{ ++ ENTER4("buffer: %p", buffer); ++ if (virt) ++ *virt = MmGetSystemAddressForMdl(buffer); ++ *length = MmGetMdlByteCount(buffer); ++ TRACE4("%p, %u", virt ? *virt : NULL, *length); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisQueryBufferSafe,4) ++ (ndis_buffer *buffer, void **virt, UINT *length, ++ enum mm_page_priority priority) ++{ ++ ENTER4("%p, %p, %p, %d", buffer, virt, length, priority); ++ if (virt) ++ *virt = MmGetSystemAddressForMdlSafe(buffer, priority); ++ *length = MmGetMdlByteCount(buffer); ++ TRACE4("%p, %u", virt ? *virt : NULL, *length); ++} ++ ++wstdcall void *WIN_FUNC(NdisBufferVirtualAddress,1) ++ (ndis_buffer *buffer) ++{ ++ ENTER3("%p", buffer); ++ return MmGetSystemAddressForMdl(buffer); ++} ++ ++wstdcall ULONG WIN_FUNC(NdisBufferLength,1) ++ (ndis_buffer *buffer) ++{ ++ ENTER3("%p", buffer); ++ return MmGetMdlByteCount(buffer); ++} ++ ++wstdcall void WIN_FUNC(NdisQueryBufferOffset,3) ++ (ndis_buffer *buffer, UINT *offset, UINT *length) ++{ ++ ENTER3("%p", buffer); ++ *offset = MmGetMdlByteOffset(buffer); ++ *length = MmGetMdlByteCount(buffer); ++ TRACE3("%d, %d", *offset, *length); ++} ++ ++wstdcall void WIN_FUNC(NdisUnchainBufferAtBack,2) ++ (struct ndis_packet *packet, ndis_buffer **buffer) ++{ ++ ndis_buffer *b, *btail; ++ ++ ENTER3("%p", packet); ++ b = packet->private.buffer_head; ++ if (!b) { ++ /* no buffer in packet */ ++ *buffer = NULL; ++ EXIT3(return); ++ } ++ btail = packet->private.buffer_tail; ++ *buffer = btail; ++ if (b == btail) { ++ /* one buffer in packet */ ++ packet->private.buffer_head = NULL; ++ packet->private.buffer_tail = NULL; ++ } else { ++ while (b->next != btail) ++ b = b->next; ++ packet->private.buffer_tail = b; ++ b->next = NULL; ++ } ++ packet->private.valid_counts = FALSE; ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(NdisUnchainBufferAtFront,2) ++ (struct ndis_packet *packet, ndis_buffer **buffer) ++{ ++ ENTER3("%p", packet); ++ if (packet->private.buffer_head == NULL) { ++ /* no buffer in packet */ ++ *buffer = NULL; ++ EXIT3(return); ++ } ++ ++ *buffer = packet->private.buffer_head; ++ if (packet->private.buffer_head == packet->private.buffer_tail) { ++ /* one buffer in packet */ ++ packet->private.buffer_head = NULL; ++ packet->private.buffer_tail = NULL; ++ } else ++ packet->private.buffer_head = (*buffer)->next; ++ ++ packet->private.valid_counts = FALSE; ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(NdisGetFirstBufferFromPacketSafe,6) ++ (struct ndis_packet *packet, ndis_buffer **first_buffer, ++ void **first_buffer_va, UINT *first_buffer_length, ++ UINT *total_buffer_length, enum mm_page_priority priority) ++{ ++ ndis_buffer *b = packet->private.buffer_head; ++ ++ ENTER3("%p(%p)", packet, b); ++ *first_buffer = b; ++ if (b) { ++ *first_buffer_va = MmGetSystemAddressForMdlSafe(b, priority); ++ *first_buffer_length = *total_buffer_length = ++ MmGetMdlByteCount(b); ++ for (b = b->next; b; b = b->next) ++ *total_buffer_length += MmGetMdlByteCount(b); ++ } else { ++ *first_buffer_va = NULL; ++ *first_buffer_length = 0; ++ *total_buffer_length = 0; ++ } ++ TRACE3("%p, %d, %d", *first_buffer_va, *first_buffer_length, ++ *total_buffer_length); ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(NdisGetFirstBufferFromPacket,6) ++ (struct ndis_packet *packet, ndis_buffer **first_buffer, ++ void **first_buffer_va, UINT *first_buffer_length, ++ UINT *total_buffer_length, enum mm_page_priority priority) ++{ ++ NdisGetFirstBufferFromPacketSafe(packet, first_buffer, ++ first_buffer_va, first_buffer_length, ++ total_buffer_length, ++ NormalPagePriority); ++} ++ ++wstdcall void WIN_FUNC(NdisAllocatePacketPoolEx,5) ++ (NDIS_STATUS *status, struct ndis_packet_pool **pool_handle, ++ UINT num_descr, UINT overflowsize, UINT proto_rsvd_length) ++{ ++ struct ndis_packet_pool *pool; ++ ++ ENTER3("buffers: %d, length: %d", num_descr, proto_rsvd_length); ++ pool = kzalloc(sizeof(*pool), irql_gfp()); ++ if (!pool) { ++ *status = NDIS_STATUS_RESOURCES; ++ EXIT3(return); ++ } ++ spin_lock_init(&pool->lock); ++ pool->max_descr = num_descr; ++ pool->num_allocated_descr = 0; ++ pool->num_used_descr = 0; ++ pool->free_descr = NULL; ++ pool->proto_rsvd_length = proto_rsvd_length; ++ *pool_handle = pool; ++ *status = NDIS_STATUS_SUCCESS; ++ TRACE3("pool: %p", pool); ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(NdisAllocatePacketPool,4) ++ (NDIS_STATUS *status, struct ndis_packet_pool **pool_handle, ++ UINT num_descr, UINT proto_rsvd_length) ++{ ++ NdisAllocatePacketPoolEx(status, pool_handle, num_descr, 0, ++ proto_rsvd_length); ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(NdisFreePacketPool,1) ++ (struct ndis_packet_pool *pool) ++{ ++ struct ndis_packet *packet, *next; ++ ++ ENTER3("pool: %p", pool); ++ if (!pool) { ++ WARNING("invalid pool"); ++ EXIT3(return); ++ } ++ spin_lock_bh(&pool->lock); ++ packet = pool->free_descr; ++ while (packet) { ++ next = (struct ndis_packet *)packet->reserved[0]; ++ kfree(packet); ++ packet = next; ++ } ++ pool->num_allocated_descr = 0; ++ pool->num_used_descr = 0; ++ pool->free_descr = NULL; ++ spin_unlock_bh(&pool->lock); ++ kfree(pool); ++ EXIT3(return); ++} ++ ++wstdcall UINT WIN_FUNC(NdisPacketPoolUsage,1) ++ (struct ndis_packet_pool *pool) ++{ ++ EXIT4(return pool->num_used_descr); ++} ++ ++wstdcall void WIN_FUNC(NdisAllocatePacket,3) ++ (NDIS_STATUS *status, struct ndis_packet **ndis_packet, ++ struct ndis_packet_pool *pool) ++{ ++ struct ndis_packet *packet; ++ int packet_length; ++ ++ ENTER4("pool: %p", pool); ++ if (!pool) { ++ *status = NDIS_STATUS_RESOURCES; ++ *ndis_packet = NULL; ++ EXIT4(return); ++ } ++ assert_irql(_irql_ <= SOFT_LEVEL); ++ if (pool->num_used_descr > pool->max_descr) { ++ TRACE3("pool %p is full: %d(%d)", pool, ++ pool->num_used_descr, pool->max_descr); ++#ifndef ALLOW_POOL_OVERFLOW ++ *status = NDIS_STATUS_RESOURCES; ++ *ndis_packet = NULL; ++ return; ++#endif ++ } ++ /* packet has space for 1 byte in protocol_reserved field */ ++ packet_length = sizeof(*packet) - 1 + pool->proto_rsvd_length + ++ sizeof(struct ndis_packet_oob_data); ++ spin_lock_bh(&pool->lock); ++ if ((packet = pool->free_descr)) ++ pool->free_descr = (void *)packet->reserved[0]; ++ spin_unlock_bh(&pool->lock); ++ if (!packet) { ++ packet = kmalloc(packet_length, irql_gfp()); ++ if (!packet) { ++ WARNING("couldn't allocate packet"); ++ *status = NDIS_STATUS_RESOURCES; ++ *ndis_packet = NULL; ++ return; ++ } ++ atomic_inc_var(pool->num_allocated_descr); ++ } ++ TRACE4("%p, %p", pool, packet); ++ atomic_inc_var(pool->num_used_descr); ++ memset(packet, 0, packet_length); ++ packet->private.oob_offset = ++ packet_length - sizeof(struct ndis_packet_oob_data); ++ packet->private.packet_flags = fPACKET_ALLOCATED_BY_NDIS; ++ packet->private.pool = pool; ++ *ndis_packet = packet; ++ *status = NDIS_STATUS_SUCCESS; ++ EXIT4(return); ++} ++ ++wstdcall void WIN_FUNC(NdisDprAllocatePacket,3) ++ (NDIS_STATUS *status, struct ndis_packet **packet, ++ struct ndis_packet_pool *pool) ++{ ++ NdisAllocatePacket(status, packet, pool); ++} ++ ++wstdcall void WIN_FUNC(NdisFreePacket,1) ++ (struct ndis_packet *packet) ++{ ++ struct ndis_packet_pool *pool; ++ ++ ENTER4("%p, %p", packet, packet->private.pool); ++ pool = packet->private.pool; ++ if (!pool) { ++ ERROR("invalid pool %p", packet); ++ EXIT4(return); ++ } ++ assert((int)pool->num_used_descr > 0); ++ atomic_dec_var(pool->num_used_descr); ++ if (packet->reserved[1]) { ++ TRACE3("%p, %p", packet, (void *)packet->reserved[1]); ++ kfree((void *)packet->reserved[1]); ++ packet->reserved[1] = 0; ++ } ++ if (pool->num_allocated_descr > MAX_ALLOCATED_NDIS_PACKETS) { ++ TRACE3("%p", pool); ++ atomic_dec_var(pool->num_allocated_descr); ++ kfree(packet); ++ } else { ++ TRACE4("%p, %p, %p", pool, packet, pool->free_descr); ++ spin_lock_bh(&pool->lock); ++ packet->reserved[0] = ++ (typeof(packet->reserved[0]))pool->free_descr; ++ pool->free_descr = packet; ++ spin_unlock_bh(&pool->lock); ++ } ++ EXIT4(return); ++} ++ ++wstdcall struct ndis_packet_stack *WIN_FUNC(NdisIMGetCurrentPacketStack,2) ++ (struct ndis_packet *packet, BOOLEAN *stacks_remain) ++{ ++ struct ndis_packet_stack *stack; ++ ++ if (!packet->reserved[1]) { ++ stack = kzalloc(2 * sizeof(*stack), irql_gfp()); ++ TRACE3("%p, %p", packet, stack); ++ packet->reserved[1] = (typeof(packet->reserved[1]))stack; ++ } else { ++ stack = (void *)packet->reserved[1];; ++ if (xchg(&stack->ndis_reserved[0], 1)) { ++ stack++; ++ if (xchg(&stack->ndis_reserved[0], 1)) ++ stack = NULL; ++ } ++ TRACE3("%p", stack); ++ } ++ if (stack) ++ *stacks_remain = TRUE; ++ else ++ *stacks_remain = FALSE; ++ ++ EXIT3(return stack); ++} ++ ++wstdcall void WIN_FUNC(NdisCopyFromPacketToPacketSafe,7) ++ (struct ndis_packet *dst, UINT dst_offset, UINT num_to_copy, ++ struct ndis_packet *src, UINT src_offset, UINT *num_copied, ++ enum mm_page_priority priority) ++{ ++ UINT dst_n, src_n, n, left; ++ ndis_buffer *dst_buf; ++ ndis_buffer *src_buf; ++ ++ ENTER4(""); ++ if (!dst || !src) { ++ *num_copied = 0; ++ EXIT4(return); ++ } ++ ++ dst_buf = dst->private.buffer_head; ++ src_buf = src->private.buffer_head; ++ ++ if (!dst_buf || !src_buf) { ++ *num_copied = 0; ++ EXIT4(return); ++ } ++ dst_n = MmGetMdlByteCount(dst_buf) - dst_offset; ++ src_n = MmGetMdlByteCount(src_buf) - src_offset; ++ ++ n = min(src_n, dst_n); ++ n = min(n, num_to_copy); ++ memcpy(MmGetSystemAddressForMdl(dst_buf) + dst_offset, ++ MmGetSystemAddressForMdl(src_buf) + src_offset, n); ++ ++ left = num_to_copy - n; ++ while (left > 0) { ++ src_offset += n; ++ dst_offset += n; ++ dst_n -= n; ++ src_n -= n; ++ if (dst_n == 0) { ++ dst_buf = dst_buf->next; ++ if (!dst_buf) ++ break; ++ dst_n = MmGetMdlByteCount(dst_buf); ++ dst_offset = 0; ++ } ++ if (src_n == 0) { ++ src_buf = src_buf->next; ++ if (!src_buf) ++ break; ++ src_n = MmGetMdlByteCount(src_buf); ++ src_offset = 0; ++ } ++ ++ n = min(src_n, dst_n); ++ n = min(n, left); ++ memcpy(MmGetSystemAddressForMdl(dst_buf) + dst_offset, ++ MmGetSystemAddressForMdl(src_buf) + src_offset, n); ++ left -= n; ++ } ++ *num_copied = num_to_copy - left; ++ EXIT4(return); ++} ++ ++wstdcall void WIN_FUNC(NdisCopyFromPacketToPacket,6) ++ (struct ndis_packet *dst, UINT dst_offset, UINT num_to_copy, ++ struct ndis_packet *src, UINT src_offset, UINT *num_copied) ++{ ++ NdisCopyFromPacketToPacketSafe(dst, dst_offset, num_to_copy, ++ src, src_offset, num_copied, ++ NormalPagePriority); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisIMCopySendPerPacketInfo,2) ++ (struct ndis_packet *dst, struct ndis_packet *src) ++{ ++ struct ndis_packet_oob_data *dst_oob, *src_oob; ++ dst_oob = NDIS_PACKET_OOB_DATA(dst); ++ src_oob = NDIS_PACKET_OOB_DATA(src); ++ memcpy(&dst_oob->ext, &src_oob->ext, sizeof(dst_oob->ext)); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisSend,3) ++ (NDIS_STATUS *status, struct ndis_mp_block *nmb, ++ struct ndis_packet *packet) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ struct miniport *mp; ++ KIRQL irql; ++ ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ if (mp->send_packets) { ++ irql = serialize_lock_irql(wnd); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx, &packet, 1); ++ serialize_unlock_irql(wnd, irql); ++ if (deserialized_driver(wnd)) ++ *status = NDIS_STATUS_PENDING; ++ else { ++ struct ndis_packet_oob_data *oob_data; ++ oob_data = NDIS_PACKET_OOB_DATA(packet); ++ *status = oob_data->status; ++ switch (*status) { ++ case NDIS_STATUS_SUCCESS: ++ free_tx_packet(wnd, packet, *status); ++ break; ++ case NDIS_STATUS_PENDING: ++ break; ++ case NDIS_STATUS_RESOURCES: ++ wnd->tx_ok = 0; ++ break; ++ case NDIS_STATUS_FAILURE: ++ default: ++ free_tx_packet(wnd, packet, *status); ++ break; ++ } ++ } ++ } else { ++ irql = serialize_lock_irql(wnd); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ *status = LIN2WIN3(mp->send, wnd->nmb->mp_ctx, packet, 0); ++ serialize_unlock_irql(wnd, irql); ++ switch (*status) { ++ case NDIS_STATUS_SUCCESS: ++ free_tx_packet(wnd, packet, *status); ++ break; ++ case NDIS_STATUS_PENDING: ++ break; ++ case NDIS_STATUS_RESOURCES: ++ wnd->tx_ok = 0; ++ break; ++ case NDIS_STATUS_FAILURE: ++ default: ++ free_tx_packet(wnd, packet, *status); ++ break; ++ } ++ } ++ EXIT3(return); ++} ++ ++/* called for serialized drivers only */ ++wstdcall void mp_timer_dpc(struct kdpc *kdpc, void *ctx, void *arg1, void *arg2) ++{ ++ struct ndis_mp_timer *timer; ++ struct ndis_mp_block *nmb; ++ ++ timer = ctx; ++ TIMERENTER("%p, %p, %p, %p", timer, timer->func, timer->ctx, timer->nmb); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ nmb = timer->nmb; ++ serialize_lock(nmb->wnd); ++ LIN2WIN4(timer->func, NULL, timer->ctx, NULL, NULL); ++ serialize_unlock(nmb->wnd); ++ TIMEREXIT(return); ++} ++WIN_FUNC_DECL(mp_timer_dpc,4) ++ ++wstdcall void WIN_FUNC(NdisMInitializeTimer,4) ++ (struct ndis_mp_timer *timer, struct ndis_mp_block *nmb, ++ DPC func, void *ctx) ++{ ++ TIMERENTER("%p, %p, %p, %p", timer, func, ctx, nmb); ++ assert_irql(_irql_ == PASSIVE_LEVEL); ++ timer->func = func; ++ timer->ctx = ctx; ++ timer->nmb = nmb; ++ if (deserialized_driver(nmb->wnd)) ++ KeInitializeDpc(&timer->kdpc, func, ctx); ++ else ++ KeInitializeDpc(&timer->kdpc, WIN_FUNC_PTR(mp_timer_dpc,4), ++ timer); ++ wrap_init_timer(&timer->nt_timer, NotificationTimer, nmb); ++ TIMEREXIT(return); ++} ++ ++wstdcall void WIN_FUNC(NdisMSetPeriodicTimer,2) ++ (struct ndis_mp_timer *timer, UINT period_ms) ++{ ++ unsigned long expires = MSEC_TO_HZ(period_ms); ++ ++ TIMERENTER("%p, %u, %ld", timer, period_ms, expires); ++ assert_irql(_irql_ <= DISPATCH_LEVEL); ++ wrap_set_timer(&timer->nt_timer, expires, expires, &timer->kdpc); ++ TIMEREXIT(return); ++} ++ ++wstdcall void WIN_FUNC(NdisMCancelTimer,2) ++ (struct ndis_mp_timer *timer, BOOLEAN *canceled) ++{ ++ TIMERENTER("%p", timer); ++ assert_irql(_irql_ <= DISPATCH_LEVEL); ++ *canceled = KeCancelTimer(&timer->nt_timer); ++ TIMERTRACE("%d", *canceled); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisInitializeTimer,3) ++ (struct ndis_timer *timer, void *func, void *ctx) ++{ ++ TIMERENTER("%p, %p, %p", timer, func, ctx); ++ assert_irql(_irql_ == PASSIVE_LEVEL); ++ KeInitializeDpc(&timer->kdpc, func, ctx); ++ wrap_init_timer(&timer->nt_timer, NotificationTimer, NULL); ++ TIMEREXIT(return); ++} ++ ++/* NdisMSetTimer is a macro that calls NdisSetTimer with ++ * ndis_mp_timer typecast to ndis_timer */ ++ ++wstdcall void WIN_FUNC(NdisSetTimer,2) ++ (struct ndis_timer *timer, UINT duetime_ms) ++{ ++ unsigned long expires = MSEC_TO_HZ(duetime_ms); ++ ++ TIMERENTER("%p, %p, %u, %ld", timer, timer->nt_timer.wrap_timer, ++ duetime_ms, expires); ++ assert_irql(_irql_ <= DISPATCH_LEVEL); ++ wrap_set_timer(&timer->nt_timer, expires, 0, &timer->kdpc); ++ TIMEREXIT(return); ++} ++ ++wstdcall void WIN_FUNC(NdisCancelTimer,2) ++ (struct ndis_timer *timer, BOOLEAN *canceled) ++{ ++ TIMERENTER("%p", timer); ++ assert_irql(_irql_ <= DISPATCH_LEVEL); ++ *canceled = KeCancelTimer(&timer->nt_timer); ++ TIMEREXIT(return); ++} ++ ++wstdcall void WIN_FUNC(NdisMRegisterAdapterShutdownHandler,3) ++ (struct ndis_mp_block *nmb, void *ctx, void *func) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ENTER1("%p", func); ++ wnd->wd->driver->ndis_driver->mp.shutdown = func; ++ wnd->shutdown_ctx = ctx; ++} ++ ++wstdcall void WIN_FUNC(NdisMDeregisterAdapterShutdownHandler,1) ++ (struct ndis_mp_block *nmb) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ wnd->wd->driver->ndis_driver->mp.shutdown = NULL; ++ wnd->shutdown_ctx = NULL; ++} ++ ++/* TODO: rt61 (serialized) driver doesn't want MiniportEnableInterrupt ++ * to be called in irq handler, but mrv800c (deserialized) driver ++ * wants. NDIS is confusing about when to call MiniportEnableInterrupt ++ * For now, handle these cases with two separate irq handlers based on ++ * observation of these two drivers. However, it is likely not ++ * correct. */ ++wstdcall void deserialized_irq_handler(struct kdpc *kdpc, void *ctx, ++ void *arg1, void *arg2) ++{ ++ struct ndis_device *wnd = ctx; ++ ndis_interrupt_handler irq_handler = arg1; ++ struct miniport *mp = arg2; ++ ++ TRACE6("%p", irq_handler); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ LIN2WIN1(irq_handler, wnd->nmb->mp_ctx); ++ if (mp->enable_interrupt) ++ LIN2WIN1(mp->enable_interrupt, wnd->nmb->mp_ctx); ++ EXIT6(return); ++} ++WIN_FUNC_DECL(deserialized_irq_handler,4) ++ ++wstdcall void serialized_irq_handler(struct kdpc *kdpc, void *ctx, ++ void *arg1, void *arg2) ++{ ++ struct ndis_device *wnd = ctx; ++ ndis_interrupt_handler irq_handler = arg1; ++ ++ TRACE6("%p, %p, %p", wnd, irq_handler, arg2); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ serialize_lock(wnd); ++ LIN2WIN1(irq_handler, arg2); ++ serialize_unlock(wnd); ++ EXIT6(return); ++} ++WIN_FUNC_DECL(serialized_irq_handler,4) ++ ++wstdcall BOOLEAN ndis_isr(struct kinterrupt *kinterrupt, void *ctx) ++{ ++ struct ndis_mp_interrupt *mp_interrupt = ctx; ++ struct ndis_device *wnd = mp_interrupt->nmb->wnd; ++ BOOLEAN recognized = TRUE, queue_handler = TRUE; ++ ++ TRACE6("%p", wnd); ++ /* kernel may call ISR when registering interrupt, in ++ * the same context if DEBUG_SHIRQ is enabled */ ++ assert_irql(_irql_ == DIRQL || _irql_ == PASSIVE_LEVEL); ++ if (mp_interrupt->shared) ++ LIN2WIN3(mp_interrupt->isr, &recognized, &queue_handler, ++ wnd->nmb->mp_ctx); ++ else { ++ struct miniport *mp; ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ LIN2WIN1(mp->disable_interrupt, wnd->nmb->mp_ctx); ++ /* it is not shared interrupt, so handler must be called */ ++ recognized = queue_handler = TRUE; ++ } ++ if (recognized) { ++ if (queue_handler) { ++ TRACE5("%p", &wnd->irq_kdpc); ++ queue_kdpc(&wnd->irq_kdpc); ++ } ++ EXIT6(return TRUE); ++ } ++ EXIT6(return FALSE); ++} ++WIN_FUNC_DECL(ndis_isr,2) ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterInterrupt,7) ++ (struct ndis_mp_interrupt *mp_interrupt, ++ struct ndis_mp_block *nmb, UINT vector, UINT level, ++ BOOLEAN req_isr, BOOLEAN shared, enum kinterrupt_mode mode) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ struct miniport *mp; ++ ++ ENTER1("%p, vector:%d, level:%d, req_isr:%d, shared:%d, mode:%d", ++ mp_interrupt, vector, level, req_isr, shared, mode); ++ ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ nt_spin_lock_init(&mp_interrupt->lock); ++ mp_interrupt->irq = vector; ++ mp_interrupt->isr = mp->isr; ++ mp_interrupt->mp_dpc = mp->handle_interrupt; ++ mp_interrupt->nmb = nmb; ++ mp_interrupt->req_isr = req_isr; ++ if (shared && !req_isr) ++ WARNING("shared but dynamic interrupt!"); ++ mp_interrupt->shared = shared; ++ wnd->mp_interrupt = mp_interrupt; ++ if (mp->enable_interrupt) ++ mp_interrupt->enable = TRUE; ++ else ++ mp_interrupt->enable = FALSE; ++ ++ if (deserialized_driver(wnd)) { ++ KeInitializeDpc(&wnd->irq_kdpc, ++ WIN_FUNC_PTR(deserialized_irq_handler,4), ++ nmb->wnd); ++ wnd->irq_kdpc.arg1 = mp->handle_interrupt; ++ wnd->irq_kdpc.arg2 = mp; ++ TRACE2("%p, %p, %p, %p", wnd->irq_kdpc.arg1, wnd->irq_kdpc.arg2, ++ nmb->wnd, nmb->mp_ctx); ++ } else { ++ KeInitializeDpc(&wnd->irq_kdpc, ++ WIN_FUNC_PTR(serialized_irq_handler,4), ++ nmb->wnd); ++ wnd->irq_kdpc.arg1 = mp->handle_interrupt; ++ wnd->irq_kdpc.arg2 = nmb->mp_ctx; ++ TRACE2("%p, %p, %p", wnd->irq_kdpc.arg1, wnd->irq_kdpc.arg2, ++ nmb->wnd); ++ } ++ ++ if (IoConnectInterrupt(&mp_interrupt->kinterrupt, ++ WIN_FUNC_PTR(ndis_isr,2), mp_interrupt, NULL, ++ vector, DIRQL, DIRQL, mode, shared, 0, FALSE) != ++ STATUS_SUCCESS) { ++ printk(KERN_WARNING "%s: request for IRQ %d failed\n", ++ DRIVER_NAME, vector); ++ return NDIS_STATUS_RESOURCES; ++ } ++ printk(KERN_INFO "%s: using IRQ %d\n", DRIVER_NAME, vector); ++ EXIT1(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(NdisMDeregisterInterrupt,1) ++ (struct ndis_mp_interrupt *mp_interrupt) ++{ ++ struct ndis_mp_block *nmb; ++ ++ ENTER1("%p", mp_interrupt); ++ nmb = xchg(&mp_interrupt->nmb, NULL); ++ TRACE1("%p", nmb); ++ if (!nmb) { ++ WARNING("interrupt already freed?"); ++ return; ++ } ++ nmb->wnd->mp_interrupt = NULL; ++ if (dequeue_kdpc(&nmb->wnd->irq_kdpc)) ++ TRACE2("interrupt kdpc was pending"); ++ flush_workqueue(wrapndis_wq); ++ IoDisconnectInterrupt(mp_interrupt->kinterrupt); ++ EXIT1(return); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(NdisMSynchronizeWithInterrupt,3) ++ (struct ndis_mp_interrupt *mp_interrupt, ++ PKSYNCHRONIZE_ROUTINE sync_func, void *ctx) ++{ ++ return KeSynchronizeExecution(mp_interrupt->kinterrupt, sync_func, ctx); ++} ++ ++/* called via function pointer; but 64-bit RNDIS driver calls directly */ ++wstdcall void WIN_FUNC(NdisMIndicateStatus,4) ++ (struct ndis_mp_block *nmb, NDIS_STATUS status, void *buf, UINT len) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ struct ndis_status_indication *si; ++ ++ ENTER2("status=0x%x len=%d", status, len); ++ switch (status) { ++ case NDIS_STATUS_MEDIA_CONNECT: ++ set_media_state(wnd, NdisMediaStateConnected); ++ break; ++ case NDIS_STATUS_MEDIA_DISCONNECT: ++ set_media_state(wnd, NdisMediaStateDisconnected); ++ break; ++ case NDIS_STATUS_MEDIA_SPECIFIC_INDICATION: ++ if (!buf) ++ break; ++ si = buf; ++ TRACE2("status_type=%d", si->status_type); ++ switch (si->status_type) { ++ case Ndis802_11StatusType_MediaStreamMode: ++ break; ++#ifdef CONFIG_WIRELESS_EXT ++ case Ndis802_11StatusType_Authentication: ++ buf = (char *)buf + sizeof(*si); ++ len -= sizeof(*si); ++ while (len > 0) { ++ int pairwise_error = 0, group_error = 0; ++ struct ndis_auth_req *auth_req = ++ (struct ndis_auth_req *)buf; ++ TRACE1(MACSTRSEP, MAC2STR(auth_req->bssid)); ++ if (auth_req->flags & 0x01) ++ TRACE2("reauth request"); ++ if (auth_req->flags & 0x02) ++ TRACE2("key update request"); ++ if (auth_req->flags & 0x06) { ++ pairwise_error = 1; ++ TRACE2("pairwise_error"); ++ } ++ if (auth_req->flags & 0x0E) { ++ group_error = 1; ++ TRACE2("group_error"); ++ } ++ if (pairwise_error || group_error) { ++ union iwreq_data wrqu; ++ struct iw_michaelmicfailure micfailure; ++ ++ memset(&micfailure, 0, sizeof(micfailure)); ++ if (pairwise_error) ++ micfailure.flags |= ++ IW_MICFAILURE_PAIRWISE; ++ if (group_error) ++ micfailure.flags |= ++ IW_MICFAILURE_GROUP; ++ memcpy(micfailure.src_addr.sa_data, ++ auth_req->bssid, ETH_ALEN); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.length = sizeof(micfailure); ++ wireless_send_event(wnd->net_dev, ++ IWEVMICHAELMICFAILURE, ++ &wrqu, (u8 *)&micfailure); ++ } ++ len -= auth_req->length; ++ buf = (char *)buf + auth_req->length; ++ } ++ break; ++ case Ndis802_11StatusType_PMKID_CandidateList: ++ { ++ u8 *end; ++ unsigned long i; ++ struct ndis_pmkid_candidate_list *cand; ++ ++ cand = buf + sizeof(struct ndis_status_indication); ++ if (len < sizeof(struct ndis_status_indication) + ++ sizeof(struct ndis_pmkid_candidate_list) || ++ cand->version != 1) { ++ WARNING("unrecognized PMKID ignored"); ++ EXIT1(return); ++ } ++ ++ end = (u8 *)buf + len; ++ TRACE2("PMKID ver %d num_cand %d", ++ cand->version, cand->num_candidates); ++ for (i = 0; i < cand->num_candidates; i++) { ++ struct iw_pmkid_cand pcand; ++ union iwreq_data wrqu; ++ struct ndis_pmkid_candidate *c = ++ &cand->candidates[i]; ++ if ((u8 *)(c + 1) > end) { ++ TRACE2("truncated PMKID"); ++ break; ++ } ++ TRACE2("%ld: " MACSTRSEP " 0x%x", ++ i, MAC2STR(c->bssid), c->flags); ++ memset(&pcand, 0, sizeof(pcand)); ++ if (c->flags & 0x01) ++ pcand.flags |= IW_PMKID_CAND_PREAUTH; ++ pcand.index = i; ++ memcpy(pcand.bssid.sa_data, c->bssid, ETH_ALEN); ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.length = sizeof(pcand); ++ wireless_send_event(wnd->net_dev, IWEVPMKIDCAND, ++ &wrqu, (u8 *)&pcand); ++ } ++ break; ++ } ++ case Ndis802_11StatusType_RadioState: ++ { ++ struct ndis_radio_status_indication *radio_status = buf; ++ if (radio_status->radio_state == ++ Ndis802_11RadioStatusOn) ++ INFO("radio is turned on"); ++ else if (radio_status->radio_state == ++ Ndis802_11RadioStatusHardwareOff) ++ INFO("radio is turned off by hardware"); ++ else if (radio_status->radio_state == ++ Ndis802_11RadioStatusSoftwareOff) ++ INFO("radio is turned off by software"); ++ break; ++ } ++#endif ++ default: ++ /* is this RSSI indication? */ ++ TRACE2("unknown indication: %x", si->status_type); ++ break; ++ } ++ break; ++ default: ++ TRACE2("unknown status: %08X", status); ++ break; ++ } ++ ++ EXIT2(return); ++} ++ ++/* called via function pointer; but 64-bit RNDIS driver calls directly */ ++wstdcall void WIN_FUNC(NdisMIndicateStatusComplete,1) ++ (struct ndis_mp_block *nmb) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ENTER2("%p", wnd); ++ if (wnd->tx_ok) ++ queue_work(wrapndis_wq, &wnd->tx_work); ++} ++ ++/* called via function pointer */ ++wstdcall void NdisMSendComplete(struct ndis_mp_block *nmb, ++ struct ndis_packet *packet, NDIS_STATUS status) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ENTER4("%p, %08X", packet, status); ++ assert_irql(_irql_ <= DISPATCH_LEVEL); ++ if (deserialized_driver(wnd)) ++ free_tx_packet(wnd, packet, status); ++ else { ++ struct ndis_packet_oob_data *oob_data; ++ NDIS_STATUS pkt_status; ++ TRACE3("%p, %08x", packet, status); ++ oob_data = NDIS_PACKET_OOB_DATA(packet); ++ switch ((pkt_status = xchg(&oob_data->status, status))) { ++ case NDIS_STATUS_NOT_RECOGNIZED: ++ free_tx_packet(wnd, packet, status); ++ break; ++ case NDIS_STATUS_PENDING: ++ case 0: ++ break; ++ default: ++ WARNING("%p: invalid status: %08X", packet, pkt_status); ++ break; ++ } ++ /* In case a serialized driver has earlier requested a ++ * pause by returning NDIS_STATUS_RESOURCES during ++ * MiniportSend(Packets), wakeup tx worker now. ++ */ ++ if (xchg(&wnd->tx_ok, 1) == 0) { ++ TRACE3("%d, %d", wnd->tx_ring_start, wnd->tx_ring_end); ++ queue_work(wrapndis_wq, &wnd->tx_work); ++ } ++ } ++ EXIT3(return); ++} ++ ++/* called via function pointer */ ++wstdcall void NdisMSendResourcesAvailable(struct ndis_mp_block *nmb) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ENTER3("%d, %d", wnd->tx_ring_start, wnd->tx_ring_end); ++ wnd->tx_ok = 1; ++ queue_work(wrapndis_wq, &wnd->tx_work); ++ EXIT3(return); ++} ++ ++wstdcall void return_packet(void *arg1, void *arg2) ++{ ++ struct ndis_device *wnd; ++ struct ndis_packet *packet; ++ struct miniport *mp; ++ KIRQL irql; ++ ++ wnd = arg1; ++ packet = arg2; ++ ENTER4("%p, %p", wnd, packet); ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ irql = serialize_lock_irql(wnd); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ LIN2WIN2(mp->return_packet, wnd->nmb->mp_ctx, packet); ++ serialize_unlock_irql(wnd, irql); ++ EXIT4(return); ++} ++WIN_FUNC_DECL(return_packet,2) ++ ++/* called via function pointer */ ++wstdcall void NdisMIndicateReceivePacket(struct ndis_mp_block *nmb, ++ struct ndis_packet **packets, ++ UINT nr_packets) ++{ ++ struct ndis_device *wnd; ++ ndis_buffer *buffer; ++ struct ndis_packet *packet; ++ struct sk_buff *skb; ++ ULONG i, length, total_length; ++ struct ndis_packet_oob_data *oob_data; ++ void *virt; ++ struct ndis_tcp_ip_checksum_packet_info csum; ++ ++ ENTER3("%p, %d", nmb, nr_packets); ++ assert_irql(_irql_ <= DISPATCH_LEVEL); ++ wnd = nmb->wnd; ++ for (i = 0; i < nr_packets; i++) { ++ packet = packets[i]; ++ if (!packet) { ++ WARNING("empty packet ignored"); ++ continue; ++ } ++ wnd->net_dev->last_rx = jiffies; ++ /* get total number of bytes in packet */ ++ NdisGetFirstBufferFromPacketSafe(packet, &buffer, &virt, ++ &length, &total_length, ++ NormalPagePriority); ++ TRACE3("%d, %d", length, total_length); ++ oob_data = NDIS_PACKET_OOB_DATA(packet); ++ TRACE3("0x%x, 0x%x, %llu", packet->private.flags, ++ packet->private.packet_flags, oob_data->time_rxed); ++ skb = dev_alloc_skb(total_length); ++ if (skb) { ++ while (buffer) { ++ memcpy_skb(skb, MmGetSystemAddressForMdl(buffer), ++ MmGetMdlByteCount(buffer)); ++ buffer = buffer->next; ++ } ++ skb->dev = wnd->net_dev; ++ skb->protocol = eth_type_trans(skb, wnd->net_dev); ++ pre_atomic_add(wnd->net_stats.rx_bytes, total_length); ++ atomic_inc_var(wnd->net_stats.rx_packets); ++ csum.value = (typeof(csum.value))(ULONG_PTR) ++ oob_data->ext.info[TcpIpChecksumPacketInfo]; ++ TRACE3("0x%05x", csum.value); ++ if (wnd->rx_csum.value && ++ (csum.rx.tcp_succeeded || csum.rx.udp_succeeded || ++ csum.rx.ip_succeeded)) ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ else ++ skb->ip_summed = CHECKSUM_NONE; ++ ++ if (in_interrupt()) ++ netif_rx(skb); ++ else ++ netif_rx_ni(skb); ++ } else { ++ WARNING("couldn't allocate skb; packet dropped"); ++ atomic_inc_var(wnd->net_stats.rx_dropped); ++ } ++ ++ /* serialized drivers check the status upon return ++ * from this function */ ++ if (!deserialized_driver(wnd)) { ++ oob_data->status = NDIS_STATUS_SUCCESS; ++ continue; ++ } ++ ++ /* if a deserialized driver sets ++ * NDIS_STATUS_RESOURCES, then it reclaims the packet ++ * upon return from this function */ ++ if (oob_data->status == NDIS_STATUS_RESOURCES) ++ continue; ++ ++ assert(oob_data->status == NDIS_STATUS_SUCCESS); ++ /* deserialized driver doesn't check the status upon ++ * return from this function; we need to call ++ * MiniportReturnPacket later for this packet. Calling ++ * MiniportReturnPacket from here is not correct - the ++ * driver doesn't expect it (at least Centrino driver ++ * crashes) */ ++ schedule_ntos_work_item(WIN_FUNC_PTR(return_packet,2), ++ wnd, packet); ++ } ++ EXIT3(return); ++} ++ ++/* called via function pointer (by NdisMEthIndicateReceive macro); the ++ * first argument is nmb->eth_db */ ++wstdcall void EthRxIndicateHandler(struct ndis_mp_block *nmb, void *rx_ctx, ++ char *header1, char *header, UINT header_size, ++ void *look_ahead, UINT look_ahead_size, ++ UINT packet_size) ++{ ++ struct sk_buff *skb = NULL; ++ struct ndis_device *wnd; ++ unsigned int skb_size = 0; ++ KIRQL irql; ++ struct ndis_packet_oob_data *oob_data; ++ ++ ENTER3("nmb = %p, rx_ctx = %p, buf = %p, size = %d, buf = %p, " ++ "size = %d, packet = %d", nmb, rx_ctx, header, header_size, ++ look_ahead, look_ahead_size, packet_size); ++ ++ wnd = nmb->wnd; ++ TRACE3("wnd = %p", wnd); ++ if (!wnd) { ++ ERROR("nmb is NULL"); ++ EXIT3(return); ++ } ++ wnd->net_dev->last_rx = jiffies; ++ ++ if (look_ahead_size < packet_size) { ++ struct ndis_packet *packet; ++ struct miniport *mp; ++ unsigned int bytes_txed; ++ NDIS_STATUS res; ++ ++ NdisAllocatePacket(&res, &packet, wnd->tx_packet_pool); ++ if (res != NDIS_STATUS_SUCCESS) { ++ atomic_inc_var(wnd->net_stats.rx_dropped); ++ EXIT3(return); ++ } ++ oob_data = NDIS_PACKET_OOB_DATA(packet); ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ irql = serialize_lock_irql(wnd); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ res = LIN2WIN6(mp->tx_data, packet, &bytes_txed, nmb, ++ rx_ctx, look_ahead_size, packet_size); ++ serialize_unlock_irql(wnd, irql); ++ TRACE3("%d, %d, %d", header_size, look_ahead_size, bytes_txed); ++ if (res == NDIS_STATUS_SUCCESS) { ++ ndis_buffer *buffer; ++ struct ndis_tcp_ip_checksum_packet_info csum; ++ skb = dev_alloc_skb(header_size + look_ahead_size + ++ bytes_txed); ++ if (!skb) { ++ ERROR("couldn't allocate skb; packet dropped"); ++ atomic_inc_var(wnd->net_stats.rx_dropped); ++ NdisFreePacket(packet); ++ return; ++ } ++ memcpy_skb(skb, header, header_size); ++ memcpy_skb(skb, look_ahead, look_ahead_size); ++ buffer = packet->private.buffer_head; ++ while (buffer) { ++ memcpy_skb(skb, ++ MmGetSystemAddressForMdl(buffer), ++ MmGetMdlByteCount(buffer)); ++ buffer = buffer->next; ++ } ++ skb_size = header_size + look_ahead_size + bytes_txed; ++ csum.value = (typeof(csum.value))(ULONG_PTR) ++ oob_data->ext.info[TcpIpChecksumPacketInfo]; ++ TRACE3("0x%05x", csum.value); ++ if (wnd->rx_csum.value && ++ (csum.rx.tcp_succeeded || csum.rx.udp_succeeded)) ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ else ++ skb->ip_summed = CHECKSUM_NONE; ++ NdisFreePacket(packet); ++ } else if (res == NDIS_STATUS_PENDING) { ++ /* driver will call td_complete */ ++ oob_data->look_ahead = kmalloc(look_ahead_size, ++ GFP_ATOMIC); ++ if (!oob_data->look_ahead) { ++ NdisFreePacket(packet); ++ ERROR("packet dropped"); ++ atomic_inc_var(wnd->net_stats.rx_dropped); ++ EXIT3(return); ++ } ++ assert(sizeof(oob_data->header) == header_size); ++ memcpy(oob_data->header, header, ++ sizeof(oob_data->header)); ++ memcpy(oob_data->look_ahead, look_ahead, ++ look_ahead_size); ++ oob_data->look_ahead_size = look_ahead_size; ++ EXIT3(return); ++ } else { ++ WARNING("packet dropped: %08X", res); ++ atomic_inc_var(wnd->net_stats.rx_dropped); ++ NdisFreePacket(packet); ++ EXIT3(return); ++ } ++ } else { ++ skb_size = header_size + packet_size; ++ skb = dev_alloc_skb(skb_size); ++ if (skb) { ++ memcpy_skb(skb, header, header_size); ++ memcpy_skb(skb, look_ahead, packet_size); ++ } ++ } ++ ++ if (skb) { ++ skb->dev = wnd->net_dev; ++ skb->protocol = eth_type_trans(skb, wnd->net_dev); ++ pre_atomic_add(wnd->net_stats.rx_bytes, skb_size); ++ atomic_inc_var(wnd->net_stats.rx_packets); ++ if (in_interrupt()) ++ netif_rx(skb); ++ else ++ netif_rx_ni(skb); ++ } ++ ++ EXIT3(return); ++} ++ ++/* called via function pointer */ ++wstdcall void NdisMTransferDataComplete(struct ndis_mp_block *nmb, ++ struct ndis_packet *packet, ++ NDIS_STATUS status, UINT bytes_txed) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ struct sk_buff *skb; ++ unsigned int skb_size; ++ struct ndis_packet_oob_data *oob_data; ++ ndis_buffer *buffer; ++ struct ndis_tcp_ip_checksum_packet_info csum; ++ ++ ENTER3("wnd = %p, packet = %p, bytes_txed = %d", ++ wnd, packet, bytes_txed); ++ if (!packet) { ++ WARNING("illegal packet"); ++ EXIT3(return); ++ } ++ wnd->net_dev->last_rx = jiffies; ++ oob_data = NDIS_PACKET_OOB_DATA(packet); ++ skb_size = sizeof(oob_data->header) + oob_data->look_ahead_size + ++ bytes_txed; ++ skb = dev_alloc_skb(skb_size); ++ if (!skb) { ++ kfree(oob_data->look_ahead); ++ NdisFreePacket(packet); ++ ERROR("couldn't allocate skb; packet dropped"); ++ atomic_inc_var(wnd->net_stats.rx_dropped); ++ EXIT3(return); ++ } ++ memcpy_skb(skb, oob_data->header, sizeof(oob_data->header)); ++ memcpy_skb(skb, oob_data->look_ahead, oob_data->look_ahead_size); ++ buffer = packet->private.buffer_head; ++ while (buffer) { ++ memcpy_skb(skb, MmGetSystemAddressForMdl(buffer), ++ MmGetMdlByteCount(buffer)); ++ buffer = buffer->next; ++ } ++ kfree(oob_data->look_ahead); ++ NdisFreePacket(packet); ++ skb->dev = wnd->net_dev; ++ skb->protocol = eth_type_trans(skb, wnd->net_dev); ++ pre_atomic_add(wnd->net_stats.rx_bytes, skb_size); ++ atomic_inc_var(wnd->net_stats.rx_packets); ++ ++ csum.value = (typeof(csum.value))(ULONG_PTR) ++ oob_data->ext.info[TcpIpChecksumPacketInfo]; ++ TRACE3("0x%05x", csum.value); ++ if (wnd->rx_csum.value && ++ (csum.rx.tcp_succeeded || csum.rx.udp_succeeded)) ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ else ++ skb->ip_summed = CHECKSUM_NONE; ++ ++ if (in_interrupt()) ++ netif_rx(skb); ++ else ++ netif_rx_ni(skb); ++} ++ ++/* called via function pointer */ ++wstdcall void EthRxComplete(struct ndis_mp_block *nmb) ++{ ++ TRACE3(""); ++} ++ ++/* called via function pointer */ ++wstdcall void NdisMQueryInformationComplete(struct ndis_mp_block *nmb, ++ NDIS_STATUS status) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ typeof(wnd->ndis_req_task) task; ++ ++ ENTER2("nmb: %p, wnd: %p, %08X", nmb, wnd, status); ++ wnd->ndis_req_status = status; ++ wnd->ndis_req_done = 1; ++ if ((task = xchg(&wnd->ndis_req_task, NULL))) ++ wake_up_process(task); ++ else ++ WARNING("invalid task"); ++ EXIT2(return); ++} ++ ++/* called via function pointer */ ++wstdcall void NdisMSetInformationComplete(struct ndis_mp_block *nmb, ++ NDIS_STATUS status) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ typeof(wnd->ndis_req_task) task; ++ ++ ENTER2("status = %08X", status); ++ wnd->ndis_req_status = status; ++ wnd->ndis_req_done = 1; ++ if ((task = xchg(&wnd->ndis_req_task, NULL))) ++ wake_up_process(task); ++ else ++ WARNING("invalid task"); ++ EXIT2(return); ++} ++ ++/* called via function pointer */ ++wstdcall void NdisMResetComplete(struct ndis_mp_block *nmb, ++ NDIS_STATUS status, BOOLEAN address_reset) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ typeof(wnd->ndis_req_task) task; ++ ++ ENTER2("status: %08X, %u", status, address_reset); ++ wnd->ndis_req_status = status; ++ wnd->ndis_req_done = address_reset + 1; ++ if ((task = xchg(&wnd->ndis_req_task, NULL))) ++ wake_up_process(task); ++ else ++ WARNING("invalid task"); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisMSleep,1) ++ (ULONG us) ++{ ++ unsigned long delay; ++ ++ ENTER4("%p: us: %u", current, us); ++ delay = USEC_TO_HZ(us); ++ sleep_hz(delay); ++ TRACE4("%p: done", current); ++} ++ ++wstdcall void WIN_FUNC(NdisGetCurrentSystemTime,1) ++ (LARGE_INTEGER *time) ++{ ++ *time = ticks_1601(); ++ TRACE5("%llu, %lu", *time, jiffies); ++} ++ ++wstdcall LONG WIN_FUNC(NdisInterlockedDecrement,1) ++ (LONG *val) ++{ ++ return InterlockedDecrement(val); ++} ++ ++wstdcall LONG WIN_FUNC(NdisInterlockedIncrement,1) ++ (LONG *val) ++{ ++ return InterlockedIncrement(val); ++} ++ ++wstdcall struct nt_list *WIN_FUNC(NdisInterlockedInsertHeadList,3) ++ (struct nt_list *head, struct nt_list *entry, ++ struct ndis_spinlock *lock) ++{ ++ return ExInterlockedInsertHeadList(head, entry, &lock->klock); ++} ++ ++wstdcall struct nt_list *WIN_FUNC(NdisInterlockedInsertTailList,3) ++ (struct nt_list *head, struct nt_list *entry, ++ struct ndis_spinlock *lock) ++{ ++ return ExInterlockedInsertTailList(head, entry, &lock->klock); ++} ++ ++wstdcall struct nt_list *WIN_FUNC(NdisInterlockedRemoveHeadList,2) ++ (struct nt_list *head, struct ndis_spinlock *lock) ++{ ++ return ExInterlockedRemoveHeadList(head, &lock->klock); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMInitializeScatterGatherDma,3) ++ (struct ndis_mp_block *nmb, BOOLEAN dma64_supported, ULONG max_phy_map) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ENTER2("dma64_supported=%d, maxtransfer=%u", dma64_supported, ++ max_phy_map); ++ if (!wrap_is_pci_bus(wnd->wd->dev_bus)) { ++ ERROR("used on a non-PCI device"); ++ return NDIS_STATUS_NOT_SUPPORTED; ++ } ++#ifdef CONFIG_X86_64 ++ if (!dma64_supported) { ++ TRACE1("64-bit DMA size is not supported"); ++ if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(32)) || ++ pci_set_consistent_dma_mask(wnd->wd->pci.pdev, ++ DMA_BIT_MASK(32))) ++ WARNING("setting dma mask failed"); ++ } ++#endif ++ if ((wnd->attributes & NDIS_ATTRIBUTE_BUS_MASTER) && ++ wrap_is_pci_bus(wnd->wd->dev_bus)) { ++ wnd->sg_dma_size = max_phy_map; ++ return NDIS_STATUS_SUCCESS; ++ } else ++ EXIT1(return NDIS_STATUS_NOT_SUPPORTED); ++} ++ ++wstdcall ULONG WIN_FUNC(NdisMGetDmaAlignment,1) ++ (struct ndis_mp_block *nmb) ++{ ++ ENTER3(""); ++ return dma_get_cache_alignment(); ++} ++ ++wstdcall CHAR WIN_FUNC(NdisSystemProcessorCount,0) ++ (void) ++{ ++ return num_online_cpus(); ++} ++ ++wstdcall void WIN_FUNC(NdisGetCurrentProcessorCounts,3) ++ (ULONG *idle, ULONG *kernel_user, ULONG *index) ++{ ++ int cpu = smp_processor_id(); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0) ++ *idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE]; ++ *kernel_user = kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM] + ++ kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; ++#else ++ *idle = kstat_cpu(cpu).cpustat.idle; ++ *kernel_user = kstat_cpu(cpu).cpustat.system + ++ kstat_cpu(cpu).cpustat.user; ++#endif ++ *index = cpu; ++} ++ ++wstdcall void WIN_FUNC(NdisInitializeEvent,1) ++ (struct ndis_event *ndis_event) ++{ ++ EVENTENTER("%p", ndis_event); ++ KeInitializeEvent(&ndis_event->nt_event, NotificationEvent, 0); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(NdisWaitEvent,2) ++ (struct ndis_event *ndis_event, UINT ms) ++{ ++ LARGE_INTEGER ticks; ++ NTSTATUS res; ++ ++ EVENTENTER("%p %u", ndis_event, ms); ++ ticks = -((LARGE_INTEGER)ms * TICKSPERMSEC); ++ res = KeWaitForSingleObject(&ndis_event->nt_event, 0, 0, TRUE, ++ ms == 0 ? NULL : &ticks); ++ if (res == STATUS_SUCCESS) ++ EXIT3(return TRUE); ++ else ++ EXIT3(return FALSE); ++} ++ ++wstdcall void WIN_FUNC(NdisSetEvent,1) ++ (struct ndis_event *ndis_event) ++{ ++ EVENTENTER("%p", ndis_event); ++ KeSetEvent(&ndis_event->nt_event, 0, 0); ++} ++ ++wstdcall void WIN_FUNC(NdisResetEvent,1) ++ (struct ndis_event *ndis_event) ++{ ++ EVENTENTER("%p", ndis_event); ++ KeResetEvent(&ndis_event->nt_event); ++} ++ ++static void ndis_worker(struct work_struct *dummy) ++{ ++ struct nt_list *ent; ++ struct ndis_work_item *ndis_work_item; ++ ++ WORKENTER(""); ++ while (1) { ++ spin_lock_bh(&ndis_work_list_lock); ++ ent = RemoveHeadList(&ndis_work_list); ++ spin_unlock_bh(&ndis_work_list_lock); ++ if (!ent) ++ break; ++ ndis_work_item = container_of(ent, struct ndis_work_item, list); ++ WORKTRACE("%p: %p, %p", ndis_work_item, ++ ndis_work_item->func, ndis_work_item->ctx); ++ LIN2WIN2(ndis_work_item->func, ndis_work_item, ++ ndis_work_item->ctx); ++ WORKTRACE("%p done", ndis_work_item); ++ } ++ WORKEXIT(return); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisScheduleWorkItem,1) ++ (struct ndis_work_item *ndis_work_item) ++{ ++ ENTER3("%p", ndis_work_item); ++ spin_lock_bh(&ndis_work_list_lock); ++ InsertTailList(&ndis_work_list, &ndis_work_item->list); ++ spin_unlock_bh(&ndis_work_list_lock); ++ WORKTRACE("scheduling %p", ndis_work_item); ++ queue_work(ndis_wq, &ndis_work); ++ EXIT3(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(NdisMGetDeviceProperty,6) ++ (struct ndis_mp_block *nmb, void **phy_dev, void **func_dev, ++ void **next_dev, void **alloc_res, void**trans_res) ++{ ++ ENTER2("nmb: %p, phy_dev = %p, func_dev = %p, next_dev = %p, " ++ "alloc_res = %p, trans_res = %p", nmb, phy_dev, func_dev, ++ next_dev, alloc_res, trans_res); ++ if (phy_dev) ++ *phy_dev = nmb->pdo; ++ if (func_dev) ++ *func_dev = nmb->fdo; ++ if (next_dev) ++ *next_dev = nmb->next_device; ++} ++ ++wstdcall void WIN_FUNC(NdisMRegisterUnloadHandler,2) ++ (struct driver_object *drv_obj, void *unload) ++{ ++ if (drv_obj) ++ drv_obj->unload = unload; ++ return; ++} ++ ++wstdcall UINT WIN_FUNC(NdisGetVersion,0) ++ (void) ++{ ++ return 0x00050001; ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMQueryAdapterInstanceName,2) ++ (struct unicode_string *name, struct ndis_mp_block *nmb) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ struct ansi_string ansi; ++ ++ if (wrap_is_pci_bus(wnd->wd->dev_bus)) ++ RtlInitAnsiString(&ansi, "PCI Ethernet Adapter"); ++ else ++ RtlInitAnsiString(&ansi, "USB Ethernet Adapter"); ++ ++ if (RtlAnsiStringToUnicodeString(name, &ansi, TRUE)) ++ EXIT2(return NDIS_STATUS_RESOURCES); ++ else ++ EXIT2(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisWriteEventLogEntry,7) ++ (void *handle, NDIS_STATUS code, ULONG value, USHORT n, ++ void *strings, ULONG datasize, void *data) ++{ ++ TRACE1("0x%x, 0x%x, %u, %u", code, value, n, datasize); ++ return NDIS_STATUS_SUCCESS; ++} ++ ++wstdcall void *WIN_FUNC(NdisGetRoutineAddress,1) ++ (struct unicode_string *unicode_string) ++{ ++ struct ansi_string ansi_string; ++ void *address; ++ ++ if (RtlUnicodeStringToAnsiString(&ansi_string, unicode_string, TRUE) != ++ STATUS_SUCCESS) ++ EXIT1(return NULL); ++ INFO("%s", ansi_string.buf); ++ address = ndis_get_routine_address(ansi_string.buf); ++ RtlFreeAnsiString(&ansi_string); ++ return address; ++} ++ ++wstdcall ULONG WIN_FUNC(NdisReadPcmciaAttributeMemory,4) ++ (struct ndis_mp_block *nmb, ULONG offset, void *buffer, ++ ULONG length) ++{ ++ TODO(); ++ return 0; ++} ++ ++wstdcall ULONG WIN_FUNC(NdisWritePcmciaAttributeMemory,4) ++ (struct ndis_mp_block *nmb, ULONG offset, void *buffer, ++ ULONG length) ++{ ++ TODO(); ++ return 0; ++} ++ ++wstdcall void WIN_FUNC(NdisMCoIndicateReceivePacket,3) ++ (struct ndis_mp_block *nmb, struct ndis_packet **packets, ++ UINT nr_packets) ++{ ++ ENTER3("nmb = %p", nmb); ++ NdisMIndicateReceivePacket(nmb, packets, nr_packets); ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(NdisMCoSendComplete,3) ++ (NDIS_STATUS status, struct ndis_mp_block *nmb, ++ struct ndis_packet *packet) ++{ ++ ENTER3("%08x", status); ++ NdisMSendComplete(nmb, packet, status); ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(NdisMCoRequestComplete,3) ++ (NDIS_STATUS status, struct ndis_mp_block *nmb, ++ struct ndis_request *ndis_request) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ typeof(wnd->ndis_req_task) task; ++ ++ ENTER3("%08X", status); ++ wnd->ndis_req_status = status; ++ wnd->ndis_req_done = 1; ++ if ((task = xchg(&wnd->ndis_req_task, NULL))) ++ wake_up_process(task); ++ else ++ WARNING("invalid task"); ++ EXIT3(return); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisIMNotifiyPnPEvent,2) ++ (struct ndis_mp_block *nmb, struct net_pnp_event *event) ++{ ++ ENTER2("%p, %d", nmb, event->code); ++ /* NdisWrapper never calls protocol's pnp event notifier, so ++ * nothing to do here */ ++ EXIT2(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(NdisCompletePnPEvent,3) ++ (NDIS_STATUS status, void *handle, struct net_pnp_event *event) ++{ ++ ENTER2("%d, %p, %d", status, handle, event->code); ++ /* NdisWrapper never calls protocol's pnp event notifier, so ++ * nothing to do here */ ++ EXIT2(return); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMSetMiniportSecondary,2) ++ (struct ndis_mp_block *nmb2, struct ndis_mp_block *nmb1) ++{ ++ ENTER3("%p, %p", nmb1, nmb2); ++ TODO(); ++ EXIT3(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMPromoteMiniport,1) ++ (struct ndis_mp_block *nmb) ++{ ++ ENTER3("%p", nmb); ++ TODO(); ++ EXIT3(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(NdisMCoActivateVcComplete,3) ++ (NDIS_STATUS status, void *handle, void *params) ++{ ++ TODO(); ++} ++ ++wstdcall void WIN_FUNC(NdisMCoDeactivateVcComplete,2) ++ (NDIS_STATUS status, void *handle) ++{ ++ TODO(); ++} ++ ++wstdcall void WIN_FUNC(NdisMRemoveMiniport,1) ++ (void *handle) ++{ ++ TODO(); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMOpenLog,3) ++ (struct ndis_device *wnd, UINT size, void *handle) ++{ ++ if (size >= sizeof(int)) ++ *((int *)handle) = 42; ++ return NDIS_STATUS_SUCCESS; ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMWriteLogData,3) ++ (void *handle, char *buffer, UINT buffer_size) ++{ ++ TODO(); ++ return NDIS_STATUS_SUCCESS; ++} ++ ++wstdcall void WIN_FUNC(NdisMFlushLog,1) ++ (void *handle) ++{ ++ TODO(); ++} ++ ++wstdcall void WIN_FUNC(NdisMCloseLog,1) ++ (void *handle) ++{ ++ TODO(); ++} ++ ++static void *ndis_get_routine_address(char *name) ++{ ++ int i; ++ ENTER2("%p", name); ++ for (i = 0; i < ARRAY_SIZE(ndis_exports); i++) { ++ if (strcmp(name, ndis_exports[i].name) == 0) { ++ TRACE2("%p", ndis_exports[i].func); ++ return ndis_exports[i].func; ++ } ++ } ++ EXIT2(return NULL); ++} ++ ++/* ndis_init_device is called for each device */ ++int ndis_init_device(struct ndis_device *wnd) ++{ ++ struct ndis_mp_block *nmb = wnd->nmb; ++ ++ KeInitializeSpinLock(&nmb->lock); ++ wnd->mp_interrupt = NULL; ++ wnd->wrap_timer_slist.next = NULL; ++ if (wnd->wd->driver->ndis_driver) ++ wnd->wd->driver->ndis_driver->mp.shutdown = NULL; ++ ++ nmb->filterdbs.eth_db = nmb; ++ nmb->filterdbs.tr_db = nmb; ++ nmb->filterdbs.fddi_db = nmb; ++ nmb->filterdbs.arc_db = nmb; ++ ++ nmb->rx_packet = WIN_FUNC_PTR(NdisMIndicateReceivePacket,3); ++ nmb->send_complete = WIN_FUNC_PTR(NdisMSendComplete,3); ++ nmb->send_resource_avail = WIN_FUNC_PTR(NdisMSendResourcesAvailable,1); ++ nmb->status = WIN_FUNC_PTR(NdisMIndicateStatus,4); ++ nmb->status_complete = WIN_FUNC_PTR(NdisMIndicateStatusComplete,1); ++ nmb->queryinfo_complete = WIN_FUNC_PTR(NdisMQueryInformationComplete,2); ++ nmb->setinfo_complete = WIN_FUNC_PTR(NdisMSetInformationComplete,2); ++ nmb->reset_complete = WIN_FUNC_PTR(NdisMResetComplete,3); ++ nmb->eth_rx_indicate = WIN_FUNC_PTR(EthRxIndicateHandler,8); ++ nmb->eth_rx_complete = WIN_FUNC_PTR(EthRxComplete,1); ++ nmb->td_complete = WIN_FUNC_PTR(NdisMTransferDataComplete,4); ++ return 0; ++} ++ ++/* ndis_exit_device is called for each device */ ++void ndis_exit_device(struct ndis_device *wnd) ++{ ++ struct wrap_device_setting *setting; ++ ENTER2("%p", wnd); ++ mutex_lock(&loader_mutex); ++ nt_list_for_each_entry(setting, &wnd->wd->settings, list) { ++ struct ndis_configuration_parameter *param; ++ param = setting->encoded; ++ if (param) { ++ if (param->type == NdisParameterString) ++ RtlFreeUnicodeString(¶m->data.string); ++ ExFreePool(param); ++ setting->encoded = NULL; ++ } ++ } ++ mutex_unlock(&loader_mutex); ++} ++ ++/* ndis_init is called once when module is loaded */ ++int ndis_init(void) ++{ ++ InitializeListHead(&ndis_work_list); ++ spin_lock_init(&ndis_work_list_lock); ++ INIT_WORK(&ndis_work, ndis_worker); ++ ++ ndis_wq = create_singlethread_workqueue("ndis_wq"); ++ if (!ndis_wq) { ++ WARNING("couldn't create worker thread"); ++ EXIT1(return -ENOMEM); ++ } ++ ++ TRACE1("ndis_wq: %p", ndis_wq); ++ return 0; ++} ++ ++/* ndis_exit is called once when module is removed */ ++void ndis_exit(void) ++{ ++ ENTER1(""); ++ if (ndis_wq) ++ destroy_workqueue(ndis_wq); ++ EXIT1(return); ++} +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/ndis.h linux-4.6-rc6-ndis/3rdparty/ndiswrapper/ndis.h +--- linux-4.6-rc6/3rdparty/ndiswrapper/ndis.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/ndis.h 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,1309 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _NDIS_H_ ++#define _NDIS_H_ ++ ++#include "ntoskernel.h" ++ ++//#define ALLOW_POOL_OVERFLOW 1 ++ ++#define NDIS_DMA_24BITS 0 ++#define NDIS_DMA_32BITS 1 ++#define NDIS_DMA_64BITS 2 ++ ++#ifdef CONFIG_X86_64 ++#define MAXIMUM_PROCESSORS 64 ++#else ++#define MAXIMUM_PROCESSORS 32 ++#endif ++ ++typedef UINT NDIS_STATUS; ++typedef UCHAR NDIS_DMA_SIZE; ++typedef LONG ndis_rssi; ++typedef ULONG ndis_key_index; ++typedef ULONG ndis_tx_power_level; ++typedef ULONGULONG ndis_key_rsc; ++typedef UCHAR mac_address[ETH_ALEN]; ++typedef ULONG ndis_fragmentation_threshold; ++typedef ULONG ndis_rts_threshold; ++typedef ULONG ndis_antenna; ++typedef ULONG ndis_oid; ++ ++typedef uint64_t NDIS_PHY_ADDRESS; ++ ++struct ndis_sg_element { ++ PHYSICAL_ADDRESS address; ++ ULONG length; ++ ULONG_PTR reserved; ++}; ++ ++struct ndis_sg_list { ++ ULONG nent; ++ ULONG_PTR reserved; ++ struct ndis_sg_element elements[]; ++}; ++ ++/* when sending packets, ndiswrapper associates exactly one sg element ++ * in sg list */ ++struct wrap_tx_sg_list { ++ ULONG nent; ++ ULONG_PTR reserved; ++ struct ndis_sg_element elements[1]; ++}; ++ ++struct ndis_phy_addr_unit { ++ NDIS_PHY_ADDRESS phy_addr; ++ UINT length; ++}; ++ ++typedef struct mdl ndis_buffer; ++ ++struct ndis_buffer_pool { ++ ndis_buffer *free_descr; ++// NT_SPIN_LOCK lock; ++ spinlock_t lock; ++ UINT max_descr; ++ UINT num_allocated_descr; ++}; ++ ++#define NDIS_PROTOCOL_ID_DEFAULT 0x00 ++#define NDIS_PROTOCOL_ID_TCP_IP 0x02 ++#define NDIS_PROTOCOL_ID_IPX 0x06 ++#define NDIS_PROTOCOL_ID_NBF 0x07 ++#define NDIS_PROTOCOL_ID_MAX 0x0F ++#define NDIS_PROTOCOL_ID_MASK 0x0F ++ ++#define fPACKET_WRAPPER_RESERVED 0x3F ++#define fPACKET_CONTAINS_MEDIA_SPECIFIC_INFO 0x40 ++#define fPACKET_ALLOCATED_BY_NDIS 0x80 ++ ++#define PROTOCOL_RESERVED_SIZE_IN_PACKET (4 * sizeof(void *)) ++ ++struct transport_header_offset { ++ USHORT protocol_type; ++ USHORT header_offset; ++}; ++ ++struct ndis_network_address { ++ USHORT length; ++ USHORT type; ++ UCHAR address[1]; ++}; ++ ++struct ndis_network_address_list { ++ LONG count; ++ USHORT type; ++ struct ndis_network_address address[1]; ++}; ++ ++struct ndis_tcp_ip_checksum_packet_info { ++ union { ++ struct { ++ ULONG v4:1; ++ ULONG v6:1; ++ ULONG tcp:1; ++ ULONG udp:1; ++ ULONG ip:1; ++ } tx; ++ struct { ++ ULONG tcp_failed:1; ++ ULONG udp_failed:1; ++ ULONG ip_failed:1; ++ ULONG tcp_succeeded:1; ++ ULONG udp_succeeded:1; ++ ULONG ip_succeeded:1; ++ ULONG loopback:1; ++ } rx; ++ ULONG value; ++ }; ++}; ++ ++enum ndis_task { ++ TcpIpChecksumNdisTask, IpSecNdisTask, TcpLargeSendNdisTask, MaxNdisTask ++}; ++ ++enum ndis_encapsulation { ++ UNSPECIFIED_Encapsulation, NULL_Encapsulation, ++ IEEE_802_3_Encapsulation, IEEE_802_5_Encapsulation, ++ LLC_SNAP_ROUTED_Encapsulation, LLC_SNAP_BRIDGED_Encapsulation ++}; ++ ++#define NDIS_TASK_OFFLOAD_VERSION 1 ++ ++struct ndis_encapsulation_format { ++ enum ndis_encapsulation encap; ++ struct { ++ ULONG fixed_header_size:1; ++ ULONG reserved:31; ++ } flags; ++ ULONG header_size; ++}; ++ ++struct ndis_task_offload_header { ++ ULONG version; ++ ULONG size; ++ ULONG reserved; ++ ULONG offset_first_task; ++ struct ndis_encapsulation_format encap_format; ++}; ++ ++struct ndis_task_offload { ++ ULONG version; ++ ULONG size; ++ enum ndis_task task; ++ ULONG offset_next_task; ++ ULONG task_buf_length; ++ UCHAR task_buf[1]; ++}; ++ ++struct v4_checksum { ++ union { ++ struct { ++ ULONG ip_opts:1; ++ ULONG tcp_opts:1; ++ ULONG tcp_csum:1; ++ ULONG udp_csum:1; ++ ULONG ip_csum:1; ++ }; ++ ULONG value; ++ }; ++}; ++ ++struct v6_checksum { ++ ULONG ip_supported:1; ++ ULONG tcp_supported:1; ++ ULONG tcp_csum:1; ++ ULONG udp_csum:1; ++}; ++ ++struct ndis_task_tcp_ip_checksum { ++ struct v4_checksum v4_tx; ++ struct v4_checksum v4_rx; ++ struct v6_checksum v6_tx; ++ struct v6_checksum v6_rx; ++}; ++ ++struct ndis_task_tcp_large_send { ++ ULONG version; ++ ULONG max_size; ++ ULONG min_seg_count; ++ BOOLEAN tcp_opts; ++ BOOLEAN ip_opts; ++}; ++ ++struct ndis_packet; ++ ++struct ndis_packet_pool { ++ struct ndis_packet *free_descr; ++// NT_SPIN_LOCK lock; ++ spinlock_t lock; ++ UINT max_descr; ++ UINT num_allocated_descr; ++ UINT num_used_descr; ++ UINT proto_rsvd_length; ++}; ++ ++struct ndis_packet_stack { ++ ULONG_PTR IM_reserved[2]; ++ ULONG_PTR ndis_reserved[4]; ++}; ++ ++enum ndis_per_packet_info { ++ TcpIpChecksumPacketInfo, IpSecPacketInfo, TcpLargeSendPacketInfo, ++ ClassificationHandlePacketInfo, NdisReserved, ++ ScatterGatherListPacketInfo, Ieee8021QInfo, OriginalPacketInfo, ++ PacketCancelId, MaxPerPacketInfo ++}; ++ ++struct ndis_packet_extension { ++ void *info[MaxPerPacketInfo]; ++}; ++ ++struct ndis_packet_private { ++ UINT nr_pages; ++ UINT len; ++ ndis_buffer *buffer_head; ++ ndis_buffer *buffer_tail; ++ struct ndis_packet_pool *pool; ++ UINT count; ++ ULONG flags; ++ BOOLEAN valid_counts; ++ UCHAR packet_flags; ++ USHORT oob_offset; ++}; ++ ++struct ndis_packet { ++ struct ndis_packet_private private; ++ /* for use by miniport */ ++ union { ++ /* for connectionless mininports */ ++ struct { ++ UCHAR miniport_reserved[2 * sizeof(void *)]; ++ UCHAR wrapper_reserved[2 * sizeof(void *)]; ++ } cl_reserved; ++ /* for deserialized miniports */ ++ struct { ++ UCHAR miniport_reserved_ex[3 * sizeof(void *)]; ++ UCHAR wrapper_reserved_ex[sizeof(void *)]; ++ } deserialized_reserved; ++ struct { ++ UCHAR mac_reserved[4 * sizeof(void *)]; ++ } mac_reserved; ++ }; ++ ULONG_PTR reserved[2]; ++ UCHAR protocol_reserved[1]; ++}; ++ ++/* OOB data */ ++struct ndis_packet_oob_data { ++ union { ++ ULONGLONG time_to_tx; ++ ULONGLONG time_txed; ++ }; ++ ULONGLONG time_rxed; ++ UINT header_size; ++ UINT media_size; ++ void *media; ++ NDIS_STATUS status; ++ ++ /* ndiswrapper specific info; extension should be right after ++ * ndis's oob_data */ ++ struct ndis_packet_extension ext; ++ union { ++ /* used for tx only */ ++ struct { ++ struct sk_buff *tx_skb; ++ union { ++ struct wrap_tx_sg_list wrap_tx_sg_list; ++ struct ndis_sg_list *tx_sg_list; ++ }; ++ }; ++ /* used for rx only */ ++ struct { ++ unsigned char header[ETH_HLEN]; ++ unsigned char *look_ahead; ++ UINT look_ahead_size; ++ }; ++ }; ++}; ++ ++#define NDIS_PACKET_OOB_DATA(packet) \ ++ (struct ndis_packet_oob_data *)(((void *)(packet)) + \ ++ (packet)->private.oob_offset) ++ ++enum ndis_device_pnp_event { ++ NdisDevicePnPEventQueryRemoved, NdisDevicePnPEventRemoved, ++ NdisDevicePnPEventSurpriseRemoved, NdisDevicePnPEventQueryStopped, ++ NdisDevicePnPEventStopped, NdisDevicePnPEventPowerProfileChanged, ++ NdisDevicePnPEventMaximum ++}; ++ ++enum ndis_request_type { ++ NdisRequestQueryInformation, NdisRequestSetInformation, ++ NdisRequestQueryStatistics, NdisRequestOpen, NdisRequestClose, ++ NdisRequestSend, NdisRequestTransferData, NdisRequestReset, ++ NdisRequestGeneric1, NdisRequestGeneric2, NdisRequestGeneric3, ++ NdisRequestGeneric4 ++}; ++ ++struct ndis_request { ++ mac_address mac; ++ enum ndis_request_type request_type; ++ union data { ++ struct query_info { ++ UINT oid; ++ void *buf; ++ UINT buf_len; ++ UINT written; ++ UINT needed; ++ } query_info; ++ struct set_info { ++ UINT oid; ++ void *buf; ++ UINT buf_len; ++ UINT written; ++ UINT needed; ++ } set_info; ++ } data; ++}; ++ ++enum ndis_medium { ++ NdisMedium802_3, NdisMedium802_5, NdisMediumFddi, NdisMediumWan, ++ NdisMediumLocalTalk, NdisMediumDix, NdisMediumArcnetRaw, ++ NdisMediumArcnet878_2, NdisMediumAtm, NdisMediumWirelessWan, ++ NdisMediumIrda, NdisMediumBpc, NdisMediumCoWan, ++ NdisMedium1394, NdisMediumMax ++}; ++ ++enum ndis_physical_medium { ++ NdisPhysicalMediumUnspecified, NdisPhysicalMediumWirelessLan, ++ NdisPhysicalMediumCableModem, NdisPhysicalMediumPhoneLine, ++ NdisPhysicalMediumPowerLine, NdisPhysicalMediumDSL, ++ NdisPhysicalMediumFibreChannel, NdisPhysicalMedium1394, ++ NdisPhysicalMediumWirelessWan, NdisPhysicalMediumMax ++}; ++ ++enum ndis_power_state { ++ NdisDeviceStateUnspecified = 0, ++ NdisDeviceStateD0, NdisDeviceStateD1, NdisDeviceStateD2, ++ NdisDeviceStateD3, NdisDeviceStateMaximum ++}; ++ ++enum ndis_power_profile { ++ NdisPowerProfileBattery, NdisPowerProfileAcOnLine ++}; ++ ++struct ndis_pm_wakeup_capabilities { ++ enum ndis_power_state min_magic_packet_wakeup; ++ enum ndis_power_state min_pattern_wakeup; ++ enum ndis_power_state min_link_change_wakeup; ++}; ++ ++#define NDIS_PNP_WAKE_UP_MAGIC_PACKET 0x00000001 ++#define NDIS_PNP_WAKE_UP_PATTERN_MATCH 0x00000002 ++#define NDIS_PNP_WAKE_UP_LINK_CHANGE 0x00000004 ++ ++enum net_pnp_event_code { ++ NetEventSetPower, NetEventQueryPower, NetEventQueryRemoveDevice, ++ NetEventCancelRemoveDevice, NetEventReconfigure, NetEventBindList, ++ NetEventBindsComplete, NetEventPnPCapabilities, NetEventMaximum ++}; ++ ++struct net_pnp_event { ++ enum net_pnp_event_code code; ++ void *buf; ++ ULONG buf_length; ++ ULONG_PTR ndis_reserved[4]; ++ ULONG_PTR transport_reserved[4]; ++ ULONG_PTR tdi_reserved[4]; ++ ULONG_PTR tdi_client_reserved[4]; ++}; ++ ++struct ndis_pnp_capabilities { ++ ULONG flags; ++ struct ndis_pm_wakeup_capabilities wakeup; ++}; ++ ++typedef void (*ndis_isr_handler)(BOOLEAN *recognized, BOOLEAN *queue_handler, ++ void *handle) wstdcall; ++typedef void (*ndis_interrupt_handler)(void *ctx) wstdcall; ++ ++struct miniport { ++ /* NDIS 3.0 */ ++ UCHAR major_version; ++ UCHAR minor_version; ++ USHORT filler; ++ UINT reserved; ++ BOOLEAN (*hangcheck)(void *ctx) wstdcall; ++ void (*disable_interrupt)(void *ctx) wstdcall; ++ void (*enable_interrupt)(void *ctx) wstdcall; ++ void (*mp_halt)(void *ctx) wstdcall; ++ ndis_interrupt_handler handle_interrupt; ++ NDIS_STATUS (*init)(NDIS_STATUS *error_status, UINT *medium_index, ++ enum ndis_medium medium[], UINT medium_array_size, ++ void *handle, void *conf_handle) wstdcall; ++ ndis_isr_handler isr; ++ NDIS_STATUS (*queryinfo)(void *ctx, ndis_oid oid, void *buffer, ++ ULONG buflen, ULONG *written, ++ ULONG *needed) wstdcall; ++ void *reconfig; ++ NDIS_STATUS (*reset)(BOOLEAN *reset_address, void *ctx) wstdcall; ++ NDIS_STATUS (*send)(void *ctx, struct ndis_packet *packet, ++ UINT flags) wstdcall; ++ NDIS_STATUS (*setinfo)(void *ctx, ndis_oid oid, void *buffer, ++ ULONG buflen, ULONG *written, ++ ULONG *needed) wstdcall; ++ NDIS_STATUS (*tx_data)(struct ndis_packet *ndis_packet, ++ UINT *bytes_txed, void *mp_ctx, void *rx_ctx, ++ UINT offset, UINT bytes_to_tx) wstdcall; ++ /* NDIS 4.0 extensions */ ++ void (*return_packet)(void *ctx, void *packet) wstdcall; ++ void (*send_packets)(void *ctx, struct ndis_packet **packets, ++ INT nr_of_packets) wstdcall; ++ void (*alloc_complete)(void *handle, void *virt, ++ NDIS_PHY_ADDRESS *phys, ++ ULONG size, void *ctx) wstdcall; ++ /* NDIS 5.0 extensions */ ++ NDIS_STATUS (*co_create_vc)(void *ctx, void *vc_handle, ++ void *vc_ctx) wstdcall; ++ NDIS_STATUS (*co_delete_vc)(void *vc_ctx) wstdcall; ++ NDIS_STATUS (*co_activate_vc)(void *vc_ctx, void *call_params) wstdcall; ++ NDIS_STATUS (*co_deactivate_vc)(void *vc_ctx) wstdcall; ++ NDIS_STATUS (*co_send_packets)(void *vc_ctx, void **packets, ++ UINT nr_of_packets) wstdcall; ++ NDIS_STATUS (*co_request)(void *ctx, void *vc_ctx, UINT *req) wstdcall; ++ /* NDIS 5.1 extensions */ ++ void (*cancel_send_packets)(void *ctx, void *id) wstdcall; ++ void (*pnp_event_notify)(void *ctx, enum ndis_device_pnp_event event, ++ void *inf_buf, ULONG inf_buf_len) wstdcall; ++ void (*shutdown)(void *ctx) wstdcall; ++ void *reserved1; ++ void *reserved2; ++ void *reserved3; ++ void *reserved4; ++}; ++ ++struct ndis_spinlock { ++ NT_SPIN_LOCK klock; ++ KIRQL irql; ++}; ++ ++union ndis_rw_lock_refcount { ++ UCHAR cache_line[16]; ++}; ++ ++struct ndis_rw_lock { ++ union { ++ struct { ++ NT_SPIN_LOCK klock; ++ void *context; ++ }; ++ UCHAR reserved[16]; ++ }; ++ union { ++ union ndis_rw_lock_refcount ref_count[MAXIMUM_PROCESSORS]; ++ /* ndiswrapper specific */ ++ volatile int count; ++ }; ++}; ++ ++struct lock_state { ++ USHORT state; ++ KIRQL irql; ++}; ++ ++struct ndis_work_item; ++typedef void (*NDIS_PROC)(struct ndis_work_item *, void *) wstdcall; ++ ++struct ndis_work_item { ++ void *ctx; ++ NDIS_PROC func; ++ union { ++ UCHAR reserved[8 * sizeof(void *)]; ++ /* ndiswrapper specific */ ++ struct nt_list list; ++ }; ++}; ++ ++struct alloc_shared_mem { ++ void *ctx; ++ ULONG size; ++ BOOLEAN cached; ++}; ++ ++struct ndis_mp_block; ++ ++/* this is opaque to drivers, so we can use it as we please */ ++struct ndis_mp_interrupt { ++ struct kinterrupt *kinterrupt; ++ NT_SPIN_LOCK lock; ++ union { ++ void *reserved; ++ unsigned int irq; ++ }; ++ ndis_isr_handler isr; ++ ndis_interrupt_handler mp_dpc; ++ struct kdpc intr_dpc; ++ struct ndis_mp_block *nmb; ++ UCHAR dpc_count; ++ BOOLEAN enable; ++ struct nt_event dpc_completed_event; ++ BOOLEAN shared; ++ BOOLEAN req_isr; ++}; ++ ++struct ndis_binary_data { ++ USHORT len; ++ void *buf; ++}; ++ ++enum ndis_parameter_type { ++ NdisParameterInteger, NdisParameterHexInteger, ++ NdisParameterString, NdisParameterMultiString, NdisParameterBinary, ++}; ++ ++typedef struct unicode_string NDIS_STRING; ++ ++struct ndis_configuration_parameter { ++ enum ndis_parameter_type type; ++ union { ++ ULONG integer; ++ NDIS_STRING string; ++ } data; ++}; ++ ++struct ndis_driver { ++ struct miniport mp; ++}; ++ ++/* IDs used to store extensions in driver_object's custom extension */ ++#define NDIS_DRIVER_CLIENT_ID 10 ++ ++struct ndis_wireless_stats { ++ ULONG length; ++ LARGE_INTEGER tx_frag; ++ LARGE_INTEGER tx_multi_frag; ++ LARGE_INTEGER failed; ++ LARGE_INTEGER retry; ++ LARGE_INTEGER multi_retry; ++ LARGE_INTEGER rtss_succ; ++ LARGE_INTEGER rtss_fail; ++ LARGE_INTEGER ack_fail; ++ LARGE_INTEGER frame_dup; ++ LARGE_INTEGER rx_frag; ++ LARGE_INTEGER rx_multi_frag; ++ LARGE_INTEGER fcs_err; ++ LARGE_INTEGER tkip_local_mic_failures; ++ LARGE_INTEGER tkip_icv_errors; ++ LARGE_INTEGER tkip_counter_measures_invoked; ++ LARGE_INTEGER tkip_replays; ++ LARGE_INTEGER ccmp_format_errors; ++ LARGE_INTEGER ccmp_replays; ++ LARGE_INTEGER ccmp_decrypt_errors; ++ LARGE_INTEGER fourway_handshake_failures; ++ LARGE_INTEGER wep_undecryptable_count; ++ LARGE_INTEGER wep_icv_errorcount; ++ LARGE_INTEGER decrypt_success_count; ++ LARGE_INTEGER decrypt_failure_count; ++}; ++ ++enum ndis_status_type { ++ Ndis802_11StatusType_Authentication, ++ Ndis802_11StatusType_MediaStreamMode, ++ Ndis802_11StatusType_PMKID_CandidateList, ++ Ndis802_11StatusType_RadioState, ++}; ++ ++struct ndis_status_indication { ++ enum ndis_status_type status_type; ++}; ++ ++enum ndis_radio_status { ++ Ndis802_11RadioStatusOn, Ndis802_11RadioStatusHardwareOff, ++ Ndis802_11RadioStatusSoftwareOff, ++}; ++ ++struct ndis_radio_status_indication ++{ ++ enum ndis_status_type status_type; ++ enum ndis_radio_status radio_state; ++}; ++ ++enum ndis_media_state { ++ NdisMediaStateConnected, ++ NdisMediaStateDisconnected, ++}; ++ ++enum ndis_media_stream_mode { ++ Ndis802_11MediaStreamOff, Ndis802_11MediaStreamOn ++}; ++ ++enum wrapper_work { ++ LINK_STATUS_OFF, LINK_STATUS_ON, SET_MULTICAST_LIST, COLLECT_IW_STATS, ++ HANGCHECK, NETIF_WAKEQ, ++}; ++ ++struct encr_info { ++ struct encr_key { ++ ULONG length; ++ UCHAR key[NDIS_ENCODING_TOKEN_MAX]; ++ } keys[MAX_ENCR_KEYS]; ++ unsigned short tx_key_index; ++}; ++ ++struct ndis_essid { ++ ULONG length; ++ UCHAR essid[NDIS_ESSID_MAX_SIZE]; ++}; ++ ++enum ndis_infrastructure_mode { ++ Ndis802_11IBSS, Ndis802_11Infrastructure, Ndis802_11AutoUnknown, ++ Ndis802_11InfrastructureMax ++}; ++ ++enum authentication_mode { ++ Ndis802_11AuthModeOpen, Ndis802_11AuthModeShared, ++ Ndis802_11AuthModeAutoSwitch, Ndis802_11AuthModeWPA, ++ Ndis802_11AuthModeWPAPSK, Ndis802_11AuthModeWPANone, ++ Ndis802_11AuthModeWPA2, Ndis802_11AuthModeWPA2PSK, ++ Ndis802_11AuthModeMax ++}; ++ ++enum encryption_status { ++ Ndis802_11WEPEnabled, ++ Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, ++ Ndis802_11WEPDisabled, ++ Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, ++ Ndis802_11WEPKeyAbsent, ++ Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, ++ Ndis802_11WEPNotSupported, ++ Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, ++ Ndis802_11Encryption2Enabled, Ndis802_11Encryption2KeyAbsent, ++ Ndis802_11Encryption3Enabled, Ndis802_11Encryption3KeyAbsent ++}; ++ ++struct ndis_auth_encr_pair { ++ enum authentication_mode auth_mode; ++ enum encryption_status encr_mode; ++}; ++ ++struct ndis_capability { ++ ULONG length; ++ ULONG version; ++ ULONG num_PMKIDs; ++ ULONG num_auth_encr_pair; ++ struct ndis_auth_encr_pair auth_encr_pair[1]; ++}; ++ ++struct ndis_guid { ++ struct guid guid; ++ union { ++ ndis_oid oid; ++ NDIS_STATUS status; ++ }; ++ ULONG size; ++ ULONG flags; ++}; ++ ++struct ndis_timer { ++ struct nt_timer nt_timer; ++ struct kdpc kdpc; ++}; ++ ++struct ndis_mp_timer { ++ struct nt_timer nt_timer; ++ struct kdpc kdpc; ++ DPC func; ++ void *ctx; ++ struct ndis_mp_block *nmb; ++ struct ndis_mp_timer *next; ++}; ++ ++typedef struct cm_partial_resource_list NDIS_RESOURCE_LIST; ++ ++struct ndis_event { ++ struct nt_event nt_event; ++}; ++ ++struct ndis_bind_paths { ++ UINT number; ++ struct unicode_string paths[1]; ++}; ++ ++struct ndis_reference { ++ NT_SPIN_LOCK lock; ++ USHORT ref_count; ++ BOOLEAN closing; ++}; ++ ++struct ndis_filterdbs { ++ union { ++ void *eth_db; ++ void *null_db; ++ }; ++ void *tr_db; ++ void *fddi_db; ++ void *arc_db; ++}; ++ ++enum ndis_interface_type { ++ NdisInterfaceInternal, NdisInterfaceIsa, NdisInterfaceEisa, ++ NdisInterfaceMca, NdisInterfaceTurboChannel, NdisInterfacePci, ++ NdisInterfacePcMcia, ++}; ++ ++struct auth_encr_capa { ++ unsigned long auth; ++ unsigned long encr; ++}; ++ ++struct ndis_pmkid_candidate { ++ mac_address bssid; ++ DWORD flags; ++}; ++ ++struct ndis_pmkid_candidate_list { ++ ULONG version; ++ ULONG num_candidates; ++ struct ndis_pmkid_candidate candidates[1]; ++}; ++ ++/* ++ * This struct contains function pointers that the drivers references ++ * directly via macros, so it's important that they are at the correct ++ * position. ++ */ ++struct ndis_mp_block { ++ void *signature; ++ struct ndis_mp_block *next; ++ struct driver_object *drv_obj; ++ void *mp_ctx; ++ struct unicode_string name; ++ struct ndis_bind_paths *bindpaths; ++ void *openqueue; ++ struct ndis_reference reference; ++ void *device_ctx; ++ UCHAR padding; ++ UCHAR lock_acquired; ++ UCHAR pmode_opens; ++ UCHAR assigned_cpu; ++ NT_SPIN_LOCK lock; ++ enum ndis_request_type *mediarequest; ++ struct ndis_mp_interrupt *interrupt; ++ ULONG flags; ++ ULONG pnp_flags; ++ struct nt_list packet_list; ++ struct ndis_packet *first_pending_tx_packet; ++ struct ndis_packet *return_packet_queue; ++ ULONG request_buffer; ++ void *set_mcast_buffer; ++ struct ndis_mp_block *primary_mp; ++ void *wrapper_ctx; ++ void *bus_data_ctx; ++ ULONG pnp_capa; ++ void *resources; ++ struct ndis_timer wakeup_dpc_timer; ++ struct unicode_string basename; ++ struct unicode_string symlink_name; ++ ULONG ndis_hangcheck_interval; ++ USHORT hangcheck_ticks; ++ USHORT hangcheck_tick; ++ NDIS_STATUS ndis_reset_status; ++ void *resetopen; ++ struct ndis_filterdbs filterdbs; ++ void *rx_packet; ++ void *send_complete; ++ void *send_resource_avail; ++ void *reset_complete; ++ ++ enum ndis_medium media_type; ++ ULONG bus_number; ++ enum ndis_interface_type bus_type; ++ enum ndis_interface_type adapter_type; ++ struct device_object *fdo; ++ struct device_object *pdo; ++ struct device_object *next_device; ++ void *mapreg; ++ void *call_mgraflist; ++ void *mp_thread; ++ void *setinfobuf; ++ USHORT setinfo_buf_len; ++ USHORT max_send_pkts; ++ NDIS_STATUS fake_status; ++ void *lock_handler; ++ struct unicode_string *adapter_instance_name; ++ void *timer_queue; ++ UINT mac_options; ++ void *pending_req; ++ UINT max_long_addrs; ++ UINT max_short_addrs; ++ UINT cur_lookahead; ++ UINT max_lookahead; ++ ++ ndis_interrupt_handler irq_bh; ++ void *disable_intr; ++ void *enable_intr; ++ void *send_pkts; ++ void *deferred_send; ++ void *eth_rx_indicate; ++ void *tr_rx_indicate; ++ void *fddi_rx_indicate; ++ void *eth_rx_complete; ++ void *tr_rx_complete; ++ void *fddi_rx_complete; ++ ++ void *status; ++ void *status_complete; ++ void *td_complete; ++ ++ void *queryinfo_complete; ++ void *setinfo_complete; ++ void *wan_tx_complete; ++ void *wan_rx; ++ void *wan_rx_complete; ++ /* ndiswrapper specific */ ++ struct ndis_device *wnd; ++}; ++ ++struct ndis_device { ++ struct ndis_mp_block *nmb; ++ struct wrap_device *wd; ++ struct net_device *net_dev; ++ void *shutdown_ctx; ++ struct ndis_mp_interrupt *mp_interrupt; ++ struct kdpc irq_kdpc; ++ unsigned long mem_start; ++ unsigned long mem_end; ++ ++ struct net_device_stats net_stats; ++ struct iw_statistics iw_stats; ++ BOOLEAN iw_stats_enabled; ++ struct ndis_wireless_stats ndis_stats; ++ ++ struct work_struct tx_work; ++ struct ndis_packet *tx_ring[TX_RING_SIZE]; ++ u8 tx_ring_start; ++ u8 tx_ring_end; ++ u8 is_tx_ring_full; ++ u8 tx_ok; ++ spinlock_t tx_ring_lock; ++ struct mutex tx_ring_mutex; ++ unsigned int max_tx_packets; ++ struct mutex ndis_req_mutex; ++ struct task_struct *ndis_req_task; ++ int ndis_req_done; ++ NDIS_STATUS ndis_req_status; ++ ULONG packet_filter; ++ ++ ULONG sg_dma_size; ++ ULONG dma_map_count; ++ dma_addr_t *dma_map_addr; ++ ++ int hangcheck_interval; ++ struct timer_list hangcheck_timer; ++ int iw_stats_interval; ++ struct timer_list iw_stats_timer; ++ unsigned long scan_timestamp; ++ struct encr_info encr_info; ++ char nick[IW_ESSID_MAX_SIZE + 1]; ++ struct ndis_essid essid; ++ struct auth_encr_capa capa; ++ enum ndis_infrastructure_mode infrastructure_mode; ++ int max_pmkids; ++ int num_pmkids; ++ struct ndis_pmkid *pmkids; ++ mac_address mac; ++ struct proc_dir_entry *procfs_iface; ++ ++ struct work_struct ndis_work; ++ unsigned long ndis_pending_work; ++ UINT attributes; ++ int iw_auth_wpa_version; ++ int iw_auth_cipher_pairwise; ++ int iw_auth_cipher_group; ++ int iw_auth_key_mgmt; ++ int iw_auth_80211_alg; ++ struct ndis_packet_pool *tx_packet_pool; ++ struct ndis_buffer_pool *tx_buffer_pool; ++ int multicast_size; ++ struct v4_checksum rx_csum; ++ struct v4_checksum tx_csum; ++ enum ndis_physical_medium physical_medium; ++ ULONG ndis_wolopts; ++ struct nt_slist wrap_timer_slist; ++ int drv_ndis_version; ++ struct ndis_pnp_capabilities pnp_capa; ++}; ++ ++BOOLEAN ndis_isr(struct kinterrupt *kinterrupt, void *ctx) wstdcall; ++ ++int ndis_init(void); ++void ndis_exit(void); ++int ndis_init_device(struct ndis_device *wnd); ++void ndis_exit_device(struct ndis_device *wnd); ++ ++int wrap_procfs_add_ndis_device(struct ndis_device *wnd); ++void wrap_procfs_remove_ndis_device(struct ndis_device *wnd); ++ ++void NdisAllocatePacketPoolEx(NDIS_STATUS *status, ++ struct ndis_packet_pool **pool_handle, ++ UINT num_descr, UINT overflowsize, ++ UINT proto_rsvd_length) wstdcall; ++void NdisFreePacketPool(struct ndis_packet_pool *pool) wstdcall; ++void NdisAllocatePacket(NDIS_STATUS *status, struct ndis_packet **packet, ++ struct ndis_packet_pool *pool) wstdcall; ++void NdisFreePacket(struct ndis_packet *descr) wstdcall; ++void NdisAllocateBufferPool(NDIS_STATUS *status, ++ struct ndis_buffer_pool **pool_handle, ++ UINT num_descr) wstdcall; ++void NdisFreeBufferPool(struct ndis_buffer_pool *pool) wstdcall; ++void NdisAllocateBuffer(NDIS_STATUS *status, ndis_buffer **buffer, ++ struct ndis_buffer_pool *pool, void *virt, ++ UINT length) wstdcall; ++void NdisFreeBuffer(ndis_buffer *descr) wstdcall; ++void NdisMIndicateReceivePacket(struct ndis_mp_block *nmb, ++ struct ndis_packet **packets, ++ UINT nr_packets) wstdcall; ++void NdisMSendComplete(struct ndis_mp_block *nmb, struct ndis_packet *packet, ++ NDIS_STATUS status) wstdcall; ++void NdisMSendResourcesAvailable(struct ndis_mp_block *nmb) wstdcall; ++void NdisMIndicateStatus(struct ndis_mp_block *nmb, ++ NDIS_STATUS status, void *buf, UINT len) wstdcall; ++void NdisMIndicateStatusComplete(struct ndis_mp_block *nmb) wstdcall; ++void NdisMQueryInformationComplete(struct ndis_mp_block *nmb, ++ NDIS_STATUS status) wstdcall; ++void NdisMSetInformationComplete(struct ndis_mp_block *nmb, ++ NDIS_STATUS status) wstdcall; ++void NdisMResetComplete(struct ndis_mp_block *nmb, NDIS_STATUS status, ++ BOOLEAN address_reset) wstdcall; ++ULONG NDIS_BUFFER_TO_SPAN_PAGES(ndis_buffer *buffer) wstdcall; ++BOOLEAN NdisWaitEvent(struct ndis_event *event, UINT timeout) wstdcall; ++void NdisSetEvent(struct ndis_event *event) wstdcall; ++void NdisMDeregisterInterrupt(struct ndis_mp_interrupt *mp_interrupt) wstdcall; ++void EthRxIndicateHandler(struct ndis_mp_block *nmb, void *rx_ctx, ++ char *header1, char *header, UINT header_size, ++ void *look_ahead, UINT look_ahead_size, ++ UINT packet_size) wstdcall; ++void EthRxComplete(struct ndis_mp_block *nmb) wstdcall; ++void NdisMTransferDataComplete(struct ndis_mp_block *nmb, ++ struct ndis_packet *packet, NDIS_STATUS status, ++ UINT bytes_txed) wstdcall; ++void NdisWriteConfiguration(NDIS_STATUS *status, struct ndis_mp_block *nmb, ++ struct unicode_string *key, ++ struct ndis_configuration_parameter *param) wstdcall; ++void NdisReadConfiguration(NDIS_STATUS *status, ++ struct ndis_configuration_parameter **param, ++ struct ndis_mp_block *nmb, ++ struct unicode_string *key, ++ enum ndis_parameter_type type) wstdcall; ++ ++/* Required OIDs */ ++#define OID_GEN_SUPPORTED_LIST 0x00010101 ++#define OID_GEN_HARDWARE_STATUS 0x00010102 ++#define OID_GEN_MEDIA_SUPPORTED 0x00010103 ++#define OID_GEN_MEDIA_IN_USE 0x00010104 ++#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105 ++#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106 ++#define OID_GEN_LINK_SPEED 0x00010107 ++#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108 ++#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109 ++#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A ++#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B ++#define OID_GEN_VENDOR_ID 0x0001010C ++#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D ++#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E ++#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F ++#define OID_GEN_DRIVER_VERSION 0x00010110 ++#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111 ++#define OID_GEN_PROTOCOL_OPTIONS 0x00010112 ++#define OID_GEN_MAC_OPTIONS 0x00010113 ++#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114 ++#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115 ++#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116 ++#define OID_GEN_SUPPORTED_GUIDS 0x00010117 ++#define OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118 /* Set only */ ++#define OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119 /* Set only */ ++#define OID_GEN_MACHINE_NAME 0x0001021A ++#define OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B /* Set only */ ++#define OID_GEN_VLAN_ID 0x0001021C ++ ++/* Optional OIDs. */ ++#define OID_GEN_MEDIA_CAPABILITIES 0x00010201 ++#define OID_GEN_PHYSICAL_MEDIUM 0x00010202 ++ ++/* Required statistics OIDs. */ ++#define OID_GEN_XMIT_OK 0x00020101 ++#define OID_GEN_RCV_OK 0x00020102 ++#define OID_GEN_XMIT_ERROR 0x00020103 ++#define OID_GEN_RCV_ERROR 0x00020104 ++#define OID_GEN_RCV_NO_BUFFER 0x00020105 ++ ++/* Optional OID statistics */ ++#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 ++#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202 ++#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 ++#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204 ++#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 ++#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206 ++#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207 ++#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208 ++#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209 ++#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A ++#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B ++#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C ++#define OID_GEN_RCV_CRC_ERROR 0x0002020D ++#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E ++#define OID_GEN_GET_TIME_CAPS 0x0002020F ++#define OID_GEN_GET_NETCARD_TIME 0x00020210 ++#define OID_GEN_NETCARD_LOAD 0x00020211 ++#define OID_GEN_DEVICE_PROFILE 0x00020212 ++ ++/* 802.3 (ethernet) OIDs */ ++#define OID_802_3_PERMANENT_ADDRESS 0x01010101 ++#define OID_802_3_CURRENT_ADDRESS 0x01010102 ++#define OID_802_3_MULTICAST_LIST 0x01010103 ++#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 ++#define OID_802_3_MAC_OPTIONS 0x01010105 ++#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001 ++#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101 ++#define OID_802_3_XMIT_ONE_COLLISION 0x01020102 ++#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103 ++#define OID_802_3_XMIT_DEFERRED 0x01020201 ++#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202 ++#define OID_802_3_RCV_OVERRUN 0x01020203 ++#define OID_802_3_XMIT_UNDERRUN 0x01020204 ++#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205 ++#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206 ++#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207 ++ ++/* PnP and power management OIDs */ ++#define OID_PNP_CAPABILITIES 0xFD010100 ++#define OID_PNP_SET_POWER 0xFD010101 ++#define OID_PNP_QUERY_POWER 0xFD010102 ++#define OID_PNP_ADD_WAKE_UP_PATTERN 0xFD010103 ++#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xFD010104 ++#define OID_PNP_WAKE_UP_PATTERN_LIST 0xFD010105 ++#define OID_PNP_ENABLE_WAKE_UP 0xFD010106 ++ ++/* PnP/PM Statistics (Optional). */ ++#define OID_PNP_WAKE_UP_OK 0xFD020200 ++#define OID_PNP_WAKE_UP_ERROR 0xFD020201 ++ ++/* The following bits are defined for OID_PNP_ENABLE_WAKE_UP */ ++#define NDIS_PNP_WAKE_UP_MAGIC_PACKET 0x00000001 ++#define NDIS_PNP_WAKE_UP_PATTERN_MATCH 0x00000002 ++#define NDIS_PNP_WAKE_UP_LINK_CHANGE 0x00000004 ++ ++/* 802.11 OIDs */ ++#define OID_802_11_BSSID 0x0D010101 ++#define OID_802_11_SSID 0x0D010102 ++#define OID_802_11_NETWORK_TYPES_SUPPORTED 0x0D010203 ++#define OID_802_11_NETWORK_TYPE_IN_USE 0x0D010204 ++#define OID_802_11_TX_POWER_LEVEL 0x0D010205 ++#define OID_802_11_RSSI 0x0D010206 ++#define OID_802_11_RSSI_TRIGGER 0x0D010207 ++#define OID_802_11_INFRASTRUCTURE_MODE 0x0D010108 ++#define OID_802_11_FRAGMENTATION_THRESHOLD 0x0D010209 ++#define OID_802_11_RTS_THRESHOLD 0x0D01020A ++#define OID_802_11_NUMBER_OF_ANTENNAS 0x0D01020B ++#define OID_802_11_RX_ANTENNA_SELECTED 0x0D01020C ++#define OID_802_11_TX_ANTENNA_SELECTED 0x0D01020D ++#define OID_802_11_SUPPORTED_RATES 0x0D01020E ++#define OID_802_11_DESIRED_RATES 0x0D010210 ++#define OID_802_11_CONFIGURATION 0x0D010211 ++#define OID_802_11_STATISTICS 0x0D020212 ++#define OID_802_11_ADD_WEP 0x0D010113 ++#define OID_802_11_REMOVE_WEP 0x0D010114 ++#define OID_802_11_DISASSOCIATE 0x0D010115 ++#define OID_802_11_POWER_MODE 0x0D010216 ++#define OID_802_11_BSSID_LIST 0x0D010217 ++#define OID_802_11_AUTHENTICATION_MODE 0x0D010118 ++#define OID_802_11_PRIVACY_FILTER 0x0D010119 ++#define OID_802_11_BSSID_LIST_SCAN 0x0D01011A ++#define OID_802_11_WEP_STATUS 0x0D01011B ++#define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS ++#define OID_802_11_RELOAD_DEFAULTS 0x0D01011C ++#define OID_802_11_ADD_KEY 0x0D01011D ++#define OID_802_11_REMOVE_KEY 0x0D01011E ++#define OID_802_11_ASSOCIATION_INFORMATION 0x0D01011F ++#define OID_802_11_TEST 0x0D010120 ++#define OID_802_11_MEDIA_STREAM_MODE 0x0D010121 ++#define OID_802_11_CAPABILITY 0x0D010122 ++#define OID_802_11_PMKID 0x0D010123 ++ ++#define NDIS_STATUS_SUCCESS 0 ++#define NDIS_STATUS_PENDING 0x00000103 ++#define NDIS_STATUS_NOT_RECOGNIZED 0x00010001 ++#define NDIS_STATUS_NOT_COPIED 0x00010002 ++#define NDIS_STATUS_NOT_ACCEPTED 0x00010003 ++#define NDIS_STATUS_CALL_ACTIVE 0x00010007 ++#define NDIS_STATUS_ONLINE 0x40010003 ++#define NDIS_STATUS_RESET_START 0x40010004 ++#define NDIS_STATUS_RESET_END 0x40010005 ++#define NDIS_STATUS_RING_STATUS 0x40010006 ++#define NDIS_STATUS_CLOSED 0x40010007 ++#define NDIS_STATUS_WAN_LINE_UP 0x40010008 ++#define NDIS_STATUS_WAN_LINE_DOWN 0x40010009 ++#define NDIS_STATUS_WAN_FRAGMENT 0x4001000A ++#define NDIS_STATUS_MEDIA_CONNECT 0x4001000B ++#define NDIS_STATUS_MEDIA_DISCONNECT 0x4001000C ++#define NDIS_STATUS_HARDWARE_LINE_UP 0x4001000D ++#define NDIS_STATUS_HARDWARE_LINE_DOWN 0x4001000E ++#define NDIS_STATUS_INTERFACE_UP 0x4001000F ++#define NDIS_STATUS_INTERFACE_DOWN 0x40010010 ++#define NDIS_STATUS_MEDIA_BUSY 0x40010011 ++#define NDIS_STATUS_MEDIA_SPECIFIC_INDICATION 0x40010012 ++#define NDIS_STATUS_WW_INDICATION NDIS_STATUS_MEDIA_SPECIFIC_INDICATION ++#define NDIS_STATUS_LINK_SPEED_CHANGE 0x40010013 ++#define NDIS_STATUS_WAN_GET_STATS 0x40010014 ++#define NDIS_STATUS_WAN_CO_FRAGMENT 0x40010015 ++#define NDIS_STATUS_WAN_CO_LINKPARAMS 0x40010016 ++#define NDIS_STATUS_NOT_RESETTABLE 0x80010001 ++#define NDIS_STATUS_SOFT_ERRORS 0x80010003 ++#define NDIS_STATUS_HARD_ERRORS 0x80010004 ++#define NDIS_STATUS_BUFFER_OVERFLOW 0x80000005 ++#define NDIS_STATUS_FAILURE 0xC0000001 ++#define NDIS_STATUS_INVALID_PARAMETER 0xC000000D ++#define NDIS_STATUS_RESOURCES 0xC000009A ++#define NDIS_STATUS_CLOSING 0xC0010002 ++#define NDIS_STATUS_BAD_VERSION 0xC0010004 ++#define NDIS_STATUS_BAD_CHARACTERISTICS 0xC0010005 ++#define NDIS_STATUS_ADAPTER_NOT_FOUND 0xC0010006 ++#define NDIS_STATUS_OPEN_FAILED 0xC0010007 ++#define NDIS_STATUS_DEVICE_FAILED 0xC0010008 ++#define NDIS_STATUS_MULTICAST_FULL 0xC0010009 ++#define NDIS_STATUS_MULTICAST_EXISTS 0xC001000A ++#define NDIS_STATUS_MULTICAST_NOT_FOUND 0xC001000B ++#define NDIS_STATUS_REQUEST_ABORTED 0xC001000C ++#define NDIS_STATUS_RESET_IN_PROGRESS 0xC001000D ++#define NDIS_STATUS_CLOSING_INDICATING 0xC001000E ++#define NDIS_STATUS_BAD_VERSION 0xC0010004 ++#define NDIS_STATUS_NOT_SUPPORTED 0xC00000BB ++#define NDIS_STATUS_INVALID_PACKET 0xC001000F ++#define NDIS_STATUS_OPEN_LIST_FULL 0xC0010010 ++#define NDIS_STATUS_ADAPTER_NOT_READY 0xC0010011 ++#define NDIS_STATUS_ADAPTER_NOT_OPEN 0xC0010012 ++#define NDIS_STATUS_NOT_INDICATING 0xC0010013 ++#define NDIS_STATUS_INVALID_LENGTH 0xC0010014 ++#define NDIS_STATUS_INVALID_DATA 0xC0010015 ++#define NDIS_STATUS_BUFFER_TOO_SHORT 0xC0010016 ++#define NDIS_STATUS_INVALID_OID 0xC0010017 ++#define NDIS_STATUS_ADAPTER_REMOVED 0xC0010018 ++#define NDIS_STATUS_UNSUPPORTED_MEDIA 0xC0010019 ++#define NDIS_STATUS_GROUP_ADDRESS_IN_USE 0xC001001A ++#define NDIS_STATUS_FILE_NOT_FOUND 0xC001001B ++#define NDIS_STATUS_ERROR_READING_FILE 0xC001001C ++#define NDIS_STATUS_ALREADY_MAPPED 0xC001001D ++#define NDIS_STATUS_RESOURCE_CONFLICT 0xC001001E ++#define NDIS_STATUS_NO_CABLE 0xC001001F ++#define NDIS_STATUS_INVALID_SAP 0xC0010020 ++#define NDIS_STATUS_SAP_IN_USE 0xC0010021 ++#define NDIS_STATUS_INVALID_ADDRESS 0xC0010022 ++#define NDIS_STATUS_VC_NOT_ACTIVATED 0xC0010023 ++#define NDIS_STATUS_DEST_OUT_OF_ORDER 0xC0010024 ++#define NDIS_STATUS_VC_NOT_AVAILABLE 0xC0010025 ++#define NDIS_STATUS_CELLRATE_NOT_AVAILABLE 0xC0010026 ++#define NDIS_STATUS_INCOMPATABLE_QOS 0xC0010027 ++#define NDIS_STATUS_AAL_PARAMS_UNSUPPORTED 0xC0010028 ++#define NDIS_STATUS_NO_ROUTE_TO_DESTINATION 0xC0010029 ++#define NDIS_STATUS_TOKEN_RING_OPEN_ERROR 0xC0011000 ++#define NDIS_STATUS_INVALID_DEVICE_REQUEST 0xC0000010 ++#define NDIS_STATUS_NETWORK_UNREACHABLE 0xC000023C ++ ++/* Event codes */ ++ ++#define EVENT_NDIS_RESOURCE_CONFLICT 0xC0001388 ++#define EVENT_NDIS_OUT_OF_RESOURCE 0xC0001389 ++#define EVENT_NDIS_HARDWARE_FAILURE 0xC000138A ++#define EVENT_NDIS_ADAPTER_NOT_FOUND 0xC000138B ++#define EVENT_NDIS_INTERRUPT_CONNECT 0xC000138C ++#define EVENT_NDIS_DRIVER_FAILURE 0xC000138D ++#define EVENT_NDIS_BAD_VERSION 0xC000138E ++#define EVENT_NDIS_TIMEOUT 0x8000138F ++#define EVENT_NDIS_NETWORK_ADDRESS 0xC0001390 ++#define EVENT_NDIS_UNSUPPORTED_CONFIGURATION 0xC0001391 ++#define EVENT_NDIS_INVALID_VALUE_FROM_ADAPTER 0xC0001392 ++#define EVENT_NDIS_MISSING_CONFIGURATION_PARAMETER 0xC0001393 ++#define EVENT_NDIS_BAD_IO_BASE_ADDRESS 0xC0001394 ++#define EVENT_NDIS_RECEIVE_SPACE_SMALL 0x40001395 ++#define EVENT_NDIS_ADAPTER_DISABLED 0x80001396 ++#define EVENT_NDIS_IO_PORT_CONFLICT 0x80001397 ++#define EVENT_NDIS_PORT_OR_DMA_CONFLICT 0x80001398 ++#define EVENT_NDIS_MEMORY_CONFLICT 0x80001399 ++#define EVENT_NDIS_INTERRUPT_CONFLICT 0x8000139A ++#define EVENT_NDIS_DMA_CONFLICT 0x8000139B ++#define EVENT_NDIS_INVALID_DOWNLOAD_FILE_ERROR 0xC000139C ++#define EVENT_NDIS_MAXRECEIVES_ERROR 0x8000139D ++#define EVENT_NDIS_MAXTRANSMITS_ERROR 0x8000139E ++#define EVENT_NDIS_MAXFRAMESIZE_ERROR 0x8000139F ++#define EVENT_NDIS_MAXINTERNALBUFS_ERROR 0x800013A0 ++#define EVENT_NDIS_MAXMULTICAST_ERROR 0x800013A1 ++#define EVENT_NDIS_PRODUCTID_ERROR 0x800013A2 ++#define EVENT_NDIS_LOBE_FAILUE_ERROR 0x800013A3 ++#define EVENT_NDIS_SIGNAL_LOSS_ERROR 0x800013A4 ++#define EVENT_NDIS_REMOVE_RECEIVED_ERROR 0x800013A5 ++#define EVENT_NDIS_TOKEN_RING_CORRECTION 0x400013A6 ++#define EVENT_NDIS_ADAPTER_CHECK_ERROR 0xC00013A7 ++#define EVENT_NDIS_RESET_FAILURE_ERROR 0x800013A8 ++#define EVENT_NDIS_CABLE_DISCONNECTED_ERROR 0x800013A9 ++#define EVENT_NDIS_RESET_FAILURE_CORRECTION 0x800013AA ++ ++/* packet filter bits used by NDIS_OID_PACKET_FILTER */ ++#define NDIS_PACKET_TYPE_DIRECTED 0x00000001 ++#define NDIS_PACKET_TYPE_MULTICAST 0x00000002 ++#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 ++#define NDIS_PACKET_TYPE_BROADCAST 0x00000008 ++#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 ++#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 ++#define NDIS_PACKET_TYPE_SMT 0x00000040 ++#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080 ++#define NDIS_PACKET_TYPE_GROUP 0x00001000 ++#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00002000 ++#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00004000 ++#define NDIS_PACKET_TYPE_MAC_FRAME 0x00008000 ++ ++/* memory allocation flags */ ++#define NDIS_MEMORY_CONTIGUOUS 0x00000001 ++#define NDIS_MEMORY_NONCACHED 0x00000002 ++ ++/* Attribute flags to NdisMSetAtrributesEx */ ++#define NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT 0x00000001 ++#define NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT 0x00000002 ++#define NDIS_ATTRIBUTE_IGNORE_TOKEN_RING_ERRORS 0x00000004 ++#define NDIS_ATTRIBUTE_BUS_MASTER 0x00000008 ++#define NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER 0x00000010 ++#define NDIS_ATTRIBUTE_DESERIALIZE 0x00000020 ++#define NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND 0x00000040 ++#define NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK 0x00000080 ++#define NDIS_ATTRIBUTE_NOT_CO_NDIS 0x00000100 ++#define NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS 0x00000200 ++ ++#define OID_TCP_TASK_OFFLOAD 0xFC010201 ++ ++#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA 0x00000001 ++#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED 0x00000002 ++#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND 0x00000004 ++#define NDIS_MAC_OPTION_NO_LOOPBACK 0x00000008 ++#define NDIS_MAC_OPTION_FULL_DUPLEX 0x00000010 ++#define NDIS_MAC_OPTION_EOTX_INDICATION 0x00000020 ++#define NDIS_MAC_OPTION_8021P_PRIORITY 0x00000040 ++#define NDIS_MAC_OPTION_SUPPORTS_MAC_ADDRESS_OVERWRITE 0x00000080 ++#define NDIS_MAC_OPTION_RECEIVE_AT_DPC 0x00000100 ++#define NDIS_MAC_OPTION_8021Q_VLAN 0x00000200 ++#define NDIS_MAC_OPTION_RESERVED 0x80000000 ++ ++#define deserialized_driver(wnd) (wnd->attributes & NDIS_ATTRIBUTE_DESERIALIZE) ++ ++static inline void serialize_lock(struct ndis_device *wnd) ++{ ++ nt_spin_lock(&wnd->nmb->lock); ++} ++ ++static inline void serialize_unlock(struct ndis_device *wnd) ++{ ++ nt_spin_unlock(&wnd->nmb->lock); ++} ++ ++static inline KIRQL serialize_lock_irql(struct ndis_device *wnd) ++{ ++ if (deserialized_driver(wnd)) ++ return raise_irql(DISPATCH_LEVEL); ++ else ++ return nt_spin_lock_irql(&wnd->nmb->lock, DISPATCH_LEVEL); ++} ++ ++static inline void serialize_unlock_irql(struct ndis_device *wnd, ++ KIRQL irql) ++{ ++ if (deserialized_driver(wnd)) ++ lower_irql(irql); ++ else ++ nt_spin_unlock_irql(&wnd->nmb->lock, irql); ++} ++ ++static inline void if_serialize_lock(struct ndis_device *wnd) ++{ ++ if (!deserialized_driver(wnd)) ++ nt_spin_lock(&wnd->nmb->lock); ++} ++ ++static inline void if_serialize_unlock(struct ndis_device *wnd) ++{ ++ if (!deserialized_driver(wnd)) ++ nt_spin_unlock(&wnd->nmb->lock); ++} ++ ++#endif /* NDIS_H */ +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/ndiswrapper.h linux-4.6-rc6-ndis/3rdparty/ndiswrapper/ndiswrapper.h +--- linux-4.6-rc6/3rdparty/ndiswrapper/ndiswrapper.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/ndiswrapper.h 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,219 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _NDISWRAPPER_H_ ++#define _NDISWRAPPER_H_ ++ ++#define DRIVER_VERSION "1.60" ++#define UTILS_VERSION "1.9" ++ ++#define DRIVER_NAME "ndiswrapper" ++#define DRIVER_CONFIG_DIR "/etc/ndiswrapper" ++ ++#define NDIS_ESSID_MAX_SIZE 32 ++#define NDIS_ENCODING_TOKEN_MAX 32 ++#define MAX_ENCR_KEYS 4 ++#define TX_RING_SIZE 16 ++#define NDIS_MAX_RATES 8 ++#define NDIS_MAX_RATES_EX 16 ++ ++#define WRAP_PCI_BUS 5 ++#define WRAP_PCMCIA_BUS 8 ++/* some USB devices, e.g., DWL-G120 have BusType as 0 */ ++#define WRAP_INTERNAL_BUS 0 ++/* documentation at msdn says 15 is PNP bus, but inf files from all ++ * vendors say 15 is USB; which is correct? */ ++#define WRAP_USB_BUS 15 ++ ++/* NDIS device must be 0, for compatibility with old versions of ++ * ndiswrapper where device type for NDIS drivers is 0 */ ++#define WRAP_NDIS_DEVICE 0 ++#define WRAP_USB_DEVICE 1 ++#define WRAP_BLUETOOTH_DEVICE1 2 ++#define WRAP_BLUETOOTH_DEVICE2 3 ++ ++#define WRAP_DEVICE_BUS(dev, bus) ((dev) << 8 | (bus)) ++#define WRAP_BUS(dev_bus) ((dev_bus) & 0x000FF) ++#define WRAP_DEVICE(dev_bus) ((dev_bus) >> 8) ++ ++#define MAX_DRIVER_NAME_LEN 32 ++#define MAX_VERSION_STRING_LEN 64 ++#define MAX_SETTING_NAME_LEN 128 ++#define MAX_SETTING_VALUE_LEN 256 ++ ++#define MAX_DRIVER_PE_IMAGES 4 ++#define MAX_DRIVER_BIN_FILES 5 ++#define MAX_DEVICE_SETTINGS 512 ++ ++#define MAX_ALLOCATED_URBS 15 ++ ++#define DEV_ANY_ID -1 ++ ++#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] ++#define MACSTRSEP "%02x:%02x:%02x:%02x:%02x:%02x" ++#define MACSTR "%02x%02x%02x%02x%02x%02x" ++#define MACINTADR(a) (int*)&((a)[0]), (int*)&((a)[1]), (int*)&((a)[2]), \ ++ (int*)&((a)[3]), (int*)&((a)[4]), (int*)&((a)[5]) ++ ++#ifdef __KERNEL__ ++/* DEBUG macros */ ++ ++#define MSG(level, fmt, ...) \ ++ printk(level DRIVER_NAME " (%s:%d): " fmt "\n", \ ++ __func__, __LINE__ , ## __VA_ARGS__) ++ ++#define WARNING(fmt, ...) MSG(KERN_WARNING, fmt, ## __VA_ARGS__) ++#define ERROR(fmt, ...) MSG(KERN_ERR, fmt , ## __VA_ARGS__) ++#define INFO(fmt, ...) MSG(KERN_INFO, fmt , ## __VA_ARGS__) ++#define TODO() WARNING("not fully implemented (yet)") ++ ++#define TRACE(level, fmt, ...) \ ++do { \ ++ if (debug >= level) \ ++ printk(KERN_INFO "%s (%s:%d): " fmt "\n", DRIVER_NAME, \ ++ __func__, __LINE__ , ## __VA_ARGS__); \ ++} while (0) ++#define TRACE0(fmt, ...) TRACE(0, fmt , ## __VA_ARGS__) ++ ++extern int debug; ++ ++#ifndef DEBUG ++#define DEBUG 0 ++#endif ++ ++/* for a block of code */ ++#if DEBUG >= 1 ++#define DBG_BLOCK(level) if (debug >= level) ++#else ++#define DBG_BLOCK(level) while (0) ++#endif ++ ++#if DEBUG >= 1 ++#define TRACE1(fmt, ...) TRACE(1, fmt , ## __VA_ARGS__) ++#else ++#define TRACE1(fmt, ...) do { } while (0) ++#endif ++ ++#if DEBUG >= 2 ++#define TRACE2(fmt, ...) TRACE(2, fmt , ## __VA_ARGS__) ++#else ++#define TRACE2(fmt, ...) do { } while (0) ++#endif ++ ++#if DEBUG >= 3 ++#define TRACE3(fmt, ...) TRACE(3, fmt , ## __VA_ARGS__) ++#else ++#define TRACE3(fmt, ...) do { } while (0) ++#endif ++ ++#if DEBUG >= 4 ++#define TRACE4(fmt, ...) TRACE(4, fmt , ## __VA_ARGS__) ++#else ++#define TRACE4(fmt, ...) do { } while (0) ++#endif ++ ++#if DEBUG >= 5 ++#define TRACE5(fmt, ...) TRACE(5, fmt , ## __VA_ARGS__) ++#else ++#define TRACE5(fmt, ...) do { } while (0) ++#endif ++ ++#if DEBUG >= 6 ++#define TRACE6(fmt, ...) TRACE(6, fmt , ## __VA_ARGS__) ++#else ++#define TRACE6(fmt, ...) do { } while (0) ++#endif ++ ++#define ENTER0(fmt, ...) TRACE0("Enter " fmt , ## __VA_ARGS__) ++#define ENTER1(fmt, ...) TRACE1("Enter " fmt , ## __VA_ARGS__) ++#define ENTER2(fmt, ...) TRACE2("Enter " fmt , ## __VA_ARGS__) ++#define ENTER3(fmt, ...) TRACE3("Enter " fmt , ## __VA_ARGS__) ++#define ENTER4(fmt, ...) TRACE4("Enter " fmt , ## __VA_ARGS__) ++#define ENTER5(fmt, ...) TRACE5("Enter " fmt , ## __VA_ARGS__) ++#define ENTER6(fmt, ...) TRACE6("Enter " fmt , ## __VA_ARGS__) ++ ++#define EXIT0(stmt) do { TRACE0("Exit"); stmt; } while (0) ++#define EXIT1(stmt) do { TRACE1("Exit"); stmt; } while (0) ++#define EXIT2(stmt) do { TRACE2("Exit"); stmt; } while (0) ++#define EXIT3(stmt) do { TRACE3("Exit"); stmt; } while (0) ++#define EXIT4(stmt) do { TRACE4("Exit"); stmt; } while (0) ++#define EXIT5(stmt) do { TRACE5("Exit"); stmt; } while (0) ++#define EXIT6(stmt) do { TRACE6("Exit"); stmt; } while (0) ++ ++#if defined(USB_DEBUG) ++#define USBTRACE TRACE0 ++#define USBENTER ENTER0 ++#define USBEXIT EXIT0 ++#else ++#define USBTRACE(fmt, ...) do { } while (0) ++#define USBENTER(fmt, ...) ++#define USBEXIT(stmt) stmt ++#endif ++ ++#if defined(EVENT_DEBUG) ++#define EVENTTRACE TRACE0 ++#define EVENTENTER ENTER0 ++#define EVENTEXIT EXIT0 ++#else ++#define EVENTTRACE(fmt, ...) do { } while (0) ++#define EVENTENTER(fmt, ...) ++#define EVENTEXIT(stmt) stmt ++#endif ++ ++#if defined(TIMER_DEBUG) ++#define TIMERTRACE TRACE0 ++#define TIMERENTER ENTER0 ++#define TIMEREXIT EXIT0 ++#else ++#define TIMERTRACE(fmt, ...) do { } while (0) ++#define TIMERENTER(fmt, ...) ++#define TIMEREXIT(stmt) stmt ++#endif ++ ++#if defined(IO_DEBUG) ++#define IOTRACE TRACE0 ++#define IOENTER ENTER0 ++#define IOEXIT EXIT0 ++#else ++#define IOTRACE(fmt, ...) do { } while (0) ++#define IOENTER(fmt, ...) ++#define IOEXIT(stmt) stmt ++#endif ++ ++#if defined(WORK_DEBUG) ++#define WORKTRACE TRACE0 ++#define WORKENTER ENTER0 ++#define WORKEXIT EXIT0 ++#else ++#define WORKTRACE(fmt, ...) do { } while (0) ++#define WORKENTER(fmt, ...) ++#define WORKEXIT(stmt) stmt ++#endif ++ ++#if DEBUG >= 1 ++#define assert(expr) \ ++do { \ ++ if (!(expr)) { \ ++ ERROR("assertion '%s' failed", #expr); \ ++ dump_stack(); \ ++ } \ ++} while (0) ++#else ++#define assert(expr) do { } while (0) ++#endif ++ ++#endif // __KERNEL__ ++ ++#endif // NDISWRAPPER_H +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/ntoskernel.c linux-4.6-rc6-ndis/3rdparty/ndiswrapper/ntoskernel.c +--- linux-4.6-rc6/3rdparty/ndiswrapper/ntoskernel.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/ntoskernel.c 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,2677 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include "ntoskernel.h" ++#include "ndis.h" ++#include "usb.h" ++#include "pnp.h" ++#include "loader.h" ++#include "ntoskernel_exports.h" ++ ++/* MDLs describe a range of virtual address with an array of physical ++ * pages right after the header. For different ranges of virtual ++ * addresses, the number of entries of physical pages may be different ++ * (depending on number of entries required). If we want to allocate ++ * MDLs from a pool, the size has to be constant. So we assume that ++ * maximum range used by a driver is MDL_CACHE_PAGES; if a driver ++ * requests an MDL for a bigger region, we allocate it with kmalloc; ++ * otherwise, we allocate from the pool */ ++ ++#define MDL_CACHE_PAGES 3 ++#define MDL_CACHE_SIZE (sizeof(struct mdl) + \ ++ (sizeof(PFN_NUMBER) * MDL_CACHE_PAGES)) ++struct wrap_mdl { ++ struct nt_list list; ++ struct mdl mdl[0]; ++}; ++ ++/* everything here is for all drivers/devices - not per driver/device */ ++static spinlock_t dispatcher_lock; ++spinlock_t ntoskernel_lock; ++static void *mdl_cache; ++static struct nt_list wrap_mdl_list; ++ ++static struct work_struct kdpc_work; ++static void kdpc_worker(struct work_struct *dummy); ++ ++static struct nt_list kdpc_list; ++static spinlock_t kdpc_list_lock; ++ ++static struct nt_list callback_objects; ++ ++struct nt_list object_list; ++ ++struct bus_driver { ++ struct nt_list list; ++ char name[MAX_DRIVER_NAME_LEN]; ++ struct driver_object drv_obj; ++}; ++ ++static struct nt_list bus_driver_list; ++ ++static struct work_struct ntos_work; ++static struct nt_list ntos_work_list; ++static spinlock_t ntos_work_lock; ++static void ntos_work_worker(struct work_struct *dummy); ++spinlock_t irp_cancel_lock; ++static NT_SPIN_LOCK nt_list_lock; ++static struct nt_slist wrap_timer_slist; ++CCHAR cpu_count; ++ ++/* compute ticks (100ns) since 1601 until when system booted into ++ * wrap_ticks_to_boot */ ++u64 wrap_ticks_to_boot; ++ ++#if defined(CONFIG_X86_64) ++static struct timer_list shared_data_timer; ++struct kuser_shared_data kuser_shared_data; ++static void update_user_shared_data_proc(unsigned long data); ++#endif ++ ++WIN_SYMBOL_MAP("KeTickCount", &jiffies) ++WIN_SYMBOL_MAP("KeNumberProcessors", &cpu_count) ++WIN_SYMBOL_MAP("NlsMbCodePageTag", FALSE) ++ ++struct workqueue_struct *ntos_wq; ++ ++#ifdef WRAP_PREEMPT ++DEFINE_PER_CPU(struct irql_info, irql_info); ++#endif ++ ++#if defined(CONFIG_X86_64) ++static void update_user_shared_data_proc(unsigned long data) ++{ ++ /* timer is supposed to be scheduled every 10ms, but bigger ++ * intervals seem to work (tried up to 50ms) */ ++ *((ULONG64 *)&kuser_shared_data.system_time) = ticks_1601(); ++ *((ULONG64 *)&kuser_shared_data.interrupt_time) = ++ jiffies * TICKSPERSEC / HZ; ++ *((ULONG64 *)&kuser_shared_data.tick) = jiffies; ++ ++ mod_timer(&shared_data_timer, jiffies + MSEC_TO_HZ(30)); ++} ++#endif ++ ++void *allocate_object(ULONG size, enum common_object_type type, ++ struct unicode_string *name) ++{ ++ struct common_object_header *hdr; ++ void *body; ++ ++ /* we pad header as prefix to body */ ++ hdr = ExAllocatePoolWithTag(NonPagedPool, OBJECT_SIZE(size), 0); ++ if (!hdr) { ++ WARNING("couldn't allocate memory"); ++ return NULL; ++ } ++ memset(hdr, 0, OBJECT_SIZE(size)); ++ if (name) { ++ hdr->name.buf = ExAllocatePoolWithTag(NonPagedPool, ++ name->max_length, 0); ++ if (!hdr->name.buf) { ++ ExFreePool(hdr); ++ return NULL; ++ } ++ memcpy(hdr->name.buf, name->buf, name->max_length); ++ hdr->name.length = name->length; ++ hdr->name.max_length = name->max_length; ++ } ++ hdr->type = type; ++ hdr->ref_count = 1; ++ spin_lock_bh(&ntoskernel_lock); ++ /* threads are looked up often (in KeWaitForXXX), so optimize ++ * for fast lookups of threads */ ++ if (type == OBJECT_TYPE_NT_THREAD) ++ InsertHeadList(&object_list, &hdr->list); ++ else ++ InsertTailList(&object_list, &hdr->list); ++ spin_unlock_bh(&ntoskernel_lock); ++ body = HEADER_TO_OBJECT(hdr); ++ TRACE3("allocated hdr: %p, body: %p", hdr, body); ++ return body; ++} ++ ++static void free_object(void *object) ++{ ++ struct common_object_header *hdr; ++ ++ hdr = OBJECT_TO_HEADER(object); ++ spin_lock_bh(&ntoskernel_lock); ++ RemoveEntryList(&hdr->list); ++ spin_unlock_bh(&ntoskernel_lock); ++ TRACE3("freed hdr: %p, body: %p", hdr, object); ++ if (hdr->name.buf) ++ ExFreePool(hdr->name.buf); ++ ExFreePool(hdr); ++} ++ ++static int add_bus_driver(const char *name) ++{ ++ struct bus_driver *bus_driver; ++ ++ bus_driver = kzalloc(sizeof(*bus_driver), GFP_KERNEL); ++ if (!bus_driver) { ++ ERROR("couldn't allocate memory"); ++ return -ENOMEM; ++ } ++ strncpy(bus_driver->name, name, sizeof(bus_driver->name)); ++ bus_driver->name[sizeof(bus_driver->name)-1] = 0; ++ spin_lock_bh(&ntoskernel_lock); ++ InsertTailList(&bus_driver_list, &bus_driver->list); ++ spin_unlock_bh(&ntoskernel_lock); ++ TRACE1("bus driver %s is at %p", name, &bus_driver->drv_obj); ++ return STATUS_SUCCESS; ++} ++ ++struct driver_object *find_bus_driver(const char *name) ++{ ++ struct bus_driver *bus_driver; ++ struct driver_object *drv_obj; ++ ++ spin_lock_bh(&ntoskernel_lock); ++ drv_obj = NULL; ++ nt_list_for_each_entry(bus_driver, &bus_driver_list, list) { ++ if (strcmp(bus_driver->name, name) == 0) { ++ drv_obj = &bus_driver->drv_obj; ++ break; ++ } ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ return drv_obj; ++} ++ ++wfastcall struct nt_list *WIN_FUNC(ExfInterlockedInsertHeadList,3) ++ (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock) ++{ ++ struct nt_list *first; ++ unsigned long flags; ++ ++ ENTER5("head = %p, entry = %p", head, entry); ++ nt_spin_lock_irqsave(lock, flags); ++ first = InsertHeadList(head, entry); ++ nt_spin_unlock_irqrestore(lock, flags); ++ TRACE5("head = %p, old = %p", head, first); ++ return first; ++} ++ ++wfastcall struct nt_list *WIN_FUNC(ExInterlockedInsertHeadList,3) ++ (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock) ++{ ++ ENTER5("%p", head); ++ return ExfInterlockedInsertHeadList(head, entry, lock); ++} ++ ++wfastcall struct nt_list *WIN_FUNC(ExfInterlockedInsertTailList,3) ++ (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock) ++{ ++ struct nt_list *last; ++ unsigned long flags; ++ ++ ENTER5("head = %p, entry = %p", head, entry); ++ nt_spin_lock_irqsave(lock, flags); ++ last = InsertTailList(head, entry); ++ nt_spin_unlock_irqrestore(lock, flags); ++ TRACE5("head = %p, old = %p", head, last); ++ return last; ++} ++ ++wfastcall struct nt_list *WIN_FUNC(ExInterlockedInsertTailList,3) ++ (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock) ++{ ++ ENTER5("%p", head); ++ return ExfInterlockedInsertTailList(head, entry, lock); ++} ++ ++wfastcall struct nt_list *WIN_FUNC(ExfInterlockedRemoveHeadList,2) ++ (struct nt_list *head, NT_SPIN_LOCK *lock) ++{ ++ struct nt_list *ret; ++ unsigned long flags; ++ ++ ENTER5("head = %p", head); ++ nt_spin_lock_irqsave(lock, flags); ++ ret = RemoveHeadList(head); ++ nt_spin_unlock_irqrestore(lock, flags); ++ TRACE5("head = %p, ret = %p", head, ret); ++ return ret; ++} ++ ++wfastcall struct nt_list *WIN_FUNC(ExInterlockedRemoveHeadList,2) ++ (struct nt_list *head, NT_SPIN_LOCK *lock) ++{ ++ ENTER5("%p", head); ++ return ExfInterlockedRemoveHeadList(head, lock); ++} ++ ++wfastcall struct nt_list *WIN_FUNC(ExfInterlockedRemoveTailList,2) ++ (struct nt_list *head, NT_SPIN_LOCK *lock) ++{ ++ struct nt_list *ret; ++ unsigned long flags; ++ ++ ENTER5("head = %p", head); ++ nt_spin_lock_irqsave(lock, flags); ++ ret = RemoveTailList(head); ++ nt_spin_unlock_irqrestore(lock, flags); ++ TRACE5("head = %p, ret = %p", head, ret); ++ return ret; ++} ++ ++wfastcall struct nt_list *WIN_FUNC(ExInterlockedRemoveTailList,2) ++ (struct nt_list *head, NT_SPIN_LOCK *lock) ++{ ++ ENTER5("%p", head); ++ return ExfInterlockedRemoveTailList(head, lock); ++} ++ ++wfastcall void WIN_FUNC(InitializeSListHead,1) ++ (nt_slist_header *head) ++{ ++ memset(head, 0, sizeof(*head)); ++} ++ ++wfastcall struct nt_slist *WIN_FUNC(ExInterlockedPushEntrySList,3) ++ (nt_slist_header *head, struct nt_slist *entry, NT_SPIN_LOCK *lock) ++{ ++ struct nt_slist *ret; ++ ++ ret = PushEntrySList(head, entry, lock); ++ return ret; ++} ++ ++wstdcall struct nt_slist *WIN_FUNC(ExpInterlockedPushEntrySList,2) ++ (nt_slist_header *head, struct nt_slist *entry) ++{ ++ struct nt_slist *ret; ++ ++ ret = PushEntrySList(head, entry, &nt_list_lock); ++ return ret; ++} ++ ++wfastcall struct nt_slist *WIN_FUNC(InterlockedPushEntrySList,2) ++ (nt_slist_header *head, struct nt_slist *entry) ++{ ++ struct nt_slist *ret; ++ ++ ret = PushEntrySList(head, entry, &nt_list_lock); ++ return ret; ++} ++ ++wfastcall struct nt_slist *WIN_FUNC(ExInterlockedPopEntrySList,2) ++ (nt_slist_header *head, NT_SPIN_LOCK *lock) ++{ ++ struct nt_slist *ret; ++ ++ ret = PopEntrySList(head, lock); ++ return ret; ++} ++ ++wstdcall struct nt_slist *WIN_FUNC(ExpInterlockedPopEntrySList,1) ++ (nt_slist_header *head) ++{ ++ struct nt_slist *ret; ++ ++ ret = PopEntrySList(head, &nt_list_lock); ++ return ret; ++} ++ ++wfastcall struct nt_slist *WIN_FUNC(InterlockedPopEntrySList,1) ++ (nt_slist_header *head) ++{ ++ struct nt_slist *ret; ++ ++ ret = PopEntrySList(head, &nt_list_lock); ++ return ret; ++} ++ ++wstdcall USHORT WIN_FUNC(ExQueryDepthSList,1) ++ (nt_slist_header *head) ++{ ++ USHORT depth; ++ ENTER5("%p", head); ++ depth = head->depth; ++ TRACE5("%d, %p", depth, head->next); ++ return depth; ++} ++ ++wfastcall LONG WIN_FUNC(InterlockedIncrement,1) ++ (LONG volatile *val) ++{ ++ return post_atomic_add(*val, 1); ++} ++ ++wfastcall LONG WIN_FUNC(InterlockedDecrement,1) ++ (LONG volatile *val) ++{ ++ return post_atomic_add(*val, -1); ++} ++ ++wfastcall LONG WIN_FUNC(InterlockedExchange,2) ++ (LONG volatile *target, LONG val) ++{ ++ return xchg(target, val); ++} ++ ++wfastcall LONG WIN_FUNC(InterlockedCompareExchange,3) ++ (LONG volatile *dest, LONG new, LONG old) ++{ ++ return cmpxchg(dest, old, new); ++} ++ ++wfastcall void WIN_FUNC(ExInterlockedAddLargeStatistic,2) ++ (LARGE_INTEGER volatile *plint, ULONG n) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++#ifdef CONFIG_X86_64 ++ __asm__ __volatile__( ++ "\n" ++ LOCK_PREFIX "add %1, %0\n\t" ++ : "+m" (*plint) ++ : "r" (n)); ++#else ++ __asm__ __volatile__( ++ "1:\t" ++ " movl %1, %%ebx\n\t" ++ " movl %%edx, %%ecx\n\t" ++ " addl %%eax, %%ebx\n\t" ++ " adcl $0, %%ecx\n\t" ++ LOCK_PREFIX "cmpxchg8b %0\n\t" ++ " jnz 1b\n\t" ++ : "+m" (*plint) ++ : "m" (n), "A" (*plint) ++ : "ebx", "ecx"); ++#endif ++ local_irq_restore(flags); ++} ++ ++static void initialize_object(struct dispatcher_header *dh, enum dh_type type, ++ int state) ++{ ++ memset(dh, 0, sizeof(*dh)); ++ set_object_type(dh, type); ++ dh->signal_state = state; ++ InitializeListHead(&dh->wait_blocks); ++} ++ ++static void timer_proc(unsigned long data) ++{ ++ struct wrap_timer *wrap_timer = (struct wrap_timer *)data; ++ struct nt_timer *nt_timer; ++ struct kdpc *kdpc; ++ ++ nt_timer = wrap_timer->nt_timer; ++ TIMERENTER("%p(%p), %lu", wrap_timer, nt_timer, jiffies); ++#ifdef TIMER_DEBUG ++ BUG_ON(wrap_timer->wrap_timer_magic != WRAP_TIMER_MAGIC); ++ BUG_ON(nt_timer->wrap_timer_magic != WRAP_TIMER_MAGIC); ++#endif ++ KeSetEvent((struct nt_event *)nt_timer, 0, FALSE); ++ if (wrap_timer->repeat) ++ mod_timer(&wrap_timer->timer, jiffies + wrap_timer->repeat); ++ kdpc = nt_timer->kdpc; ++ if (kdpc) ++ queue_kdpc(kdpc); ++ TIMEREXIT(return); ++} ++ ++void wrap_init_timer(struct nt_timer *nt_timer, enum timer_type type, ++ struct ndis_mp_block *nmb) ++{ ++ struct wrap_timer *wrap_timer; ++ ++ /* TODO: if a timer is initialized more than once, we allocate ++ * memory for wrap_timer more than once for the same nt_timer, ++ * wasting memory. We can check if nt_timer->wrap_timer_magic is ++ * set and not allocate, but it is not guaranteed always to be ++ * safe */ ++ TIMERENTER("%p", nt_timer); ++ /* we allocate memory for wrap_timer behind driver's back and ++ * there is no NDIS/DDK function where this memory can be ++ * freed, so we use slack_kmalloc so it gets freed when driver ++ * is unloaded */ ++ if (nmb) ++ wrap_timer = kzalloc(sizeof(*wrap_timer), irql_gfp()); ++ else ++ wrap_timer = slack_kzalloc(sizeof(*wrap_timer)); ++ if (!wrap_timer) { ++ ERROR("couldn't allocate memory for timer"); ++ return; ++ } ++ ++ init_timer(&wrap_timer->timer); ++ wrap_timer->timer.data = (unsigned long)wrap_timer; ++ wrap_timer->timer.function = timer_proc; ++ wrap_timer->nt_timer = nt_timer; ++#ifdef TIMER_DEBUG ++ wrap_timer->wrap_timer_magic = WRAP_TIMER_MAGIC; ++#endif ++ nt_timer->wrap_timer = wrap_timer; ++ nt_timer->kdpc = NULL; ++ initialize_object(&nt_timer->dh, (enum dh_type)type, 0); ++ nt_timer->wrap_timer_magic = WRAP_TIMER_MAGIC; ++ TIMERTRACE("timer %p (%p)", wrap_timer, nt_timer); ++ spin_lock_bh(&ntoskernel_lock); ++ if (nmb) { ++ wrap_timer->slist.next = nmb->wnd->wrap_timer_slist.next; ++ nmb->wnd->wrap_timer_slist.next = &wrap_timer->slist; ++ } else { ++ wrap_timer->slist.next = wrap_timer_slist.next; ++ wrap_timer_slist.next = &wrap_timer->slist; ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ TIMEREXIT(return); ++} ++ ++wstdcall void WIN_FUNC(KeInitializeTimerEx,2) ++ (struct nt_timer *nt_timer, enum timer_type type) ++{ ++ TIMERENTER("%p", nt_timer); ++ wrap_init_timer(nt_timer, type, NULL); ++} ++ ++wstdcall void WIN_FUNC(KeInitializeTimer,1) ++ (struct nt_timer *nt_timer) ++{ ++ TIMERENTER("%p", nt_timer); ++ wrap_init_timer(nt_timer, NotificationTimer, NULL); ++} ++ ++/* expires and repeat are in HZ */ ++BOOLEAN wrap_set_timer(struct nt_timer *nt_timer, unsigned long expires_hz, ++ unsigned long repeat_hz, struct kdpc *kdpc) ++{ ++ struct wrap_timer *wrap_timer; ++ ++ TIMERENTER("%p, %lu, %lu, %p, %lu", ++ nt_timer, expires_hz, repeat_hz, kdpc, jiffies); ++ ++ wrap_timer = nt_timer->wrap_timer; ++ TIMERTRACE("%p", wrap_timer); ++#ifdef TIMER_DEBUG ++ if (wrap_timer->nt_timer != nt_timer) ++ WARNING("bad timers: %p, %p, %p", wrap_timer, nt_timer, ++ wrap_timer->nt_timer); ++ if (nt_timer->wrap_timer_magic != WRAP_TIMER_MAGIC) { ++ WARNING("buggy Windows timer didn't initialize timer %p", ++ nt_timer); ++ return FALSE; ++ } ++ if (wrap_timer->wrap_timer_magic != WRAP_TIMER_MAGIC) { ++ WARNING("timer %p is not initialized (%lx)?", ++ wrap_timer, wrap_timer->wrap_timer_magic); ++ wrap_timer->wrap_timer_magic = WRAP_TIMER_MAGIC; ++ } ++#endif ++ KeClearEvent((struct nt_event *)nt_timer); ++ nt_timer->kdpc = kdpc; ++ wrap_timer->repeat = repeat_hz; ++ if (mod_timer(&wrap_timer->timer, jiffies + expires_hz)) ++ TIMEREXIT(return TRUE); ++ else ++ TIMEREXIT(return FALSE); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeSetTimerEx,4) ++ (struct nt_timer *nt_timer, LARGE_INTEGER duetime_ticks, ++ LONG period_ms, struct kdpc *kdpc) ++{ ++ unsigned long expires_hz, repeat_hz; ++ ++ TIMERENTER("%p, %lld, %d", nt_timer, duetime_ticks, period_ms); ++ expires_hz = SYSTEM_TIME_TO_HZ(duetime_ticks); ++ repeat_hz = MSEC_TO_HZ(period_ms); ++ return wrap_set_timer(nt_timer, expires_hz, repeat_hz, kdpc); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeSetTimer,3) ++ (struct nt_timer *nt_timer, LARGE_INTEGER duetime_ticks, ++ struct kdpc *kdpc) ++{ ++ TIMERENTER("%p, %lld, %p", nt_timer, duetime_ticks, kdpc); ++ return KeSetTimerEx(nt_timer, duetime_ticks, 0, kdpc); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeCancelTimer,1) ++ (struct nt_timer *nt_timer) ++{ ++ struct wrap_timer *wrap_timer; ++ int ret; ++ ++ TIMERENTER("%p", nt_timer); ++ wrap_timer = nt_timer->wrap_timer; ++ if (!wrap_timer) { ++ ERROR("invalid wrap_timer"); ++ return TRUE; ++ } ++#ifdef TIMER_DEBUG ++ BUG_ON(wrap_timer->wrap_timer_magic != WRAP_TIMER_MAGIC); ++#endif ++ /* disable timer before deleting so if it is periodic timer, it ++ * won't be re-armed after deleting */ ++ wrap_timer->repeat = 0; ++ ret = del_timer_sync(&wrap_timer->timer); ++ /* the documentation for KeCancelTimer suggests the DPC is ++ * deqeued, but actually DPC is left to run */ ++ if (ret) ++ TIMEREXIT(return TRUE); ++ else ++ TIMEREXIT(return FALSE); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeReadStateTimer,1) ++ (struct nt_timer *nt_timer) ++{ ++ if (nt_timer->dh.signal_state) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++wstdcall void WIN_FUNC(KeInitializeDpc,3) ++ (struct kdpc *kdpc, void *func, void *ctx) ++{ ++ ENTER3("%p, %p, %p", kdpc, func, ctx); ++ memset(kdpc, 0, sizeof(*kdpc)); ++ kdpc->func = func; ++ kdpc->ctx = ctx; ++ InitializeListHead(&kdpc->list); ++} ++ ++static void kdpc_worker(struct work_struct *dummy) ++{ ++ struct nt_list *entry; ++ struct kdpc *kdpc; ++ unsigned long flags; ++ KIRQL irql; ++ ++ WORKENTER(""); ++ irql = raise_irql(DISPATCH_LEVEL); ++ while (1) { ++ spin_lock_irqsave(&kdpc_list_lock, flags); ++ entry = RemoveHeadList(&kdpc_list); ++ if (entry) { ++ kdpc = container_of(entry, struct kdpc, list); ++ assert(kdpc->queued); ++ kdpc->queued = 0; ++ } else ++ kdpc = NULL; ++ spin_unlock_irqrestore(&kdpc_list_lock, flags); ++ if (!kdpc) ++ break; ++ WORKTRACE("%p, %p, %p, %p, %p", kdpc, kdpc->func, kdpc->ctx, ++ kdpc->arg1, kdpc->arg2); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ LIN2WIN4(kdpc->func, kdpc, kdpc->ctx, kdpc->arg1, kdpc->arg2); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ } ++ lower_irql(irql); ++ WORKEXIT(return); ++} ++ ++wstdcall void WIN_FUNC(KeFlushQueuedDpcs,0) ++ (void) ++{ ++ kdpc_worker(NULL); ++} ++ ++BOOLEAN queue_kdpc(struct kdpc *kdpc) ++{ ++ BOOLEAN ret; ++ unsigned long flags; ++ ++ WORKENTER("%p", kdpc); ++ spin_lock_irqsave(&kdpc_list_lock, flags); ++ if (kdpc->queued) ++ ret = FALSE; ++ else { ++ if (unlikely(kdpc->importance == HighImportance)) ++ InsertHeadList(&kdpc_list, &kdpc->list); ++ else ++ InsertTailList(&kdpc_list, &kdpc->list); ++ kdpc->queued = 1; ++ ret = TRUE; ++ } ++ spin_unlock_irqrestore(&kdpc_list_lock, flags); ++ if (ret == TRUE) ++ queue_work(ntos_wq, &kdpc_work); ++ WORKTRACE("%d", ret); ++ return ret; ++} ++ ++BOOLEAN dequeue_kdpc(struct kdpc *kdpc) ++{ ++ BOOLEAN ret; ++ unsigned long flags; ++ ++ WORKENTER("%p", kdpc); ++ spin_lock_irqsave(&kdpc_list_lock, flags); ++ if (kdpc->queued) { ++ RemoveEntryList(&kdpc->list); ++ kdpc->queued = 0; ++ ret = TRUE; ++ } else ++ ret = FALSE; ++ spin_unlock_irqrestore(&kdpc_list_lock, flags); ++ WORKTRACE("%d", ret); ++ return ret; ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeInsertQueueDpc,3) ++ (struct kdpc *kdpc, void *arg1, void *arg2) ++{ ++ WORKENTER("%p, %p, %p", kdpc, arg1, arg2); ++ kdpc->arg1 = arg1; ++ kdpc->arg2 = arg2; ++ return queue_kdpc(kdpc); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeRemoveQueueDpc,1) ++ (struct kdpc *kdpc) ++{ ++ return dequeue_kdpc(kdpc); ++} ++ ++wstdcall void WIN_FUNC(KeSetImportanceDpc,2) ++ (struct kdpc *kdpc, enum kdpc_importance importance) ++{ ++ kdpc->importance = importance; ++} ++ ++static void ntos_work_worker(struct work_struct *dummy) ++{ ++ struct ntos_work_item *ntos_work_item; ++ struct nt_list *cur; ++ ++ while (1) { ++ spin_lock_bh(&ntos_work_lock); ++ cur = RemoveHeadList(&ntos_work_list); ++ spin_unlock_bh(&ntos_work_lock); ++ if (!cur) ++ break; ++ ntos_work_item = container_of(cur, struct ntos_work_item, list); ++ WORKTRACE("%p: executing %p, %p, %p", current, ++ ntos_work_item->func, ntos_work_item->arg1, ++ ntos_work_item->arg2); ++ LIN2WIN2(ntos_work_item->func, ntos_work_item->arg1, ++ ntos_work_item->arg2); ++ kfree(ntos_work_item); ++ } ++ WORKEXIT(return); ++} ++ ++int schedule_ntos_work_item(NTOS_WORK_FUNC func, void *arg1, void *arg2) ++{ ++ struct ntos_work_item *ntos_work_item; ++ ++ WORKENTER("adding work: %p, %p, %p", func, arg1, arg2); ++ ntos_work_item = kmalloc(sizeof(*ntos_work_item), irql_gfp()); ++ if (!ntos_work_item) { ++ ERROR("couldn't allocate memory"); ++ return -ENOMEM; ++ } ++ ntos_work_item->func = func; ++ ntos_work_item->arg1 = arg1; ++ ntos_work_item->arg2 = arg2; ++ spin_lock_bh(&ntos_work_lock); ++ InsertTailList(&ntos_work_list, &ntos_work_item->list); ++ spin_unlock_bh(&ntos_work_lock); ++ queue_work(ntos_wq, &ntos_work); ++ WORKEXIT(return 0); ++} ++ ++wstdcall void WIN_FUNC(KeInitializeSpinLock,1) ++ (NT_SPIN_LOCK *lock) ++{ ++ ENTER6("%p", lock); ++ nt_spin_lock_init(lock); ++} ++ ++wstdcall void WIN_FUNC(KeAcquireSpinLock,2) ++ (NT_SPIN_LOCK *lock, KIRQL *irql) ++{ ++ ENTER6("%p", lock); ++ *irql = nt_spin_lock_irql(lock, DISPATCH_LEVEL); ++} ++ ++wstdcall void WIN_FUNC(KeReleaseSpinLock,2) ++ (NT_SPIN_LOCK *lock, KIRQL oldirql) ++{ ++ ENTER6("%p", lock); ++ nt_spin_unlock_irql(lock, oldirql); ++} ++ ++wstdcall void WIN_FUNC(KeAcquireSpinLockAtDpcLevel,1) ++ (NT_SPIN_LOCK *lock) ++{ ++ ENTER6("%p", lock); ++ nt_spin_lock(lock); ++} ++ ++wstdcall void WIN_FUNC(KeReleaseSpinLockFromDpcLevel,1) ++ (NT_SPIN_LOCK *lock) ++{ ++ ENTER6("%p", lock); ++ nt_spin_unlock(lock); ++} ++ ++wstdcall void WIN_FUNC(KeRaiseIrql,2) ++ (KIRQL newirql, KIRQL *oldirql) ++{ ++ ENTER6("%d", newirql); ++ *oldirql = raise_irql(newirql); ++} ++ ++wstdcall KIRQL WIN_FUNC(KeRaiseIrqlToDpcLevel,0) ++ (void) ++{ ++ return raise_irql(DISPATCH_LEVEL); ++} ++ ++wstdcall void WIN_FUNC(KeLowerIrql,1) ++ (KIRQL irql) ++{ ++ ENTER6("%d", irql); ++ lower_irql(irql); ++} ++ ++wstdcall KIRQL WIN_FUNC(KeAcquireSpinLockRaiseToDpc,1) ++ (NT_SPIN_LOCK *lock) ++{ ++ ENTER6("%p", lock); ++ return nt_spin_lock_irql(lock, DISPATCH_LEVEL); ++} ++ ++wstdcall void *WIN_FUNC(ExAllocatePoolWithTag,3) ++ (enum pool_type pool_type, SIZE_T size, ULONG tag) ++{ ++ void *addr; ++ ++ ENTER4("pool_type: %d, size: %zu, tag: 0x%x", pool_type, size, tag); ++ assert_irql(_irql_ <= DISPATCH_LEVEL); ++ if (size < PAGE_SIZE) ++ addr = kmalloc(size, irql_gfp()); ++ else { ++ if (irql_gfp() & GFP_ATOMIC) { ++ addr = __vmalloc(size, GFP_ATOMIC | __GFP_HIGHMEM, ++ PAGE_KERNEL); ++ TRACE1("%p, %zu", addr, size); ++ } else { ++ addr = vmalloc(size); ++ TRACE1("%p, %zu", addr, size); ++ } ++ } ++ DBG_BLOCK(1) { ++ if (addr) ++ TRACE4("addr: %p, %zu", addr, size); ++ else ++ TRACE1("failed: %zu", size); ++ } ++ return addr; ++} ++WIN_FUNC_DECL(ExAllocatePoolWithTag,3) ++ ++wstdcall void WIN_FUNC(ExFreePoolWithTag,2) ++ (void *addr, ULONG tag) ++{ ++ TRACE4("%p", addr); ++ if ((unsigned long)addr < VMALLOC_START || ++ (unsigned long)addr >= VMALLOC_END) ++ kfree(addr); ++ else ++ vfree(addr); ++ ++ EXIT4(return); ++} ++ ++wstdcall void WIN_FUNC(ExFreePool,1) ++ (void *addr) ++{ ++ ExFreePoolWithTag(addr, 0); ++} ++WIN_FUNC_DECL(ExFreePool,1) ++ ++wstdcall void WIN_FUNC(ExInitializeNPagedLookasideList,7) ++ (struct npaged_lookaside_list *lookaside, ++ LOOKASIDE_ALLOC_FUNC *alloc_func, LOOKASIDE_FREE_FUNC *free_func, ++ ULONG flags, SIZE_T size, ULONG tag, USHORT depth) ++{ ++ ENTER3("lookaside: %p, size: %zu, flags: %u, head: %p, " ++ "alloc: %p, free: %p", lookaside, size, flags, ++ lookaside, alloc_func, free_func); ++ ++ memset(lookaside, 0, sizeof(*lookaside)); ++ ++ lookaside->size = size; ++ lookaside->tag = tag; ++ lookaside->depth = 4; ++ lookaside->maxdepth = 256; ++ lookaside->pool_type = NonPagedPool; ++ ++ if (alloc_func) ++ lookaside->alloc_func = alloc_func; ++ else ++ lookaside->alloc_func = WIN_FUNC_PTR(ExAllocatePoolWithTag,3); ++ if (free_func) ++ lookaside->free_func = free_func; ++ else ++ lookaside->free_func = WIN_FUNC_PTR(ExFreePool,1); ++ ++#ifndef CONFIG_X86_64 ++ nt_spin_lock_init(&lookaside->obsolete); ++#endif ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(ExDeleteNPagedLookasideList,1) ++ (struct npaged_lookaside_list *lookaside) ++{ ++ struct nt_slist *entry; ++ ++ ENTER3("lookaside = %p", lookaside); ++ while ((entry = ExpInterlockedPopEntrySList(&lookaside->head))) ++ LIN2WIN1(lookaside->free_func, entry); ++ EXIT3(return); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ExCreateCallback,4) ++ (struct callback_object **object, struct object_attributes *attributes, ++ BOOLEAN create, BOOLEAN allow_multiple_callbacks) ++{ ++ struct callback_object *obj; ++ ++ ENTER2(""); ++ spin_lock_bh(&ntoskernel_lock); ++ nt_list_for_each_entry(obj, &callback_objects, callback_funcs) { ++ if (obj->attributes == attributes) { ++ spin_unlock_bh(&ntoskernel_lock); ++ *object = obj; ++ return STATUS_SUCCESS; ++ } ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ obj = allocate_object(sizeof(struct callback_object), ++ OBJECT_TYPE_CALLBACK, NULL); ++ if (!obj) ++ EXIT2(return STATUS_INSUFFICIENT_RESOURCES); ++ InitializeListHead(&obj->callback_funcs); ++ nt_spin_lock_init(&obj->lock); ++ obj->allow_multiple_callbacks = allow_multiple_callbacks; ++ obj->attributes = attributes; ++ *object = obj; ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++wstdcall void *WIN_FUNC(ExRegisterCallback,3) ++ (struct callback_object *object, PCALLBACK_FUNCTION func, void *context) ++{ ++ struct callback_func *callback; ++ KIRQL irql; ++ ++ ENTER2(""); ++ irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL); ++ if (object->allow_multiple_callbacks == FALSE && ++ !IsListEmpty(&object->callback_funcs)) { ++ nt_spin_unlock_irql(&object->lock, irql); ++ EXIT2(return NULL); ++ } ++ nt_spin_unlock_irql(&object->lock, irql); ++ callback = kmalloc(sizeof(*callback), GFP_KERNEL); ++ if (!callback) { ++ ERROR("couldn't allocate memory"); ++ return NULL; ++ } ++ callback->func = func; ++ callback->context = context; ++ callback->object = object; ++ irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL); ++ InsertTailList(&object->callback_funcs, &callback->list); ++ nt_spin_unlock_irql(&object->lock, irql); ++ EXIT2(return callback); ++} ++ ++wstdcall void WIN_FUNC(ExUnregisterCallback,1) ++ (struct callback_func *callback) ++{ ++ struct callback_object *object; ++ KIRQL irql; ++ ++ ENTER3("%p", callback); ++ if (!callback) ++ return; ++ object = callback->object; ++ irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL); ++ RemoveEntryList(&callback->list); ++ nt_spin_unlock_irql(&object->lock, irql); ++ kfree(callback); ++ return; ++} ++ ++wstdcall void WIN_FUNC(ExNotifyCallback,3) ++ (struct callback_object *object, void *arg1, void *arg2) ++{ ++ struct callback_func *callback; ++ KIRQL irql; ++ ++ ENTER3("%p", object); ++ irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL); ++ nt_list_for_each_entry(callback, &object->callback_funcs, list) { ++ LIN2WIN3(callback->func, callback->context, arg1, arg2); ++ } ++ nt_spin_unlock_irql(&object->lock, irql); ++ return; ++} ++ ++/* check and set signaled state; should be called with dispatcher_lock held */ ++/* @grab indicates if the event should be grabbed or checked ++ * - note that a semaphore may stay in signaled state for multiple ++ * 'grabs' if the count is > 1 */ ++static int grab_object(struct dispatcher_header *dh, ++ struct task_struct *thread, int grab) ++{ ++ EVENTTRACE("%p, %p, %d, %d", dh, thread, grab, dh->signal_state); ++ if (unlikely(is_mutex_object(dh))) { ++ struct nt_mutex *nt_mutex; ++ nt_mutex = container_of(dh, struct nt_mutex, dh); ++ EVENTTRACE("%p, %p, %d, %p, %d", nt_mutex, ++ nt_mutex->owner_thread, dh->signal_state, ++ thread, grab); ++ /* either no thread owns the mutex or this thread owns ++ * it */ ++ assert(dh->signal_state == 1 && nt_mutex->owner_thread == NULL); ++ assert(dh->signal_state < 1 && nt_mutex->owner_thread != NULL); ++ if ((dh->signal_state == 1 && nt_mutex->owner_thread == NULL) || ++ nt_mutex->owner_thread == thread) { ++ if (grab) { ++ dh->signal_state--; ++ nt_mutex->owner_thread = thread; ++ } ++ EVENTEXIT(return 1); ++ } ++ } else if (dh->signal_state > 0) { ++ /* to grab, decrement signal_state for synchronization ++ * or semaphore objects */ ++ if (grab && (is_synch_object(dh) || is_semaphore_object(dh))) ++ dh->signal_state--; ++ EVENTEXIT(return 1); ++ } ++ EVENTEXIT(return 0); ++} ++ ++/* this function should be called holding dispatcher_lock */ ++static void object_signaled(struct dispatcher_header *dh) ++{ ++ struct nt_list *cur, *next; ++ struct wait_block *wb; ++ ++ EVENTENTER("%p", dh); ++ nt_list_for_each_safe(cur, next, &dh->wait_blocks) { ++ wb = container_of(cur, struct wait_block, list); ++ assert(wb->thread != NULL); ++ assert(wb->object == NULL); ++ if (!grab_object(dh, wb->thread, 1)) ++ continue; ++ EVENTTRACE("%p (%p): waking %p", dh, wb, wb->thread); ++ RemoveEntryList(cur); ++ wb->object = dh; ++ *(wb->wait_done) = 1; ++ wake_up_process(wb->thread); ++ } ++ EVENTEXIT(return); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(KeWaitForMultipleObjects,8) ++ (ULONG count, void *object[], enum wait_type wait_type, ++ KWAIT_REASON wait_reason, KPROCESSOR_MODE wait_mode, ++ BOOLEAN alertable, LARGE_INTEGER *timeout, ++ struct wait_block *wait_block_array) ++{ ++ int i, res = 0, wait_count, wait_done; ++ typeof(jiffies) wait_hz = 0; ++ struct wait_block *wb, wb_array[THREAD_WAIT_OBJECTS]; ++ struct dispatcher_header *dh; ++ KIRQL irql = current_irql(); ++ ++ EVENTENTER("%p, %d, %u, %p", current, count, wait_type, timeout); ++ ++ if (count > MAX_WAIT_OBJECTS || ++ (count > THREAD_WAIT_OBJECTS && wait_block_array == NULL)) ++ EVENTEXIT(return STATUS_INVALID_PARAMETER); ++ ++ if (wait_block_array == NULL) ++ wb = wb_array; ++ else ++ wb = wait_block_array; ++ ++ /* If *timeout == 0: In the case of WaitAny, if an object can ++ * be grabbed (object is in signaled state), grab and ++ * return. In the case of WaitAll, we have to first make sure ++ * all objects can be grabbed. If any/some of them can't be ++ * grabbed, either we return STATUS_TIMEOUT or wait for them, ++ * depending on how to satisfy wait. If all of them can be ++ * grabbed, we will grab them in the next loop below */ ++ ++ spin_lock_bh(&dispatcher_lock); ++ for (i = wait_count = 0; i < count; i++) { ++ dh = object[i]; ++ EVENTTRACE("%p: event %p (%d)", current, dh, dh->signal_state); ++ /* wait_type == 1 for WaitAny, 0 for WaitAll */ ++ if (grab_object(dh, current, wait_type)) { ++ if (wait_type == WaitAny) { ++ spin_unlock_bh(&dispatcher_lock); ++ EVENTEXIT(return STATUS_WAIT_0 + i); ++ } ++ } else { ++ EVENTTRACE("%p: wait for %p", current, dh); ++ wait_count++; ++ } ++ } ++ ++ if (timeout && *timeout == 0 && wait_count) { ++ spin_unlock_bh(&dispatcher_lock); ++ EVENTEXIT(return STATUS_TIMEOUT); ++ } ++ ++ /* get the list of objects the thread needs to wait on and add ++ * the thread on the wait list for each such object */ ++ /* if *timeout == 0, this step will grab all the objects */ ++ wait_done = 0; ++ for (i = 0; i < count; i++) { ++ dh = object[i]; ++ EVENTTRACE("%p: event %p (%d)", current, dh, dh->signal_state); ++ wb[i].object = NULL; ++ if (grab_object(dh, current, 1)) { ++ EVENTTRACE("%p: no wait for %p (%d)", ++ current, dh, dh->signal_state); ++ /* mark that we are not waiting on this object */ ++ wb[i].thread = NULL; ++ } else { ++ wb[i].wait_done = &wait_done; ++ wb[i].thread = current; ++ EVENTTRACE("%p: wait for %p", current, dh); ++ InsertTailList(&dh->wait_blocks, &wb[i].list); ++ } ++ } ++ spin_unlock_bh(&dispatcher_lock); ++ if (wait_count == 0) ++ EVENTEXIT(return STATUS_SUCCESS); ++ ++ assert(timeout == NULL || *timeout != 0); ++ if (timeout == NULL) ++ wait_hz = 0; ++ else ++ wait_hz = SYSTEM_TIME_TO_HZ(*timeout); ++ ++ if (irql >= DISPATCH_LEVEL) { ++ WARNING("attempt to wait with irql %d", irql); ++ EVENTEXIT(return STATUS_INVALID_PARAMETER); ++ } ++ EVENTTRACE("%p: sleep for %ld on %p", current, wait_hz, &wait_done); ++ /* we don't honor 'alertable' - according to description for ++ * this, even if waiting in non-alertable state, thread may be ++ * alerted in some circumstances */ ++ while (wait_count) { ++ res = wait_condition(wait_done, wait_hz, TASK_INTERRUPTIBLE); ++ spin_lock_bh(&dispatcher_lock); ++ EVENTTRACE("%p woke up: %d, %d", current, res, wait_done); ++ /* the event may have been set by the time ++ * wrap_wait_event returned and spinlock obtained, so ++ * don't rely on value of 'res' - check event status */ ++ if (!wait_done) { ++ assert(res <= 0); ++ /* timed out or interrupted; remove from wait list */ ++ for (i = 0; i < count; i++) { ++ if (!wb[i].thread) ++ continue; ++ EVENTTRACE("%p: timedout, dequeue %p (%p)", ++ current, object[i], wb[i].object); ++ assert(wb[i].object == NULL); ++ RemoveEntryList(&wb[i].list); ++ } ++ spin_unlock_bh(&dispatcher_lock); ++ if (res < 0) ++ EVENTEXIT(return STATUS_ALERTED); ++ else ++ EVENTEXIT(return STATUS_TIMEOUT); ++ } ++ assert(res > 0); ++ /* woken because object(s) signaled */ ++ for (i = 0; wait_count && i < count; i++) { ++ if (!wb[i].thread || !wb[i].object) ++ continue; ++ DBG_BLOCK(1) { ++ if (wb[i].object != object[i]) { ++ EVENTTRACE("oops %p != %p", ++ wb[i].object, object[i]); ++ continue; ++ } ++ } ++ wait_count--; ++ if (wait_type == WaitAny) { ++ int j; ++ /* done; remove from rest of wait list */ ++ for (j = i + 1; j < count; j++) { ++ if (wb[j].thread && !wb[j].object) ++ RemoveEntryList(&wb[j].list); ++ } ++ spin_unlock_bh(&dispatcher_lock); ++ EVENTEXIT(return STATUS_WAIT_0 + i); ++ } ++ } ++ wait_done = 0; ++ spin_unlock_bh(&dispatcher_lock); ++ if (wait_count == 0) ++ EVENTEXIT(return STATUS_SUCCESS); ++ ++ /* this thread is still waiting for more objects, so ++ * let it wait for remaining time and those objects */ ++ if (timeout) ++ wait_hz = res; ++ else ++ wait_hz = 0; ++ } ++ /* should never reach here, but compiler wants return value */ ++ ERROR("%p: wait_hz: %ld", current, wait_hz); ++ EVENTEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(KeWaitForSingleObject,5) ++ (void *object, KWAIT_REASON wait_reason, KPROCESSOR_MODE wait_mode, ++ BOOLEAN alertable, LARGE_INTEGER *timeout) ++{ ++ return KeWaitForMultipleObjects(1, &object, WaitAny, wait_reason, ++ wait_mode, alertable, timeout, NULL); ++} ++ ++wstdcall void WIN_FUNC(KeInitializeEvent,3) ++ (struct nt_event *nt_event, enum event_type type, BOOLEAN state) ++{ ++ EVENTENTER("event = %p, type = %d, state = %d", nt_event, type, state); ++ initialize_object(&nt_event->dh, (enum dh_type)type, state); ++ EVENTEXIT(return); ++} ++ ++wstdcall LONG WIN_FUNC(KeSetEvent,3) ++ (struct nt_event *nt_event, KPRIORITY incr, BOOLEAN wait) ++{ ++ LONG old_state; ++ ++ EVENTENTER("%p, %d", nt_event, nt_event->dh.type); ++ if (wait == TRUE) ++ WARNING("wait = %d, not yet implemented", wait); ++ spin_lock_bh(&dispatcher_lock); ++ old_state = nt_event->dh.signal_state; ++ nt_event->dh.signal_state = 1; ++ if (old_state == 0) ++ object_signaled(&nt_event->dh); ++ spin_unlock_bh(&dispatcher_lock); ++ EVENTEXIT(return old_state); ++} ++ ++wstdcall void WIN_FUNC(KeClearEvent,1) ++ (struct nt_event *nt_event) ++{ ++ EVENTENTER("%p", nt_event); ++ nt_event->dh.signal_state = 0; ++ EVENTEXIT(return); ++} ++ ++wstdcall LONG WIN_FUNC(KeResetEvent,1) ++ (struct nt_event *nt_event) ++{ ++ LONG old_state; ++ ++ EVENTENTER("%p", nt_event); ++ old_state = xchg(&nt_event->dh.signal_state, 0); ++ EVENTEXIT(return old_state); ++} ++ ++wstdcall LONG WIN_FUNC(KeReadStateEvent,1) ++ (struct nt_event *nt_event) ++{ ++ LONG state; ++ ++ state = nt_event->dh.signal_state; ++ EVENTTRACE("%d", state); ++ return state; ++} ++ ++wstdcall void WIN_FUNC(KeInitializeMutex,2) ++ (struct nt_mutex *mutex, ULONG level) ++{ ++ EVENTENTER("%p", mutex); ++ initialize_object(&mutex->dh, MutexObject, 1); ++ mutex->dh.size = sizeof(*mutex); ++ InitializeListHead(&mutex->list); ++ mutex->abandoned = FALSE; ++ mutex->apc_disable = 1; ++ mutex->owner_thread = NULL; ++ EVENTEXIT(return); ++} ++ ++wstdcall LONG WIN_FUNC(KeReleaseMutex,2) ++ (struct nt_mutex *mutex, BOOLEAN wait) ++{ ++ LONG ret; ++ struct task_struct *thread; ++ ++ EVENTENTER("%p, %d, %p", mutex, wait, current); ++ if (wait == TRUE) ++ WARNING("wait: %d", wait); ++ thread = current; ++ spin_lock_bh(&dispatcher_lock); ++ EVENTTRACE("%p, %p, %p, %d", mutex, thread, mutex->owner_thread, ++ mutex->dh.signal_state); ++ if ((mutex->owner_thread == thread) && (mutex->dh.signal_state <= 0)) { ++ ret = mutex->dh.signal_state++; ++ if (ret == 0) { ++ mutex->owner_thread = NULL; ++ object_signaled(&mutex->dh); ++ } ++ } else { ++ ret = STATUS_MUTANT_NOT_OWNED; ++ WARNING("invalid mutex: %p, %p, %p", mutex, mutex->owner_thread, ++ thread); ++ } ++ EVENTTRACE("%p, %p, %p, %d", mutex, thread, mutex->owner_thread, ++ mutex->dh.signal_state); ++ spin_unlock_bh(&dispatcher_lock); ++ EVENTEXIT(return ret); ++} ++ ++wstdcall void WIN_FUNC(KeInitializeSemaphore,3) ++ (struct nt_semaphore *semaphore, LONG count, LONG limit) ++{ ++ EVENTENTER("%p: %d", semaphore, count); ++ /* if limit > 1, we need to satisfy as many waits (until count ++ * becomes 0); so we keep decrementing count every time a wait ++ * is satisfied */ ++ initialize_object(&semaphore->dh, SemaphoreObject, count); ++ semaphore->dh.size = sizeof(*semaphore); ++ semaphore->limit = limit; ++ EVENTEXIT(return); ++} ++ ++wstdcall LONG WIN_FUNC(KeReleaseSemaphore,4) ++ (struct nt_semaphore *semaphore, KPRIORITY incr, LONG adjustment, ++ BOOLEAN wait) ++{ ++ LONG ret; ++ ++ EVENTENTER("%p", semaphore); ++ spin_lock_bh(&dispatcher_lock); ++ ret = semaphore->dh.signal_state; ++ assert(ret >= 0); ++ if (semaphore->dh.signal_state + adjustment <= semaphore->limit) ++ semaphore->dh.signal_state += adjustment; ++ else { ++ WARNING("releasing %d over limit %d", adjustment, ++ semaphore->limit); ++ semaphore->dh.signal_state = semaphore->limit; ++ } ++ if (semaphore->dh.signal_state > 0) ++ object_signaled(&semaphore->dh); ++ spin_unlock_bh(&dispatcher_lock); ++ EVENTEXIT(return ret); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(KeDelayExecutionThread,3) ++ (KPROCESSOR_MODE wait_mode, BOOLEAN alertable, LARGE_INTEGER *interval) ++{ ++ int res; ++ long timeout; ++ ++ if (wait_mode != 0) ++ ERROR("invalid wait_mode %d", wait_mode); ++ ++ timeout = SYSTEM_TIME_TO_HZ(*interval); ++ EVENTTRACE("%p, %lld, %ld", current, *interval, timeout); ++ if (timeout <= 0) ++ EVENTEXIT(return STATUS_SUCCESS); ++ ++ if (alertable) ++ set_current_state(TASK_INTERRUPTIBLE); ++ else ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ ++ res = schedule_timeout(timeout); ++ EVENTTRACE("%p, %d", current, res); ++ if (res == 0) ++ EVENTEXIT(return STATUS_SUCCESS); ++ else ++ EVENTEXIT(return STATUS_ALERTED); ++} ++ ++wstdcall ULONGLONG WIN_FUNC(KeQueryInterruptTime,0) ++ (void) ++{ ++ EXIT5(return jiffies * TICKSPERJIFFY); ++} ++ ++wstdcall ULONG WIN_FUNC(KeQueryTimeIncrement,0) ++ (void) ++{ ++ EXIT5(return TICKSPERSEC / HZ); ++} ++ ++wstdcall void WIN_FUNC(KeQuerySystemTime,1) ++ (LARGE_INTEGER *time) ++{ ++ *time = ticks_1601(); ++ TRACE5("%llu, %lu", *time, jiffies); ++} ++ ++wstdcall void WIN_FUNC(KeQueryTickCount,1) ++ (LARGE_INTEGER *count) ++{ ++ *count = jiffies; ++} ++ ++wstdcall LARGE_INTEGER WIN_FUNC(KeQueryPerformanceCounter,1) ++ (LARGE_INTEGER *counter) ++{ ++ if (counter) ++ *counter = HZ; ++ return jiffies; ++} ++ ++wstdcall KAFFINITY WIN_FUNC(KeQueryActiveProcessors,0) ++ (void) ++{ ++ int i, n; ++ KAFFINITY bits = 0; ++ n = num_online_cpus(); ++ for (i = 0; i < n; i++) ++ bits = (bits << 1) | 1; ++ return bits; ++} ++ ++struct nt_thread *get_current_nt_thread(void) ++{ ++ struct task_struct *task = current; ++ struct nt_thread *thread; ++ struct common_object_header *header; ++ ++ TRACE6("task: %p", task); ++ thread = NULL; ++ spin_lock_bh(&ntoskernel_lock); ++ nt_list_for_each_entry(header, &object_list, list) { ++ TRACE6("%p, %d", header, header->type); ++ if (header->type != OBJECT_TYPE_NT_THREAD) ++ break; ++ thread = HEADER_TO_OBJECT(header); ++ TRACE6("%p, %p", thread, thread->task); ++ if (thread->task == task) ++ break; ++ else ++ thread = NULL; ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ if (thread == NULL) ++ TRACE4("couldn't find thread for task %p, %d", task, task->pid); ++ TRACE6("%p", thread); ++ return thread; ++} ++ ++static struct task_struct *get_nt_thread_task(struct nt_thread *thread) ++{ ++ struct task_struct *task; ++ struct common_object_header *header; ++ ++ TRACE6("%p", thread); ++ task = NULL; ++ spin_lock_bh(&ntoskernel_lock); ++ nt_list_for_each_entry(header, &object_list, list) { ++ TRACE6("%p, %d", header, header->type); ++ if (header->type != OBJECT_TYPE_NT_THREAD) ++ break; ++ if (thread == HEADER_TO_OBJECT(header)) { ++ task = thread->task; ++ break; ++ } ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ if (task == NULL) ++ TRACE2("%p: couldn't find task for %p", current, thread); ++ return task; ++} ++ ++static struct nt_thread *create_nt_thread(struct task_struct *task) ++{ ++ struct nt_thread *thread; ++ thread = allocate_object(sizeof(*thread), OBJECT_TYPE_NT_THREAD, NULL); ++ if (!thread) { ++ ERROR("couldn't allocate thread object"); ++ EXIT2(return NULL); ++ } ++ thread->task = task; ++ if (task) ++ thread->pid = task->pid; ++ else ++ thread->pid = 0; ++ nt_spin_lock_init(&thread->lock); ++ InitializeListHead(&thread->irps); ++ initialize_object(&thread->dh, ThreadObject, 0); ++ thread->dh.size = sizeof(*thread); ++ thread->prio = LOW_PRIORITY; ++ return thread; ++} ++ ++wstdcall struct nt_thread *WIN_FUNC(KeGetCurrentThread,0) ++ (void) ++{ ++ struct nt_thread *thread = get_current_nt_thread(); ++ TRACE2("%p, %p", thread, current); ++ return thread; ++} ++ ++wstdcall KPRIORITY WIN_FUNC(KeQueryPriorityThread,1) ++ (struct nt_thread *thread) ++{ ++ KPRIORITY prio; ++ struct task_struct *task; ++ ++ TRACE2("%p", thread); ++#ifdef CONFIG_X86_64 ++ /* sis163u driver for amd64 passes 0x1f from thread created by ++ * PsCreateSystemThread - no idea what is 0x1f */ ++ if (thread == (void *)0x1f) ++ thread = get_current_nt_thread(); ++#endif ++ if (!thread) { ++ TRACE2("invalid thread"); ++ EXIT2(return LOW_REALTIME_PRIORITY); ++ } ++ task = get_nt_thread_task(thread); ++ if (!task) { ++ TRACE2("couldn't find task for thread: %p", thread); ++ EXIT2(return LOW_REALTIME_PRIORITY); ++ } ++ ++ prio = thread->prio; ++ ++ TRACE2("%d", prio); ++ return prio; ++} ++ ++wstdcall KPRIORITY WIN_FUNC(KeSetPriorityThread,2) ++ (struct nt_thread *thread, KPRIORITY prio) ++{ ++ KPRIORITY old_prio; ++ struct task_struct *task; ++ ++ TRACE2("thread: %p, priority = %u", thread, prio); ++#ifdef CONFIG_X86_64 ++ if (thread == (void *)0x1f) ++ thread = get_current_nt_thread(); ++#endif ++ if (!thread) { ++ TRACE2("invalid thread"); ++ EXIT2(return LOW_REALTIME_PRIORITY); ++ } ++ task = get_nt_thread_task(thread); ++ if (!task) { ++ TRACE2("couldn't find task for thread: %p", thread); ++ EXIT2(return LOW_REALTIME_PRIORITY); ++ } ++ ++ old_prio = thread->prio; ++ thread->prio = prio; ++ ++ TRACE2("%d, %d", old_prio, thread->prio); ++ return old_prio; ++} ++ ++struct thread_trampoline { ++ void (*func)(void *) wstdcall; ++ void *ctx; ++ struct nt_thread *thread; ++ struct completion started; ++}; ++ ++static int ntdriver_thread(void *data) ++{ ++ struct thread_trampoline *thread_tramp = data; ++ /* yes, a tramp! */ ++ typeof(thread_tramp->func) func = thread_tramp->func; ++ typeof(thread_tramp->ctx) ctx = thread_tramp->ctx; ++ ++ thread_tramp->thread->task = current; ++ thread_tramp->thread->pid = current->pid; ++ TRACE2("thread: %p, task: %p (%d)", thread_tramp->thread, ++ current, current->pid); ++ complete(&thread_tramp->started); ++ ++#ifdef PF_NOFREEZE ++ current->flags |= PF_NOFREEZE; ++#endif ++ strncpy(current->comm, "ntdriver", sizeof(current->comm)); ++ current->comm[sizeof(current->comm)-1] = 0; ++ LIN2WIN1(func, ctx); ++ ERROR("task: %p", current); ++ return 0; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(PsCreateSystemThread,7) ++ (void **handle, ULONG access, void *obj_attr, void *process, ++ void *client_id, void (*func)(void *) wstdcall, void *ctx) ++{ ++ struct thread_trampoline thread_tramp; ++ ++ ENTER2("handle = %p, access = %u, obj_attr = %p, process = %p, " ++ "client_id = %p, func = %p, context = %p", handle, access, ++ obj_attr, process, client_id, func, ctx); ++ ++ thread_tramp.thread = create_nt_thread(NULL); ++ if (!thread_tramp.thread) { ++ ERROR("couldn't allocate thread object"); ++ EXIT2(return STATUS_RESOURCES); ++ } ++ TRACE2("thread: %p", thread_tramp.thread); ++ thread_tramp.func = func; ++ thread_tramp.ctx = ctx; ++ init_completion(&thread_tramp.started); ++ ++ thread_tramp.thread->task = kthread_run(ntdriver_thread, ++ &thread_tramp, "ntdriver"); ++ if (IS_ERR(thread_tramp.thread->task)) { ++ free_object(thread_tramp.thread); ++ EXIT2(return STATUS_FAILURE); ++ } ++ TRACE2("created task: %p", thread_tramp.thread->task); ++ ++ wait_for_completion(&thread_tramp.started); ++ *handle = OBJECT_TO_HEADER(thread_tramp.thread); ++ TRACE2("created thread: %p, %p", thread_tramp.thread, *handle); ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(PsTerminateSystemThread,1) ++ (NTSTATUS status) ++{ ++ struct nt_thread *thread; ++ ++ TRACE2("%p, %08X", current, status); ++ thread = get_current_nt_thread(); ++ TRACE2("%p", thread); ++ if (thread) { ++ KeSetEvent((struct nt_event *)&thread->dh, 0, FALSE); ++ while (1) { ++ struct nt_list *ent; ++ struct irp *irp; ++ KIRQL irql; ++ irql = nt_spin_lock_irql(&thread->lock, DISPATCH_LEVEL); ++ ent = RemoveHeadList(&thread->irps); ++ nt_spin_unlock_irql(&thread->lock, irql); ++ if (!ent) ++ break; ++ irp = container_of(ent, struct irp, thread_list); ++ IOTRACE("%p", irp); ++ IoCancelIrp(irp); ++ } ++ /* the driver may later query this status with ++ * ZwQueryInformationThread */ ++ thread->status = status; ++ } else ++ ERROR("couldn't find thread for task: %p", current); ++ ++ complete_and_exit(NULL, status); ++ ERROR("oops: %p, %d", thread->task, thread->pid); ++ return STATUS_FAILURE; ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeRemoveEntryDeviceQueue,2) ++ (struct kdevice_queue *dev_queue, struct kdevice_queue_entry *entry) ++{ ++ struct kdevice_queue_entry *e; ++ KIRQL irql; ++ ++ irql = nt_spin_lock_irql(&dev_queue->lock, DISPATCH_LEVEL); ++ nt_list_for_each_entry(e, &dev_queue->list, list) { ++ if (e == entry) { ++ RemoveEntryList(&e->list); ++ nt_spin_unlock_irql(&dev_queue->lock, irql); ++ return TRUE; ++ } ++ } ++ nt_spin_unlock_irql(&dev_queue->lock, irql); ++ return FALSE; ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeSynchronizeExecution,3) ++ (struct kinterrupt *interrupt, PKSYNCHRONIZE_ROUTINE synch_routine, ++ void *ctx) ++{ ++ BOOLEAN ret; ++ unsigned long flags; ++ ++ nt_spin_lock_irqsave(interrupt->actual_lock, flags); ++ ret = LIN2WIN1(synch_routine, ctx); ++ nt_spin_unlock_irqrestore(interrupt->actual_lock, flags); ++ TRACE6("%d", ret); ++ return ret; ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeRegisterBugCheckReasonCallback,4) ++ (void *callback_record, void *callback_routine, UINT reason, ++ char *component) ++{ ++ TRACE1("callback_record: %p, callback_routine: %p, reason: %d, " ++ "component: %s", callback_record, callback_routine, reason, ++ component); ++ TODO(); ++ return FALSE; ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeDeregisterBugCheckReasonCallback,1) ++ (void *callback_record) ++{ ++ TRACE1("callback_record: %p", callback_record); ++ TODO(); ++ return TRUE; ++} ++ ++wstdcall void *WIN_FUNC(MmAllocateContiguousMemorySpecifyCache,5) ++ (SIZE_T size, PHYSICAL_ADDRESS lowest, PHYSICAL_ADDRESS highest, ++ PHYSICAL_ADDRESS boundary, enum memory_caching_type cache_type) ++{ ++ void *addr; ++ gfp_t flags; ++ ++ ENTER2("%zu, 0x%llx, 0x%llx, 0x%llx, %d", size, lowest, ++ highest, boundary, cache_type); ++ flags = irql_gfp(); ++ addr = wrap_get_free_pages(flags, size); ++ TRACE2("%p, %zu, 0x%x", addr, size, flags); ++ if (addr && ((virt_to_phys(addr) + size) <= highest)) ++ EXIT2(return addr); ++#ifdef CONFIG_X86_64 ++ /* GFP_DMA is really only 16MB even on x86-64, but there is no ++ * other zone available */ ++ if (highest <= DMA_BIT_MASK(31)) ++ flags |= __GFP_DMA; ++ else if (highest <= DMA_BIT_MASK(32)) ++ flags |= __GFP_DMA32; ++#else ++ if (highest <= DMA_BIT_MASK(24)) ++ flags |= __GFP_DMA; ++ else if (highest > DMA_BIT_MASK(30)) ++ flags |= __GFP_HIGHMEM; ++#endif ++ if (addr) ++ free_pages((unsigned long)addr, get_order(size)); ++ addr = wrap_get_free_pages(flags, size); ++ TRACE2("%p, %zu, 0x%x", addr, size, flags); ++ return addr; ++} ++ ++wstdcall void WIN_FUNC(MmFreeContiguousMemorySpecifyCache,3) ++ (void *base, SIZE_T size, enum memory_caching_type cache_type) ++{ ++ TRACE2("%p, %zu", base, size); ++ free_pages((unsigned long)base, get_order(size)); ++} ++ ++wstdcall PHYSICAL_ADDRESS WIN_FUNC(MmGetPhysicalAddress,1) ++ (void *base) ++{ ++ unsigned long phy = virt_to_phys(base); ++ TRACE2("%p, %p", base, (void *)phy); ++ return phy; ++} ++ ++/* Atheros card with pciid 168C:0014 calls this function with 0xf0000 ++ * and 0xf6ef0 address, and then check for things that seem to be ++ * related to ACPI: "_SM_" and "_DMI_". This may be the hack they do ++ * to check if this card is installed in IBM thinkpads; we can ++ * probably get this device to work if we create a buffer with the ++ * strings as required by the driver and return virtual address for ++ * that address instead */ ++wstdcall void __iomem *WIN_FUNC(MmMapIoSpace,3) ++ (PHYSICAL_ADDRESS phys_addr, SIZE_T size, ++ enum memory_caching_type cache) ++{ ++ void __iomem *virt; ++ ENTER1("cache type: %d", cache); ++ if (cache == MmCached) ++ virt = ioremap(phys_addr, size); ++ else ++ virt = ioremap_nocache(phys_addr, size); ++ TRACE1("%llx, %zu, %p", phys_addr, size, virt); ++ return virt; ++} ++ ++wstdcall void WIN_FUNC(MmUnmapIoSpace,2) ++ (void __iomem *addr, SIZE_T size) ++{ ++ ENTER1("%p, %zu", addr, size); ++ iounmap(addr); ++ return; ++} ++ ++wstdcall ULONG WIN_FUNC(MmSizeOfMdl,2) ++ (void *base, ULONG length) ++{ ++ return sizeof(struct mdl) + ++ (sizeof(PFN_NUMBER) * SPAN_PAGES(base, length)); ++} ++ ++struct mdl *allocate_init_mdl(void *virt, ULONG length) ++{ ++ struct wrap_mdl *wrap_mdl; ++ struct mdl *mdl; ++ int mdl_size = MmSizeOfMdl(virt, length); ++ ++ if (mdl_size <= MDL_CACHE_SIZE) { ++ wrap_mdl = kmem_cache_alloc(mdl_cache, irql_gfp()); ++ if (!wrap_mdl) ++ return NULL; ++ spin_lock_bh(&dispatcher_lock); ++ InsertHeadList(&wrap_mdl_list, &wrap_mdl->list); ++ spin_unlock_bh(&dispatcher_lock); ++ mdl = wrap_mdl->mdl; ++ TRACE3("allocated mdl from cache: %p(%p), %p(%d)", ++ wrap_mdl, mdl, virt, length); ++ memset(mdl, 0, MDL_CACHE_SIZE); ++ MmInitializeMdl(mdl, virt, length); ++ /* mark the MDL as allocated from cache pool so when ++ * it is freed, we free it back to the pool */ ++ mdl->flags = MDL_ALLOCATED_FIXED_SIZE | MDL_CACHE_ALLOCATED; ++ } else { ++ wrap_mdl = ++ kmalloc(sizeof(*wrap_mdl) + mdl_size, irql_gfp()); ++ if (!wrap_mdl) ++ return NULL; ++ mdl = wrap_mdl->mdl; ++ TRACE3("allocated mdl from memory: %p(%p), %p(%d)", ++ wrap_mdl, mdl, virt, length); ++ spin_lock_bh(&dispatcher_lock); ++ InsertHeadList(&wrap_mdl_list, &wrap_mdl->list); ++ spin_unlock_bh(&dispatcher_lock); ++ memset(mdl, 0, mdl_size); ++ MmInitializeMdl(mdl, virt, length); ++ mdl->flags = MDL_ALLOCATED_FIXED_SIZE; ++ } ++ return mdl; ++} ++ ++void free_mdl(struct mdl *mdl) ++{ ++ /* A driver may allocate Mdl with NdisAllocateBuffer and free ++ * with IoFreeMdl (e.g., 64-bit Broadcom). Since we need to ++ * treat buffers allocated with Ndis calls differently, we ++ * must call NdisFreeBuffer if it is allocated with Ndis ++ * function. We set 'pool' field in Ndis functions. */ ++ if (!mdl) ++ return; ++ if (mdl->pool) ++ NdisFreeBuffer(mdl); ++ else { ++ struct wrap_mdl *wrap_mdl = (struct wrap_mdl *) ++ ((char *)mdl - offsetof(struct wrap_mdl, mdl)); ++ spin_lock_bh(&dispatcher_lock); ++ RemoveEntryList(&wrap_mdl->list); ++ spin_unlock_bh(&dispatcher_lock); ++ ++ if (mdl->flags & MDL_CACHE_ALLOCATED) { ++ TRACE3("freeing mdl cache: %p, %p, %p", ++ wrap_mdl, mdl, mdl->mappedsystemva); ++ kmem_cache_free(mdl_cache, wrap_mdl); ++ } else { ++ TRACE3("freeing mdl: %p, %p, %p", ++ wrap_mdl, mdl, mdl->mappedsystemva); ++ kfree(wrap_mdl); ++ } ++ } ++ return; ++} ++ ++wstdcall void WIN_FUNC(IoBuildPartialMdl,4) ++ (struct mdl *source, struct mdl *target, void *virt, ULONG length) ++{ ++ MmInitializeMdl(target, virt, length); ++ target->flags |= MDL_PARTIAL; ++} ++ ++wstdcall void WIN_FUNC(MmBuildMdlForNonPagedPool,1) ++ (struct mdl *mdl) ++{ ++ PFN_NUMBER *mdl_pages; ++ int i, n; ++ ++ ENTER4("%p", mdl); ++ /* already mapped */ ++// mdl->mappedsystemva = MmGetMdlVirtualAddress(mdl); ++ mdl->flags |= MDL_SOURCE_IS_NONPAGED_POOL; ++ TRACE4("%p, %p, %p, %d, %d", mdl, mdl->mappedsystemva, mdl->startva, ++ mdl->byteoffset, mdl->bytecount); ++ n = SPAN_PAGES(MmGetSystemAddressForMdl(mdl), MmGetMdlByteCount(mdl)); ++ if (n > MDL_CACHE_PAGES) ++ WARNING("%p, %d, %d", MmGetSystemAddressForMdl(mdl), ++ MmGetMdlByteCount(mdl), n); ++ mdl_pages = MmGetMdlPfnArray(mdl); ++ for (i = 0; i < n; i++) ++ mdl_pages[i] = (ULONG_PTR)mdl->startva + (i * PAGE_SIZE); ++ EXIT4(return); ++} ++ ++wstdcall void *WIN_FUNC(MmMapLockedPages,2) ++ (struct mdl *mdl, KPROCESSOR_MODE access_mode) ++{ ++ /* already mapped */ ++// mdl->mappedsystemva = MmGetMdlVirtualAddress(mdl); ++ mdl->flags |= MDL_MAPPED_TO_SYSTEM_VA; ++ /* what is the need for MDL_PARTIAL_HAS_BEEN_MAPPED? */ ++ if (mdl->flags & MDL_PARTIAL) ++ mdl->flags |= MDL_PARTIAL_HAS_BEEN_MAPPED; ++ return mdl->mappedsystemva; ++} ++ ++wstdcall void *WIN_FUNC(MmMapLockedPagesSpecifyCache,6) ++ (struct mdl *mdl, KPROCESSOR_MODE access_mode, ++ enum memory_caching_type cache_type, void *base_address, ++ ULONG bug_check, enum mm_page_priority priority) ++{ ++ return MmMapLockedPages(mdl, access_mode); ++} ++ ++wstdcall void WIN_FUNC(MmUnmapLockedPages,2) ++ (void *base, struct mdl *mdl) ++{ ++ mdl->flags &= ~MDL_MAPPED_TO_SYSTEM_VA; ++ return; ++} ++ ++wstdcall void WIN_FUNC(MmProbeAndLockPages,3) ++ (struct mdl *mdl, KPROCESSOR_MODE access_mode, ++ enum lock_operation operation) ++{ ++ /* already locked */ ++ mdl->flags |= MDL_PAGES_LOCKED; ++ return; ++} ++ ++wstdcall void WIN_FUNC(MmUnlockPages,1) ++ (struct mdl *mdl) ++{ ++ mdl->flags &= ~MDL_PAGES_LOCKED; ++ return; ++} ++ ++wstdcall BOOLEAN WIN_FUNC(MmIsAddressValid,1) ++ (void *virt_addr) ++{ ++ if (virt_addr_valid(virt_addr)) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++wstdcall void *WIN_FUNC(MmLockPagableDataSection,1) ++ (void *address) ++{ ++ return address; ++} ++ ++wstdcall void WIN_FUNC(MmUnlockPagableImageSection,1) ++ (void *handle) ++{ ++ return; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ObReferenceObjectByHandle,6) ++ (void *handle, ACCESS_MASK desired_access, void *obj_type, ++ KPROCESSOR_MODE access_mode, void **object, void *handle_info) ++{ ++ struct common_object_header *hdr; ++ ++ TRACE2("%p", handle); ++ hdr = HANDLE_TO_HEADER(handle); ++ atomic_inc_var(hdr->ref_count); ++ *object = HEADER_TO_OBJECT(hdr); ++ TRACE2("%p, %p, %d, %p", hdr, object, hdr->ref_count, *object); ++ return STATUS_SUCCESS; ++} ++ ++/* DDK doesn't say if return value should be before incrementing or ++ * after incrementing reference count, but according to #reactos ++ * developers, it should be return value after incrementing */ ++wfastcall LONG WIN_FUNC(ObfReferenceObject,1) ++ (void *object) ++{ ++ struct common_object_header *hdr; ++ LONG ret; ++ ++ hdr = OBJECT_TO_HEADER(object); ++ ret = post_atomic_add(hdr->ref_count, 1); ++ TRACE2("%p, %d, %p", hdr, hdr->ref_count, object); ++ return ret; ++} ++ ++static int dereference_object(void *object) ++{ ++ struct common_object_header *hdr; ++ int ref_count; ++ ++ ENTER2("object: %p", object); ++ hdr = OBJECT_TO_HEADER(object); ++ TRACE2("hdr: %p", hdr); ++ ref_count = post_atomic_add(hdr->ref_count, -1); ++ TRACE2("object: %p, %d", object, ref_count); ++ if (ref_count < 0) ++ ERROR("invalid object: %p (%d)", object, ref_count); ++ if (ref_count <= 0) { ++ free_object(object); ++ return 1; ++ } else ++ return 0; ++} ++ ++wfastcall void WIN_FUNC(ObfDereferenceObject,1) ++ (void *object) ++{ ++ TRACE2("%p", object); ++ dereference_object(object); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwCreateFile,11) ++ (void **handle, ACCESS_MASK access_mask, ++ struct object_attributes *obj_attr, struct io_status_block *iosb, ++ LARGE_INTEGER *size, ULONG file_attr, ULONG share_access, ++ ULONG create_disposition, ULONG create_options, void *ea_buffer, ++ ULONG ea_length) ++{ ++ struct common_object_header *coh; ++ struct file_object *fo; ++ struct ansi_string ansi; ++ struct wrap_bin_file *bin_file; ++ char *file_basename; ++ NTSTATUS status; ++ ++ spin_lock_bh(&ntoskernel_lock); ++ nt_list_for_each_entry(coh, &object_list, list) { ++ if (coh->type != OBJECT_TYPE_FILE) ++ continue; ++ /* TODO: check if file is opened in shared mode */ ++ if (!RtlCompareUnicodeString(&coh->name, obj_attr->name, TRUE)) { ++ fo = HEADER_TO_OBJECT(coh); ++ bin_file = fo->wrap_bin_file; ++ *handle = coh; ++ spin_unlock_bh(&ntoskernel_lock); ++ ObReferenceObject(fo); ++ iosb->status = FILE_OPENED; ++ iosb->info = bin_file->size; ++ EXIT2(return STATUS_SUCCESS); ++ } ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ ++ if (RtlUnicodeStringToAnsiString(&ansi, obj_attr->name, TRUE) != ++ STATUS_SUCCESS) ++ EXIT2(return STATUS_INSUFFICIENT_RESOURCES); ++ ++ file_basename = strrchr(ansi.buf, '\\'); ++ if (file_basename) ++ file_basename++; ++ else ++ file_basename = ansi.buf; ++ TRACE2("file: '%s', '%s'", ansi.buf, file_basename); ++ ++ fo = allocate_object(sizeof(struct file_object), OBJECT_TYPE_FILE, ++ obj_attr->name); ++ if (!fo) { ++ RtlFreeAnsiString(&ansi); ++ iosb->status = STATUS_INSUFFICIENT_RESOURCES; ++ iosb->info = 0; ++ EXIT2(return STATUS_FAILURE); ++ } ++ coh = OBJECT_TO_HEADER(fo); ++ bin_file = get_bin_file(file_basename); ++ if (bin_file) { ++ TRACE2("%s, %s", bin_file->name, file_basename); ++ fo->flags = FILE_OPENED; ++ } else if (access_mask & FILE_WRITE_DATA) { ++ bin_file = kzalloc(sizeof(*bin_file), GFP_KERNEL); ++ if (bin_file) { ++ strncpy(bin_file->name, file_basename, ++ sizeof(bin_file->name)); ++ bin_file->name[sizeof(bin_file->name)-1] = 0; ++ bin_file->data = vmalloc(*size); ++ if (bin_file->data) { ++ memset(bin_file->data, 0, *size); ++ bin_file->size = *size; ++ fo->flags = FILE_CREATED; ++ } else { ++ kfree(bin_file); ++ bin_file = NULL; ++ } ++ } ++ } else ++ bin_file = NULL; ++ ++ RtlFreeAnsiString(&ansi); ++ if (!bin_file) { ++ iosb->status = FILE_DOES_NOT_EXIST; ++ iosb->info = 0; ++ free_object(fo); ++ EXIT2(return STATUS_FAILURE); ++ } ++ ++ fo->wrap_bin_file = bin_file; ++ fo->current_byte_offset = 0; ++ if (access_mask & FILE_READ_DATA) ++ fo->read_access = TRUE; ++ if (access_mask & FILE_WRITE_DATA) ++ fo->write_access = TRUE; ++ iosb->status = FILE_OPENED; ++ iosb->info = bin_file->size; ++ *handle = coh; ++ TRACE2("handle: %p", *handle); ++ status = STATUS_SUCCESS; ++ EXIT2(return status); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwOpenFile,6) ++ (void **handle, ACCESS_MASK access_mask, ++ struct object_attributes *obj_attr, struct io_status_block *iosb, ++ ULONG share_access, ULONG open_options) ++{ ++ LARGE_INTEGER size; ++ return ZwCreateFile(handle, access_mask, obj_attr, iosb, &size, 0, ++ share_access, 0, open_options, NULL, 0); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwReadFile,9) ++ (void *handle, struct nt_event *event, void *apc_routine, ++ void *apc_context, struct io_status_block *iosb, void *buffer, ++ ULONG length, LARGE_INTEGER *byte_offset, ULONG *key) ++{ ++ struct file_object *fo; ++ struct common_object_header *coh; ++ ULONG count; ++ size_t offset; ++ struct wrap_bin_file *file; ++ ++ TRACE2("%p", handle); ++ coh = handle; ++ if (coh->type != OBJECT_TYPE_FILE) { ++ ERROR("handle %p is invalid: %d", handle, coh->type); ++ EXIT2(return STATUS_FAILURE); ++ } ++ fo = HANDLE_TO_OBJECT(coh); ++ file = fo->wrap_bin_file; ++ TRACE2("file: %s (%zu)", file->name, file->size); ++ spin_lock_bh(&ntoskernel_lock); ++ if (byte_offset) ++ offset = *byte_offset; ++ else ++ offset = fo->current_byte_offset; ++ count = min((size_t)length, file->size - offset); ++ TRACE2("count: %u, offset: %zu, length: %u", count, offset, length); ++ memcpy(buffer, ((void *)file->data) + offset, count); ++ fo->current_byte_offset = offset + count; ++ spin_unlock_bh(&ntoskernel_lock); ++ iosb->status = STATUS_SUCCESS; ++ iosb->info = count; ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwWriteFile,9) ++ (void *handle, struct nt_event *event, void *apc_routine, ++ void *apc_context, struct io_status_block *iosb, void *buffer, ++ ULONG length, LARGE_INTEGER *byte_offset, ULONG *key) ++{ ++ struct file_object *fo; ++ struct common_object_header *coh; ++ struct wrap_bin_file *file; ++ unsigned long offset; ++ ++ TRACE2("%p", handle); ++ coh = handle; ++ if (coh->type != OBJECT_TYPE_FILE) { ++ ERROR("handle %p is invalid: %d", handle, coh->type); ++ EXIT2(return STATUS_FAILURE); ++ } ++ fo = HANDLE_TO_OBJECT(coh); ++ file = fo->wrap_bin_file; ++ TRACE2("file: %zu, %u", file->size, length); ++ spin_lock_bh(&ntoskernel_lock); ++ if (byte_offset) ++ offset = *byte_offset; ++ else ++ offset = fo->current_byte_offset; ++ if (length + offset > file->size) { ++ WARNING("%lu, %zu", length + offset, file->size); ++ /* TODO: implement writing past end of current size */ ++ iosb->status = STATUS_FAILURE; ++ iosb->info = 0; ++ } else { ++ memcpy(file->data + offset, buffer, length); ++ iosb->status = STATUS_SUCCESS; ++ iosb->info = length; ++ fo->current_byte_offset = offset + length; ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ EXIT2(return iosb->status); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwClose,1) ++ (void *handle) ++{ ++ struct common_object_header *coh; ++ ++ TRACE2("%p", handle); ++ if (handle == NULL) { ++ TRACE1(""); ++ EXIT2(return STATUS_SUCCESS); ++ } ++ coh = handle; ++ if (coh->type == OBJECT_TYPE_FILE) { ++ struct file_object *fo; ++ struct wrap_bin_file *bin_file; ++ typeof(fo->flags) flags; ++ ++ fo = HANDLE_TO_OBJECT(handle); ++ flags = fo->flags; ++ bin_file = fo->wrap_bin_file; ++ if (dereference_object(fo)) { ++ if (flags == FILE_CREATED) { ++ vfree(bin_file->data); ++ kfree(bin_file); ++ } else ++ free_bin_file(bin_file); ++ } ++ } else if (coh->type == OBJECT_TYPE_NT_THREAD) { ++ struct nt_thread *thread = HANDLE_TO_OBJECT(handle); ++ TRACE2("thread: %p (%p)", thread, handle); ++ ObDereferenceObject(thread); ++ } else { ++ /* TODO: can we just dereference object here? */ ++ WARNING("closing handle 0x%x not implemented", coh->type); ++ } ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwQueryInformationFile,5) ++ (void *handle, struct io_status_block *iosb, void *info, ++ ULONG length, enum file_info_class class) ++{ ++ struct file_object *fo; ++ struct file_name_info *fni; ++ struct file_std_info *fsi; ++ struct wrap_bin_file *file; ++ struct common_object_header *coh; ++ ++ ENTER2("%p", handle); ++ coh = handle; ++ if (coh->type != OBJECT_TYPE_FILE) { ++ ERROR("handle %p is invalid: %d", coh, coh->type); ++ EXIT2(return STATUS_FAILURE); ++ } ++ fo = HANDLE_TO_OBJECT(handle); ++ TRACE2("fo: %p, %d", fo, class); ++ switch (class) { ++ case FileNameInformation: ++ fni = info; ++ fni->length = min(length, (typeof(length))coh->name.length); ++ memcpy(fni->name, coh->name.buf, fni->length); ++ iosb->status = STATUS_SUCCESS; ++ iosb->info = fni->length; ++ break; ++ case FileStandardInformation: ++ fsi = info; ++ file = fo->wrap_bin_file; ++ fsi->alloc_size = file->size; ++ fsi->eof = file->size; ++ fsi->num_links = 1; ++ fsi->delete_pending = FALSE; ++ fsi->dir = FALSE; ++ iosb->status = STATUS_SUCCESS; ++ iosb->info = 0; ++ break; ++ default: ++ WARNING("type %d not implemented yet", class); ++ iosb->status = STATUS_FAILURE; ++ iosb->info = 0; ++ break; ++ } ++ EXIT2(return iosb->status); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwOpenSection,3) ++ (void **handle, ACCESS_MASK access, struct object_attributes *obj_attrs) ++{ ++ INFO("%p, 0x%x, %d", obj_attrs, obj_attrs->attributes, access); ++ TODO(); ++ *handle = obj_attrs; ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwMapViewOfSection,10) ++ (void *secn_handle, void *process_handle, void **base_address, ++ ULONG zero_bits, SIZE_T commit_size, LARGE_INTEGER *secn_offset, ++ SIZE_T *view_size, enum section_inherit inherit, ULONG alloc_type, ++ ULONG protect) ++{ ++ INFO("%p, %p, %p", secn_handle, process_handle, base_address); ++ TODO(); ++ *base_address = (void *)0xdeadbeef; ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwUnmapViewOfSection,2) ++ (void *process_handle, void *base_address) ++{ ++ INFO("%p, %p", process_handle, base_address); ++ TODO(); ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwCreateKey,7) ++ (void **handle, ACCESS_MASK desired_access, ++ struct object_attributes *attr, ULONG title_index, ++ struct unicode_string *class, ULONG create_options, ++ ULONG *disposition) ++{ ++ struct ansi_string ansi; ++ if (RtlUnicodeStringToAnsiString(&ansi, attr->name, TRUE) == ++ STATUS_SUCCESS) { ++ TRACE1("key: %s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ *handle = NULL; ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwOpenKey,3) ++ (void **handle, ACCESS_MASK desired_access, ++ struct object_attributes *attr) ++{ ++ struct ansi_string ansi; ++ if (RtlUnicodeStringToAnsiString(&ansi, attr->name, TRUE) == ++ STATUS_SUCCESS) { ++ TRACE1("key: %s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ *handle = NULL; ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwSetValueKey,6) ++ (void *handle, struct unicode_string *name, ULONG title_index, ++ ULONG type, void *data, ULONG data_size) ++{ ++ struct ansi_string ansi; ++ if (RtlUnicodeStringToAnsiString(&ansi, name, TRUE) == ++ STATUS_SUCCESS) { ++ TRACE1("key: %s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwQueryValueKey,6) ++ (void *handle, struct unicode_string *name, ++ enum key_value_information_class class, void *info, ++ ULONG length, ULONG *res_length) ++{ ++ struct ansi_string ansi; ++ if (RtlUnicodeStringToAnsiString(&ansi, name, TRUE) == STATUS_SUCCESS) { ++ TRACE1("key: %s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ TODO(); ++ return STATUS_INVALID_PARAMETER; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwDeleteKey,1) ++ (void *handle) ++{ ++ ENTER2("%p", handle); ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwPowerInformation,5) ++ (INT info_level, void *in_buf, ULONG in_buf_len, void *out_buf, ++ ULONG out_buf_len) ++{ ++ INFO("%d, %u, %u", info_level, in_buf_len, out_buf_len); ++ TODO(); ++ return STATUS_ACCESS_DENIED; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(WmiSystemControl,4) ++ (struct wmilib_context *info, struct device_object *dev_obj, ++ struct irp *irp, void *irp_disposition) ++{ ++ TODO(); ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(WmiCompleteRequest,5) ++ (struct device_object *dev_obj, struct irp *irp, NTSTATUS status, ++ ULONG buffer_used, CCHAR priority_boost) ++{ ++ TODO(); ++ return STATUS_SUCCESS; ++} ++ ++noregparm NTSTATUS WIN_FUNC(WmiTraceMessage,12) ++ (void *tracehandle, ULONG message_flags, ++ void *message_guid, USHORT message_no, ...) ++{ ++ TODO(); ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(WmiQueryTraceInformation,4) ++ (enum trace_information_class trace_info_class, void *trace_info, ++ ULONG *req_length, void *buf) ++{ ++ TODO(); ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++/* this function can't be wstdcall as it takes variable number of args */ ++__attribute__((format(printf, 1, 2))) ++noregparm ULONG WIN_FUNC(DbgPrint,12) ++ (char *format, ...) ++{ ++#if DEBUG >= 1 ++ va_list args; ++ static char buf[100]; ++ ++ va_start(args, format); ++ vsnprintf(buf, sizeof(buf), format, args); ++ printk(KERN_DEBUG "%s (%s): %s", DRIVER_NAME, __func__, buf); ++ va_end(args); ++#endif ++ return STATUS_SUCCESS; ++} ++ ++__attribute__((format(printf, 3, 4))) ++noregparm ULONG WIN_FUNC(DbgPrintEx,12) ++ (ULONG component_id, ULONG severity, char *format, ...) ++{ ++#if DEBUG >= 1 ++ va_list args; ++ static char buf[100]; ++ ++ va_start(args, format); ++ vsnprintf(buf, sizeof(buf), format, args); ++ TRACE1("component_id: %d, severity: %d\n", component_id, severity); ++ printk(KERN_DEBUG "%s (%s): %s", DRIVER_NAME, __func__, buf); ++ va_end(args); ++#endif ++ return STATUS_SUCCESS; ++} ++ ++wstdcall void WIN_FUNC(KeBugCheck,1) ++ (ULONG code) ++{ ++ ERROR("Unrecoverable error reported by the driver"); ++ ERROR("code: 0x%x\n", code); ++ dump_stack(); ++ return; ++} ++ ++wstdcall void WIN_FUNC(KeBugCheckEx,5) ++ (ULONG code, ULONG_PTR param1, ULONG_PTR param2, ++ ULONG_PTR param3, ULONG_PTR param4) ++{ ++ ERROR("Unrecoverable error reported by the driver"); ++ ERROR("code: 0x%x, params: 0x%lx 0x%lx 0x%lx 0x%lx\n", code, param1, ++ param2, param3, param4); ++ dump_stack(); ++ return; ++} ++ ++wstdcall void WIN_FUNC(ExSystemTimeToLocalTime,2) ++ (LARGE_INTEGER *system_time, LARGE_INTEGER *local_time) ++{ ++ *local_time = *system_time; ++} ++ ++wstdcall ULONG WIN_FUNC(ExSetTimerResolution,2) ++ (ULONG time, BOOLEAN set) ++{ ++ /* why a driver should change system wide timer resolution is ++ * beyond me */ ++ return time; ++} ++ ++wstdcall void WIN_FUNC(DbgBreakPoint,0) ++ (void) ++{ ++ TODO(); ++} ++ ++wstdcall void WIN_FUNC(_except_handler3,0) ++ (void) ++{ ++ TODO(); ++} ++ ++wstdcall void WIN_FUNC(__C_specific_handler,0) ++ (void) ++{ ++ TODO(); ++} ++ ++wstdcall void WIN_FUNC(_purecall,0) ++ (void) ++{ ++ TODO(); ++} ++ ++struct worker_init_struct { ++ struct work_struct work; ++ struct completion completion; ++ struct nt_thread *nt_thread; ++}; ++ ++int ntoskernel_init(void) ++{ ++ struct timeval now; ++ ++ spin_lock_init(&dispatcher_lock); ++ spin_lock_init(&ntoskernel_lock); ++ spin_lock_init(&ntos_work_lock); ++ spin_lock_init(&kdpc_list_lock); ++ spin_lock_init(&irp_cancel_lock); ++ InitializeListHead(&wrap_mdl_list); ++ InitializeListHead(&kdpc_list); ++ InitializeListHead(&callback_objects); ++ InitializeListHead(&bus_driver_list); ++ InitializeListHead(&object_list); ++ InitializeListHead(&ntos_work_list); ++ ++ nt_spin_lock_init(&nt_list_lock); ++ ++ INIT_WORK(&kdpc_work, kdpc_worker); ++ INIT_WORK(&ntos_work, ntos_work_worker); ++ wrap_timer_slist.next = NULL; ++ ++ do_gettimeofday(&now); ++ wrap_ticks_to_boot = TICKS_1601_TO_1970; ++ wrap_ticks_to_boot += (u64)now.tv_sec * TICKSPERSEC; ++ wrap_ticks_to_boot += now.tv_usec * 10; ++ wrap_ticks_to_boot -= jiffies * TICKSPERJIFFY; ++ TRACE2("%llu", wrap_ticks_to_boot); ++ ++ cpu_count = num_online_cpus(); ++ ++#ifdef WRAP_PREEMPT ++ do { ++ int cpu; ++ for_each_possible_cpu(cpu) { ++ struct irql_info *info; ++ info = &per_cpu(irql_info, cpu); ++ mutex_init(&(info->lock)); ++ info->task = NULL; ++ info->count = 0; ++#ifdef CONFIG_SMP ++ cpumask_setall(&info->cpus_allowed); ++#endif ++ } ++ } while (0); ++#endif ++ ++ ntos_wq = create_singlethread_workqueue("ntos_wq"); ++ if (!ntos_wq) { ++ WARNING("couldn't create ntos_wq thread"); ++ return -ENOMEM; ++ } ++ TRACE1("ntos_wq: %p", ntos_wq); ++ ++ if (add_bus_driver("PCI") ++#ifdef ENABLE_USB ++ || add_bus_driver("USB") ++#endif ++ ) { ++ ntoskernel_exit(); ++ return -ENOMEM; ++ } ++ mdl_cache = ++ wrap_kmem_cache_create(DRIVER_NAME "_mdl", ++ sizeof(struct wrap_mdl) + MDL_CACHE_SIZE, ++ 0, 0); ++ TRACE2("%p", mdl_cache); ++ if (!mdl_cache) { ++ ERROR("couldn't allocate MDL cache"); ++ ntoskernel_exit(); ++ return -ENOMEM; ++ } ++ ++#if defined(CONFIG_X86_64) ++ memset(&kuser_shared_data, 0, sizeof(kuser_shared_data)); ++ *((ULONG64 *)&kuser_shared_data.system_time) = ticks_1601(); ++ init_timer(&shared_data_timer); ++ shared_data_timer.function = update_user_shared_data_proc; ++ shared_data_timer.data = 0; ++#endif ++ return 0; ++} ++ ++int ntoskernel_init_device(struct wrap_device *wd) ++{ ++#if defined(CONFIG_X86_64) ++ if (kuser_shared_data.reserved1) ++ mod_timer(&shared_data_timer, jiffies + MSEC_TO_HZ(30)); ++#endif ++ return 0; ++} ++ ++void ntoskernel_exit_device(struct wrap_device *wd) ++{ ++ ENTER2(""); ++ ++ KeFlushQueuedDpcs(); ++ EXIT2(return); ++} ++ ++void ntoskernel_exit(void) ++{ ++ struct nt_list *cur; ++ ++ ENTER2(""); ++ ++ /* free kernel (Ke) timers */ ++ TRACE2("freeing timers"); ++ while (1) { ++ struct wrap_timer *wrap_timer; ++ struct nt_slist *slist; ++ ++ spin_lock_bh(&ntoskernel_lock); ++ if ((slist = wrap_timer_slist.next)) ++ wrap_timer_slist.next = slist->next; ++ spin_unlock_bh(&ntoskernel_lock); ++ TIMERTRACE("%p", slist); ++ if (!slist) ++ break; ++ wrap_timer = container_of(slist, struct wrap_timer, slist); ++ if (del_timer_sync(&wrap_timer->timer)) ++ WARNING("Buggy Windows driver left timer %p running", ++ wrap_timer->nt_timer); ++ memset(wrap_timer, 0, sizeof(*wrap_timer)); ++ slack_kfree(wrap_timer); ++ } ++ ++ TRACE2("freeing MDLs"); ++ if (mdl_cache) { ++ spin_lock_bh(&ntoskernel_lock); ++ if (!IsListEmpty(&wrap_mdl_list)) ++ ERROR("Windows driver didn't free all MDLs; " ++ "freeing them now"); ++ while ((cur = RemoveHeadList(&wrap_mdl_list))) { ++ struct wrap_mdl *wrap_mdl; ++ wrap_mdl = container_of(cur, struct wrap_mdl, list); ++ if (wrap_mdl->mdl->flags & MDL_CACHE_ALLOCATED) ++ kmem_cache_free(mdl_cache, wrap_mdl); ++ else ++ kfree(wrap_mdl); ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ kmem_cache_destroy(mdl_cache); ++ mdl_cache = NULL; ++ } ++ ++ TRACE2("freeing callbacks"); ++ spin_lock_bh(&ntoskernel_lock); ++ while ((cur = RemoveHeadList(&callback_objects))) { ++ struct callback_object *object; ++ struct nt_list *ent; ++ object = container_of(cur, struct callback_object, list); ++ while ((ent = RemoveHeadList(&object->callback_funcs))) { ++ struct callback_func *f; ++ f = container_of(ent, struct callback_func, list); ++ kfree(f); ++ } ++ kfree(object); ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ ++ spin_lock_bh(&ntoskernel_lock); ++ while ((cur = RemoveHeadList(&bus_driver_list))) { ++ struct bus_driver *bus_driver; ++ bus_driver = container_of(cur, struct bus_driver, list); ++ /* TODO: make sure all all drivers are shutdown/removed */ ++ kfree(bus_driver); ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ ++#if defined(CONFIG_X86_64) ++ del_timer_sync(&shared_data_timer); ++#endif ++ if (ntos_wq) ++ destroy_workqueue(ntos_wq); ++ ENTER2("freeing objects"); ++ spin_lock_bh(&ntoskernel_lock); ++ while ((cur = RemoveHeadList(&object_list))) { ++ struct common_object_header *hdr; ++ hdr = container_of(cur, struct common_object_header, list); ++ if (hdr->type == OBJECT_TYPE_NT_THREAD) ++ TRACE1("object %p(%d) was not freed, freeing it now", ++ HEADER_TO_OBJECT(hdr), hdr->type); ++ else ++ WARNING("object %p(%d) was not freed, freeing it now", ++ HEADER_TO_OBJECT(hdr), hdr->type); ++ ExFreePool(hdr); ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ ++ EXIT2(return); ++} +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/ntoskernel.h linux-4.6-rc6-ndis/3rdparty/ndiswrapper/ntoskernel.h +--- linux-4.6-rc6/3rdparty/ndiswrapper/ntoskernel.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/ntoskernel.h 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,1090 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _NTOSKERNEL_H_ ++#define _NTOSKERNEL_H_ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if !defined(CONFIG_X86) && !defined(CONFIG_X86_64) ++#error "this module is for x86 or x86_64 architectures only" ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) ++#define gfp_t unsigned int __nocast ++ ++static inline void *_kzalloc(size_t size, gfp_t flags) ++{ ++ void *p = kmalloc(size, flags); ++ if (likely(p != NULL)) ++ memset(p, 0, size); ++ return p; ++} ++ ++#define kzalloc(size, flags) _kzalloc(size, flags) ++#endif ++ ++/* Interrupt backwards compatibility stuff */ ++#include ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) ++#ifndef IRQ_HANDLED ++#define IRQ_HANDLED ++#define IRQ_NONE ++#define irqreturn_t void ++#endif ++#endif /* Linux < 2.6.29 */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) ++#ifndef mutex_init ++#define mutex semaphore ++#define mutex_init(m) sema_init(m, 1) ++#define mutex_lock(m) down(m) ++#define mutex_trylock(m) (!down_trylock(m)) ++#define mutex_unlock(m) up(m) ++#define mutex_is_locked(m) (atomic_read(m.count) == 0) ++#endif ++#endif /* Linux < 2.6.16 */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) ++#define set_cpus_allowed_ptr(task, mask) set_cpus_allowed(task, *mask) ++#endif /* Linux < 2.6.26 */ ++ ++#ifdef CONFIG_SMP ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) ++#define cpumask_copy(dst, src) do { *dst = *src; } while (0) ++#define cpumask_equal(mask1, mask2) cpus_equal(*mask1, *mask2) ++#define cpumask_setall(mask) cpus_setall(*mask) ++static cpumask_t cpumasks[NR_CPUS]; ++#define cpumask_of(cpu) \ ++({ \ ++ cpumasks[cpu] = cpumask_of_cpu(cpu); \ ++ &cpumasks[cpu]; \ ++}) ++#endif /* Linux < 2.6.28 */ ++#endif /* CONFIG_SMP */ ++ ++#ifndef tsk_cpus_allowed ++#define tsk_cpus_allowed(tsk) (&(tsk)->cpus_allowed) ++#endif ++ ++#ifndef __packed ++#define __packed __attribute__((packed)) ++#endif ++ ++/* pci functions in 2.6 kernels have problems allocating dma buffers, ++ * but seem to work fine with dma functions ++ */ ++#include ++ ++#define PCI_DMA_ALLOC_COHERENT(pci_dev,size,dma_handle) \ ++ dma_alloc_coherent(&pci_dev->dev,size,dma_handle, \ ++ GFP_KERNEL | __GFP_REPEAT) ++#define PCI_DMA_FREE_COHERENT(pci_dev,size,cpu_addr,dma_handle) \ ++ dma_free_coherent(&pci_dev->dev,size,cpu_addr,dma_handle) ++#define PCI_DMA_MAP_SINGLE(pci_dev,addr,size,direction) \ ++ dma_map_single(&pci_dev->dev,addr,size,direction) ++#define PCI_DMA_UNMAP_SINGLE(pci_dev,dma_handle,size,direction) \ ++ dma_unmap_single(&pci_dev->dev,dma_handle,size,direction) ++#define MAP_SG(pci_dev, sglist, nents, direction) \ ++ dma_map_sg(&pci_dev->dev, sglist, nents, direction) ++#define UNMAP_SG(pci_dev, sglist, nents, direction) \ ++ dma_unmap_sg(&pci_dev->dev, sglist, nents, direction) ++#define PCI_DMA_MAP_ERROR(dma_addr) dma_mapping_error(dma_addr) ++ ++ ++#if defined(CONFIG_NET_RADIO) && !defined(CONFIG_WIRELESS_EXT) ++#define CONFIG_WIRELESS_EXT ++#endif ++ ++#define prepare_wait_condition(task, var, value) \ ++do { \ ++ var = value; \ ++ task = current; \ ++ barrier(); \ ++} while (0) ++ ++/* Wait in wait_state (e.g., TASK_INTERRUPTIBLE) for condition to ++ * become true; timeout is either jiffies (> 0) to wait or 0 to wait ++ * forever. ++ * When timeout == 0, return value is ++ * > 0 if condition becomes true, or ++ * < 0 if signal is pending on the thread. ++ * When timeout > 0, return value is ++ * > 0 if condition becomes true before timeout, ++ * < 0 if signal is pending on the thread before timeout, or ++ * 0 if timedout (condition may have become true at the same time) ++ */ ++ ++#define wait_condition(condition, timeout, wait_state) \ ++({ \ ++ long ret = timeout ? timeout : 1; \ ++ while (1) { \ ++ if (signal_pending(current)) { \ ++ ret = -ERESTARTSYS; \ ++ break; \ ++ } \ ++ set_current_state(wait_state); \ ++ if (condition) { \ ++ __set_current_state(TASK_RUNNING); \ ++ break; \ ++ } \ ++ if (timeout) { \ ++ ret = schedule_timeout(ret); \ ++ if (!ret) \ ++ break; \ ++ } else \ ++ schedule(); \ ++ } \ ++ ret; \ ++}) ++ ++#ifdef WRAP_WQ ++ ++struct wrap_workqueue_struct; ++ ++struct wrap_work_struct { ++ struct list_head list; ++ void (*func)(struct wrap_work_struct *data); ++ void *data; ++ /* whether/on which thread scheduled */ ++ struct workqueue_thread *thread; ++}; ++ ++#define work_struct wrap_work_struct ++#define workqueue_struct wrap_workqueue_struct ++ ++#undef INIT_WORK ++#define INIT_WORK(work, pfunc) \ ++ do { \ ++ (work)->func = (pfunc); \ ++ (work)->data = (work); \ ++ (work)->thread = NULL; \ ++ } while (0) ++ ++#undef create_singlethread_workqueue ++#define create_singlethread_workqueue(wq) wrap_create_wq(wq, 1, 0) ++#undef create_workqueue ++#define create_workqueue(wq) wrap_create_wq(wq, 0, 0) ++#undef destroy_workqueue ++#define destroy_workqueue(wq) wrap_destroy_wq(wq) ++#undef queue_work ++#define queue_work(wq, work) wrap_queue_work(wq, work) ++#undef flush_workqueue ++#define flush_workqueue(wq) wrap_flush_wq(wq) ++ ++struct workqueue_struct *wrap_create_wq(const char *name, u8 singlethread, ++ u8 freeze); ++void wrap_destroy_wq(struct workqueue_struct *workq); ++int wrap_queue_work(struct workqueue_struct *workq, struct work_struct *work); ++void wrap_cancel_work(struct work_struct *work); ++void wrap_flush_wq(struct workqueue_struct *workq); ++ ++#else // WRAP_WQ ++ ++/* Compatibility for Linux before 2.6.20 where INIT_WORK takes 3 arguments */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) && \ ++ !defined(INIT_WORK_NAR) && \ ++ !defined(INIT_DELAYED_WORK_DEFERRABLE) ++typedef void (*compat_work_func_t)(void *work); ++typedef void (*work_func_t)(struct work_struct *work); ++static inline void (INIT_WORK)(struct work_struct *work, work_func_t func) ++{ ++ INIT_WORK(work, (compat_work_func_t)func, work); ++} ++#undef INIT_WORK ++#endif ++ ++#endif // WRAP_WQ ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) ++#define ISR_PT_REGS_PARAM_DECL ++#else ++#define ISR_PT_REGS_PARAM_DECL , struct pt_regs *regs ++#endif ++ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16) ++#define for_each_possible_cpu(_cpu) for_each_cpu(_cpu) ++#endif ++ ++#ifndef CHECKSUM_PARTIAL ++#define CHECKSUM_PARTIAL CHECKSUM_HW ++#endif ++ ++#ifndef IRQF_SHARED ++#define IRQF_SHARED SA_SHIRQ ++#endif ++ ++#ifndef UMH_WAIT_PROC ++#define UMH_WAIT_PROC 1 ++#endif ++ ++#define memcpy_skb(skb, from, length) \ ++ memcpy(skb_put(skb, length), from, length) ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++#ifndef DMA_BIT_MASK ++#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) ++#endif ++#endif ++ ++#ifndef __GFP_DMA32 ++#define __GFP_DMA32 GFP_DMA ++#endif ++ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22) ++#define wrap_kmem_cache_create(name, size, align, flags) \ ++ kmem_cache_create(name, size, align, flags, NULL, NULL) ++#else ++#define wrap_kmem_cache_create(name, size, align, flags) \ ++ kmem_cache_create(name, size, align, flags, NULL) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) ++#define netdev_mc_count(dev) ((dev)->mc_count) ++#define usb_alloc_coherent(dev, size, mem_flags, dma) (usb_buffer_alloc((dev), (size), (mem_flags), (dma))) ++#define usb_free_coherent(dev, size, addr, dma) (usb_buffer_free((dev), (size), (addr), (dma))) ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0) ++#define daemonize(name, ...) do {} while (0) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0) ++#define add_taint(flag, lockdep_ok) add_taint(flag) ++#endif ++ ++#include "winnt_types.h" ++#include "ndiswrapper.h" ++#include "pe_linker.h" ++#include "wrapmem.h" ++#include "lin2win.h" ++#include "loader.h" ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ++static inline void netif_tx_lock(struct net_device *dev) ++{ ++ spin_lock(&dev->xmit_lock); ++} ++static inline void netif_tx_unlock(struct net_device *dev) ++{ ++ spin_unlock(&dev->xmit_lock); ++} ++static inline void netif_tx_lock_bh(struct net_device *dev) ++{ ++ spin_lock_bh(&dev->xmit_lock); ++} ++static inline void netif_tx_unlock_bh(struct net_device *dev) ++{ ++ spin_unlock_bh(&dev->xmit_lock); ++} ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) ++static inline void netif_poll_enable(struct net_device *dev) ++{ ++} ++static inline void netif_poll_disable(struct net_device *dev) ++{ ++} ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) ++#define proc_net_root init_net.proc_net ++#else ++#define proc_net_root proc_net ++#endif ++ ++#if ((LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0)) && \ ++ (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0))) || \ ++ (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,42)) ++#ifndef skb_frag_page ++#define skb_frag_page(frag) ((frag)->page) ++#endif ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0) ++#define netdev_notifier_info_to_dev(x) ((struct net_device *)(x)) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) ++static inline void reinit_completion(struct completion *x) ++{ ++ INIT_COMPLETION(*x); ++} ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0) ++#define prandom_seed(seed) net_srandom(seed) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ++#define strncasecmp strnicmp ++#endif ++ ++/* TICK is 100ns */ ++#define TICKSPERSEC 10000000 ++#define TICKSPERMSEC 10000 ++#define SECSPERDAY 86400 ++#define TICKSPERJIFFY ((TICKSPERSEC + HZ - 1) / HZ) ++ ++#define int_div_round(x, y) (((x) + (y - 1)) / (y)) ++ ++/* 1601 to 1970 is 369 years plus 89 leap days */ ++#define SECS_1601_TO_1970 ((369 * 365 + 89) * (u64)SECSPERDAY) ++#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC) ++ ++/* 100ns units to HZ; if sys_time is negative, relative to current ++ * clock, otherwise from year 1601 */ ++#define SYSTEM_TIME_TO_HZ(sys_time) \ ++ (((sys_time) <= 0) ? \ ++ int_div_round(((u64)HZ * (-(sys_time))), TICKSPERSEC) : \ ++ int_div_round(((s64)HZ * ((sys_time) - ticks_1601())), TICKSPERSEC)) ++ ++#define MSEC_TO_HZ(ms) int_div_round((ms * HZ), 1000) ++#define USEC_TO_HZ(us) int_div_round((us * HZ), 1000000) ++ ++extern u64 wrap_ticks_to_boot; ++ ++static inline u64 ticks_1601(void) ++{ ++ return wrap_ticks_to_boot + (u64)jiffies * TICKSPERJIFFY; ++} ++ ++typedef void (*generic_func)(void); ++ ++struct wrap_export { ++ const char *name; ++ generic_func func; ++}; ++ ++#ifdef CONFIG_X86_64 ++ ++#define WIN_SYMBOL(name, argc) \ ++ {#name, (generic_func) win2lin_ ## name ## _ ## argc} ++#define WIN_WIN_SYMBOL(name, argc) \ ++ {#name, (generic_func) win2lin__win_ ## name ## _ ## argc} ++#define WIN_FUNC_DECL(name, argc) \ ++ extern typeof(name) win2lin_ ## name ## _ ## argc; ++#define WIN_FUNC_PTR(name, argc) win2lin_ ## name ## _ ## argc ++ ++#else ++ ++#define WIN_SYMBOL(name, argc) {#name, (generic_func)name} ++#define WIN_WIN_SYMBOL(name, argc) {#name, (generic_func)_win_ ## name} ++#define WIN_FUNC_DECL(name, argc) ++#define WIN_FUNC_PTR(name, argc) name ++ ++#endif ++ ++#define WIN_FUNC(name, argc) (name) ++/* map name s to f - if f is different from s */ ++#define WIN_SYMBOL_MAP(s, f) ++ ++#define POOL_TAG(A, B, C, D) \ ++ ((ULONG)((A) + ((B) << 8) + ((C) << 16) + ((D) << 24))) ++ ++struct pe_image { ++ char name[MAX_DRIVER_NAME_LEN]; ++ UINT (*entry)(struct driver_object *, struct unicode_string *) wstdcall; ++ void *image; ++ int size; ++ int type; ++ ++ IMAGE_NT_HEADERS *nt_hdr; ++ IMAGE_OPTIONAL_HEADER *opt_hdr; ++}; ++ ++struct ndis_mp_block; ++ ++struct wrap_timer { ++ struct nt_slist slist; ++ struct timer_list timer; ++ struct nt_timer *nt_timer; ++ long repeat; ++#ifdef TIMER_DEBUG ++ unsigned long wrap_timer_magic; ++#endif ++}; ++ ++struct ntos_work_item { ++ struct nt_list list; ++ void *arg1; ++ void *arg2; ++ NTOS_WORK_FUNC func; ++}; ++ ++struct wrap_device_setting { ++ struct nt_list list; ++ char name[MAX_SETTING_NAME_LEN]; ++ char value[MAX_SETTING_VALUE_LEN]; ++ void *encoded; ++}; ++ ++struct wrap_bin_file { ++ char name[MAX_DRIVER_NAME_LEN]; ++ size_t size; ++ void *data; ++}; ++ ++#define WRAP_DRIVER_CLIENT_ID 1 ++ ++struct wrap_driver { ++ struct nt_list list; ++ struct driver_object *drv_obj; ++ char name[MAX_DRIVER_NAME_LEN]; ++ char version[MAX_SETTING_VALUE_LEN]; ++ unsigned short num_pe_images; ++ struct pe_image pe_images[MAX_DRIVER_PE_IMAGES]; ++ unsigned short num_bin_files; ++ struct wrap_bin_file *bin_files; ++ struct nt_list settings; ++ int dev_type; ++ struct ndis_driver *ndis_driver; ++}; ++ ++enum hw_status { ++ HW_INITIALIZED = 1, HW_SUSPENDED, HW_HALTED, HW_DISABLED, ++}; ++ ++struct wrap_device { ++ /* first part is (de)initialized once by loader */ ++ struct nt_list list; ++ int dev_bus; ++ int vendor; ++ int device; ++ int subvendor; ++ int subdevice; ++ char conf_file_name[MAX_DRIVER_NAME_LEN]; ++ char driver_name[MAX_DRIVER_NAME_LEN]; ++ struct wrap_driver *driver; ++ struct nt_list settings; ++ ++ /* rest should be (de)initialized when a device is ++ * (un)plugged */ ++ struct cm_resource_list *resource_list; ++ unsigned long hw_status; ++ struct device_object *pdo; ++ union { ++ struct { ++ struct pci_dev *pdev; ++ enum device_power_state wake_state; ++ } pci; ++ struct { ++ struct usb_device *udev; ++ struct usb_interface *intf; ++ int num_alloc_urbs; ++ struct nt_list wrap_urb_list; ++ } usb; ++ }; ++}; ++ ++#define wrap_is_pci_bus(dev_bus) \ ++ (WRAP_BUS(dev_bus) == WRAP_PCI_BUS || \ ++ WRAP_BUS(dev_bus) == WRAP_PCMCIA_BUS) ++#ifdef ENABLE_USB ++/* earlier versions of ndiswrapper used 0 as USB_BUS */ ++#define wrap_is_usb_bus(dev_bus) \ ++ (WRAP_BUS(dev_bus) == WRAP_USB_BUS || \ ++ WRAP_BUS(dev_bus) == WRAP_INTERNAL_BUS) ++#else ++#define wrap_is_usb_bus(dev_bus) 0 ++#endif ++#define wrap_is_bluetooth_device(dev_bus) \ ++ (WRAP_DEVICE(dev_bus) == WRAP_BLUETOOTH_DEVICE1 || \ ++ WRAP_DEVICE(dev_bus) == WRAP_BLUETOOTH_DEVICE2) ++ ++extern struct workqueue_struct *ntos_wq; ++extern struct workqueue_struct *ndis_wq; ++extern struct workqueue_struct *wrapndis_wq; ++ ++#define atomic_unary_op(var, size, oper) \ ++do { \ ++ if (size == 1) \ ++ __asm__ __volatile__( \ ++ LOCK_PREFIX oper "b %b0\n\t" : "+m" (var)); \ ++ else if (size == 2) \ ++ __asm__ __volatile__( \ ++ LOCK_PREFIX oper "w %w0\n\t" : "+m" (var)); \ ++ else if (size == 4) \ ++ __asm__ __volatile__( \ ++ LOCK_PREFIX oper "l %0\n\t" : "+m" (var)); \ ++ else if (size == 8) \ ++ __asm__ __volatile__( \ ++ LOCK_PREFIX oper "q %q0\n\t" : "+m" (var)); \ ++ else { \ ++ extern void _invalid_op_size_(void); \ ++ _invalid_op_size_(); \ ++ } \ ++} while (0) ++ ++#define atomic_inc_var_size(var, size) atomic_unary_op(var, size, "inc") ++ ++#define atomic_inc_var(var) atomic_inc_var_size(var, sizeof(var)) ++ ++#define atomic_dec_var_size(var, size) atomic_unary_op(var, size, "dec") ++ ++#define atomic_dec_var(var) atomic_dec_var_size(var, sizeof(var)) ++ ++#define pre_atomic_add(var, i) \ ++({ \ ++ typeof(var) pre; \ ++ __asm__ __volatile__( \ ++ LOCK_PREFIX "xadd %0, %1\n\t" \ ++ : "=r"(pre), "+m"(var) \ ++ : "0"(i)); \ ++ pre; \ ++}) ++ ++#define post_atomic_add(var, i) (pre_atomic_add(var, i) + i) ++ ++//#define DEBUG_IRQL 1 ++ ++#ifdef DEBUG_IRQL ++#define assert_irql(cond) \ ++do { \ ++ KIRQL _irql_ = current_irql(); \ ++ if (!(cond)) { \ ++ WARNING("assertion '%s' failed: %d", #cond, _irql_); \ ++ DBG_BLOCK(4) { \ ++ dump_stack(); \ ++ } \ ++ } \ ++} while (0) ++#else ++#define assert_irql(cond) do { } while (0) ++#endif ++ ++/* When preempt is enabled, we should preempt_disable to raise IRQL to ++ * DISPATCH_LEVEL, to be consistent with the semantics. However, using ++ * a mutex instead, so that only ndiswrapper threads run one at a time ++ * on a processor when at DISPATCH_LEVEL seems to be enough. So that ++ * is what we will use until we learn otherwise. If ++ * preempt_(en|dis)able is required for some reason, comment out ++ * following #define. */ ++ ++#define WRAP_PREEMPT 1 ++ ++#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PREEMPT_RT) ++#ifndef WRAP_PREEMPT ++#define WRAP_PREEMPT 1 ++#endif ++#endif ++ ++//#undef WRAP_PREEMPT ++ ++#ifdef WRAP_PREEMPT ++ ++struct irql_info { ++ int count; ++ struct mutex lock; ++#ifdef CONFIG_SMP ++ cpumask_t cpus_allowed; ++#endif ++ struct task_struct *task; ++}; ++ ++DECLARE_PER_CPU(struct irql_info, irql_info); ++ ++static inline KIRQL raise_irql(KIRQL newirql) ++{ ++ struct irql_info *info; ++ ++ assert(newirql == DISPATCH_LEVEL); ++ info = &get_cpu_var(irql_info); ++ if (info->task == current) { ++ assert(info->count > 0); ++ assert(mutex_is_locked(&info->lock)); ++#if defined(CONFIG_SMP) && DEBUG >= 1 ++ assert(cpumask_equal(tsk_cpus_allowed(current), ++ cpumask_of(smp_processor_id()))); ++#endif ++ info->count++; ++ put_cpu_var(irql_info); ++ return DISPATCH_LEVEL; ++ } ++ /* TODO: is this enough to pin down to current cpu? */ ++#ifdef CONFIG_SMP ++ assert(task_cpu(current) == smp_processor_id()); ++ cpumask_copy(&info->cpus_allowed, tsk_cpus_allowed(current)); ++ set_cpus_allowed_ptr(current, cpumask_of(smp_processor_id())); ++#endif ++ put_cpu_var(irql_info); ++ mutex_lock(&info->lock); ++ assert(info->count == 0); ++ assert(info->task == NULL); ++ info->count = 1; ++ info->task = current; ++ return PASSIVE_LEVEL; ++} ++ ++static inline void lower_irql(KIRQL oldirql) ++{ ++ struct irql_info *info; ++ ++ assert(oldirql <= DISPATCH_LEVEL); ++ info = &get_cpu_var(irql_info); ++ assert(info->task == current); ++ assert(mutex_is_locked(&info->lock)); ++ assert(info->count > 0); ++ if (--info->count == 0) { ++ info->task = NULL; ++#ifdef CONFIG_SMP ++ set_cpus_allowed_ptr(current, &info->cpus_allowed); ++#endif ++ mutex_unlock(&info->lock); ++ } ++ put_cpu_var(irql_info); ++} ++ ++static inline KIRQL current_irql(void) ++{ ++ int count; ++ if (in_irq() || irqs_disabled()) ++ EXIT4(return DIRQL); ++ if (in_atomic() || in_interrupt()) ++ EXIT4(return SOFT_IRQL); ++ count = get_cpu_var(irql_info).count; ++ put_cpu_var(irql_info); ++ if (count) ++ EXIT6(return DISPATCH_LEVEL); ++ else ++ EXIT6(return PASSIVE_LEVEL); ++} ++ ++#else ++ ++static inline KIRQL current_irql(void) ++{ ++ if (in_irq() || irqs_disabled()) ++ EXIT4(return DIRQL); ++ if (in_interrupt()) ++ EXIT4(return SOFT_IRQL); ++ if (in_atomic()) ++ EXIT6(return DISPATCH_LEVEL); ++ else ++ EXIT6(return PASSIVE_LEVEL); ++} ++ ++static inline KIRQL raise_irql(KIRQL newirql) ++{ ++ KIRQL ret = in_atomic() ? DISPATCH_LEVEL : PASSIVE_LEVEL; ++ assert(newirql == DISPATCH_LEVEL); ++ assert(current_irql() <= DISPATCH_LEVEL); ++ preempt_disable(); ++ return ret; ++} ++ ++static inline void lower_irql(KIRQL oldirql) ++{ ++ assert(current_irql() == DISPATCH_LEVEL); ++ preempt_enable(); ++} ++ ++#endif ++ ++#define irql_gfp() (in_atomic() ? GFP_ATOMIC : GFP_KERNEL) ++ ++/* Windows spinlocks are of type ULONG_PTR which is not big enough to ++ * store Linux spinlocks; so we implement Windows spinlocks using ++ * ULONG_PTR space with our own functions/macros */ ++ ++/* Windows seems to use 0 for unlocked state of spinlock - if Linux ++ * convention of 1 for unlocked state is used, at least prism54 driver ++ * crashes */ ++ ++#define NT_SPIN_LOCK_UNLOCKED 0 ++#define NT_SPIN_LOCK_LOCKED 1 ++ ++static inline void nt_spin_lock_init(NT_SPIN_LOCK *lock) ++{ ++ *lock = NT_SPIN_LOCK_UNLOCKED; ++} ++ ++#ifdef CONFIG_SMP ++ ++static inline void nt_spin_lock(NT_SPIN_LOCK *lock) ++{ ++ while (1) { ++ unsigned long lockval = xchg(lock, NT_SPIN_LOCK_LOCKED); ++ ++ if (likely(lockval == NT_SPIN_LOCK_UNLOCKED)) ++ break; ++ if (unlikely(lockval > NT_SPIN_LOCK_LOCKED)) { ++ ERROR("bad spinlock: 0x%lx at %p", lockval, lock); ++ return; ++ } ++ /* "rep; nop" doesn't change cx register, it's a "pause" */ ++ __asm__ __volatile__("rep; nop"); ++ } ++} ++ ++static inline void nt_spin_unlock(NT_SPIN_LOCK *lock) ++{ ++ unsigned long lockval = xchg(lock, NT_SPIN_LOCK_UNLOCKED); ++ ++ if (likely(lockval == NT_SPIN_LOCK_LOCKED)) ++ return; ++ WARNING("unlocking unlocked spinlock: 0x%lx at %p", lockval, lock); ++} ++ ++#else // CONFIG_SMP ++ ++#define nt_spin_lock(lock) do { } while (0) ++ ++#define nt_spin_unlock(lock) do { } while (0) ++ ++#endif // CONFIG_SMP ++ ++/* When kernel would've disabled preempt (e.g., in interrupt ++ * handlers), we need to fake preempt so driver thinks it is running ++ * at right IRQL */ ++ ++/* raise IRQL to given (higher) IRQL if necessary before locking */ ++static inline KIRQL nt_spin_lock_irql(NT_SPIN_LOCK *lock, KIRQL newirql) ++{ ++ KIRQL oldirql = raise_irql(newirql); ++ nt_spin_lock(lock); ++ return oldirql; ++} ++ ++/* lower IRQL to given (lower) IRQL if necessary after unlocking */ ++static inline void nt_spin_unlock_irql(NT_SPIN_LOCK *lock, KIRQL oldirql) ++{ ++ nt_spin_unlock(lock); ++ lower_irql(oldirql); ++} ++ ++#define nt_spin_lock_irqsave(lock, flags) \ ++do { \ ++ local_irq_save(flags); \ ++ preempt_disable(); \ ++ nt_spin_lock(lock); \ ++} while (0) ++ ++#define nt_spin_unlock_irqrestore(lock, flags) \ ++do { \ ++ nt_spin_unlock(lock); \ ++ preempt_enable(); \ ++ local_irq_restore(flags); \ ++} while (0) ++ ++static inline ULONG SPAN_PAGES(void *ptr, SIZE_T length) ++{ ++ return PAGE_ALIGN(((unsigned long)ptr & (PAGE_SIZE - 1)) + length) ++ >> PAGE_SHIFT; ++} ++ ++#ifdef CONFIG_X86_64 ++ ++/* TODO: can these be implemented without using spinlock? */ ++ ++static inline struct nt_slist *PushEntrySList(nt_slist_header *head, ++ struct nt_slist *entry, ++ NT_SPIN_LOCK *lock) ++{ ++ KIRQL irql = nt_spin_lock_irql(lock, DISPATCH_LEVEL); ++ entry->next = head->next; ++ head->next = entry; ++ head->depth++; ++ nt_spin_unlock_irql(lock, irql); ++ TRACE4("%p, %p, %p", head, entry, entry->next); ++ return entry->next; ++} ++ ++static inline struct nt_slist *PopEntrySList(nt_slist_header *head, ++ NT_SPIN_LOCK *lock) ++{ ++ struct nt_slist *entry; ++ KIRQL irql = nt_spin_lock_irql(lock, DISPATCH_LEVEL); ++ entry = head->next; ++ if (entry) { ++ head->next = entry->next; ++ head->depth--; ++ } ++ nt_spin_unlock_irql(lock, irql); ++ TRACE4("%p, %p", head, entry); ++ return entry; ++} ++ ++#else ++ ++#define u64_low_32(x) ((u32)x) ++#define u64_high_32(x) ((u32)(x >> 32)) ++ ++static inline u64 nt_cmpxchg8b(volatile u64 *ptr, u64 old, u64 new) ++{ ++ u64 prev; ++ ++ __asm__ __volatile__( ++ "\n" ++ LOCK_PREFIX "cmpxchg8b %0\n" ++ : "+m" (*ptr), "=A" (prev) ++ : "A" (old), "b" (u64_low_32(new)), "c" (u64_high_32(new))); ++ return prev; ++} ++ ++/* slist routines below update slist atomically - no need for ++ * spinlocks */ ++ ++static inline struct nt_slist *PushEntrySList(nt_slist_header *head, ++ struct nt_slist *entry, ++ NT_SPIN_LOCK *lock) ++{ ++ nt_slist_header old, new; ++ do { ++ old.align = head->align; ++ entry->next = old.next; ++ new.next = entry; ++ new.depth = old.depth + 1; ++ } while (nt_cmpxchg8b(&head->align, old.align, new.align) != old.align); ++ TRACE4("%p, %p, %p", head, entry, old.next); ++ return old.next; ++} ++ ++static inline struct nt_slist *PopEntrySList(nt_slist_header *head, ++ NT_SPIN_LOCK *lock) ++{ ++ struct nt_slist *entry; ++ nt_slist_header old, new; ++ do { ++ old.align = head->align; ++ entry = old.next; ++ if (!entry) ++ break; ++ new.next = entry->next; ++ new.depth = old.depth - 1; ++ } while (nt_cmpxchg8b(&head->align, old.align, new.align) != old.align); ++ TRACE4("%p, %p", head, entry); ++ return entry; ++} ++ ++#endif ++ ++#define sleep_hz(n) \ ++do { \ ++ set_current_state(TASK_INTERRUPTIBLE); \ ++ schedule_timeout(n); \ ++} while (0) ++ ++int ntoskernel_init(void); ++void ntoskernel_exit(void); ++int ntoskernel_init_device(struct wrap_device *wd); ++void ntoskernel_exit_device(struct wrap_device *wd); ++void *allocate_object(ULONG size, enum common_object_type type, ++ struct unicode_string *name); ++ ++#ifdef ENABLE_USB ++int usb_init(void); ++void usb_exit(void); ++#else ++static inline int usb_init(void) { return 0; } ++static inline void usb_exit(void) {} ++#endif ++int usb_init_device(struct wrap_device *wd); ++void usb_exit_device(struct wrap_device *wd); ++ ++int wrap_procfs_init(void); ++void wrap_procfs_remove(void); ++ ++int link_pe_images(struct pe_image *pe_image, unsigned short n); ++ ++int stricmp(const char *s1, const char *s2); ++void dump_bytes(const char *name, const u8 *from, int len); ++struct mdl *allocate_init_mdl(void *virt, ULONG length); ++void free_mdl(struct mdl *mdl); ++struct driver_object *find_bus_driver(const char *name); ++void free_custom_extensions(struct driver_extension *drv_obj_ext); ++struct nt_thread *get_current_nt_thread(void); ++u64 ticks_1601(void); ++int schedule_ntos_work_item(NTOS_WORK_FUNC func, void *arg1, void *arg2); ++void wrap_init_timer(struct nt_timer *nt_timer, enum timer_type type, ++ struct ndis_mp_block *nmb); ++BOOLEAN wrap_set_timer(struct nt_timer *nt_timer, unsigned long expires_hz, ++ unsigned long repeat_hz, struct kdpc *kdpc); ++ ++LONG InterlockedDecrement(LONG volatile *val) wfastcall; ++LONG InterlockedIncrement(LONG volatile *val) wfastcall; ++struct nt_list *ExInterlockedInsertHeadList ++ (struct nt_list *head, struct nt_list *entry, ++ NT_SPIN_LOCK *lock) wfastcall; ++struct nt_list *ExInterlockedInsertTailList ++ (struct nt_list *head, struct nt_list *entry, ++ NT_SPIN_LOCK *lock) wfastcall; ++struct nt_list *ExInterlockedRemoveHeadList ++ (struct nt_list *head, NT_SPIN_LOCK *lock) wfastcall; ++NTSTATUS IofCallDriver(struct device_object *dev_obj, struct irp *irp) wfastcall; ++KIRQL KfRaiseIrql(KIRQL newirql) wfastcall; ++void KfLowerIrql(KIRQL oldirql) wfastcall; ++KIRQL KfAcquireSpinLock(NT_SPIN_LOCK *lock) wfastcall; ++void KfReleaseSpinLock(NT_SPIN_LOCK *lock, KIRQL oldirql) wfastcall; ++void IofCompleteRequest(struct irp *irp, CHAR prio_boost) wfastcall; ++void KefReleaseSpinLockFromDpcLevel(NT_SPIN_LOCK *lock) wfastcall; ++ ++LONG ObfReferenceObject(void *object) wfastcall; ++void ObfDereferenceObject(void *object) wfastcall; ++ ++#define ObReferenceObject(object) ObfReferenceObject(object) ++#define ObDereferenceObject(object) ObfDereferenceObject(object) ++ ++/* prevent expansion of ExAllocatePoolWithTag macro */ ++void *(ExAllocatePoolWithTag)(enum pool_type pool_type, SIZE_T size, ++ ULONG tag) wstdcall; ++ ++void ExFreePool(void *p) wstdcall; ++ULONG MmSizeOfMdl(void *base, ULONG length) wstdcall; ++void __iomem *MmMapIoSpace(PHYSICAL_ADDRESS phys_addr, SIZE_T size, ++ enum memory_caching_type cache) wstdcall; ++void MmUnmapIoSpace(void __iomem *addr, SIZE_T size) wstdcall; ++void MmProbeAndLockPages(struct mdl *mdl, KPROCESSOR_MODE access_mode, ++ enum lock_operation operation) wstdcall; ++void MmUnlockPages(struct mdl *mdl) wstdcall; ++void KeInitializeEvent(struct nt_event *nt_event, ++ enum event_type type, BOOLEAN state) wstdcall; ++LONG KeSetEvent(struct nt_event *nt_event, KPRIORITY incr, ++ BOOLEAN wait) wstdcall; ++LONG KeResetEvent(struct nt_event *nt_event) wstdcall; ++BOOLEAN queue_kdpc(struct kdpc *kdpc); ++BOOLEAN dequeue_kdpc(struct kdpc *kdpc); ++ ++NTSTATUS IoConnectInterrupt(struct kinterrupt **kinterrupt, ++ PKSERVICE_ROUTINE service_routine, ++ void *service_context, NT_SPIN_LOCK *lock, ++ ULONG vector, KIRQL irql, KIRQL synch_irql, ++ enum kinterrupt_mode interrupt_mode, ++ BOOLEAN shareable, KAFFINITY processor_enable_mask, ++ BOOLEAN floating_save) wstdcall; ++void IoDisconnectInterrupt(struct kinterrupt *interrupt) wstdcall; ++BOOLEAN KeSynchronizeExecution(struct kinterrupt *interrupt, ++ PKSYNCHRONIZE_ROUTINE synch_routine, ++ void *ctx) wstdcall; ++ ++NTSTATUS KeWaitForSingleObject(void *object, KWAIT_REASON reason, ++ KPROCESSOR_MODE waitmode, BOOLEAN alertable, ++ LARGE_INTEGER *timeout) wstdcall; ++void MmBuildMdlForNonPagedPool(struct mdl *mdl) wstdcall; ++NTSTATUS IoCreateDevice(struct driver_object *driver, ULONG dev_ext_length, ++ struct unicode_string *dev_name, DEVICE_TYPE dev_type, ++ ULONG dev_chars, BOOLEAN exclusive, ++ struct device_object **dev_obj) wstdcall; ++NTSTATUS IoCreateSymbolicLink(struct unicode_string *link, ++ struct unicode_string *dev_name) wstdcall; ++void IoDeleteDevice(struct device_object *dev) wstdcall; ++void IoDetachDevice(struct device_object *topdev) wstdcall; ++struct device_object *IoGetAttachedDevice(struct device_object *dev) wstdcall; ++struct device_object *IoGetAttachedDeviceReference ++ (struct device_object *dev) wstdcall; ++NTSTATUS IoAllocateDriverObjectExtension ++ (struct driver_object *drv_obj, void *client_id, ULONG extlen, ++ void **ext) wstdcall; ++void *IoGetDriverObjectExtension(struct driver_object *drv, ++ void *client_id) wstdcall; ++struct device_object *IoAttachDeviceToDeviceStack ++ (struct device_object *src, struct device_object *dst) wstdcall; ++BOOLEAN IoCancelIrp(struct irp *irp) wstdcall; ++struct irp *IoBuildSynchronousFsdRequest ++ (ULONG major_func, struct device_object *dev_obj, void *buf, ++ ULONG length, LARGE_INTEGER *offset, struct nt_event *event, ++ struct io_status_block *status) wstdcall; ++ ++NTSTATUS IoPassIrpDown(struct device_object *dev_obj, struct irp *irp) wstdcall; ++WIN_FUNC_DECL(IoPassIrpDown,2); ++NTSTATUS IoSyncForwardIrp(struct device_object *dev_obj, ++ struct irp *irp) wstdcall; ++NTSTATUS IoAsyncForwardIrp(struct device_object *dev_obj, ++ struct irp *irp) wstdcall; ++NTSTATUS IoInvalidDeviceRequest(struct device_object *dev_obj, ++ struct irp *irp) wstdcall; ++ ++void KeInitializeSpinLock(NT_SPIN_LOCK *lock) wstdcall; ++void IoAcquireCancelSpinLock(KIRQL *irql) wstdcall; ++void IoReleaseCancelSpinLock(KIRQL irql) wstdcall; ++ ++NTSTATUS RtlUnicodeStringToAnsiString ++ (struct ansi_string *dst, const struct unicode_string *src, ++ BOOLEAN dup) wstdcall; ++NTSTATUS RtlAnsiStringToUnicodeString ++ (struct unicode_string *dst, const struct ansi_string *src, ++ BOOLEAN dup) wstdcall; ++void RtlInitAnsiString(struct ansi_string *dst, const char *src) wstdcall; ++void RtlInitUnicodeString(struct unicode_string *dest, ++ const wchar_t *src) wstdcall; ++void RtlFreeUnicodeString(struct unicode_string *string) wstdcall; ++void RtlFreeAnsiString(struct ansi_string *string) wstdcall; ++LONG RtlCompareUnicodeString(const struct unicode_string *s1, ++ const struct unicode_string *s2, ++ BOOLEAN case_insensitive) wstdcall; ++NTSTATUS RtlUpcaseUnicodeString(struct unicode_string *dst, ++ struct unicode_string *src, ++ BOOLEAN alloc) wstdcall; ++BOOLEAN KeCancelTimer(struct nt_timer *nt_timer) wstdcall; ++void KeInitializeDpc(struct kdpc *kdpc, void *func, void *ctx) wstdcall; ++ ++extern spinlock_t ntoskernel_lock; ++extern spinlock_t irp_cancel_lock; ++extern struct nt_list object_list; ++extern CCHAR cpu_count; ++#ifdef CONFIG_X86_64 ++extern struct kuser_shared_data kuser_shared_data; ++#endif ++ ++#define IoCompleteRequest(irp, prio) IofCompleteRequest(irp, prio) ++#define IoCallDriver(dev, irp) IofCallDriver(dev, irp) ++ ++#if defined(IO_DEBUG) ++#define DUMP_IRP(_irp) \ ++do { \ ++ struct io_stack_location *_irp_sl; \ ++ _irp_sl = IoGetCurrentIrpStackLocation(_irp); \ ++ IOTRACE("irp: %p, stack size: %d, cl: %d, sl: %p, dev_obj: %p, " \ ++ "mj_fn: %d, minor_fn: %d, nt_urb: %p, event: %p", \ ++ _irp, _irp->stack_count, (_irp)->current_location, \ ++ _irp_sl, _irp_sl->dev_obj, _irp_sl->major_fn, \ ++ _irp_sl->minor_fn, IRP_URB(_irp), \ ++ (_irp)->user_event); \ ++} while (0) ++#else ++#define DUMP_IRP(_irp) do { } while (0) ++#endif ++ ++#endif // _NTOSKERNEL_H_ +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/ntoskernel_io.c linux-4.6-rc6-ndis/3rdparty/ndiswrapper/ntoskernel_io.c +--- linux-4.6-rc6/3rdparty/ndiswrapper/ntoskernel_io.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/ntoskernel_io.c 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,1161 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include "ntoskernel.h" ++#include "ndis.h" ++#include "wrapndis.h" ++#include "usb.h" ++#include "loader.h" ++#include "ntoskernel_io_exports.h" ++ ++wstdcall void WIN_FUNC(IoAcquireCancelSpinLock,1) ++ (KIRQL *irql) __acquires(irql) ++{ ++ spin_lock_bh(&irp_cancel_lock); ++ *irql = 0; ++} ++ ++wstdcall void WIN_FUNC(IoReleaseCancelSpinLock,1) ++ (KIRQL irql) __releases(irql) ++{ ++ spin_unlock_bh(&irp_cancel_lock); ++} ++ ++wstdcall int WIN_FUNC(IoIsWdmVersionAvailable,2) ++ (UCHAR major, UCHAR minor) ++{ ++ IOENTER("%d, %x", major, minor); ++ if (major == 1 && ++ (minor == 0x30 || // Windows 2003 ++ minor == 0x20 || // Windows XP ++ minor == 0x10)) // Windows 2000 ++ IOEXIT(return TRUE); ++ IOEXIT(return FALSE); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(IoIs32bitProcess,1) ++ (struct irp *irp) ++{ ++#ifdef CONFIG_X86_64 ++ return FALSE; ++#else ++ return TRUE; ++#endif ++} ++ ++wstdcall void WIN_FUNC(IoInitializeIrp,3) ++ (struct irp *irp, USHORT size, CCHAR stack_count) ++{ ++ IOENTER("irp: %p, %d, %d", irp, size, stack_count); ++ ++ memset(irp, 0, size); ++ irp->size = size; ++ irp->stack_count = stack_count; ++ irp->current_location = stack_count; ++ IoGetCurrentIrpStackLocation(irp) = IRP_SL(irp, stack_count); ++ IOEXIT(return); ++} ++ ++wstdcall void WIN_FUNC(IoReuseIrp,2) ++ (struct irp *irp, NTSTATUS status) ++{ ++ IOENTER("%p, %d", irp, status); ++ if (irp) { ++ UCHAR alloc_flags; ++ ++ alloc_flags = irp->alloc_flags; ++ IoInitializeIrp(irp, irp->size, irp->stack_count); ++ irp->alloc_flags = alloc_flags; ++ irp->io_status.status = status; ++ } ++ IOEXIT(return); ++} ++ ++wstdcall struct irp *WIN_FUNC(IoAllocateIrp,2) ++ (char stack_count, BOOLEAN charge_quota) ++{ ++ struct irp *irp; ++ int irp_size; ++ ++ IOENTER("count: %d", stack_count); ++ stack_count++; ++ irp_size = IoSizeOfIrp(stack_count); ++ irp = kmalloc(irp_size, irql_gfp()); ++ if (irp) ++ IoInitializeIrp(irp, irp_size, stack_count); ++ IOTRACE("irp %p", irp); ++ IOEXIT(return irp); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(IoCancelIrp,1) ++ (struct irp *irp) ++{ ++ typeof(irp->cancel_routine) cancel_routine; ++ ++ /* NB: this function may be called at DISPATCH_LEVEL */ ++ IOTRACE("irp: %p", irp); ++ if (!irp) ++ return FALSE; ++ DUMP_IRP(irp); ++ IoAcquireCancelSpinLock(&irp->cancel_irql); ++ cancel_routine = xchg(&irp->cancel_routine, NULL); ++ IOTRACE("%p", cancel_routine); ++ irp->cancel = TRUE; ++ if (cancel_routine) { ++ struct device_object *dev_obj; ++ ++ if (irp->current_location >= 0 && ++ irp->current_location < irp->stack_count) ++ dev_obj = IoGetCurrentIrpStackLocation(irp)->dev_obj; ++ else ++ dev_obj = NULL; ++ IOTRACE("current_location: %d, dev_obj: %p", ++ irp->current_location, dev_obj); ++ /* cancel_routine will release the spin lock */ ++ __release(irp->cancel_irql); ++ LIN2WIN2(cancel_routine, dev_obj, irp); ++ /* in usb's cancel, irp->cancel is set to indicate ++ * status of cancel */ ++ IOEXIT(return xchg(&irp->cancel, TRUE)); ++ } else { ++ IOTRACE("irp %p already canceled", irp); ++ IoReleaseCancelSpinLock(irp->cancel_irql); ++ IOEXIT(return FALSE); ++ } ++} ++ ++wstdcall void IoQueueThreadIrp(struct irp *irp) ++{ ++ struct nt_thread *thread; ++ KIRQL irql; ++ ++ thread = get_current_nt_thread(); ++ if (thread) { ++ IOTRACE("thread: %p, task: %p", thread, thread->task); ++ irp->flags |= IRP_SYNCHRONOUS_API; ++ irql = nt_spin_lock_irql(&thread->lock, DISPATCH_LEVEL); ++ InsertTailList(&thread->irps, &irp->thread_list); ++ IoIrpThread(irp) = thread; ++ nt_spin_unlock_irql(&thread->lock, irql); ++ } else ++ IoIrpThread(irp) = NULL; ++} ++ ++wstdcall void IoDequeueThreadIrp(struct irp *irp) ++{ ++ struct nt_thread *thread; ++ KIRQL irql; ++ ++ thread = IoIrpThread(irp); ++ if (thread) { ++ irql = nt_spin_lock_irql(&thread->lock, DISPATCH_LEVEL); ++ RemoveEntryList(&irp->thread_list); ++ nt_spin_unlock_irql(&thread->lock, irql); ++ } ++} ++ ++wstdcall void WIN_FUNC(IoFreeIrp,1) ++ (struct irp *irp) ++{ ++ IOENTER("irp = %p", irp); ++ if (!irp) { ++ WARNING("irp is NULL"); ++ return; ++ } ++ ++ if (irp->flags & IRP_SYNCHRONOUS_API) ++ IoDequeueThreadIrp(irp); ++ IoCancelIrp(irp); ++ kfree(irp); ++ ++ IOEXIT(return); ++} ++ ++wstdcall struct irp *WIN_FUNC(IoBuildAsynchronousFsdRequest,6) ++ (ULONG major_fn, struct device_object *dev_obj, void *buffer, ++ ULONG length, LARGE_INTEGER *offset, ++ struct io_status_block *user_status) ++{ ++ struct irp *irp; ++ struct io_stack_location *irp_sl; ++ ++ IOENTER("%p", dev_obj); ++ if (!dev_obj) ++ IOEXIT(return NULL); ++ irp = IoAllocateIrp(dev_obj->stack_count, FALSE); ++ if (irp == NULL) { ++ WARNING("couldn't allocate irp"); ++ IOEXIT(return NULL); ++ } ++ ++ irp_sl = IoGetNextIrpStackLocation(irp); ++ irp_sl->major_fn = major_fn; ++ IOTRACE("major_fn: %d", major_fn); ++ irp_sl->minor_fn = 0; ++ irp_sl->flags = 0; ++ irp_sl->control = 0; ++ irp_sl->dev_obj = dev_obj; ++ irp_sl->file_obj = NULL; ++ irp_sl->completion_routine = NULL; ++ ++ if (dev_obj->flags & DO_DIRECT_IO) { ++ irp->mdl = IoAllocateMdl(buffer, length, FALSE, FALSE, irp); ++ if (irp->mdl == NULL) { ++ IoFreeIrp(irp); ++ return NULL; ++ } ++ MmProbeAndLockPages(irp->mdl, KernelMode, ++ major_fn == IRP_MJ_WRITE ? ++ IoReadAccess : IoWriteAccess); ++ IOTRACE("mdl: %p", irp->mdl); ++ } else if (dev_obj->flags & DO_BUFFERED_IO) { ++ irp->associated_irp.system_buffer = buffer; ++ irp->flags = IRP_BUFFERED_IO; ++ irp->mdl = NULL; ++ IOTRACE("buffer: %p", buffer); ++ } ++ if (major_fn == IRP_MJ_READ) { ++ irp_sl->params.read.length = length; ++ irp_sl->params.read.byte_offset = *offset; ++ } else if (major_fn == IRP_MJ_WRITE) { ++ irp_sl->params.write.length = length; ++ irp_sl->params.write.byte_offset = *offset; ++ } ++ irp->user_status = user_status; ++ IOTRACE("irp: %p", irp); ++ return irp; ++} ++ ++wstdcall struct irp *WIN_FUNC(IoBuildSynchronousFsdRequest,7) ++ (ULONG major_fn, struct device_object *dev_obj, void *buf, ++ ULONG length, LARGE_INTEGER *offset, struct nt_event *event, ++ struct io_status_block *user_status) ++{ ++ struct irp *irp; ++ ++ irp = IoBuildAsynchronousFsdRequest(major_fn, dev_obj, buf, length, ++ offset, user_status); ++ if (irp == NULL) ++ return NULL; ++ irp->user_event = event; ++ IoQueueThreadIrp(irp); ++ return irp; ++} ++ ++wstdcall struct irp *WIN_FUNC(IoBuildDeviceIoControlRequest,9) ++ (ULONG ioctl, struct device_object *dev_obj, ++ void *input_buf, ULONG input_buf_len, void *output_buf, ++ ULONG output_buf_len, BOOLEAN internal_ioctl, ++ struct nt_event *event, struct io_status_block *io_status) ++{ ++ struct irp *irp; ++ struct io_stack_location *irp_sl; ++ ULONG buf_len; ++ ++ IOENTER("%p, 0x%08x, %d", dev_obj, ioctl, internal_ioctl); ++ if (!dev_obj) ++ IOEXIT(return NULL); ++ irp = IoAllocateIrp(dev_obj->stack_count, FALSE); ++ if (irp == NULL) { ++ WARNING("couldn't allocate irp"); ++ return NULL; ++ } ++ irp_sl = IoGetNextIrpStackLocation(irp); ++ irp_sl->params.dev_ioctl.code = ioctl; ++ irp_sl->params.dev_ioctl.input_buf_len = input_buf_len; ++ irp_sl->params.dev_ioctl.output_buf_len = output_buf_len; ++ irp_sl->major_fn = (internal_ioctl) ? ++ IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL; ++ IOTRACE("%d", IO_METHOD_FROM_CTL_CODE(ioctl)); ++ ++ switch (IO_METHOD_FROM_CTL_CODE(ioctl)) { ++ case METHOD_BUFFERED: ++ buf_len = max(input_buf_len, output_buf_len); ++ if (buf_len) { ++ irp->associated_irp.system_buffer = ++ ExAllocatePoolWithTag(NonPagedPool, buf_len, 0); ++ if (!irp->associated_irp.system_buffer) { ++ IoFreeIrp(irp); ++ IOEXIT(return NULL); ++ } ++ irp->associated_irp.system_buffer = input_buf; ++ if (input_buf) ++ memcpy(irp->associated_irp.system_buffer, ++ input_buf, input_buf_len); ++ irp->flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; ++ if (output_buf) ++ irp->flags = IRP_INPUT_OPERATION; ++ irp->user_buf = output_buf; ++ } else ++ irp->user_buf = NULL; ++ break; ++ case METHOD_IN_DIRECT: ++ case METHOD_OUT_DIRECT: ++ if (input_buf) { ++ irp->associated_irp.system_buffer = ++ ExAllocatePoolWithTag(NonPagedPool, ++ input_buf_len, 0); ++ if (!irp->associated_irp.system_buffer) { ++ IoFreeIrp(irp); ++ IOEXIT(return NULL); ++ } ++ memcpy(irp->associated_irp.system_buffer, ++ input_buf, input_buf_len); ++ irp->flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; ++ } ++ /* TODO: we are supposed to setup MDL, but USB layer ++ * doesn't use MDLs. Moreover, USB layer mirrors ++ * non-DMAable buffers, so no need to allocate ++ * DMAable buffer here */ ++ if (output_buf) { ++ irp->associated_irp.system_buffer = ++ ExAllocatePoolWithTag(NonPagedPool, ++ output_buf_len, 0); ++ if (!irp->associated_irp.system_buffer) { ++ IoFreeIrp(irp); ++ IOEXIT(return NULL); ++ } ++ irp->flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; ++ } ++ break; ++ case METHOD_NEITHER: ++ irp->user_buf = output_buf; ++ irp_sl->params.dev_ioctl.type3_input_buf = input_buf; ++ break; ++ } ++ ++ irp->user_status = io_status; ++ irp->user_event = event; ++ IoQueueThreadIrp(irp); ++ ++ IOTRACE("irp: %p", irp); ++ IOEXIT(return irp); ++} ++ ++wfastcall NTSTATUS WIN_FUNC(IofCallDriver,2) ++ (struct device_object *dev_obj, struct irp *irp) ++{ ++ struct io_stack_location *irp_sl; ++ NTSTATUS status; ++ driver_dispatch_t *major_func; ++ struct driver_object *drv_obj; ++ ++ if (irp->current_location <= 0) { ++ ERROR("invalid irp: %p, %d", irp, irp->current_location); ++ return STATUS_INVALID_PARAMETER; ++ } ++ IOTRACE("%p, %p, %p, %d, %d, %p", dev_obj, irp, dev_obj->drv_obj, ++ irp->current_location, irp->stack_count, ++ IoGetCurrentIrpStackLocation(irp)); ++ IoSetNextIrpStackLocation(irp); ++ DUMP_IRP(irp); ++ irp_sl = IoGetCurrentIrpStackLocation(irp); ++ drv_obj = dev_obj->drv_obj; ++ irp_sl->dev_obj = dev_obj; ++ major_func = drv_obj->major_func[irp_sl->major_fn]; ++ IOTRACE("major_func: %p, dev_obj: %p", major_func, dev_obj); ++ if (major_func) ++ status = LIN2WIN2(major_func, dev_obj, irp); ++ else { ++ ERROR("major_function %d is not implemented", ++ irp_sl->major_fn); ++ status = STATUS_NOT_SUPPORTED; ++ } ++ IOEXIT(return status); ++} ++ ++wfastcall void WIN_FUNC(IofCompleteRequest,2) ++ (struct irp *irp, CHAR prio_boost) ++{ ++ struct io_stack_location *irp_sl; ++ ++#ifdef IO_DEBUG ++ DUMP_IRP(irp); ++ if (irp->io_status.status == STATUS_PENDING) { ++ ERROR("invalid irp: %p, STATUS_PENDING", irp); ++ return; ++ } ++ if (irp->current_location < 0 || ++ irp->current_location >= irp->stack_count) { ++ ERROR("invalid irp: %p, %d", irp, irp->current_location); ++ return; ++ } ++#endif ++ for (irp_sl = IoGetCurrentIrpStackLocation(irp); ++ irp->current_location < irp->stack_count; irp_sl++) { ++ struct device_object *dev_obj; ++ NTSTATUS status; ++ ++ DUMP_IRP(irp); ++ if (irp_sl->control & SL_PENDING_RETURNED) ++ irp->pending_returned = TRUE; ++ ++ /* current_location and dev_obj must be same as when ++ * driver called IoSetCompletionRoutine, which sets ++ * completion routine at next (lower) location, which ++ * is what we are going to call below; so we set ++ * current_location and dev_obj for the previous ++ * (higher) location */ ++ IoSkipCurrentIrpStackLocation(irp); ++ if (irp->current_location < irp->stack_count) ++ dev_obj = IoGetCurrentIrpStackLocation(irp)->dev_obj; ++ else ++ dev_obj = NULL; ++ ++ IOTRACE("%d, %d, %p", irp->current_location, irp->stack_count, ++ dev_obj); ++ if (irp_sl->completion_routine && ++ ((irp->io_status.status == STATUS_SUCCESS && ++ irp_sl->control & SL_INVOKE_ON_SUCCESS) || ++ (irp->io_status.status != STATUS_SUCCESS && ++ irp_sl->control & SL_INVOKE_ON_ERROR) || ++ (irp->cancel == TRUE && ++ irp_sl->control & SL_INVOKE_ON_CANCEL))) { ++ IOTRACE("calling completion_routine at: %p, %p", ++ irp_sl->completion_routine, irp_sl->context); ++ status = LIN2WIN3(irp_sl->completion_routine, ++ dev_obj, irp, irp_sl->context); ++ IOTRACE("status: %08X", status); ++ if (status == STATUS_MORE_PROCESSING_REQUIRED) ++ IOEXIT(return); ++ } else { ++ /* propagate pending status to next irp_sl */ ++ if (irp->pending_returned && ++ irp->current_location < irp->stack_count) ++ IoMarkIrpPending(irp); ++ } ++ } ++ ++ if (irp->user_status) { ++ irp->user_status->status = irp->io_status.status; ++ irp->user_status->info = irp->io_status.info; ++ } ++ ++ if (irp->user_event) { ++ IOTRACE("setting event %p", irp->user_event); ++ KeSetEvent(irp->user_event, prio_boost, FALSE); ++ } ++ ++ if (irp->associated_irp.system_buffer && ++ (irp->flags & IRP_DEALLOCATE_BUFFER)) ++ ExFreePool(irp->associated_irp.system_buffer); ++ else { ++ struct mdl *mdl; ++ while ((mdl = irp->mdl)) { ++ irp->mdl = mdl->next; ++ MmUnlockPages(mdl); ++ IoFreeMdl(mdl); ++ } ++ } ++ IOTRACE("freeing irp %p", irp); ++ IoFreeIrp(irp); ++ IOEXIT(return); ++} ++ ++wstdcall NTSTATUS IoPassIrpDown(struct device_object *dev_obj, struct irp *irp) ++{ ++ IoSkipCurrentIrpStackLocation(irp); ++ IOEXIT(return IoCallDriver(dev_obj, irp)); ++} ++ ++wstdcall NTSTATUS IoIrpSyncComplete(struct device_object *dev_obj, ++ struct irp *irp, void *context) ++{ ++ if (irp->pending_returned == TRUE) ++ KeSetEvent(context, IO_NO_INCREMENT, FALSE); ++ IOEXIT(return STATUS_MORE_PROCESSING_REQUIRED); ++} ++WIN_FUNC_DECL(IoIrpSyncComplete,3) ++ ++wstdcall NTSTATUS IoSyncForwardIrp(struct device_object *dev_obj, ++ struct irp *irp) ++{ ++ struct nt_event event; ++ NTSTATUS status; ++ ++ IoCopyCurrentIrpStackLocationToNext(irp); ++ KeInitializeEvent(&event, SynchronizationEvent, FALSE); ++ /* completion function is called as Windows function */ ++ IoSetCompletionRoutine(irp, WIN_FUNC_PTR(IoIrpSyncComplete,3), &event, ++ TRUE, TRUE, TRUE); ++ status = IoCallDriver(dev_obj, irp); ++ IOTRACE("%08X", status); ++ if (status == STATUS_PENDING) { ++ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, ++ NULL); ++ status = irp->io_status.status; ++ } ++ IOTRACE("%08X", status); ++ IOEXIT(return status); ++} ++WIN_FUNC_DECL(IoSyncForwardIrp,2) ++ ++wstdcall NTSTATUS IoAsyncForwardIrp(struct device_object *dev_obj, ++ struct irp *irp) ++{ ++ NTSTATUS status; ++ ++ IoCopyCurrentIrpStackLocationToNext(irp); ++ status = IoCallDriver(dev_obj, irp); ++ IOEXIT(return status); ++} ++WIN_FUNC_DECL(IoAsyncForwardIrp,2) ++ ++wstdcall NTSTATUS IoInvalidDeviceRequest(struct device_object *dev_obj, ++ struct irp *irp) ++{ ++ struct io_stack_location *irp_sl; ++ NTSTATUS status; ++ ++ irp_sl = IoGetCurrentIrpStackLocation(irp); ++ WARNING("%d:%d not implemented", irp_sl->major_fn, irp_sl->minor_fn); ++ irp->io_status.status = STATUS_SUCCESS; ++ irp->io_status.info = 0; ++ status = irp->io_status.status; ++ IoCompleteRequest(irp, IO_NO_INCREMENT); ++ IOEXIT(return status); ++} ++WIN_FUNC_DECL(IoInvalidDeviceRequest,2) ++ ++static irqreturn_t io_irq_isr(int irq, void *data ISR_PT_REGS_PARAM_DECL) ++{ ++ struct kinterrupt *interrupt = data; ++ BOOLEAN ret; ++ ++#ifdef CONFIG_DEBUG_SHIRQ ++ if (!interrupt->u.enabled) ++ EXIT1(return IRQ_NONE); ++#endif ++ TRACE6("%p", interrupt); ++ nt_spin_lock(interrupt->actual_lock); ++ ret = LIN2WIN2(interrupt->isr, interrupt, interrupt->isr_ctx); ++ nt_spin_unlock(interrupt->actual_lock); ++ if (ret == TRUE) ++ EXIT6(return IRQ_HANDLED); ++ else ++ EXIT6(return IRQ_NONE); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoConnectInterrupt,11) ++ (struct kinterrupt **kinterrupt, PKSERVICE_ROUTINE isr, void *isr_ctx, ++ NT_SPIN_LOCK *lock, ULONG vector, KIRQL irql, KIRQL synch_irql, ++ enum kinterrupt_mode mode, BOOLEAN shared, KAFFINITY cpu_mask, ++ BOOLEAN save_fp) ++{ ++ struct kinterrupt *interrupt; ++ IOENTER(""); ++ interrupt = kzalloc(sizeof(*interrupt), GFP_KERNEL); ++ if (!interrupt) ++ IOEXIT(return STATUS_INSUFFICIENT_RESOURCES); ++ interrupt->vector = vector; ++ interrupt->cpu_mask = cpu_mask; ++ nt_spin_lock_init(&interrupt->lock); ++ if (lock) ++ interrupt->actual_lock = lock; ++ else ++ interrupt->actual_lock = &interrupt->lock; ++ interrupt->shared = shared; ++ interrupt->save_fp = save_fp; ++ interrupt->isr = isr; ++ interrupt->isr_ctx = isr_ctx; ++ InitializeListHead(&interrupt->list); ++ interrupt->irql = irql; ++ interrupt->synch_irql = synch_irql; ++ interrupt->mode = mode; ++ if (request_irq(vector, io_irq_isr, shared ? IRQF_SHARED : 0, ++ DRIVER_NAME, interrupt)) { ++ WARNING("request for irq %d failed", vector); ++ kfree(interrupt); ++ IOEXIT(return STATUS_INSUFFICIENT_RESOURCES); ++ } ++ *kinterrupt = interrupt; ++#ifdef CONFIG_DEBUG_SHIRQ ++ interrupt->u.enabled = 1; ++#endif ++ IOEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(IoDisconnectInterrupt,1) ++ (struct kinterrupt *interrupt) ++{ ++#ifdef CONFIG_DEBUG_SHIRQ ++ interrupt->u.enabled = 0; ++#endif ++ free_irq(interrupt->vector, interrupt); ++ kfree(interrupt); ++} ++ ++wstdcall struct mdl *WIN_FUNC(IoAllocateMdl,5) ++ (void *virt, ULONG length, BOOLEAN second_buf, BOOLEAN charge_quota, ++ struct irp *irp) ++{ ++ struct mdl *mdl; ++ mdl = allocate_init_mdl(virt, length); ++ if (!mdl) ++ return NULL; ++ if (irp) { ++ if (second_buf == TRUE) { ++ struct mdl *last; ++ ++ last = irp->mdl; ++ while (last->next) ++ last = last->next; ++ last->next = mdl; ++ } else ++ irp->mdl = mdl; ++ } ++ IOTRACE("%p", mdl); ++ return mdl; ++} ++ ++wstdcall void WIN_FUNC(IoFreeMdl,1) ++ (struct mdl *mdl) ++{ ++ IOTRACE("%p", mdl); ++ free_mdl(mdl); ++} ++ ++wstdcall struct io_workitem *WIN_FUNC(IoAllocateWorkItem,1) ++ (struct device_object *dev_obj) ++{ ++ struct io_workitem *io_workitem; ++ ++ IOENTER("%p", dev_obj); ++ io_workitem = kmalloc(sizeof(*io_workitem), irql_gfp()); ++ if (!io_workitem) ++ IOEXIT(return NULL); ++ io_workitem->dev_obj = dev_obj; ++ IOEXIT(return io_workitem); ++} ++ ++wstdcall void WIN_FUNC(IoFreeWorkItem,1) ++ (struct io_workitem *io_workitem) ++{ ++ kfree(io_workitem); ++ IOEXIT(return); ++} ++ ++wstdcall void WIN_FUNC(IoQueueWorkItem,4) ++ (struct io_workitem *io_workitem, void *func, ++ enum work_queue_type queue_type, void *context) ++{ ++ IOENTER("%p, %p", io_workitem, io_workitem->dev_obj); ++ io_workitem->worker_routine = func; ++ io_workitem->context = context; ++ schedule_ntos_work_item(func, io_workitem->dev_obj, context); ++ IOEXIT(return); ++} ++ ++wstdcall void WIN_FUNC(ExQueueWorkItem,2) ++ (struct io_workitem *io_workitem, enum work_queue_type queue_type) ++{ ++ IOENTER("%p", io_workitem); ++ schedule_ntos_work_item(io_workitem->worker_routine, ++ io_workitem->dev_obj, io_workitem->context); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoAllocateDriverObjectExtension,4) ++ (struct driver_object *drv_obj, void *client_id, ULONG extlen, ++ void **ext) ++{ ++ struct custom_ext *ce; ++ ++ IOENTER("%p, %p", drv_obj, client_id); ++ ce = kmalloc(sizeof(*ce) + extlen, irql_gfp()); ++ if (ce == NULL) ++ return STATUS_INSUFFICIENT_RESOURCES; ++ ++ IOTRACE("custom_ext: %p", ce); ++ ce->client_id = client_id; ++ spin_lock_bh(&ntoskernel_lock); ++ InsertTailList(&drv_obj->drv_ext->custom_ext, &ce->list); ++ spin_unlock_bh(&ntoskernel_lock); ++ ++ *ext = (void *)ce + sizeof(*ce); ++ IOTRACE("ext: %p", *ext); ++ IOEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall void *WIN_FUNC(IoGetDriverObjectExtension,2) ++ (struct driver_object *drv_obj, void *client_id) ++{ ++ struct custom_ext *ce; ++ void *ret; ++ ++ IOENTER("drv_obj: %p, client_id: %p", drv_obj, client_id); ++ ret = NULL; ++ spin_lock_bh(&ntoskernel_lock); ++ nt_list_for_each_entry(ce, &drv_obj->drv_ext->custom_ext, list) { ++ if (ce->client_id == client_id) { ++ ret = (void *)ce + sizeof(*ce); ++ break; ++ } ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ IOTRACE("ret: %p", ret); ++ return ret; ++} ++ ++void free_custom_extensions(struct driver_extension *drv_ext) ++{ ++ struct nt_list *ent; ++ ++ IOENTER("%p", drv_ext); ++ spin_lock_bh(&ntoskernel_lock); ++ while ((ent = RemoveHeadList(&drv_ext->custom_ext))) ++ kfree(ent); ++ spin_unlock_bh(&ntoskernel_lock); ++ IOEXIT(return); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoCreateDevice,7) ++ (struct driver_object *drv_obj, ULONG dev_ext_length, ++ struct unicode_string *dev_name, DEVICE_TYPE dev_type, ++ ULONG dev_chars, BOOLEAN exclusive, struct device_object **newdev) ++{ ++ struct device_object *dev; ++ struct dev_obj_ext *dev_obj_ext; ++ int size; ++ ++ IOENTER("%p, %u, %p", drv_obj, dev_ext_length, dev_name); ++ ++ size = sizeof(*dev) + dev_ext_length + sizeof(*dev_obj_ext); ++ dev = allocate_object(size, OBJECT_TYPE_DEVICE, dev_name); ++ if (!dev) ++ IOEXIT(return STATUS_INSUFFICIENT_RESOURCES); ++ if (dev_ext_length) ++ dev->dev_ext = dev + 1; ++ else ++ dev->dev_ext = NULL; ++ ++ dev_obj_ext = ((void *)(dev + 1)) + dev_ext_length; ++ dev_obj_ext->dev_obj = dev; ++ dev_obj_ext->size = 0; ++ dev_obj_ext->type = IO_TYPE_DEVICE; ++ dev->dev_obj_ext = dev_obj_ext; ++ ++ dev->type = dev_type; ++ dev->flags = 0; ++ dev->size = sizeof(*dev) + dev_ext_length; ++ dev->ref_count = 1; ++ dev->attached = NULL; ++ dev->stack_count = 1; ++ ++ dev->drv_obj = drv_obj; ++ dev->next = drv_obj->dev_obj; ++ drv_obj->dev_obj = dev; ++ ++ dev->align_req = 1; ++ dev->characteristics = dev_chars; ++ dev->io_timer = NULL; ++ KeInitializeEvent(&dev->lock, SynchronizationEvent, TRUE); ++ dev->vpb = NULL; ++ ++ IOTRACE("dev: %p, ext: %p", dev, dev->dev_ext); ++ *newdev = dev; ++ IOEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoCreateUnprotectedSymbolicLink,2) ++ (struct unicode_string *link, struct unicode_string *dev_name) ++{ ++ struct ansi_string ansi; ++ ++ IOENTER("%p, %p", dev_name, link); ++ if (dev_name && (RtlUnicodeStringToAnsiString(&ansi, dev_name, TRUE) == ++ STATUS_SUCCESS)) { ++ IOTRACE("dev_name: %s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ if (link && (RtlUnicodeStringToAnsiString(&ansi, link, TRUE) == ++ STATUS_SUCCESS)) { ++ IOTRACE("link: %s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++// TODO(); ++ IOEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoCreateSymbolicLink,2) ++ (struct unicode_string *link, struct unicode_string *dev_name) ++{ ++ IOEXIT(return IoCreateUnprotectedSymbolicLink(link, dev_name)); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoDeleteSymbolicLink,1) ++ (struct unicode_string *link) ++{ ++ struct ansi_string ansi; ++ ++ IOENTER("%p", link); ++ if (link && (RtlUnicodeStringToAnsiString(&ansi, link, TRUE) == ++ STATUS_SUCCESS)) { ++ IOTRACE("dev_name: %s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ IOEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(IoDeleteDevice,1) ++ (struct device_object *dev) ++{ ++ IOENTER("%p", dev); ++ if (dev == NULL) ++ IOEXIT(return); ++ IOTRACE("drv_obj: %p", dev->drv_obj); ++ if (dev->drv_obj) { ++ struct device_object *prev; ++ ++ prev = dev->drv_obj->dev_obj; ++ IOTRACE("dev_obj: %p", prev); ++ if (prev == dev) ++ dev->drv_obj->dev_obj = dev->next; ++ else if (prev) { ++ while (prev->next != dev) ++ prev = prev->next; ++ prev->next = dev->next; ++ } ++ } ++ ObDereferenceObject(dev); ++ IOEXIT(return); ++} ++ ++wstdcall void WIN_FUNC(IoDetachDevice,1) ++ (struct device_object *tgt) ++{ ++ struct device_object *tail; ++ ++ IOENTER("%p", tgt); ++ if (!tgt) ++ IOEXIT(return); ++ tail = tgt->attached; ++ if (!tail) ++ IOEXIT(return); ++ IOTRACE("tail: %p", tail); ++ ++ spin_lock_bh(&ntoskernel_lock); ++ tgt->attached = tail->attached; ++ IOTRACE("attached:%p", tgt->attached); ++ for ( ; tail; tail = tail->attached) { ++ IOTRACE("tail:%p", tail); ++ tail->stack_count--; ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ IOEXIT(return); ++} ++ ++wstdcall struct device_object *WIN_FUNC(IoGetAttachedDevice,1) ++ (struct device_object *dev) ++{ ++ IOENTER("%p", dev); ++ if (!dev) ++ IOEXIT(return NULL); ++ spin_lock_bh(&ntoskernel_lock); ++ while (dev->attached) ++ dev = dev->attached; ++ spin_unlock_bh(&ntoskernel_lock); ++ IOEXIT(return dev); ++} ++ ++wstdcall struct device_object *WIN_FUNC(IoGetAttachedDeviceReference,1) ++ (struct device_object *dev) ++{ ++ IOENTER("%p", dev); ++ if (!dev) ++ IOEXIT(return NULL); ++ dev = IoGetAttachedDevice(dev); ++ ObReferenceObject(dev); ++ IOEXIT(return dev); ++} ++ ++wstdcall struct device_object *WIN_FUNC(IoAttachDeviceToDeviceStack,2) ++ (struct device_object *src, struct device_object *tgt) ++{ ++ struct device_object *attached; ++ struct dev_obj_ext *src_dev_ext; ++ ++ IOENTER("%p, %p", src, tgt); ++ attached = IoGetAttachedDevice(tgt); ++ IOTRACE("%p", attached); ++ src_dev_ext = src->dev_obj_ext; ++ spin_lock_bh(&ntoskernel_lock); ++ if (attached) ++ attached->attached = src; ++ src->attached = NULL; ++ src->stack_count = attached->stack_count + 1; ++ src_dev_ext->attached_to = attached; ++ spin_unlock_bh(&ntoskernel_lock); ++ IOTRACE("stack_count: %d -> %d", attached->stack_count, ++ src->stack_count); ++ IOEXIT(return attached); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoGetDeviceProperty,5) ++ (struct device_object *pdo, enum device_registry_property dev_property, ++ ULONG buffer_len, void *buffer, ULONG *result_len) ++{ ++ struct ansi_string ansi; ++ struct unicode_string unicode; ++ struct wrap_device *wd; ++ ULONG need; ++ ++ IOENTER("dev_obj = %p, dev_property = %d, buffer_len = %u, " ++ "buffer = %p, result_len = %p", pdo, dev_property, ++ buffer_len, buffer, result_len); ++ ++ wd = pdo->reserved; ++ switch (dev_property) { ++ case DevicePropertyDeviceDescription: ++ case DevicePropertyFriendlyName: ++ case DevicePropertyDriverKeyName: ++ if (wrap_is_pci_bus(wd->dev_bus)) ++ RtlInitAnsiString(&ansi, "PCI"); ++ else // if (wrap_is_usb_bus(wd->dev_bus)) ++ RtlInitAnsiString(&ansi, "USB"); ++ need = sizeof(wchar_t) * (ansi.max_length + 1); ++ if (buffer_len < need) { ++ *result_len = need; ++ IOEXIT(return STATUS_BUFFER_TOO_SMALL); ++ } ++ unicode.max_length = buffer_len; ++ unicode.buf = buffer; ++ if (RtlAnsiStringToUnicodeString(&unicode, &ansi, ++ FALSE) != STATUS_SUCCESS) { ++ *result_len = unicode.length; ++ IOEXIT(return STATUS_BUFFER_TOO_SMALL); ++ } ++ IOEXIT(return STATUS_SUCCESS); ++ default: ++ WARNING("%d not implemented", dev_property); ++ IOEXIT(return STATUS_INVALID_PARAMETER_2); ++ } ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoGetDeviceObjectPointer,4) ++ (struct unicode_string *name, ACCESS_MASK desired_access, ++ struct file_object *file_obj, struct device_object *dev_obj) ++{ ++ struct common_object_header *coh; ++ ++ dev_obj = NULL; ++ /* TODO: access is not checked and file_obj is filled with zeroes */ ++ spin_lock_bh(&ntoskernel_lock); ++ nt_list_for_each_entry(coh, &object_list, list) { ++ TRACE5("header: %p, type: %d", coh, coh->type); ++ if (coh->type != OBJECT_TYPE_DEVICE) ++ continue; ++ if (!RtlCompareUnicodeString(&coh->name, name, TRUE)) { ++ dev_obj = HEADER_TO_OBJECT(coh); ++ TRACE5("dev_obj: %p", dev_obj); ++ break; ++ } ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ if (dev_obj) { ++ memset(file_obj, 0, sizeof(*file_obj)); ++ WARNING("file_obj filled with zeroes"); ++ IOEXIT(return STATUS_SUCCESS); ++ } else ++ IOEXIT(return STATUS_OBJECT_NAME_INVALID); ++} ++ ++/* NOTE: Make sure to compile with -freg-struct-return, so gcc will ++ * return union in register, like Windows */ ++wstdcall union power_state WIN_FUNC(PoSetPowerState,3) ++ (struct device_object *dev_obj, enum power_state_type type, ++ union power_state state) ++{ ++ IOEXIT(return state); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(PoCallDriver,2) ++ (struct device_object *dev_obj, struct irp *irp) ++{ ++ return IoCallDriver(dev_obj, irp); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(PoRequestPowerIrp,6) ++ (struct device_object *dev_obj, UCHAR minor_fn, ++ union power_state power_state, void *completion_func, ++ void *context, struct irp **pirp) ++{ ++ struct irp *irp; ++ struct io_stack_location *irp_sl; ++ ++ TRACE1("%p, %d, %p", dev_obj, dev_obj->stack_count, dev_obj->drv_obj); ++ irp = IoAllocateIrp(dev_obj->stack_count, FALSE); ++ if (!irp) ++ return STATUS_INSUFFICIENT_RESOURCES; ++ irp_sl = IoGetNextIrpStackLocation(irp); ++ irp_sl->major_fn = IRP_MJ_POWER; ++ irp_sl->minor_fn = minor_fn; ++ if (minor_fn == IRP_MN_WAIT_WAKE) ++ irp_sl->params.power.type = SystemPowerState; ++ else ++ irp_sl->params.power.type = DevicePowerState; ++ irp_sl->params.power.state = power_state; ++ irp_sl->completion_routine = completion_func; ++ irp->io_status.status = STATUS_NOT_SUPPORTED; ++ *pirp = irp; ++ return PoCallDriver(dev_obj, irp); ++} ++ ++wstdcall void WIN_FUNC(PoStartNextPowerIrp,1) ++ (struct irp *irp) ++{ ++ IOENTER("irp = %p", irp); ++ IOEXIT(return); ++} ++ ++wstdcall void WIN_FUNC(IoInitializeRemoveLockEx,5) ++ (struct io_remove_lock *lock, ULONG alloc_tag, ULONG max_locked_min, ++ ULONG high_mark, ULONG lock_size) ++{ ++ TODO(); ++} ++ ++wstdcall void *WIN_FUNC(IoAllocateErrorLogEntry,2) ++ (void *io_object, UCHAR entry_size) ++{ ++ /* not implemented fully */ ++ void *ret = kmalloc(sizeof(struct io_error_log_packet) + entry_size, ++ irql_gfp()); ++ TRACE2("%p", ret); ++ if (ret) ++ return ret + sizeof(struct io_error_log_packet); ++ else ++ return NULL; ++} ++ ++wstdcall void WIN_FUNC(IoWriteErrorLogEntry,1) ++ (void *entry) ++{ ++ /* TODO: log error with codes and message */ ++ ERROR(""); ++} ++ ++wstdcall void WIN_FUNC(IoFreeErrorLogEntry,1) ++ (void *entry) ++{ ++ TRACE2("%p", entry); ++ kfree(entry - sizeof(struct io_error_log_packet)); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoAcquireRemoveLockEx,5) ++ (struct io_remove_lock *lock, void *tag, char *file, ULONG line, ++ ULONG lock_size) ++{ ++ TODO(); ++ IOEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoReleaseRemoveLockEx,3) ++ (struct io_remove_lock *lock, void *tag, ULONG lock_size) ++{ ++ TODO(); ++ IOEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoRegisterDeviceInterface,4) ++ (struct device_object *pdo, struct guid *guid_class, ++ struct unicode_string *reference, struct unicode_string *link) ++{ ++ struct ansi_string ansi; ++ ++ /* TODO: check if pdo is valid */ ++ RtlInitAnsiString(&ansi, "ndis"); ++ ENTER1("pdo: %p, ref: %p, link: %p, %x, %x, %x", pdo, reference, link, ++ guid_class->data1, guid_class->data2, guid_class->data3); ++ return RtlAnsiStringToUnicodeString(link, &ansi, TRUE); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoSetDeviceInterfaceState,2) ++ (struct unicode_string *link, BOOLEAN enable) ++{ ++ ENTER1("link: %p, enable: %d", link, enable); ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoOpenDeviceRegistryKey,4) ++ (struct device_object *dev_obj, ULONG type, ACCESS_MASK mask, ++ void **handle) ++{ ++ ENTER1("dev_obj: %p", dev_obj); ++ *handle = dev_obj; ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoWMIRegistrationControl,2) ++ (struct device_object *dev_obj, ULONG action) ++{ ++ ENTER2("%p, %d", dev_obj, action); ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(IoInvalidateDeviceRelations,2) ++ (struct device_object *dev_obj, enum device_relation_type type) ++{ ++ INFO("%p, %d", dev_obj, type); ++ TODO(); ++} ++ ++wstdcall void WIN_FUNC(IoInvalidateDeviceState,1) ++ (struct device_object *pdo) ++{ ++ INFO("%p", pdo); ++ TODO(); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoRegisterPlugPlayNotification,7) ++ (UINT category, ULONG flags, void *data, struct driver_object *object, ++ void *callback, void *context, void **notification_entry) ++{ ++ TRACE2("category: %d, flags 0x%x, data: %p, object: %p, callback: %p, " ++ "context: %p, notification_entry: %p", category, flags, data, ++ object, callback, context, notification_entry); ++ TODO(); ++ IOEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoUnregisterPlugPlayNotification,1) ++ (void *notification_entry) ++{ ++ TRACE2("%p", notification_entry); ++ TODO(); ++ IOEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoWMIOpenBlock,3) ++ (struct guid *guid, ULONG access, void *object) ++{ ++ TODO(); ++ IOEXIT(return STATUS_NOT_IMPLEMENTED); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoWMIQueryAllData,3) ++ (void *data_block_object, UINT *buffer_size, void *buffer) ++{ ++ TODO(); ++ IOEXIT(return STATUS_NOT_IMPLEMENTED); ++} ++ ++wstdcall void WIN_FUNC(IoGetStackLimits,2) ++ (ULONG_PTR *LowLimit, ULONG_PTR *HighLimit) ++{ ++ *LowLimit = (ULONG_PTR)&LowLimit & ~(THREAD_SIZE - 1); ++ *HighLimit = *LowLimit + THREAD_SIZE; ++ IOTRACE("LowLimit: 0x%lx, HighLimit: 0x%lx", *LowLimit, *HighLimit); ++ IOEXIT(return); ++} +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/pe_linker.c linux-4.6-rc6-ndis/3rdparty/ndiswrapper/pe_linker.c +--- linux-4.6-rc6/3rdparty/ndiswrapper/pe_linker.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/pe_linker.c 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,600 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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. ++ * ++ */ ++ ++#ifdef TEST_LOADER ++ ++#include "usr_linker.h" ++ ++#else ++ ++#include ++#include ++ ++//#define DEBUGLINKER 2 ++ ++#include "ntoskernel.h" ++ ++#endif ++ ++struct pe_exports { ++ char *dll; ++ char *name; ++ generic_func addr; ++}; ++ ++static struct pe_exports pe_exports[40]; ++static int num_pe_exports; ++ ++#define RVA2VA(image, rva, type) (type)(ULONG_PTR)((void *)image + rva) ++#define CHECK_SZ(a,b) { if (sizeof(a) != b) { \ ++ ERROR("%s is bad, got %zd, expected %d", \ ++ #a , sizeof(a), (b)); return -EINVAL; } } ++ ++#if defined(DEBUGLINKER) && DEBUGLINKER > 0 ++#define DBGLINKER(fmt, ...) printk(KERN_INFO "%s (%s:%d): " fmt "\n", \ ++ DRIVER_NAME, __func__, \ ++ __LINE__ , ## __VA_ARGS__); ++static const char *image_directory_name[] = { ++ "EXPORT", ++ "IMPORT", ++ "RESOURCE", ++ "EXCEPTION", ++ "SECURITY", ++ "BASERELOC", ++ "DEBUG", ++ "COPYRIGHT", ++ "GLOBALPTR", ++ "TLS", ++ "LOAD_CONFIG", ++ "BOUND_IMPORT", ++ "IAT", ++ "DELAY_IMPORT", ++ "COM_DESCRIPTOR" }; ++#else ++#define DBGLINKER(fmt, ...) do { } while (0) ++#endif ++ ++#ifndef TEST_LOADER ++extern struct wrap_export ntoskernel_exports[], ntoskernel_io_exports[], ++ ndis_exports[], crt_exports[], hal_exports[], rtl_exports[]; ++#ifdef ENABLE_USB ++extern struct wrap_export usb_exports[]; ++#endif ++ ++static int get_export(char *name, generic_func *func) ++{ ++ int i, j; ++ ++ struct wrap_export *exports[] = { ++ ntoskernel_exports, ++ ntoskernel_io_exports, ++ ndis_exports, ++ crt_exports, ++ hal_exports, ++ rtl_exports, ++#ifdef ENABLE_USB ++ usb_exports, ++#endif ++ }; ++ ++ for (j = 0; j < ARRAY_SIZE(exports); j++) ++ for (i = 0; exports[j][i].name != NULL; i++) ++ if (strcmp(exports[j][i].name, name) == 0) { ++ *func = exports[j][i].func; ++ return 0; ++ } ++ ++ for (i = 0; i < num_pe_exports; i++) ++ if (strcmp(pe_exports[i].name, name) == 0) { ++ *func = pe_exports[i].addr; ++ return 0; ++ } ++ ++ return -1; ++} ++#endif // TEST_LOADER ++ ++static void *get_dll_init(char *name) ++{ ++ int i; ++ for (i = 0; i < num_pe_exports; i++) ++ if ((strcmp(pe_exports[i].dll, name) == 0) && ++ (strcmp(pe_exports[i].name, "DllInitialize") == 0)) ++ return (void *)pe_exports[i].addr; ++ return NULL; ++} ++ ++/* ++ * Find and validate the coff header ++ * ++ */ ++static int check_nt_hdr(IMAGE_NT_HEADERS *nt_hdr) ++{ ++ int i; ++ WORD attr; ++ PIMAGE_OPTIONAL_HEADER opt_hdr; ++ ++ /* Validate the "PE\0\0" signature */ ++ if (nt_hdr->Signature != IMAGE_NT_SIGNATURE) { ++ ERROR("is this driver file? bad signature %08x", ++ nt_hdr->Signature); ++ return -EINVAL; ++ } ++ ++ opt_hdr = &nt_hdr->OptionalHeader; ++ /* Make sure Image is PE32 or PE32+ */ ++#ifdef CONFIG_X86_64 ++ if (opt_hdr->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) { ++ ERROR("kernel is 64-bit, but Windows driver is not 64-bit;" ++ "bad magic: %04X", opt_hdr->Magic); ++ return -EINVAL; ++ } ++#else ++ if (opt_hdr->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ ERROR("kernel is 32-bit, but Windows driver is not 32-bit;" ++ "bad magic: %04X", opt_hdr->Magic); ++ return -EINVAL; ++ } ++#endif ++ ++ /* Validate the image for the current architecture. */ ++#ifdef CONFIG_X86_64 ++ if (nt_hdr->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) { ++ ERROR("kernel is 64-bit, but Windows driver is not 64-bit;" ++ " (PE signature is %04X)", nt_hdr->FileHeader.Machine); ++ return -EINVAL; ++ } ++#else ++ if (nt_hdr->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) { ++ ERROR("kernel is 32-bit, but Windows driver is not 32-bit;" ++ " (PE signature is %04X)", nt_hdr->FileHeader.Machine); ++ return -EINVAL; ++ } ++#endif ++ ++ /* Must have attributes */ ++#ifdef CONFIG_X86_64 ++ attr = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE; ++#else ++ attr = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE; ++#endif ++ if ((nt_hdr->FileHeader.Characteristics & attr) != attr) ++ return -EINVAL; ++ ++ /* Must be relocatable */ ++ attr = IMAGE_FILE_RELOCS_STRIPPED; ++ if ((nt_hdr->FileHeader.Characteristics & attr)) ++ return -EINVAL; ++ ++ /* Make sure we have at least one section */ ++ if (nt_hdr->FileHeader.NumberOfSections == 0) ++ return -EINVAL; ++ ++ if (opt_hdr->SectionAlignment < opt_hdr->FileAlignment) { ++ ERROR("alignment mismatch: section: 0x%x, file: 0x%x", ++ opt_hdr->SectionAlignment, opt_hdr->FileAlignment); ++ return -EINVAL; ++ } ++ ++ DBGLINKER("number of datadictionary entries %d", ++ opt_hdr->NumberOfRvaAndSizes); ++ for (i = 0; i < opt_hdr->NumberOfRvaAndSizes; i++) { ++ DBGLINKER("datadirectory %s RVA:%X Size:%d", ++ (i <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR) ? ++ image_directory_name[i] : "unknown", ++ opt_hdr->DataDirectory[i].VirtualAddress, ++ opt_hdr->DataDirectory[i].Size); ++ } ++ ++ if ((nt_hdr->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) ++ return IMAGE_FILE_EXECUTABLE_IMAGE; ++ if ((nt_hdr->FileHeader.Characteristics & IMAGE_FILE_DLL)) ++ return IMAGE_FILE_DLL; ++ return -EINVAL; ++} ++ ++static int import(void *image, IMAGE_IMPORT_DESCRIPTOR *dirent, char *dll) ++{ ++ ULONG_PTR *lookup_tbl, *address_tbl; ++ char *symname = NULL; ++ int i; ++ int ret = 0; ++ generic_func adr; ++ ++ lookup_tbl = RVA2VA(image, dirent->u.OriginalFirstThunk, ULONG_PTR *); ++ address_tbl = RVA2VA(image, dirent->FirstThunk, ULONG_PTR *); ++ ++ for (i = 0; lookup_tbl[i]; i++) { ++ if (IMAGE_SNAP_BY_ORDINAL(lookup_tbl[i])) { ++ ERROR("ordinal import not supported: %llu", ++ (uint64_t)lookup_tbl[i]); ++ return -1; ++ } ++ else { ++ symname = RVA2VA(image, ++ ((lookup_tbl[i] & ++ ~IMAGE_ORDINAL_FLAG) + 2), char *); ++ } ++ ++ if (get_export(symname, &adr) < 0) { ++ ERROR("unknown symbol: %s:'%s'", dll, symname); ++ ret = -1; ++ } else { ++ DBGLINKER("found symbol: %s:%s: addr: %p, rva = %llu", ++ dll, symname, adr, (uint64_t)address_tbl[i]); ++ address_tbl[i] = (ULONG_PTR)adr; ++ } ++ } ++ return ret; ++} ++ ++static int read_exports(struct pe_image *pe) ++{ ++ IMAGE_EXPORT_DIRECTORY *export_dir_table; ++ uint32_t *export_addr_table; ++ int i; ++ uint32_t *name_table; ++ PIMAGE_OPTIONAL_HEADER opt_hdr; ++ IMAGE_DATA_DIRECTORY *export_data_dir; ++ ++ opt_hdr = &pe->nt_hdr->OptionalHeader; ++ export_data_dir = ++ &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; ++ ++ if (export_data_dir->Size == 0) { ++ DBGLINKER("no exports"); ++ return 0; ++ } ++ ++ export_dir_table = ++ RVA2VA(pe->image, export_data_dir->VirtualAddress, ++ IMAGE_EXPORT_DIRECTORY *); ++ ++ name_table = (unsigned int *)(pe->image + ++ export_dir_table->AddressOfNames); ++ export_addr_table = (uint32_t *) ++ (pe->image + export_dir_table->AddressOfFunctions); ++ ++ for (i = 0; i < export_dir_table->NumberOfNames; i++) { ++ ++ if (export_data_dir->VirtualAddress <= *export_addr_table || ++ *export_addr_table >= (export_data_dir->VirtualAddress + ++ export_data_dir->Size)) ++ DBGLINKER("forwarder rva"); ++ ++ DBGLINKER("export symbol: %s, at %p", ++ (char *)(pe->image + *name_table), ++ pe->image + *export_addr_table); ++ ++ pe_exports[num_pe_exports].dll = pe->name; ++ pe_exports[num_pe_exports].name = pe->image + *name_table; ++ pe_exports[num_pe_exports].addr = ++ pe->image + *export_addr_table; ++ ++ num_pe_exports++; ++ name_table++; ++ export_addr_table++; ++ } ++ return 0; ++} ++ ++static int fixup_imports(void *image, IMAGE_NT_HEADERS *nt_hdr) ++{ ++ int i; ++ char *name; ++ int ret = 0; ++ IMAGE_IMPORT_DESCRIPTOR *dirent; ++ IMAGE_DATA_DIRECTORY *import_data_dir; ++ PIMAGE_OPTIONAL_HEADER opt_hdr; ++ ++ opt_hdr = &nt_hdr->OptionalHeader; ++ import_data_dir = ++ &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; ++ dirent = RVA2VA(image, import_data_dir->VirtualAddress, ++ IMAGE_IMPORT_DESCRIPTOR *); ++ ++ for (i = 0; dirent[i].Name; i++) { ++ name = RVA2VA(image, dirent[i].Name, char*); ++ ++ DBGLINKER("imports from dll: %s", name); ++ ret += import(image, &dirent[i], name); ++ } ++ return ret; ++} ++ ++static int fixup_reloc(void *image, IMAGE_NT_HEADERS *nt_hdr) ++{ ++ ULONG_PTR base; ++ ULONG_PTR size; ++ IMAGE_BASE_RELOCATION *fixup_block; ++ IMAGE_DATA_DIRECTORY *base_reloc_data_dir; ++ PIMAGE_OPTIONAL_HEADER opt_hdr; ++ ++ opt_hdr = &nt_hdr->OptionalHeader; ++ base = opt_hdr->ImageBase; ++ base_reloc_data_dir = ++ &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; ++ if (base_reloc_data_dir->Size == 0) ++ return 0; ++ ++ fixup_block = RVA2VA(image, base_reloc_data_dir->VirtualAddress, ++ IMAGE_BASE_RELOCATION *); ++ DBGLINKER("fixup_block=%p, image=%p", fixup_block, image); ++ DBGLINKER("fixup_block info: %x %d", ++ fixup_block->VirtualAddress, fixup_block->SizeOfBlock); ++ ++ while (fixup_block->SizeOfBlock) { ++ int i; ++ WORD fixup, offset; ++ ++ size = (fixup_block->SizeOfBlock - ++ sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); ++ DBGLINKER("found %llu relocations in this block", ++ (uint64_t)size); ++ ++ for (i = 0; i < size; i++) { ++ fixup = fixup_block->TypeOffset[i]; ++ offset = fixup & 0xfff; ++ switch ((fixup >> 12) & 0x0f) { ++ case IMAGE_REL_BASED_ABSOLUTE: ++ break; ++ ++ case IMAGE_REL_BASED_HIGHLOW: { ++ uint32_t addr; ++ uint32_t *loc = ++ RVA2VA(image, ++ fixup_block->VirtualAddress + ++ offset, uint32_t *); ++ addr = RVA2VA(image, (*loc - base), uint32_t); ++ DBGLINKER("relocation: *%p (Val:%X)= %X", ++ loc, *loc, addr); ++ *loc = addr; ++ } ++ break; ++ ++ case IMAGE_REL_BASED_DIR64: { ++ uint64_t addr; ++ uint64_t *loc = ++ RVA2VA(image, ++ fixup_block->VirtualAddress + ++ offset, uint64_t *); ++ addr = RVA2VA(image, (*loc - base), uint64_t); ++ DBGLINKER("relocation: *%p (Val:%llX)= %llx", ++ loc, *loc, addr); ++ *loc = addr; ++ } ++ break; ++ ++ default: ++ ERROR("unknown fixup: %08X", ++ (fixup >> 12) & 0x0f); ++ return -EOPNOTSUPP; ++ break; ++ } ++ } ++ DBGLINKER("finished relocating block"); ++ ++ fixup_block = (IMAGE_BASE_RELOCATION *) ++ ((void *)fixup_block + fixup_block->SizeOfBlock); ++ }; ++ DBGLINKER("done relocating all"); ++ ++ return 0; ++} ++ ++/* Expand the image in memory if necessary. The image on disk does not ++ * necessarily maps the image of the driver in memory, so we have to ++ * re-write it in order to fulfill the sections alignments. The ++ * advantage to do that is that rva_to_va becomes a simple ++ * addition. */ ++static int fix_pe_image(struct pe_image *pe) ++{ ++ void *image; ++ IMAGE_SECTION_HEADER *sect_hdr; ++ int i, sections; ++ int image_size; ++ ++ if (pe->size == pe->opt_hdr->SizeOfImage) { ++ /* Nothing to do */ ++ return 0; ++ } ++ ++ image_size = pe->opt_hdr->SizeOfImage; ++#ifdef CONFIG_X86_64 ++#ifdef PAGE_KERNEL_EXECUTABLE ++ image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM, ++ PAGE_KERNEL_EXECUTABLE); ++#elif defined PAGE_KERNEL_EXEC ++ image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM, ++ PAGE_KERNEL_EXEC); ++#else ++#error x86_64 should have either PAGE_KERNEL_EXECUTABLE or PAGE_KERNEL_EXEC ++#endif ++#else ++#ifdef cpu_has_nx ++ /* hate to play with kernel macros, but PAGE_KERNEL_EXEC is ++ * not available to modules! */ ++ if (cpu_has_nx) ++ image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM, ++ __pgprot(__PAGE_KERNEL & ~_PAGE_NX)); ++ else ++ image = vmalloc(image_size); ++#else ++ image = vmalloc(image_size); ++#endif ++#endif ++ if (image == NULL) { ++ ERROR("failed to allocate enough space for new image:" ++ " %d bytes", image_size); ++ return -ENOMEM; ++ } ++ memset(image, 0, image_size); ++ ++ /* Copy all the headers, ie everything before the first section. */ ++ ++ sections = pe->nt_hdr->FileHeader.NumberOfSections; ++ sect_hdr = IMAGE_FIRST_SECTION(pe->nt_hdr); ++ ++ DBGLINKER("copying headers: %u bytes", sect_hdr->PointerToRawData); ++ ++ memcpy(image, pe->image, sect_hdr->PointerToRawData); ++ ++ /* Copy all the sections */ ++ for (i = 0; i < sections; i++) { ++ DBGLINKER("Copy section %s from %x to %x", ++ sect_hdr->Name, sect_hdr->PointerToRawData, ++ sect_hdr->VirtualAddress); ++ if (sect_hdr->VirtualAddress+sect_hdr->SizeOfRawData > ++ image_size) { ++ ERROR("Invalid section %s in driver", sect_hdr->Name); ++ vfree(image); ++ return -EINVAL; ++ } ++ ++ memcpy(image+sect_hdr->VirtualAddress, ++ pe->image + sect_hdr->PointerToRawData, ++ sect_hdr->SizeOfRawData); ++ sect_hdr++; ++ } ++ ++ vfree(pe->image); ++ pe->image = image; ++ pe->size = image_size; ++ ++ /* Update our internal pointers */ ++ pe->nt_hdr = (IMAGE_NT_HEADERS *) ++ (pe->image + ((IMAGE_DOS_HEADER *)pe->image)->e_lfanew); ++ pe->opt_hdr = &pe->nt_hdr->OptionalHeader; ++ ++ DBGLINKER("set nt headers: nt_hdr=%p, opt_hdr=%p, image=%p", ++ pe->nt_hdr, pe->opt_hdr, pe->image); ++ ++ return 0; ++} ++ ++#if defined(CONFIG_X86_64) ++static void fix_user_shared_data_addr(char *driver, unsigned long length) ++{ ++ unsigned long i, n, max_addr, *addr; ++ ++ TRACE1("fixing KI_USER_SHARED_DATA address in the driver"); ++ n = length - sizeof(unsigned long); ++ max_addr = KI_USER_SHARED_DATA + sizeof(kuser_shared_data); ++ for (i = 0; i < n; i++) { ++ addr = (unsigned long *)(driver + i); ++ if (*addr >= KI_USER_SHARED_DATA && *addr < max_addr) { ++ *addr -= KI_USER_SHARED_DATA; ++ *addr += (unsigned long)&kuser_shared_data; ++ kuser_shared_data.reserved1 = 1; ++ } ++ } ++} ++#endif ++ ++int link_pe_images(struct pe_image *pe_image, unsigned short n) ++{ ++ int i; ++ struct pe_image *pe; ++ ++#if DEBUG >= 1 ++ /* Sanity checks */ ++ CHECK_SZ(IMAGE_SECTION_HEADER, IMAGE_SIZEOF_SECTION_HEADER); ++ CHECK_SZ(IMAGE_FILE_HEADER, IMAGE_SIZEOF_FILE_HEADER); ++ CHECK_SZ(IMAGE_OPTIONAL_HEADER, IMAGE_SIZEOF_NT_OPTIONAL_HEADER); ++ CHECK_SZ(IMAGE_NT_HEADERS, 4 + IMAGE_SIZEOF_FILE_HEADER + ++ IMAGE_SIZEOF_NT_OPTIONAL_HEADER); ++ CHECK_SZ(IMAGE_DOS_HEADER, 0x40); ++ CHECK_SZ(IMAGE_EXPORT_DIRECTORY, 40); ++ CHECK_SZ(IMAGE_BASE_RELOCATION, 8); ++ CHECK_SZ(IMAGE_IMPORT_DESCRIPTOR, 20); ++#endif ++ ++ for (i = 0; i < n; i++) { ++ IMAGE_DOS_HEADER *dos_hdr; ++ pe = &pe_image[i]; ++ dos_hdr = pe->image; ++ ++ if (pe->size < sizeof(IMAGE_DOS_HEADER)) { ++ TRACE1("image too small: %d", pe->size); ++ return -EINVAL; ++ } ++ ++ pe->nt_hdr = ++ (IMAGE_NT_HEADERS *)(pe->image + dos_hdr->e_lfanew); ++ pe->opt_hdr = &pe->nt_hdr->OptionalHeader; ++ ++ pe->type = check_nt_hdr(pe->nt_hdr); ++ if (pe->type <= 0) { ++ TRACE1("type <= 0"); ++ return -EINVAL; ++ } ++ ++ if (fix_pe_image(pe)) { ++ TRACE1("bad PE image"); ++ return -EINVAL; ++ } ++ ++ if (read_exports(pe)) { ++ TRACE1("read exports failed"); ++ return -EINVAL; ++ } ++ } ++ ++ for (i = 0; i < n; i++) { ++ pe = &pe_image[i]; ++ ++ if (fixup_reloc(pe->image, pe->nt_hdr)) { ++ TRACE1("fixup reloc failed"); ++ return -EINVAL; ++ } ++ if (fixup_imports(pe->image, pe->nt_hdr)) { ++ TRACE1("fixup imports failed"); ++ return -EINVAL; ++ } ++#if defined(CONFIG_X86_64) ++ fix_user_shared_data_addr(pe_image[i].image, pe_image[i].size); ++#endif ++ flush_icache_range((unsigned long)pe->image, pe->size); ++ ++ pe->entry = ++ RVA2VA(pe->image, ++ pe->opt_hdr->AddressOfEntryPoint, void *); ++ TRACE1("entry is at %p, rva at %08X", pe->entry, ++ pe->opt_hdr->AddressOfEntryPoint); ++ } ++ ++ for (i = 0; i < n; i++) { ++ pe = &pe_image[i]; ++ ++ if (pe->type == IMAGE_FILE_DLL) { ++ struct unicode_string ustring; ++ char *buf = "0/0t0m0p00"; ++ int (*dll_entry)(struct unicode_string *ustring) ++ wstdcall; ++ ++ memset(&ustring, 0, sizeof(ustring)); ++ ustring.buf = (wchar_t *)buf; ++ dll_entry = (void *)get_dll_init(pe->name); ++ ++ TRACE1("calling dll_init at %p", dll_entry); ++ if (!dll_entry || dll_entry(&ustring)) ++ ERROR("DLL initialize failed for %s", ++ pe->name); ++ } ++ else if (pe->type != IMAGE_FILE_EXECUTABLE_IMAGE) ++ ERROR("illegal image type: %d", pe->type); ++ } ++ return 0; ++} +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/pe_linker.h linux-4.6-rc6-ndis/3rdparty/ndiswrapper/pe_linker.h +--- linux-4.6-rc6/3rdparty/ndiswrapper/pe_linker.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/pe_linker.h 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,992 @@ ++/* ++ * This file is an excerpt of winnt.h from WINE, which bears the ++ * following copyright: ++ * ++ * Win32 definitions for Windows NT ++ * ++ * Copyright 1996 Alexandre Julliard ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++/* ++ * File formats definitions ++ */ ++typedef struct _IMAGE_DOS_HEADER { ++ WORD e_magic; /* 00: MZ Header signature */ ++ WORD e_cblp; /* 02: Bytes on last page of file */ ++ WORD e_cp; /* 04: Pages in file */ ++ WORD e_crlc; /* 06: Relocations */ ++ WORD e_cparhdr; /* 08: Size of header in paragraphs */ ++ WORD e_minalloc; /* 0a: Minimum extra paragraphs needed */ ++ WORD e_maxalloc; /* 0c: Maximum extra paragraphs needed */ ++ WORD e_ss; /* 0e: Initial (relative) SS value */ ++ WORD e_sp; /* 10: Initial SP value */ ++ WORD e_csum; /* 12: Checksum */ ++ WORD e_ip; /* 14: Initial IP value */ ++ WORD e_cs; /* 16: Initial (relative) CS value */ ++ WORD e_lfarlc; /* 18: File address of relocation table */ ++ WORD e_ovno; /* 1a: Overlay number */ ++ WORD e_res[4]; /* 1c: Reserved words */ ++ WORD e_oemid; /* 24: OEM identifier (for e_oeminfo) */ ++ WORD e_oeminfo; /* 26: OEM information; e_oemid specific */ ++ WORD e_res2[10]; /* 28: Reserved words */ ++ DWORD e_lfanew; /* 3c: Offset to extended header */ ++} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; ++ ++#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */ ++#define IMAGE_OS2_SIGNATURE 0x454E /* NE */ ++#define IMAGE_OS2_SIGNATURE_LE 0x454C /* LE */ ++#define IMAGE_OS2_SIGNATURE_LX 0x584C /* LX */ ++#define IMAGE_VXD_SIGNATURE 0x454C /* LE */ ++#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ ++ ++/* ++ * This is the Windows executable (NE) header. ++ * the name IMAGE_OS2_HEADER is misleading, but in the SDK this way. ++ */ ++typedef struct ++{ ++ WORD ne_magic; /* 00 NE signature 'NE' */ ++ BYTE ne_ver; /* 02 Linker version number */ ++ BYTE ne_rev; /* 03 Linker revision number */ ++ WORD ne_enttab; /* 04 Offset to entry table relative to NE */ ++ WORD ne_cbenttab; /* 06 Length of entry table in bytes */ ++ LONG ne_crc; /* 08 Checksum */ ++ WORD ne_flags; /* 0c Flags about segments in this file */ ++ WORD ne_autodata; /* 0e Automatic data segment number */ ++ WORD ne_heap; /* 10 Initial size of local heap */ ++ WORD ne_stack; /* 12 Initial size of stack */ ++ DWORD ne_csip; /* 14 Initial CS:IP */ ++ DWORD ne_sssp; /* 18 Initial SS:SP */ ++ WORD ne_cseg; /* 1c # of entries in segment table */ ++ WORD ne_cmod; /* 1e # of entries in module reference tab. */ ++ WORD ne_cbnrestab; /* 20 Length of nonresident-name table */ ++ WORD ne_segtab; /* 22 Offset to segment table */ ++ WORD ne_rsrctab; /* 24 Offset to resource table */ ++ WORD ne_restab; /* 26 Offset to resident-name table */ ++ WORD ne_modtab; /* 28 Offset to module reference table */ ++ WORD ne_imptab; /* 2a Offset to imported name table */ ++ DWORD ne_nrestab; /* 2c Offset to nonresident-name table */ ++ WORD ne_cmovent; /* 30 # of movable entry points */ ++ WORD ne_align; /* 32 Logical sector alignment shift count */ ++ WORD ne_cres; /* 34 # of resource segments */ ++ BYTE ne_exetyp; /* 36 Flags indicating target OS */ ++ BYTE ne_flagsothers; /* 37 Additional information flags */ ++ WORD ne_pretthunks; /* 38 Offset to return thunks */ ++ WORD ne_psegrefbytes; /* 3a Offset to segment ref. bytes */ ++ WORD ne_swaparea; /* 3c Reserved by Microsoft */ ++ WORD ne_expver; /* 3e Expected Windows version number */ ++} IMAGE_OS2_HEADER, *PIMAGE_OS2_HEADER; ++ ++typedef struct _IMAGE_VXD_HEADER { ++ WORD e32_magic; ++ BYTE e32_border; ++ BYTE e32_worder; ++ DWORD e32_level; ++ WORD e32_cpu; ++ WORD e32_os; ++ DWORD e32_ver; ++ DWORD e32_mflags; ++ DWORD e32_mpages; ++ DWORD e32_startobj; ++ DWORD e32_eip; ++ DWORD e32_stackobj; ++ DWORD e32_esp; ++ DWORD e32_pagesize; ++ DWORD e32_lastpagesize; ++ DWORD e32_fixupsize; ++ DWORD e32_fixupsum; ++ DWORD e32_ldrsize; ++ DWORD e32_ldrsum; ++ DWORD e32_objtab; ++ DWORD e32_objcnt; ++ DWORD e32_objmap; ++ DWORD e32_itermap; ++ DWORD e32_rsrctab; ++ DWORD e32_rsrccnt; ++ DWORD e32_restab; ++ DWORD e32_enttab; ++ DWORD e32_dirtab; ++ DWORD e32_dircnt; ++ DWORD e32_fpagetab; ++ DWORD e32_frectab; ++ DWORD e32_impmod; ++ DWORD e32_impmodcnt; ++ DWORD e32_impproc; ++ DWORD e32_pagesum; ++ DWORD e32_datapage; ++ DWORD e32_preload; ++ DWORD e32_nrestab; ++ DWORD e32_cbnrestab; ++ DWORD e32_nressum; ++ DWORD e32_autodata; ++ DWORD e32_debuginfo; ++ DWORD e32_debuglen; ++ DWORD e32_instpreload; ++ DWORD e32_instdemand; ++ DWORD e32_heapsize; ++ BYTE e32_res3[12]; ++ DWORD e32_winresoff; ++ DWORD e32_winreslen; ++ WORD e32_devid; ++ WORD e32_ddkver; ++} IMAGE_VXD_HEADER, *PIMAGE_VXD_HEADER; ++ ++/* These defines describe the meanings of the bits in the ++ Characteristics field */ ++ ++#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 /* No relocation info */ ++#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 ++#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 ++#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 ++#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 ++#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 ++#define IMAGE_FILE_16BIT_MACHINE 0x0040 ++#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 ++#define IMAGE_FILE_32BIT_MACHINE 0x0100 ++#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 ++#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 ++#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 ++#define IMAGE_FILE_SYSTEM 0x1000 ++#define IMAGE_FILE_DLL 0x2000 ++#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 ++#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 ++ ++/* These are the settings of the Machine field. */ ++#define IMAGE_FILE_MACHINE_UNKNOWN 0 ++#define IMAGE_FILE_MACHINE_I860 0x014d ++#define IMAGE_FILE_MACHINE_I386 0x014c ++#define IMAGE_FILE_MACHINE_R3000 0x0162 ++#define IMAGE_FILE_MACHINE_R4000 0x0166 ++#define IMAGE_FILE_MACHINE_R10000 0x0168 ++#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 ++#define IMAGE_FILE_MACHINE_ALPHA 0x0184 ++#define IMAGE_FILE_MACHINE_SH3 0x01a2 ++#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 ++#define IMAGE_FILE_MACHINE_SH3E 0x01a4 ++#define IMAGE_FILE_MACHINE_SH4 0x01a6 ++#define IMAGE_FILE_MACHINE_SH5 0x01a8 ++#define IMAGE_FILE_MACHINE_ARM 0x01c0 ++#define IMAGE_FILE_MACHINE_THUMB 0x01c2 ++#define IMAGE_FILE_MACHINE_AM33 0x01d3 ++#define IMAGE_FILE_MACHINE_POWERPC 0x01f0 ++#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 ++#define IMAGE_FILE_MACHINE_IA64 0x0200 ++#define IMAGE_FILE_MACHINE_MIPS16 0x0266 ++#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 ++#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 ++#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 ++#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 ++#define IMAGE_FILE_MACHINE_TRICORE 0x0520 ++#define IMAGE_FILE_MACHINE_CEF 0x0cef ++#define IMAGE_FILE_MACHINE_EBC 0x0ebc ++#define IMAGE_FILE_MACHINE_AMD64 0x8664 ++#define IMAGE_FILE_MACHINE_M32R 0x9041 ++#define IMAGE_FILE_MACHINE_CEE 0xc0ee ++ ++#define IMAGE_SIZEOF_FILE_HEADER 20 ++#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56 ++#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28 ++#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER32 224 ++#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER64 240 ++#define IMAGE_SIZEOF_SHORT_NAME 8 ++#define IMAGE_SIZEOF_SECTION_HEADER 40 ++#define IMAGE_SIZEOF_SYMBOL 18 ++#define IMAGE_SIZEOF_AUX_SYMBOL 18 ++#define IMAGE_SIZEOF_RELOCATION 10 ++#define IMAGE_SIZEOF_BASE_RELOCATION 8 ++#define IMAGE_SIZEOF_LINENUMBER 6 ++#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 ++ ++/* Possible Magic values */ ++#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x010b ++#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x020b ++#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x0107 ++ ++#ifdef CONFIG_X86_64 ++#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL_HEADER64 ++#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR64_MAGIC ++#else ++#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL_HEADER32 ++#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR32_MAGIC ++#endif ++ ++/* These are indexes into the DataDirectory array */ ++#define IMAGE_FILE_EXPORT_DIRECTORY 0 ++#define IMAGE_FILE_IMPORT_DIRECTORY 1 ++#define IMAGE_FILE_RESOURCE_DIRECTORY 2 ++#define IMAGE_FILE_EXCEPTION_DIRECTORY 3 ++#define IMAGE_FILE_SECURITY_DIRECTORY 4 ++#define IMAGE_FILE_BASE_RELOCATION_TABLE 5 ++#define IMAGE_FILE_DEBUG_DIRECTORY 6 ++#define IMAGE_FILE_DESCRIPTION_STRING 7 ++#define IMAGE_FILE_MACHINE_VALUE 8 /* Mips */ ++#define IMAGE_FILE_THREAD_LOCAL_STORAGE 9 ++#define IMAGE_FILE_CALLBACK_DIRECTORY 10 ++ ++/* Directory Entries, indices into the DataDirectory array */ ++ ++#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 ++#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 ++#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 ++#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 ++#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 ++#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 ++#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 ++#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 ++#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* (MIPS GP) */ ++#define IMAGE_DIRECTORY_ENTRY_TLS 9 ++#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 ++#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 ++#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */ ++#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 ++#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 ++ ++/* Subsystem Values */ ++ ++#define IMAGE_SUBSYSTEM_UNKNOWN 0 ++#define IMAGE_SUBSYSTEM_NATIVE 1 ++#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 /* Windows GUI subsystem */ ++#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 /* Windows character subsystem */ ++#define IMAGE_SUBSYSTEM_OS2_CUI 5 ++#define IMAGE_SUBSYSTEM_POSIX_CUI 7 ++#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 /* native Win9x driver */ ++#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 /* Windows CE subsystem */ ++#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 ++#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 ++#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 ++#define IMAGE_SUBSYSTEM_EFI_ROM 13 ++#define IMAGE_SUBSYSTEM_XBOX 14 ++ ++typedef struct _IMAGE_FILE_HEADER { ++ WORD Machine; ++ WORD NumberOfSections; ++ DWORD TimeDateStamp; ++ DWORD PointerToSymbolTable; ++ DWORD NumberOfSymbols; ++ WORD SizeOfOptionalHeader; ++ WORD Characteristics; ++} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; ++ ++typedef struct _IMAGE_DATA_DIRECTORY { ++ DWORD VirtualAddress; ++ DWORD Size; ++} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; ++ ++#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 ++ ++typedef struct _IMAGE_OPTIONAL_HEADER32 { ++ ++ /* Standard fields */ ++ ++ WORD Magic; ++ BYTE MajorLinkerVersion; ++ BYTE MinorLinkerVersion; ++ DWORD SizeOfCode; ++ DWORD SizeOfInitializedData; ++ DWORD SizeOfUninitializedData; ++ DWORD AddressOfEntryPoint; ++ DWORD BaseOfCode; ++ DWORD BaseOfData; ++ ++ /* NT additional fields */ ++ DWORD ImageBase; ++ DWORD SectionAlignment; ++ DWORD FileAlignment; ++ WORD MajorOperatingSystemVersion; ++ WORD MinorOperatingSystemVersion; ++ WORD MajorImageVersion; ++ WORD MinorImageVersion; ++ WORD MajorSubsystemVersion; ++ WORD MinorSubsystemVersion; ++ DWORD Win32VersionValue; ++ DWORD SizeOfImage; ++ DWORD SizeOfHeaders; ++ DWORD CheckSum; ++ WORD Subsystem; ++ WORD DllCharacteristics; ++ DWORD SizeOfStackReserve; ++ DWORD SizeOfStackCommit; ++ DWORD SizeOfHeapReserve; ++ DWORD SizeOfHeapCommit; ++ DWORD LoaderFlags; ++ DWORD NumberOfRvaAndSizes; ++ IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; ++} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; ++ ++typedef struct _IMAGE_OPTIONAL_HEADER64 { ++ ++ /* Standard fields */ ++ ++ WORD Magic; ++ BYTE MajorLinkerVersion; ++ BYTE MinorLinkerVersion; ++ DWORD SizeOfCode; ++ DWORD SizeOfInitializedData; ++ DWORD SizeOfUninitializedData; ++ DWORD AddressOfEntryPoint; ++ DWORD BaseOfCode; ++ ++ /* NT additional fields */ ++ ULONGLONG ImageBase; ++ DWORD SectionAlignment; ++ DWORD FileAlignment; ++ WORD MajorOperatingSystemVersion; ++ WORD MinorOperatingSystemVersion; ++ WORD MajorImageVersion; ++ WORD MinorImageVersion; ++ WORD MajorSubsystemVersion; ++ WORD MinorSubsystemVersion; ++ DWORD Win32VersionValue; ++ DWORD SizeOfImage; ++ DWORD SizeOfHeaders; ++ DWORD CheckSum; ++ WORD Subsystem; ++ WORD DllCharacteristics; ++ ULONGLONG SizeOfStackReserve; ++ ULONGLONG SizeOfStackCommit; ++ ULONGLONG SizeOfHeapReserve; ++ ULONGLONG SizeOfHeapCommit; ++ DWORD LoaderFlags; ++ DWORD NumberOfRvaAndSizes; ++ IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; ++} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; ++ ++#ifdef CONFIG_X86_64 ++typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER; ++typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER; ++#else ++typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER; ++typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER; ++#endif ++ ++typedef struct _IMAGE_NT_HEADERS32 { ++ DWORD Signature; /* "PE"\0\0 */ /* 0x00 */ ++ IMAGE_FILE_HEADER FileHeader; /* 0x04 */ ++ IMAGE_OPTIONAL_HEADER32 OptionalHeader; /* 0x18 */ ++} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; ++ ++typedef struct _IMAGE_NT_HEADERS64 { ++ DWORD Signature; /* "PE"\0\0 */ /* 0x00 */ ++ IMAGE_FILE_HEADER FileHeader; /* 0x04 */ ++ IMAGE_OPTIONAL_HEADER64 OptionalHeader; /* 0x18 */ ++} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64; ++ ++#ifdef CONFIG_X86_64 ++typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS; ++typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS; ++#else ++typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; ++typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; ++#endif ++ ++#define IMAGE_SIZEOF_SHORT_NAME 8 ++ ++typedef struct _IMAGE_SECTION_HEADER { ++ BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; ++ union { ++ DWORD PhysicalAddress; ++ DWORD VirtualSize; ++ } Misc; ++ DWORD VirtualAddress; ++ DWORD SizeOfRawData; ++ DWORD PointerToRawData; ++ DWORD PointerToRelocations; ++ DWORD PointerToLinenumbers; ++ WORD NumberOfRelocations; ++ WORD NumberOfLinenumbers; ++ DWORD Characteristics; ++} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; ++ ++#define IMAGE_SIZEOF_SECTION_HEADER 40 ++ ++#define IMAGE_FIRST_SECTION(ntheader) \ ++((PIMAGE_SECTION_HEADER)((LPBYTE)&((PIMAGE_NT_HEADERS)(ntheader))->OptionalHeader + \ ++((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader)) ++ ++/* These defines are for the Characteristics bitfield. */ ++/* #define IMAGE_SCN_TYPE_REG 0x00000000 - Reserved */ ++/* #define IMAGE_SCN_TYPE_DSECT 0x00000001 - Reserved */ ++/* #define IMAGE_SCN_TYPE_NOLOAD 0x00000002 - Reserved */ ++/* #define IMAGE_SCN_TYPE_GROUP 0x00000004 - Reserved */ ++#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* Reserved */ ++/* #define IMAGE_SCN_TYPE_COPY 0x00000010 - Reserved */ ++ ++#define IMAGE_SCN_CNT_CODE 0x00000020 ++#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 ++#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 ++ ++#define IMAGE_SCN_LNK_OTHER 0x00000100 ++#define IMAGE_SCN_LNK_INFO 0x00000200 ++/* #define IMAGE_SCN_TYPE_OVER 0x00000400 - Reserved */ ++#define IMAGE_SCN_LNK_REMOVE 0x00000800 ++#define IMAGE_SCN_LNK_COMDAT 0x00001000 ++ ++/* 0x00002000 - Reserved */ ++/* #define IMAGE_SCN_MEM_PROTECTED 0x00004000 - Obsolete */ ++#define IMAGE_SCN_MEM_FARDATA 0x00008000 ++ ++/* #define IMAGE_SCN_MEM_SYSHEAP 0x00010000 - Obsolete */ ++#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 ++#define IMAGE_SCN_MEM_16BIT 0x00020000 ++#define IMAGE_SCN_MEM_LOCKED 0x00040000 ++#define IMAGE_SCN_MEM_PRELOAD 0x00080000 ++ ++#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 ++#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 ++#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 ++#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 ++#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 /* Default */ ++#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 ++#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 ++#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 ++#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 ++#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 ++#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 ++#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 ++#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 ++#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 ++/* 0x00F00000 - Unused */ ++#define IMAGE_SCN_ALIGN_MASK 0x00F00000 ++ ++#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 ++ ++ ++#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 ++#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 ++#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 ++#define IMAGE_SCN_MEM_SHARED 0x10000000 ++#define IMAGE_SCN_MEM_EXECUTE 0x20000000 ++#define IMAGE_SCN_MEM_READ 0x40000000 ++#define IMAGE_SCN_MEM_WRITE 0x80000000 ++ ++typedef struct _IMAGE_SYMBOL { ++ union { ++ BYTE ShortName[8]; ++ struct { ++ DWORD Short; ++ DWORD Long; ++ } Name; ++ DWORD LongName[2]; ++ } N; ++ DWORD Value; ++ SHORT SectionNumber; ++ WORD Type; ++ BYTE StorageClass; ++ BYTE NumberOfAuxSymbols; ++} IMAGE_SYMBOL; ++typedef IMAGE_SYMBOL *PIMAGE_SYMBOL; ++ ++#define IMAGE_SIZEOF_SYMBOL 18 ++ ++typedef struct _IMAGE_LINENUMBER { ++ union { ++ DWORD SymbolTableIndex; ++ DWORD VirtualAddress; ++ } Type; ++ WORD Linenumber; ++} IMAGE_LINENUMBER; ++typedef IMAGE_LINENUMBER *PIMAGE_LINENUMBER; ++ ++#define IMAGE_SIZEOF_LINENUMBER 6 ++ ++typedef union _IMAGE_AUX_SYMBOL { ++ struct { ++ DWORD TagIndex; ++ union { ++ struct { ++ WORD Linenumber; ++ WORD Size; ++ } LnSz; ++ DWORD TotalSize; ++ } Misc; ++ union { ++ struct { ++ DWORD PointerToLinenumber; ++ DWORD PointerToNextFunction; ++ } Function; ++ struct { ++ WORD Dimension[4]; ++ } Array; ++ } FcnAry; ++ WORD TvIndex; ++ } Sym; ++ struct { ++ BYTE Name[IMAGE_SIZEOF_SYMBOL]; ++ } File; ++ struct { ++ DWORD Length; ++ WORD NumberOfRelocations; ++ WORD NumberOfLinenumbers; ++ DWORD CheckSum; ++ SHORT Number; ++ BYTE Selection; ++ } Section; ++} IMAGE_AUX_SYMBOL; ++typedef IMAGE_AUX_SYMBOL *PIMAGE_AUX_SYMBOL; ++ ++#define IMAGE_SIZEOF_AUX_SYMBOL 18 ++ ++#define IMAGE_SYM_UNDEFINED (SHORT)0 ++#define IMAGE_SYM_ABSOLUTE (SHORT)-1 ++#define IMAGE_SYM_DEBUG (SHORT)-2 ++ ++#define IMAGE_SYM_TYPE_NULL 0x0000 ++#define IMAGE_SYM_TYPE_VOID 0x0001 ++#define IMAGE_SYM_TYPE_CHAR 0x0002 ++#define IMAGE_SYM_TYPE_SHORT 0x0003 ++#define IMAGE_SYM_TYPE_INT 0x0004 ++#define IMAGE_SYM_TYPE_LONG 0x0005 ++#define IMAGE_SYM_TYPE_FLOAT 0x0006 ++#define IMAGE_SYM_TYPE_DOUBLE 0x0007 ++#define IMAGE_SYM_TYPE_STRUCT 0x0008 ++#define IMAGE_SYM_TYPE_UNION 0x0009 ++#define IMAGE_SYM_TYPE_ENUM 0x000A ++#define IMAGE_SYM_TYPE_MOE 0x000B ++#define IMAGE_SYM_TYPE_BYTE 0x000C ++#define IMAGE_SYM_TYPE_WORD 0x000D ++#define IMAGE_SYM_TYPE_UINT 0x000E ++#define IMAGE_SYM_TYPE_DWORD 0x000F ++#define IMAGE_SYM_TYPE_PCODE 0x8000 ++ ++#define IMAGE_SYM_DTYPE_NULL 0 ++#define IMAGE_SYM_DTYPE_POINTER 1 ++#define IMAGE_SYM_DTYPE_FUNCTION 2 ++#define IMAGE_SYM_DTYPE_ARRAY 3 ++ ++#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE )-1 ++#define IMAGE_SYM_CLASS_NULL 0x0000 ++#define IMAGE_SYM_CLASS_AUTOMATIC 0x0001 ++#define IMAGE_SYM_CLASS_EXTERNAL 0x0002 ++#define IMAGE_SYM_CLASS_STATIC 0x0003 ++#define IMAGE_SYM_CLASS_REGISTER 0x0004 ++#define IMAGE_SYM_CLASS_EXTERNAL_DEF 0x0005 ++#define IMAGE_SYM_CLASS_LABEL 0x0006 ++#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 0x0007 ++#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 0x0008 ++#define IMAGE_SYM_CLASS_ARGUMENT 0x0009 ++#define IMAGE_SYM_CLASS_STRUCT_TAG 0x000A ++#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 0x000B ++#define IMAGE_SYM_CLASS_UNION_TAG 0x000C ++#define IMAGE_SYM_CLASS_TYPE_DEFINITION 0x000D ++#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 0x000E ++#define IMAGE_SYM_CLASS_ENUM_TAG 0x000F ++#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 0x0010 ++#define IMAGE_SYM_CLASS_REGISTER_PARAM 0x0011 ++#define IMAGE_SYM_CLASS_BIT_FIELD 0x0012 ++ ++#define IMAGE_SYM_CLASS_FAR_EXTERNAL 0x0044 ++#define IMAGE_SYM_CLASS_BLOCK 0x0064 ++#define IMAGE_SYM_CLASS_FUNCTION 0x0065 ++#define IMAGE_SYM_CLASS_END_OF_STRUCT 0x0066 ++#define IMAGE_SYM_CLASS_FILE 0x0067 ++#define IMAGE_SYM_CLASS_SECTION 0x0068 ++#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069 ++ ++#define N_BTMASK 0x000F ++#define N_TMASK 0x0030 ++#define N_TMASK1 0x00C0 ++#define N_TMASK2 0x00F0 ++#define N_BTSHFT 4 ++#define N_TSHIFT 2 ++ ++#define BTYPE(x) ((x) & N_BTMASK) ++ ++#ifndef ISPTR ++#define ISPTR(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT)) ++#endif ++ ++#ifndef ISFCN ++#define ISFCN(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT)) ++#endif ++ ++#ifndef ISARY ++#define ISARY(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT)) ++#endif ++ ++#ifndef ISTAG ++#define ISTAG(x) ((x)==IMAGE_SYM_CLASS_STRUCT_TAG || (x)==IMAGE_SYM_CLASS_UNION_TAG || (x)==IMAGE_SYM_CLASS_ENUM_TAG) ++#endif ++ ++#ifndef INCREF ++#define INCREF(x) ((((x)&~N_BTMASK)<>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK)) ++#endif ++ ++#define IMAGE_COMDAT_SELECT_NODUPLICATES 1 ++#define IMAGE_COMDAT_SELECT_ANY 2 ++#define IMAGE_COMDAT_SELECT_SAME_SIZE 3 ++#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4 ++#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 ++#define IMAGE_COMDAT_SELECT_LARGEST 6 ++#define IMAGE_COMDAT_SELECT_NEWEST 7 ++ ++#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 ++#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 ++#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 ++ ++/* Export module directory */ ++ ++typedef struct _IMAGE_EXPORT_DIRECTORY { ++ DWORD Characteristics; ++ DWORD TimeDateStamp; ++ WORD MajorVersion; ++ WORD MinorVersion; ++ DWORD Name; ++ DWORD Base; ++ DWORD NumberOfFunctions; ++ DWORD NumberOfNames; ++ DWORD AddressOfFunctions; ++ DWORD AddressOfNames; ++ DWORD AddressOfNameOrdinals; ++} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; ++ ++/* Import name entry */ ++typedef struct _IMAGE_IMPORT_BY_NAME { ++ WORD Hint; ++ BYTE Name[1]; ++} IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME; ++ ++/* Import thunk */ ++typedef struct _IMAGE_THUNK_DATA32 { ++ union { ++ DWORD ForwarderString; ++ DWORD Function; ++ DWORD Ordinal; ++ DWORD AddressOfData; ++ } u1; ++} IMAGE_THUNK_DATA32,*PIMAGE_THUNK_DATA32; ++ ++typedef struct _IMAGE_THUNK_DATA64 { ++ union { ++ ULONGLONG ForwarderString; ++ ULONGLONG Function; ++ ULONGLONG Ordinal; ++ ULONGLONG AddressOfData; ++ } u1; ++} IMAGE_THUNK_DATA64,*PIMAGE_THUNK_DATA64; ++ ++#ifdef CONFIG_X86_64 ++typedef IMAGE_THUNK_DATA32 IMAGE_THUNK_DATA; ++typedef PIMAGE_THUNK_DATA32 PIMAGE_THUNK_DATA; ++#else ++typedef IMAGE_THUNK_DATA64 IMAGE_THUNK_DATA; ++typedef PIMAGE_THUNK_DATA64 PIMAGE_THUNK_DATA; ++#endif ++ ++/* Import module directory */ ++ ++typedef struct __packed _IMAGE_IMPORT_DESCRIPTOR { ++ union { ++ DWORD Characteristics; /* 0 for terminating null ++ * import descriptor */ ++ DWORD OriginalFirstThunk; /* RVA to original unbound ++ * IAT */ ++ } u; ++ DWORD TimeDateStamp; /* 0 if not bound, ++ * -1 if bound, and real date\time stamp ++ * in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ++ * (new BIND) ++ * otherwise date/time stamp of DLL bound to ++ * (Old BIND) ++ */ ++ DWORD ForwarderChain; /* -1 if no forwarders */ ++ DWORD Name; ++ /* RVA to IAT (if bound this IAT has actual addresses) */ ++ DWORD FirstThunk; ++} IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR; ++ ++#define IMAGE_ORDINAL_FLAG32 0x80000000 ++#define IMAGE_ORDINAL_FLAG64 0x8000000000000000UL ++#define IMAGE_SNAP_BY_ORDINAL32(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG32) != 0) ++#define IMAGE_SNAP_BY_ORDINAL64(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG64) != 0) ++#define IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) ++ ++#ifdef CONFIG_X86_64 ++#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG64 ++#define IMAGE_SNAP_BY_ORDINAL IMAGE_SNAP_BY_ORDINAL64 ++#else ++#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG32 ++#define IMAGE_SNAP_BY_ORDINAL IMAGE_SNAP_BY_ORDINAL32 ++#endif ++ ++typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR ++{ ++ DWORD TimeDateStamp; ++ WORD OffsetModuleName; ++ WORD NumberOfModuleForwarderRefs; ++/* Array of zero or more IMAGE_BOUND_FORWARDER_REF follows */ ++} IMAGE_BOUND_IMPORT_DESCRIPTOR, *PIMAGE_BOUND_IMPORT_DESCRIPTOR; ++ ++typedef struct _IMAGE_BOUND_FORWARDER_REF ++{ ++ DWORD TimeDateStamp; ++ WORD OffsetModuleName; ++ WORD Reserved; ++} IMAGE_BOUND_FORWARDER_REF, *PIMAGE_BOUND_FORWARDER_REF; ++ ++typedef struct _IMAGE_BASE_RELOCATION ++{ ++ DWORD VirtualAddress; ++ DWORD SizeOfBlock; ++ WORD TypeOffset[0]; ++} IMAGE_BASE_RELOCATION,*PIMAGE_BASE_RELOCATION; ++ ++typedef struct _IMAGE_RELOCATION ++{ ++ union { ++ DWORD VirtualAddress; ++ DWORD RelocCount; ++ } DUMMYUNIONNAME; ++ DWORD SymbolTableIndex; ++ WORD Type; ++} IMAGE_RELOCATION, *PIMAGE_RELOCATION; ++ ++#define IMAGE_SIZEOF_RELOCATION 10 ++ ++/* generic relocation types */ ++#define IMAGE_REL_BASED_ABSOLUTE 0 ++#define IMAGE_REL_BASED_HIGH 1 ++#define IMAGE_REL_BASED_LOW 2 ++#define IMAGE_REL_BASED_HIGHLOW 3 ++#define IMAGE_REL_BASED_HIGHADJ 4 ++#define IMAGE_REL_BASED_MIPS_JMPADDR 5 ++#define IMAGE_REL_BASED_SECTION 6 ++#define IMAGE_REL_BASED_REL 7 ++#define IMAGE_REL_BASED_MIPS_JMPADDR16 9 ++#define IMAGE_REL_BASED_IA64_IMM64 9 /* yes, 9 too */ ++#define IMAGE_REL_BASED_DIR64 10 ++#define IMAGE_REL_BASED_HIGH3ADJ 11 ++ ++/* I386 relocation types */ ++#define IMAGE_REL_I386_ABSOLUTE 0 ++#define IMAGE_REL_I386_DIR16 1 ++#define IMAGE_REL_I386_REL16 2 ++#define IMAGE_REL_I386_DIR32 6 ++#define IMAGE_REL_I386_DIR32NB 7 ++#define IMAGE_REL_I386_SEG12 9 ++#define IMAGE_REL_I386_SECTION 10 ++#define IMAGE_REL_I386_SECREL 11 ++#define IMAGE_REL_I386_REL32 20 ++ ++/* MIPS relocation types */ ++#define IMAGE_REL_MIPS_ABSOLUTE 0x0000 ++#define IMAGE_REL_MIPS_REFHALF 0x0001 ++#define IMAGE_REL_MIPS_REFWORD 0x0002 ++#define IMAGE_REL_MIPS_JMPADDR 0x0003 ++#define IMAGE_REL_MIPS_REFHI 0x0004 ++#define IMAGE_REL_MIPS_REFLO 0x0005 ++#define IMAGE_REL_MIPS_GPREL 0x0006 ++#define IMAGE_REL_MIPS_LITERAL 0x0007 ++#define IMAGE_REL_MIPS_SECTION 0x000A ++#define IMAGE_REL_MIPS_SECREL 0x000B ++#define IMAGE_REL_MIPS_SECRELLO 0x000C ++#define IMAGE_REL_MIPS_SECRELHI 0x000D ++#define IMAGE_REL_MIPS_JMPADDR16 0x0010 ++#define IMAGE_REL_MIPS_REFWORDNB 0x0022 ++#define IMAGE_REL_MIPS_PAIR 0x0025 ++ ++/* ALPHA relocation types */ ++#define IMAGE_REL_ALPHA_ABSOLUTE 0x0000 ++#define IMAGE_REL_ALPHA_REFLONG 0x0001 ++#define IMAGE_REL_ALPHA_REFQUAD 0x0002 ++#define IMAGE_REL_ALPHA_GPREL 0x0003 ++#define IMAGE_REL_ALPHA_LITERAL 0x0004 ++#define IMAGE_REL_ALPHA_LITUSE 0x0005 ++#define IMAGE_REL_ALPHA_GPDISP 0x0006 ++#define IMAGE_REL_ALPHA_BRADDR 0x0007 ++#define IMAGE_REL_ALPHA_HINT 0x0008 ++#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x0009 ++#define IMAGE_REL_ALPHA_REFHI 0x000A ++#define IMAGE_REL_ALPHA_REFLO 0x000B ++#define IMAGE_REL_ALPHA_PAIR 0x000C ++#define IMAGE_REL_ALPHA_MATCH 0x000D ++#define IMAGE_REL_ALPHA_SECTION 0x000E ++#define IMAGE_REL_ALPHA_SECREL 0x000F ++#define IMAGE_REL_ALPHA_REFLONGNB 0x0010 ++#define IMAGE_REL_ALPHA_SECRELLO 0x0011 ++#define IMAGE_REL_ALPHA_SECRELHI 0x0012 ++#define IMAGE_REL_ALPHA_REFQ3 0x0013 ++#define IMAGE_REL_ALPHA_REFQ2 0x0014 ++#define IMAGE_REL_ALPHA_REFQ1 0x0015 ++#define IMAGE_REL_ALPHA_GPRELLO 0x0016 ++#define IMAGE_REL_ALPHA_GPRELHI 0x0017 ++ ++/* PowerPC relocation types */ ++#define IMAGE_REL_PPC_ABSOLUTE 0x0000 ++#define IMAGE_REL_PPC_ADDR64 0x0001 ++#define IMAGE_REL_PPC_ADDR 0x0002 ++#define IMAGE_REL_PPC_ADDR24 0x0003 ++#define IMAGE_REL_PPC_ADDR16 0x0004 ++#define IMAGE_REL_PPC_ADDR14 0x0005 ++#define IMAGE_REL_PPC_REL24 0x0006 ++#define IMAGE_REL_PPC_REL14 0x0007 ++#define IMAGE_REL_PPC_TOCREL16 0x0008 ++#define IMAGE_REL_PPC_TOCREL14 0x0009 ++#define IMAGE_REL_PPC_ADDR32NB 0x000A ++#define IMAGE_REL_PPC_SECREL 0x000B ++#define IMAGE_REL_PPC_SECTION 0x000C ++#define IMAGE_REL_PPC_IFGLUE 0x000D ++#define IMAGE_REL_PPC_IMGLUE 0x000E ++#define IMAGE_REL_PPC_SECREL16 0x000F ++#define IMAGE_REL_PPC_REFHI 0x0010 ++#define IMAGE_REL_PPC_REFLO 0x0011 ++#define IMAGE_REL_PPC_PAIR 0x0012 ++#define IMAGE_REL_PPC_SECRELLO 0x0013 ++#define IMAGE_REL_PPC_SECRELHI 0x0014 ++#define IMAGE_REL_PPC_GPREL 0x0015 ++#define IMAGE_REL_PPC_TYPEMASK 0x00FF ++/* modifier bits */ ++#define IMAGE_REL_PPC_NEG 0x0100 ++#define IMAGE_REL_PPC_BRTAKEN 0x0200 ++#define IMAGE_REL_PPC_BRNTAKEN 0x0400 ++#define IMAGE_REL_PPC_TOCDEFN 0x0800 ++ ++/* SH3 ? relocation type */ ++#define IMAGE_REL_SH3_ABSOLUTE 0x0000 ++#define IMAGE_REL_SH3_DIRECT16 0x0001 ++#define IMAGE_REL_SH3_DIRECT 0x0002 ++#define IMAGE_REL_SH3_DIRECT8 0x0003 ++#define IMAGE_REL_SH3_DIRECT8_WORD 0x0004 ++#define IMAGE_REL_SH3_DIRECT8_LONG 0x0005 ++#define IMAGE_REL_SH3_DIRECT4 0x0006 ++#define IMAGE_REL_SH3_DIRECT4_WORD 0x0007 ++#define IMAGE_REL_SH3_DIRECT4_LONG 0x0008 ++#define IMAGE_REL_SH3_PCREL8_WORD 0x0009 ++#define IMAGE_REL_SH3_PCREL8_LONG 0x000A ++#define IMAGE_REL_SH3_PCREL12_WORD 0x000B ++#define IMAGE_REL_SH3_STARTOF_SECTION 0x000C ++#define IMAGE_REL_SH3_SIZEOF_SECTION 0x000D ++#define IMAGE_REL_SH3_SECTION 0x000E ++#define IMAGE_REL_SH3_SECREL 0x000F ++#define IMAGE_REL_SH3_DIRECT32_NB 0x0010 ++ ++/* ARM (Archimedes?) relocation types */ ++#define IMAGE_REL_ARM_ABSOLUTE 0x0000 ++#define IMAGE_REL_ARM_ADDR 0x0001 ++#define IMAGE_REL_ARM_ADDR32NB 0x0002 ++#define IMAGE_REL_ARM_BRANCH24 0x0003 ++#define IMAGE_REL_ARM_BRANCH11 0x0004 ++#define IMAGE_REL_ARM_SECTION 0x000E ++#define IMAGE_REL_ARM_SECREL 0x000F ++ ++/* IA64 relocation types */ ++#define IMAGE_REL_IA64_ABSOLUTE 0x0000 ++#define IMAGE_REL_IA64_IMM14 0x0001 ++#define IMAGE_REL_IA64_IMM22 0x0002 ++#define IMAGE_REL_IA64_IMM64 0x0003 ++#define IMAGE_REL_IA64_DIR 0x0004 ++#define IMAGE_REL_IA64_DIR64 0x0005 ++#define IMAGE_REL_IA64_PCREL21B 0x0006 ++#define IMAGE_REL_IA64_PCREL21M 0x0007 ++#define IMAGE_REL_IA64_PCREL21F 0x0008 ++#define IMAGE_REL_IA64_GPREL22 0x0009 ++#define IMAGE_REL_IA64_LTOFF22 0x000A ++#define IMAGE_REL_IA64_SECTION 0x000B ++#define IMAGE_REL_IA64_SECREL22 0x000C ++#define IMAGE_REL_IA64_SECREL64I 0x000D ++#define IMAGE_REL_IA64_SECREL 0x000E ++#define IMAGE_REL_IA64_LTOFF64 0x000F ++#define IMAGE_REL_IA64_DIR32NB 0x0010 ++#define IMAGE_REL_IA64_RESERVED_11 0x0011 ++#define IMAGE_REL_IA64_RESERVED_12 0x0012 ++#define IMAGE_REL_IA64_RESERVED_13 0x0013 ++#define IMAGE_REL_IA64_RESERVED_14 0x0014 ++#define IMAGE_REL_IA64_RESERVED_15 0x0015 ++#define IMAGE_REL_IA64_RESERVED_16 0x0016 ++#define IMAGE_REL_IA64_ADDEND 0x001F ++ ++/* archive format */ ++ ++#define IMAGE_ARCHIVE_START_SIZE 8 ++#define IMAGE_ARCHIVE_START "!\n" ++#define IMAGE_ARCHIVE_END "`\n" ++#define IMAGE_ARCHIVE_PAD "\n" ++#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " ++#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " ++ ++typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER ++{ ++ BYTE Name[16]; ++ BYTE Date[12]; ++ BYTE UserID[6]; ++ BYTE GroupID[6]; ++ BYTE Mode[8]; ++ BYTE Size[10]; ++ BYTE EndHeader[2]; ++} IMAGE_ARCHIVE_MEMBER_HEADER, *PIMAGE_ARCHIVE_MEMBER_HEADER; ++ ++#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 ++ ++/* ++ * Resource directory stuff ++ */ ++typedef struct _IMAGE_RESOURCE_DIRECTORY { ++ DWORD Characteristics; ++ DWORD TimeDateStamp; ++ WORD MajorVersion; ++ WORD MinorVersion; ++ WORD NumberOfNamedEntries; ++ WORD NumberOfIdEntries; ++ /* IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; */ ++} IMAGE_RESOURCE_DIRECTORY,*PIMAGE_RESOURCE_DIRECTORY; ++ ++#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 ++#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 ++ ++typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { ++ union { ++ struct { ++#ifdef BITFIELDS_BIGENDIAN ++ unsigned NameIsString:1; ++ unsigned NameOffset:31; ++#else ++ unsigned NameOffset:31; ++ unsigned NameIsString:1; ++#endif ++ } DUMMYSTRUCTNAME1; ++ DWORD Name; ++ struct { ++#ifdef WORDS_BIGENDIAN ++ WORD __pad; ++ WORD Id; ++#else ++ WORD Id; ++ WORD __pad; ++#endif ++ } DUMMYSTRUCTNAME2; ++ } DUMMYUNIONNAME1; ++ union { ++ DWORD OffsetToData; ++ struct { ++#ifdef BITFIELDS_BIGENDIAN ++ unsigned DataIsDirectory:1; ++ unsigned OffsetToDirectory:31; ++#else ++ unsigned OffsetToDirectory:31; ++ unsigned DataIsDirectory:1; ++#endif ++ } DUMMYSTRUCTNAME3; ++ } DUMMYUNIONNAME2; ++} IMAGE_RESOURCE_DIRECTORY_ENTRY,*PIMAGE_RESOURCE_DIRECTORY_ENTRY; ++ ++ ++typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING { ++ WORD Length; ++ CHAR NameString[ 1 ]; ++} IMAGE_RESOURCE_DIRECTORY_STRING,*PIMAGE_RESOURCE_DIRECTORY_STRING; +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/pnp.c linux-4.6-rc6-ndis/3rdparty/ndiswrapper/pnp.c +--- linux-4.6-rc6/3rdparty/ndiswrapper/pnp.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/pnp.c 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,697 @@ ++/* ++ * Copyright (C) 2005 Giridhar Pemmasani ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include "usb.h" ++#include "pnp.h" ++#include "wrapndis.h" ++#include "loader.h" ++ ++/* Functions callable from the NDIS driver */ ++wstdcall NTSTATUS pdoDispatchDeviceControl(struct device_object *pdo, ++ struct irp *irp); ++wstdcall NTSTATUS pdoDispatchPnp(struct device_object *pdo, struct irp *irp); ++wstdcall NTSTATUS pdoDispatchPower(struct device_object *pdo, struct irp *irp); ++ ++static NTSTATUS start_pdo(struct device_object *pdo) ++{ ++ int i, ret, count, resources_size; ++ struct wrap_device *wd; ++ struct pci_dev *pdev; ++ struct cm_partial_resource_descriptor *entry; ++ struct cm_partial_resource_list *partial_resource_list; ++ ++ ENTER1("%p, %p", pdo, pdo->reserved); ++ wd = pdo->reserved; ++ if (ntoskernel_init_device(wd)) ++ EXIT1(return STATUS_FAILURE); ++ if (wrap_is_usb_bus(wd->dev_bus)) { ++ if (usb_init_device(wd)) { ++ ntoskernel_exit_device(wd); ++ EXIT1(return STATUS_FAILURE); ++ } ++ EXIT1(return STATUS_SUCCESS); ++ } ++ if (!wrap_is_pci_bus(wd->dev_bus)) ++ EXIT1(return STATUS_SUCCESS); ++ pdev = wd->pci.pdev; ++ ret = pci_enable_device(pdev); ++ if (ret) { ++ ERROR("couldn't enable PCI device: %x", ret); ++ return STATUS_FAILURE; ++ } ++ ret = pci_request_regions(pdev, DRIVER_NAME); ++ if (ret) { ++ ERROR("couldn't request PCI regions: %x", ret); ++ goto err_enable; ++ } ++ pci_set_power_state(pdev, PCI_D0); ++#ifdef CONFIG_X86_64 ++ /* 64-bit broadcom driver doesn't work if DMA is allocated ++ * from over 1GB */ ++ if (wd->vendor == 0x14e4) { ++ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(30)) || ++ pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(30))) ++ WARNING("couldn't set DMA mask; this driver " ++ "may not work with more than 1GB RAM"); ++ } ++#endif ++ /* IRQ resource entry is filled in from pdev, instead of ++ * pci_resource macros */ ++ for (i = count = 0; pci_resource_start(pdev, i); i++) ++ if ((pci_resource_flags(pdev, i) & IORESOURCE_MEM) || ++ (pci_resource_flags(pdev, i) & IORESOURCE_IO)) ++ count++; ++ /* space for entry for IRQ is already in ++ * cm_partial_resource_list */ ++ resources_size = sizeof(struct cm_resource_list) + ++ sizeof(struct cm_partial_resource_descriptor) * count; ++ TRACE2("resources: %d, %d", count, resources_size); ++ wd->resource_list = kzalloc(resources_size, GFP_KERNEL); ++ if (!wd->resource_list) { ++ WARNING("couldn't allocate memory"); ++ goto err_regions; ++ } ++ wd->resource_list->count = 1; ++ wd->resource_list->list[0].interface_type = PCIBus; ++ /* bus_number is not used by WDM drivers */ ++ wd->resource_list->list[0].bus_number = pdev->bus->number; ++ ++ partial_resource_list = ++ &wd->resource_list->list->partial_resource_list; ++ partial_resource_list->version = 1; ++ partial_resource_list->revision = 1; ++ partial_resource_list->count = count + 1; ++ ++ for (i = count = 0; pci_resource_start(pdev, i); i++) { ++ entry = &partial_resource_list->partial_descriptors[count]; ++ TRACE2("%d", count); ++ if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { ++ entry->type = CmResourceTypeMemory; ++ entry->flags = CM_RESOURCE_MEMORY_READ_WRITE; ++ entry->share = CmResourceShareDeviceExclusive; ++ } else if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { ++ entry->type = CmResourceTypePort; ++ entry->flags = CM_RESOURCE_PORT_IO; ++ entry->share = CmResourceShareDeviceExclusive; ++#if 0 ++ } else if (pci_resource_flags(pdev, i) & IORESOURCE_DMA) { ++ /* it looks like no driver uses this resource */ ++ typeof(pci_resource_flags(pdev, 0)) flags; ++ entry->type = CmResourceTypeDma; ++ flags = pci_resource_flags(pdev, i); ++ if (flags & IORESOURCE_DMA_TYPEA) ++ entry->flags |= CM_RESOURCE_DMA_TYPE_A; ++ else if (flags & IORESOURCE_DMA_TYPEB) ++ entry->flags |= CM_RESOURCE_DMA_TYPE_B; ++ else if (flags & IORESOURCE_DMA_TYPEF) ++ entry->flags |= CM_RESOURCE_DMA_TYPE_F; ++ if (flags & IORESOURCE_DMA_8BIT) ++ entry->flags |= CM_RESOURCE_DMA_8; ++ else if (flags & IORESOURCE_DMA_16BIT) ++ entry->flags |= CM_RESOURCE_DMA_16; ++ /* what about 32bit DMA? */ ++ else if (flags & IORESOURCE_DMA_8AND16BIT) ++ entry->flags |= CM_RESOURCE_DMA_8_AND_16; ++ if (flags & IORESOURCE_DMA_MASTER) ++ entry->flags |= CM_RESOURCE_DMA_BUS_MASTER; ++ entry->u.dma.channel = pci_resource_start(pdev, i); ++ /* what should this be? */ ++ entry->u.dma.port = 1; ++#endif ++ } else ++ continue; ++ /* TODO: Add other resource types? */ ++ entry->u.generic.start = ++ (ULONG_PTR)pci_resource_start(pdev, i); ++ entry->u.generic.length = pci_resource_len(pdev, i); ++ count++; ++ } ++ ++ /* put IRQ resource at the end */ ++ entry = &partial_resource_list->partial_descriptors[count++]; ++ entry->type = CmResourceTypeInterrupt; ++ entry->flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; ++ /* we assume all devices use shared IRQ */ ++ entry->share = CmResourceShareShared; ++ /* as per documentation, interrupt level should be DIRQL, but ++ * examples from DDK as well some drivers, such as AR5211, ++ * RT8180L use interrupt level as interrupt vector also in ++ * NdisMRegisterInterrupt */ ++ entry->u.interrupt.level = pdev->irq; ++ entry->u.interrupt.vector = pdev->irq; ++ entry->u.interrupt.affinity = -1; ++ ++ TRACE2("resource list count %d, irq: %d", ++ partial_resource_list->count, pdev->irq); ++ pci_set_drvdata(pdev, wd); ++ EXIT1(return STATUS_SUCCESS); ++err_regions: ++ pci_release_regions(pdev); ++err_enable: ++ pci_disable_device(pdev); ++ wd->pci.pdev = NULL; ++ wd->pdo = NULL; ++ EXIT1(return STATUS_FAILURE); ++} ++ ++static void remove_pdo(struct device_object *pdo) ++{ ++ struct wrap_device *wd = pdo->reserved; ++ ++ ntoskernel_exit_device(wd); ++ if (wrap_is_pci_bus(wd->dev_bus)) { ++ struct pci_dev *pdev = wd->pci.pdev; ++ pci_release_regions(pdev); ++ pci_disable_device(pdev); ++ wd->pci.pdev = NULL; ++ pci_set_drvdata(pdev, NULL); ++ } else if (wrap_is_usb_bus(wd->dev_bus)) { ++ usb_exit_device(wd); ++ } ++ kfree(wd->resource_list); ++ wd->resource_list = NULL; ++ return; ++} ++ ++static NTSTATUS IoSendIrpTopDev(struct device_object *dev_obj, ULONG major_fn, ++ ULONG minor_fn, struct io_stack_location *sl) ++{ ++ NTSTATUS status; ++ struct nt_event event; ++ struct irp *irp; ++ struct io_stack_location *irp_sl; ++ struct device_object *top_dev = IoGetAttachedDeviceReference(dev_obj); ++ ++ KeInitializeEvent(&event, NotificationEvent, FALSE); ++ irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, top_dev, NULL, 0, NULL, ++ &event, NULL); ++ irp->io_status.status = STATUS_NOT_IMPLEMENTED; ++ irp->io_status.info = 0; ++ irp_sl = IoGetNextIrpStackLocation(irp); ++ if (sl) ++ memcpy(irp_sl, sl, sizeof(*irp_sl)); ++ irp_sl->major_fn = major_fn; ++ irp_sl->minor_fn = minor_fn; ++ status = IoCallDriver(top_dev, irp); ++ if (status == STATUS_PENDING) { ++ KeWaitForSingleObject(&event, Executive, KernelMode, ++ FALSE, NULL); ++ status = irp->io_status.status; ++ } ++ ObDereferenceObject(top_dev); ++ return status; ++} ++ ++wstdcall NTSTATUS pdoDispatchDeviceControl(struct device_object *pdo, ++ struct irp *irp) ++{ ++ NTSTATUS status; ++ struct wrap_device *wd = pdo->reserved; ++ ++ DUMP_IRP(irp); ++ (void)wd; ++ if (wrap_is_usb_bus(wd->dev_bus)) { ++ status = wrap_submit_irp(pdo, irp); ++ IOTRACE("status: %08X", status); ++ if (status != STATUS_PENDING) ++ IoCompleteRequest(irp, IO_NO_INCREMENT); ++ } else { ++ status = irp->io_status.status = STATUS_NOT_IMPLEMENTED; ++ IoCompleteRequest(irp, IO_NO_INCREMENT); ++ } ++ IOEXIT(return status); ++} ++WIN_FUNC_DECL(pdoDispatchDeviceControl,2) ++ ++wstdcall NTSTATUS pdoDispatchPnp(struct device_object *pdo, struct irp *irp) ++{ ++ struct io_stack_location *irp_sl; ++ NTSTATUS status; ++ struct wrap_device *wd = pdo->reserved; ++ ++ irp_sl = IoGetCurrentIrpStackLocation(irp); ++ TRACE2("%p %d:%d", pdo, irp_sl->major_fn, irp_sl->minor_fn); ++ switch (irp_sl->minor_fn) { ++ case IRP_MN_START_DEVICE: ++ status = start_pdo(pdo); ++ break; ++ case IRP_MN_QUERY_STOP_DEVICE: ++ case IRP_MN_STOP_DEVICE: ++ case IRP_MN_QUERY_REMOVE_DEVICE: ++ status = STATUS_SUCCESS; ++ break; ++ case IRP_MN_REMOVE_DEVICE: ++ remove_pdo(pdo); ++ status = STATUS_SUCCESS; ++ break; ++ case IRP_MN_QUERY_INTERFACE: ++ if (wrap_is_usb_bus(wd->dev_bus)) ++ status = usb_query_interface(wd, irp_sl); ++ else ++ status = STATUS_NOT_IMPLEMENTED; ++ break; ++ default: ++ TRACE2("fn %d not implemented", irp_sl->minor_fn); ++ status = STATUS_SUCCESS; ++ break; ++ } ++ irp->io_status.status = status; ++ TRACE2("status: %08X", status); ++ IoCompleteRequest(irp, IO_NO_INCREMENT); ++ IOEXIT(return status); ++} ++WIN_FUNC_DECL(pdoDispatchPnp,2) ++ ++wstdcall NTSTATUS pdoDispatchPower(struct device_object *pdo, struct irp *irp) ++{ ++ struct io_stack_location *irp_sl; ++ struct wrap_device *wd; ++ union power_state power_state; ++ struct pci_dev *pdev; ++ NTSTATUS status; ++ ++ irp_sl = IoGetCurrentIrpStackLocation(irp); ++ wd = pdo->reserved; ++ TRACE2("pdo: %p, fn: %d:%d, wd: %p", ++ pdo, irp_sl->major_fn, irp_sl->minor_fn, wd); ++ switch (irp_sl->minor_fn) { ++ case IRP_MN_WAIT_WAKE: ++ /* TODO: this is not complete/correct */ ++ TRACE2("state: %d, completion: %p", ++ irp_sl->params.power.state.system_state, ++ irp_sl->completion_routine); ++ IoMarkIrpPending(irp); ++ status = STATUS_PENDING; ++ break; ++ case IRP_MN_SET_POWER: ++ power_state = irp_sl->params.power.state; ++ if (power_state.device_state == PowerDeviceD0) { ++ TRACE2("resuming %p", wd); ++ if (wrap_is_pci_bus(wd->dev_bus)) { ++ pdev = wd->pci.pdev; ++ pci_restore_state(pdev); ++ if (wd->pci.wake_state == PowerDeviceD3) { ++ pci_enable_wake(wd->pci.pdev, ++ PCI_D3hot, 0); ++ pci_enable_wake(wd->pci.pdev, ++ PCI_D3cold, 0); ++ } ++ pci_set_power_state(pdev, PCI_D0); ++ } else if (wrap_is_usb_bus(wd->dev_bus)) { ++ wrap_resume_urbs(wd); ++ } ++ } else { ++ TRACE2("suspending device %p", wd); ++ if (wrap_is_pci_bus(wd->dev_bus)) { ++ pdev = wd->pci.pdev; ++ pci_save_state(pdev); ++ TRACE2("%d", wd->pci.wake_state); ++ if (wd->pci.wake_state == PowerDeviceD3) { ++ pci_enable_wake(wd->pci.pdev, ++ PCI_D3hot, 1); ++ pci_enable_wake(wd->pci.pdev, ++ PCI_D3cold, 1); ++ } ++ pci_set_power_state(pdev, PCI_D3hot); ++ } else if (wrap_is_usb_bus(wd->dev_bus)) { ++ wrap_suspend_urbs(wd); ++ } ++ } ++ status = STATUS_SUCCESS; ++ break; ++ case IRP_MN_QUERY_POWER: ++ status = STATUS_SUCCESS; ++ break; ++ default: ++ TRACE2("fn %d not implemented", irp_sl->minor_fn); ++ status = STATUS_SUCCESS; ++ break; ++ } ++ irp->io_status.status = status; ++ IoCompleteRequest(irp, IO_NO_INCREMENT); ++ return status; ++} ++WIN_FUNC_DECL(pdoDispatchPower,2) ++ ++static NTSTATUS pnp_set_device_power_state(struct wrap_device *wd, ++ enum device_power_state state) ++{ ++ NTSTATUS status; ++ struct device_object *pdo; ++ struct io_stack_location irp_sl; ++ ++ pdo = wd->pdo; ++ IOTRACE("%p, %p", pdo, IoGetAttachedDevice(pdo)); ++ memset(&irp_sl, 0, sizeof(irp_sl)); ++ irp_sl.params.power.state.device_state = state; ++ irp_sl.params.power.type = DevicePowerState; ++ if (state > PowerDeviceD0) { ++ status = IoSendIrpTopDev(pdo, IRP_MJ_POWER, IRP_MN_QUERY_POWER, ++ &irp_sl); ++ if (status != STATUS_SUCCESS) { ++ TRACE1("query of power to %d returns %08X", ++ state, status); ++ EXIT1(return status); ++ } ++ } ++ status = IoSendIrpTopDev(pdo, IRP_MJ_POWER, IRP_MN_SET_POWER, &irp_sl); ++ if (status != STATUS_SUCCESS) ++ WARNING("setting power to %d failed: %08X", state, status); ++ EXIT1(return status); ++} ++ ++static NTSTATUS pnp_start_device(struct wrap_device *wd) ++{ ++ struct device_object *fdo; ++ struct device_object *pdo; ++ struct io_stack_location irp_sl; ++ NTSTATUS status; ++ ++ pdo = wd->pdo; ++ /* TODO: for now we use same resources for both translated ++ * resources and raw resources */ ++ memset(&irp_sl, 0, sizeof(irp_sl)); ++ irp_sl.params.start_device.allocated_resources = ++ wd->resource_list; ++ irp_sl.params.start_device.allocated_resources_translated = ++ wd->resource_list; ++ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_START_DEVICE, &irp_sl); ++ fdo = IoGetAttachedDevice(pdo); ++ fdo->drv_obj->drv_ext->count++; ++ if (status != STATUS_SUCCESS) ++ WARNING("Windows driver couldn't initialize the device (%08X)", ++ status); ++ EXIT1(return status); ++} ++ ++#if 0 ++static NTSTATUS pnp_stop_device(struct wrap_device *wd) ++{ ++ struct device_object *pdo; ++ NTSTATUS status; ++ ++ pdo = wd->pdo; ++ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_QUERY_STOP_DEVICE, ++ NULL); ++ if (status != STATUS_SUCCESS) ++ WARNING("status: %08X", status); ++ /* for now we ignore query status */ ++ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_STOP_DEVICE, NULL); ++ if (status != STATUS_SUCCESS) ++ WARNING("status: %08X", status); ++ if (status != STATUS_SUCCESS) ++ WARNING("status: %08X", status); ++ EXIT2(return status); ++} ++#endif ++ ++static NTSTATUS pnp_remove_device(struct wrap_device *wd) ++{ ++ struct device_object *pdo, *fdo; ++ struct driver_object *fdo_drv_obj; ++ NTSTATUS status; ++ ++ pdo = wd->pdo; ++ fdo = IoGetAttachedDevice(pdo); ++ fdo_drv_obj = fdo->drv_obj; ++ TRACE2("%p, %p, %p", pdo, fdo, fdo_drv_obj); ++ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_QUERY_REMOVE_DEVICE, ++ NULL); ++ if (status != STATUS_SUCCESS) ++ WARNING("status: %08X", status); ++ ++ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_REMOVE_DEVICE, NULL); ++ if (status != STATUS_SUCCESS) ++ WARNING("status: %08X", status); ++ /* TODO: should we use count in drv_ext or driver's Object ++ * header reference count to keep count of devices associated ++ * with a driver? */ ++ if (status == STATUS_SUCCESS) ++ fdo_drv_obj->drv_ext->count--; ++ TRACE1("count: %d", fdo_drv_obj->drv_ext->count); ++ if ((LONG)fdo_drv_obj->drv_ext->count < 0) ++ WARNING("wrong count: %d", fdo_drv_obj->drv_ext->count); ++ if (fdo_drv_obj->drv_ext->count == 0) { ++ struct wrap_driver *wrap_driver; ++ TRACE1("unloading driver: %p", fdo_drv_obj); ++ wrap_driver = ++ IoGetDriverObjectExtension(fdo_drv_obj, ++ (void *)WRAP_DRIVER_CLIENT_ID); ++ if (fdo_drv_obj->unload) ++ LIN2WIN1(fdo_drv_obj->unload, fdo_drv_obj); ++ if (wrap_driver) { ++ mutex_lock(&loader_mutex); ++ unload_wrap_driver(wrap_driver); ++ mutex_unlock(&loader_mutex); ++ } else ++ ERROR("couldn't get wrap_driver"); ++ ObDereferenceObject(fdo_drv_obj); ++ } ++ IoDeleteDevice(pdo); ++ unload_wrap_device(wd); ++ EXIT1(return status); ++} ++ ++WIN_FUNC_DECL(IoInvalidDeviceRequest,2) ++ ++static struct device_object *alloc_pdo(struct driver_object *drv_obj) ++{ ++ struct device_object *pdo; ++ NTSTATUS status; ++ int i; ++ struct ansi_string ansi_name; ++ struct unicode_string unicode_name; ++ ++ RtlInitAnsiString(&ansi_name, "NDISpdo"); ++ if (RtlAnsiStringToUnicodeString(&unicode_name, &ansi_name, TRUE) == ++ STATUS_SUCCESS) { ++ status = IoCreateDevice(drv_obj, 0, &unicode_name, ++ FILE_DEVICE_UNKNOWN, ++ FILE_AUTOGENERATED_DEVICE_NAME, ++ FALSE, &pdo); ++ RtlFreeUnicodeString(&unicode_name); ++ } else { ++ status = IoCreateDevice(drv_obj, 0, NULL, ++ FILE_DEVICE_UNKNOWN, ++ FILE_AUTOGENERATED_DEVICE_NAME, ++ FALSE, &pdo); ++ } ++ TRACE1("%p, %d, %p", drv_obj, status, pdo); ++ if (status != STATUS_SUCCESS) ++ return NULL; ++ /* dispatch routines are called as Windows functions */ ++ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) ++ drv_obj->major_func[i] = WIN_FUNC_PTR(IoInvalidDeviceRequest,2); ++ drv_obj->major_func[IRP_MJ_INTERNAL_DEVICE_CONTROL] = ++ WIN_FUNC_PTR(pdoDispatchDeviceControl,2); ++ drv_obj->major_func[IRP_MJ_DEVICE_CONTROL] = ++ WIN_FUNC_PTR(pdoDispatchDeviceControl,2); ++ drv_obj->major_func[IRP_MJ_POWER] = WIN_FUNC_PTR(pdoDispatchPower,2); ++ drv_obj->major_func[IRP_MJ_PNP] = WIN_FUNC_PTR(pdoDispatchPnp,2); ++ return pdo; ++} ++ ++static int wrap_pnp_start_device(struct wrap_device *wd) ++{ ++ struct wrap_driver *driver; ++ struct device_object *pdo; ++ struct driver_object *pdo_drv_obj; ++ ++ ENTER1("wd: %p", wd); ++ ++ if (!((wrap_is_pci_bus(wd->dev_bus)) || ++ (wrap_is_usb_bus(wd->dev_bus)))) { ++ ERROR("bus type %d (%d) not supported", ++ WRAP_BUS(wd->dev_bus), wd->dev_bus); ++ EXIT1(return -EINVAL); ++ } ++ driver = load_wrap_driver(wd); ++ if (!driver) ++ return -ENODEV; ++ ++ wd->driver = driver; ++ wd->dev_bus = WRAP_DEVICE_BUS(driver->dev_type, WRAP_BUS(wd->dev_bus)); ++ TRACE1("dev type: %d, bus type: %d, %d", WRAP_DEVICE(wd->dev_bus), ++ WRAP_BUS(wd->dev_bus), wd->dev_bus); ++ TRACE1("%d, %d", driver->dev_type, wrap_is_usb_bus(wd->dev_bus)); ++ /* first create pdo */ ++ if (wrap_is_pci_bus(wd->dev_bus)) ++ pdo_drv_obj = find_bus_driver("PCI"); ++ else // if (wrap_is_usb_bus(wd->dev_bus)) ++ pdo_drv_obj = find_bus_driver("USB"); ++ if (!pdo_drv_obj) ++ return -EINVAL; ++ pdo = alloc_pdo(pdo_drv_obj); ++ if (!pdo) ++ return -ENOMEM; ++ wd->pdo = pdo; ++ pdo->reserved = wd; ++ if (WRAP_DEVICE(wd->dev_bus) == WRAP_NDIS_DEVICE) { ++ if (init_ndis_driver(driver->drv_obj)) { ++ IoDeleteDevice(pdo); ++ return -EINVAL; ++ } ++ } ++ TRACE1("%p", driver->drv_obj->drv_ext->add_device); ++ if (driver->drv_obj->drv_ext->add_device(driver->drv_obj, pdo) != ++ STATUS_SUCCESS) { ++ IoDeleteDevice(pdo); ++ return -ENOMEM; ++ } ++ if (pnp_start_device(wd) != STATUS_SUCCESS) { ++ /* TODO: we need proper cleanup, to deallocate memory, ++ * for example */ ++ pnp_remove_device(wd); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++int wrap_pnp_start_pci_device(struct pci_dev *pdev, ++ const struct pci_device_id *ent) ++{ ++ struct load_device load_device; ++ struct wrap_device *wd; ++ ++ ENTER1("called for %04x:%04x:%04x:%04x", pdev->vendor, pdev->device, ++ pdev->subsystem_vendor, pdev->subsystem_device); ++ ++ load_device.bus = WRAP_PCI_BUS; ++ load_device.vendor = pdev->vendor; ++ load_device.device = pdev->device; ++ load_device.subvendor = pdev->subsystem_vendor; ++ load_device.subdevice = pdev->subsystem_device; ++ wd = load_wrap_device(&load_device); ++ if (!wd) ++ EXIT1(return -ENODEV); ++ wd->pci.pdev = pdev; ++ return wrap_pnp_start_device(wd); ++} ++ ++void wrap_pnp_remove_pci_device(struct pci_dev *pdev) ++{ ++ struct wrap_device *wd; ++ ++ wd = (struct wrap_device *)pci_get_drvdata(pdev); ++ ENTER1("%p, %p", pdev, wd); ++ if (!wd) ++ EXIT1(return); ++ pnp_remove_device(wd); ++} ++ ++int wrap_pnp_suspend_pci_device(struct pci_dev *pdev, pm_message_t state) ++{ ++ struct wrap_device *wd; ++ ++ wd = (struct wrap_device *)pci_get_drvdata(pdev); ++ return pnp_set_device_power_state(wd, PowerDeviceD3); ++} ++ ++int wrap_pnp_resume_pci_device(struct pci_dev *pdev) ++{ ++ struct wrap_device *wd; ++ ++ wd = (struct wrap_device *)pci_get_drvdata(pdev); ++ return pnp_set_device_power_state(wd, PowerDeviceD0); ++} ++ ++#ifdef ENABLE_USB ++int wrap_pnp_start_usb_device(struct usb_interface *intf, ++ const struct usb_device_id *usb_id) ++{ ++ struct wrap_device *wd; ++ int ret; ++ struct usb_device *udev = interface_to_usbdev(intf); ++ ENTER1("%04x, %04x, %04x", udev->descriptor.idVendor, ++ udev->descriptor.idProduct, udev->descriptor.bDeviceClass); ++ ++ /* USB device (e.g., RNDIS) may have multiple interfaces; ++ initialize one interface only (is there a way to know which ++ of these interfaces is for network?) */ ++ ++ if ((wd = get_wrap_device(udev, WRAP_USB_BUS))) { ++ TRACE1("device already initialized: %p", wd); ++ usb_set_intfdata(intf, NULL); ++ ret = 0; ++ } else { ++ struct load_device load_device; ++ ++ load_device.bus = WRAP_USB_BUS; ++ load_device.vendor = le16_to_cpu(udev->descriptor.idVendor); ++ load_device.device = le16_to_cpu(udev->descriptor.idProduct); ++ load_device.subvendor = 0; ++ load_device.subdevice = 0; ++ wd = load_wrap_device(&load_device); ++ TRACE2("%p", wd); ++ if (wd) { ++ /* some devices (e.g., TI 4150, RNDIS) need ++ * full reset */ ++ ret = usb_reset_device(udev); ++ if (ret) ++ WARNING("reset failed: %d", ret); ++ usb_set_intfdata(intf, wd); ++ wd->usb.intf = intf; ++ wd->usb.udev = udev; ++ ret = wrap_pnp_start_device(wd); ++ } else ++ ret = -ENODEV; ++ } ++ ++ TRACE2("ret: %d", ret); ++ if (ret) ++ EXIT1(return ret); ++ else ++ return 0; ++} ++ ++void wrap_pnp_remove_usb_device(struct usb_interface *intf) ++{ ++ struct wrap_device *wd; ++ ++ wd = (struct wrap_device *)usb_get_intfdata(intf); ++ TRACE1("%p, %p", intf, wd); ++ if (wd == NULL) ++ EXIT1(return); ++ usb_set_intfdata(intf, NULL); ++ wd->usb.intf = NULL; ++ pnp_remove_device(wd); ++} ++ ++int wrap_pnp_suspend_usb_device(struct usb_interface *intf, pm_message_t state) ++{ ++ struct wrap_device *wd; ++ ++ wd = usb_get_intfdata(intf); ++ ENTER1("%p, %p", intf, wd); ++ if (!wd) ++ EXIT1(return 0); ++ if (pnp_set_device_power_state(wd, PowerDeviceD3)) ++ return -1; ++ return 0; ++} ++ ++int wrap_pnp_resume_usb_device(struct usb_interface *intf) ++{ ++ struct wrap_device *wd; ++ wd = usb_get_intfdata(intf); ++ ENTER1("%p, %p", intf, wd); ++ if (!wd) ++ EXIT1(return 0); ++ if (pnp_set_device_power_state(wd, PowerDeviceD0)) ++ return -1; ++ return 0; ++} ++ ++#endif // USB +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/pnp.h linux-4.6-rc6-ndis/3rdparty/ndiswrapper/pnp.h +--- linux-4.6-rc6/3rdparty/ndiswrapper/pnp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/pnp.h 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,36 @@ ++/* ++ * Copyright (C) 2005 Giridhar Pemmasani ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _PNP_H_ ++#define _PNP_H_ ++ ++#include "ntoskernel.h" ++#include "ndis.h" ++#include "wrapndis.h" ++ ++int wrap_pnp_start_pci_device(struct pci_dev *pdev, ++ const struct pci_device_id *ent); ++void wrap_pnp_remove_pci_device(struct pci_dev *pdev); ++int wrap_pnp_suspend_pci_device(struct pci_dev *pdev, pm_message_t state); ++int wrap_pnp_resume_pci_device(struct pci_dev *pdev); ++ ++int wrap_pnp_start_usb_device(struct usb_interface *intf, ++ const struct usb_device_id *usb_id); ++void wrap_pnp_remove_usb_device(struct usb_interface *intf); ++int wrap_pnp_suspend_usb_device(struct usb_interface *intf, ++ pm_message_t state); ++int wrap_pnp_resume_usb_device(struct usb_interface *intf); ++ ++#endif +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/proc.c linux-4.6-rc6-ndis/3rdparty/ndiswrapper/proc.c +--- linux-4.6-rc6/3rdparty/ndiswrapper/proc.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/proc.c 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,588 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++#include ++#include ++#include ++#include ++ ++#include "ndis.h" ++#include "iw_ndis.h" ++#include "wrapndis.h" ++#include "pnp.h" ++#include "wrapper.h" ++ ++#define MAX_PROC_STR_LEN 32 ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) ++static kuid_t proc_kuid; ++static kgid_t proc_kgid; ++#else ++#define proc_kuid proc_uid ++#define proc_kgid proc_gid ++#define kuid_t uid_t ++#define kgid_t gid_t ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++static inline struct inode *file_inode(struct file *f) ++{ ++ return f->f_dentry->d_inode; ++} ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0) ++static inline struct inode *file_inode(struct file *f) ++{ ++ return f->f_path.dentry->d_inode; ++} ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) ++static inline void proc_set_user(struct proc_dir_entry *de, kuid_t uid, ++ kgid_t gid) ++{ ++ de->uid = uid; ++ de->gid = gid; ++} ++ ++static inline void proc_remove(struct proc_dir_entry *de) ++{ ++ if (de) ++ remove_proc_entry(de->name, de->parent); ++} ++ ++static inline void *PDE_DATA(const struct inode *inode) ++{ ++ return PDE(inode)->data; ++} ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) ++static inline struct proc_dir_entry *proc_create_data(const char *name, ++ umode_t mode, struct proc_dir_entry *parent, ++ struct file_operations *fops, void *data) ++{ ++ struct proc_dir_entry *de; ++ ++ de = create_proc_entry(name, mode, parent); ++ if (de) { ++ de->data = data; ++ de->proc_fops = fops; ++ } ++ ++ return de; ++} ++#endif ++ ++static int do_proc_make_entry(const char *name, umode_t mode, ++ struct proc_dir_entry *parent, ++ struct file_operations *fops, kuid_t uid, ++ kgid_t gid, struct ndis_device *wnd) ++{ ++ struct proc_dir_entry *de; ++ ++ de = proc_create_data(name, mode, parent, fops, wnd); ++ if (de == NULL) { ++ ERROR("couldn't create proc entry for '%s'", name); ++ return -ENOMEM; ++ } ++ proc_set_user(de, uid, gid); ++ return 0; ++} ++ ++#define PROC_DECLARE_RO(name) \ ++ static int proc_##name##_open(struct inode *inode, struct file *file) \ ++ { \ ++ return single_open(file, proc_##name##_read, PDE_DATA(inode)); \ ++ } \ ++ static struct file_operations name##_fops = { \ ++ .owner = THIS_MODULE, \ ++ .open = proc_##name##_open, \ ++ .read = seq_read, \ ++ .llseek = seq_lseek, \ ++ .release = single_release, \ ++ }; ++ ++#define PROC_DECLARE_RW(name) \ ++ static int proc_##name##_open(struct inode *inode, struct file *file) \ ++ { \ ++ return single_open(file, proc_##name##_read, PDE_DATA(inode)); \ ++ } \ ++ static struct file_operations name##_fops = { \ ++ .owner = THIS_MODULE, \ ++ .open = proc_##name##_open, \ ++ .read = seq_read, \ ++ .llseek = seq_lseek, \ ++ .release = single_release, \ ++ .write = proc_##name##_write, \ ++ }; ++ ++#define proc_make_entry_ro(name, parent, wnd) \ ++ do_proc_make_entry(#name, S_IFREG | S_IRUSR | S_IRGRP, parent, \ ++ &name##_fops, proc_kuid, proc_kgid, wnd) ++#define proc_make_entry_rw(name, parent, wnd) \ ++ do_proc_make_entry(#name, \ ++ S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP, \ ++ parent, &name##_fops, proc_kuid, proc_kgid, wnd) ++ ++#define add_text(fmt, ...) seq_printf(sf, fmt, ##__VA_ARGS__) ++ ++static struct proc_dir_entry *wrap_procfs_entry; ++ ++static int proc_stats_read(struct seq_file *sf, void *v) ++{ ++ struct ndis_device *wnd = (struct ndis_device *)sf->private; ++ struct ndis_wireless_stats stats; ++ NDIS_STATUS res; ++ ndis_rssi rssi; ++ ++ res = mp_query(wnd, OID_802_11_RSSI, &rssi, sizeof(rssi)); ++ if (!res) ++ add_text("signal_level=%d dBm\n", (s32)rssi); ++ ++ res = mp_query(wnd, OID_802_11_STATISTICS, &stats, sizeof(stats)); ++ if (!res) { ++ add_text("tx_frames=%llu\n", stats.tx_frag); ++ add_text("tx_multicast_frames=%llu\n", stats.tx_multi_frag); ++ add_text("tx_failed=%llu\n", stats.failed); ++ add_text("tx_retry=%llu\n", stats.retry); ++ add_text("tx_multi_retry=%llu\n", stats.multi_retry); ++ add_text("tx_rtss_success=%llu\n", stats.rtss_succ); ++ add_text("tx_rtss_fail=%llu\n", stats.rtss_fail); ++ add_text("ack_fail=%llu\n", stats.ack_fail); ++ add_text("frame_duplicates=%llu\n", stats.frame_dup); ++ add_text("rx_frames=%llu\n", stats.rx_frag); ++ add_text("rx_multicast_frames=%llu\n", stats.rx_multi_frag); ++ add_text("fcs_errors=%llu\n", stats.fcs_err); ++ } ++ ++ return 0; ++} ++ ++PROC_DECLARE_RO(stats) ++ ++static int proc_encr_read(struct seq_file *sf, void *v) ++{ ++ struct ndis_device *wnd = (struct ndis_device *)sf->private; ++ int i, encr_status, auth_mode, infra_mode; ++ NDIS_STATUS res; ++ struct ndis_essid essid; ++ mac_address ap_address; ++ ++ res = mp_query(wnd, OID_802_11_BSSID, ++ &ap_address, sizeof(ap_address)); ++ if (res) ++ memset(ap_address, 0, ETH_ALEN); ++ add_text("ap_address=" MACSTRSEP "\n", MAC2STR(ap_address)); ++ ++ res = mp_query(wnd, OID_802_11_SSID, &essid, sizeof(essid)); ++ if (!res) ++ add_text("essid=%.*s\n", essid.length, essid.essid); ++ ++ res = mp_query_int(wnd, OID_802_11_ENCRYPTION_STATUS, &encr_status); ++ if (!res) { ++ typeof(&wnd->encr_info.keys[0]) tx_key; ++ add_text("tx_key=%u\n", wnd->encr_info.tx_key_index); ++ add_text("key="); ++ tx_key = &wnd->encr_info.keys[wnd->encr_info.tx_key_index]; ++ if (tx_key->length > 0) ++ for (i = 0; i < tx_key->length; i++) ++ add_text("%2.2X", tx_key->key[i]); ++ else ++ add_text("off"); ++ add_text("\n"); ++ add_text("encr_mode=%d\n", encr_status); ++ } ++ res = mp_query_int(wnd, OID_802_11_AUTHENTICATION_MODE, &auth_mode); ++ if (!res) ++ add_text("auth_mode=%d\n", auth_mode); ++ res = mp_query_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, &infra_mode); ++ add_text("mode=%s\n", (infra_mode == Ndis802_11IBSS) ? "adhoc" : ++ (infra_mode == Ndis802_11Infrastructure) ? "managed" : "auto"); ++ ++ return 0; ++} ++ ++PROC_DECLARE_RO(encr) ++ ++static int proc_hw_read(struct seq_file *sf, void *v) ++{ ++ struct ndis_device *wnd = (struct ndis_device *)sf->private; ++ struct ndis_configuration config; ++ enum ndis_power power_mode; ++ NDIS_STATUS res; ++ ndis_tx_power_level tx_power; ++ ULONG bit_rate; ++ ndis_rts_threshold rts_threshold; ++ ndis_fragmentation_threshold frag_threshold; ++ ndis_antenna antenna; ++ ULONG packet_filter; ++ int n; ++ mac_address mac; ++ char *hw_status[] = {"ready", "initializing", "resetting", "closing", ++ "not ready"}; ++ ++ res = mp_query_int(wnd, OID_GEN_HARDWARE_STATUS, &n); ++ if (res == NDIS_STATUS_SUCCESS && n >= 0 && n < ARRAY_SIZE(hw_status)) ++ add_text("status=%s\n", hw_status[n]); ++ ++ res = mp_query(wnd, OID_802_3_CURRENT_ADDRESS, mac, sizeof(mac)); ++ if (!res) ++ add_text("mac: " MACSTRSEP "\n", MAC2STR(mac)); ++ res = mp_query(wnd, OID_802_11_CONFIGURATION, &config, sizeof(config)); ++ if (!res) { ++ add_text("beacon_period=%u msec\n", config.beacon_period); ++ add_text("atim_window=%u msec\n", config.atim_window); ++ add_text("frequency=%u kHz\n", config.ds_config); ++ add_text("hop_pattern=%u\n", config.fh_config.hop_pattern); ++ add_text("hop_set=%u\n", config.fh_config.hop_set); ++ add_text("dwell_time=%u msec\n", config.fh_config.dwell_time); ++ } ++ ++ res = mp_query(wnd, OID_802_11_TX_POWER_LEVEL, ++ &tx_power, sizeof(tx_power)); ++ if (!res) ++ add_text("tx_power=%u mW\n", tx_power); ++ ++ res = mp_query(wnd, OID_GEN_LINK_SPEED, &bit_rate, sizeof(bit_rate)); ++ if (!res) ++ add_text("bit_rate=%u kBps\n", (u32)bit_rate / 10); ++ ++ res = mp_query(wnd, OID_802_11_RTS_THRESHOLD, ++ &rts_threshold, sizeof(rts_threshold)); ++ if (!res) ++ add_text("rts_threshold=%u bytes\n", rts_threshold); ++ ++ res = mp_query(wnd, OID_802_11_FRAGMENTATION_THRESHOLD, ++ &frag_threshold, sizeof(frag_threshold)); ++ if (!res) ++ add_text("frag_threshold=%u bytes\n", frag_threshold); ++ ++ res = mp_query_int(wnd, OID_802_11_POWER_MODE, &power_mode); ++ if (!res) ++ add_text("power_mode=%s\n", ++ (power_mode == NDIS_POWER_OFF) ? "always_on" : ++ (power_mode == NDIS_POWER_MAX) ? "max_savings" : ++ "min_savings"); ++ ++ res = mp_query(wnd, OID_802_11_NUMBER_OF_ANTENNAS, ++ &antenna, sizeof(antenna)); ++ if (!res) ++ add_text("num_antennas=%u\n", antenna); ++ ++ res = mp_query(wnd, OID_802_11_TX_ANTENNA_SELECTED, ++ &antenna, sizeof(antenna)); ++ if (!res) ++ add_text("tx_antenna=%u\n", antenna); ++ ++ res = mp_query(wnd, OID_802_11_RX_ANTENNA_SELECTED, ++ &antenna, sizeof(antenna)); ++ if (!res) ++ add_text("rx_antenna=%u\n", antenna); ++ ++ add_text("encryption_modes=%s%s%s%s%s%s%s\n", ++ test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr) ? ++ "WEP" : "none", ++ test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr) ? ++ "; TKIP with WPA" : "", ++ test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ? ++ ", WPA2" : "", ++ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ? ++ ", WPA2PSK" : "", ++ test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr) ? ++ "; AES/CCMP with WPA" : "", ++ test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ? ++ ", WPA2" : "", ++ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ? ++ ", WPA2PSK" : ""); ++ ++ res = mp_query_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, &packet_filter); ++ if (!res) { ++ if (packet_filter != wnd->packet_filter) ++ WARNING("wrong packet_filter? 0x%08x, 0x%08x\n", ++ packet_filter, wnd->packet_filter); ++ add_text("packet_filter: 0x%08x\n", packet_filter); ++ } ++ ++ return 0; ++} ++ ++PROC_DECLARE_RO(hw) ++ ++static int proc_settings_read(struct seq_file *sf, void *v) ++{ ++ struct ndis_device *wnd = (struct ndis_device *)sf->private; ++ struct wrap_device_setting *setting; ++ ++ add_text("hangcheck_interval=%d\n", (hangcheck_interval == 0) ? ++ (wnd->hangcheck_interval / HZ) : -1); ++ ++ list_for_each_entry(setting, &wnd->wd->settings, list) { ++ add_text("%s=%s\n", setting->name, setting->value); ++ } ++ ++ list_for_each_entry(setting, &wnd->wd->driver->settings, list) { ++ add_text("%s=%s\n", setting->name, setting->value); ++ } ++ ++ return 0; ++} ++ ++static ssize_t proc_settings_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ndis_device *wnd = PDE_DATA(file_inode(file)); ++ char setting[MAX_PROC_STR_LEN], *p; ++ unsigned int i; ++ NDIS_STATUS res; ++ ++ if (count > MAX_PROC_STR_LEN) ++ return -EINVAL; ++ ++ memset(setting, 0, sizeof(setting)); ++ if (copy_from_user(setting, buf, count)) ++ return -EFAULT; ++ ++ if ((p = strchr(setting, '\n'))) ++ *p = 0; ++ ++ if ((p = strchr(setting, '='))) ++ *p = 0; ++ ++ if (!strcmp(setting, "hangcheck_interval")) { ++ if (!p) ++ return -EINVAL; ++ p++; ++ i = simple_strtol(p, NULL, 10); ++ hangcheck_del(wnd); ++ if (i > 0) { ++ wnd->hangcheck_interval = i * HZ; ++ hangcheck_add(wnd); ++ } ++ } else if (!strcmp(setting, "suspend")) { ++ if (!p) ++ return -EINVAL; ++ p++; ++ i = simple_strtol(p, NULL, 10); ++ if (i <= 0 || i > 3) ++ return -EINVAL; ++ i = -1; ++ if (wrap_is_pci_bus(wnd->wd->dev_bus)) ++ i = wrap_pnp_suspend_pci_device(wnd->wd->pci.pdev, ++ PMSG_SUSPEND); ++ else if (wrap_is_usb_bus(wnd->wd->dev_bus)) ++ i = wrap_pnp_suspend_usb_device(wnd->wd->usb.intf, ++ PMSG_SUSPEND); ++ if (i) ++ return -EINVAL; ++ } else if (!strcmp(setting, "resume")) { ++ i = -1; ++ if (wrap_is_pci_bus(wnd->wd->dev_bus)) ++ i = wrap_pnp_resume_pci_device(wnd->wd->pci.pdev); ++ else if (wrap_is_usb_bus(wnd->wd->dev_bus)) ++ i = wrap_pnp_resume_usb_device(wnd->wd->usb.intf); ++ if (i) ++ return -EINVAL; ++ } else if (!strcmp(setting, "stats_enabled")) { ++ if (!p) ++ return -EINVAL; ++ p++; ++ i = simple_strtol(p, NULL, 10); ++ if (i > 0) ++ wnd->iw_stats_enabled = TRUE; ++ else ++ wnd->iw_stats_enabled = FALSE; ++ } else if (!strcmp(setting, "packet_filter")) { ++ if (!p) ++ return -EINVAL; ++ p++; ++ i = simple_strtol(p, NULL, 10); ++ res = mp_set_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, i); ++ if (res) ++ WARNING("setting packet_filter failed: %08X", res); ++ } else if (!strcmp(setting, "reinit")) { ++ if (ndis_reinit(wnd) != NDIS_STATUS_SUCCESS) ++ return -EFAULT; ++ } else { ++ struct ndis_configuration_parameter param; ++ struct unicode_string key; ++ struct ansi_string ansi; ++ ++ if (!p) ++ return -EINVAL; ++ p++; ++ RtlInitAnsiString(&ansi, p); ++ if (RtlAnsiStringToUnicodeString(¶m.data.string, &ansi, ++ TRUE) != STATUS_SUCCESS) ++ EXIT1(return -EFAULT); ++ param.type = NdisParameterString; ++ RtlInitAnsiString(&ansi, setting); ++ if (RtlAnsiStringToUnicodeString(&key, &ansi, ++ TRUE) != STATUS_SUCCESS) { ++ RtlFreeUnicodeString(¶m.data.string); ++ EXIT1(return -EINVAL); ++ } ++ NdisWriteConfiguration(&res, wnd->nmb, &key, ¶m); ++ RtlFreeUnicodeString(&key); ++ RtlFreeUnicodeString(¶m.data.string); ++ if (res != NDIS_STATUS_SUCCESS) ++ return -EFAULT; ++ } ++ return count; ++} ++ ++PROC_DECLARE_RW(settings) ++ ++int wrap_procfs_add_ndis_device(struct ndis_device *wnd) ++{ ++ int ret; ++ ++ if (wrap_procfs_entry == NULL) ++ return -ENOMEM; ++ ++ if (wnd->procfs_iface) { ++ ERROR("%s already registered?", wnd->net_dev->name); ++ return -EINVAL; ++ } ++ wnd->procfs_iface = proc_mkdir(wnd->net_dev->name, wrap_procfs_entry); ++ if (wnd->procfs_iface == NULL) { ++ ERROR("couldn't create proc directory"); ++ return -ENOMEM; ++ } ++ proc_set_user(wnd->procfs_iface, proc_kuid, proc_kgid); ++ ++ ret = proc_make_entry_ro(hw, wnd->procfs_iface, wnd); ++ if (ret) ++ goto err_hw; ++ ++ ret = proc_make_entry_ro(stats, wnd->procfs_iface, wnd); ++ if (ret) ++ goto err_stats; ++ ++ ret = proc_make_entry_ro(encr, wnd->procfs_iface, wnd); ++ if (ret) ++ goto err_encr; ++ ++ ret = proc_make_entry_rw(settings, wnd->procfs_iface, wnd); ++ if (ret) ++ goto err_settings; ++ ++ return 0; ++ ++err_settings: ++ remove_proc_entry("encr", wnd->procfs_iface); ++err_encr: ++ remove_proc_entry("stats", wnd->procfs_iface); ++err_stats: ++ remove_proc_entry("hw", wnd->procfs_iface); ++err_hw: ++ proc_remove(wnd->procfs_iface); ++ wnd->procfs_iface = NULL; ++ return -ENOMEM; ++} ++ ++void wrap_procfs_remove_ndis_device(struct ndis_device *wnd) ++{ ++ struct proc_dir_entry *procfs_iface = xchg(&wnd->procfs_iface, NULL); ++ ++ if (procfs_iface == NULL) ++ return; ++ remove_proc_entry("hw", procfs_iface); ++ remove_proc_entry("stats", procfs_iface); ++ remove_proc_entry("encr", procfs_iface); ++ remove_proc_entry("settings", procfs_iface); ++ if (wrap_procfs_entry) ++ proc_remove(procfs_iface); ++} ++ ++static int proc_debug_read(struct seq_file *sf, void *v) ++{ ++#if ALLOC_DEBUG ++ enum alloc_type type; ++#endif ++ ++ add_text("%d\n", debug); ++#if ALLOC_DEBUG ++ for (type = 0; type < ALLOC_TYPE_MAX; type++) ++ add_text("total size of allocations in %s: %d\n", ++ alloc_type_name[type], alloc_size(type)); ++#endif ++ return 0; ++} ++ ++static ssize_t proc_debug_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ int i; ++ char setting[MAX_PROC_STR_LEN], *p; ++ ++ if (count > MAX_PROC_STR_LEN) ++ return -EINVAL; ++ ++ memset(setting, 0, sizeof(setting)); ++ if (copy_from_user(setting, buf, count)) ++ return -EFAULT; ++ ++ if ((p = strchr(setting, '\n'))) ++ *p = 0; ++ ++ if ((p = strchr(setting, '='))) ++ *p = 0; ++ ++ i = simple_strtol(setting, NULL, 10); ++ if (i >= 0 && i < 10) ++ debug = i; ++ else ++ return -EINVAL; ++ return count; ++} ++ ++PROC_DECLARE_RW(debug) ++ ++int wrap_procfs_init(void) ++{ ++ int ret; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) ++ struct user_namespace *ns = current_user_ns(); ++ proc_kuid = make_kuid(ns, proc_uid); ++ if (!uid_valid(proc_kuid)) { ++ ERROR("invalid UID\n"); ++ return -EINVAL; ++ } ++ proc_kgid = make_kgid(ns, proc_gid); ++ if (!gid_valid(proc_kgid)) { ++ ERROR("invalid GID\n"); ++ return -EINVAL; ++ } ++#endif ++ ++ wrap_procfs_entry = proc_mkdir(DRIVER_NAME, proc_net_root); ++ if (wrap_procfs_entry == NULL) { ++ ERROR("couldn't create procfs directory"); ++ return -ENOMEM; ++ } ++ proc_set_user(wrap_procfs_entry, proc_kuid, proc_kgid); ++ ++ ret = proc_make_entry_rw(debug, wrap_procfs_entry, NULL); ++ ++ return ret; ++} ++ ++void wrap_procfs_remove(void) ++{ ++ if (wrap_procfs_entry == NULL) ++ return; ++ remove_proc_entry("debug", wrap_procfs_entry); ++ proc_remove(wrap_procfs_entry); ++} +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/rtl.c linux-4.6-rc6-ndis/3rdparty/ndiswrapper/rtl.c +--- linux-4.6-rc6/3rdparty/ndiswrapper/rtl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/rtl.c 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,715 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * Copyright (C) 2006-2007 Giridhar Pemmasani ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include "ntoskernel.h" ++#include "rtl_exports.h" ++ ++wstdcall SIZE_T WIN_FUNC(RtlCompareMemory,3) ++ (const void *a, const void *b, SIZE_T len) ++{ ++ size_t i; ++ char *x, *y; ++ ++ ENTER1("%p %p %zd", a, b, len); ++ x = (char *)a; ++ y = (char *)b; ++ /* MSDN says this should return number of bytes that compare as ++ * equal. This can be interpreted as either all bytes that are ++ * equal in 'len' bytes or that only until the bytes compare as ++ * not equal. Initially we had it the former way, but Realtek driver ++ * doesn't like it that way - it takes many attempts to associate ++ * with WPA. ReactOS returns the number of bytes that are equal ++ * before the first differing byte. ++ * According to lords at #reactos, that is the way it should be ++ * and that msdn is wrong about it! ++ */ ++ for (i = 0; i < len && x[i] == y[i]; i++) ++ ; ++ return i; ++} ++ ++wstdcall void WIN_FUNC(RtlCopyMemory,3) ++ (void *dst, const void *src, SIZE_T length) ++{ ++ memcpy(dst, src, length); ++} ++ ++wstdcall void WIN_FUNC(RtlZeroMemory,2) ++ (void *dst, SIZE_T length) ++{ ++ memset(dst, 0, length); ++} ++ ++wstdcall void WIN_FUNC(RtlSecureZeroMemory,2) ++ (void *dst, SIZE_T length) ++{ ++ memset(dst, 0, length); ++} ++ ++wstdcall void WIN_FUNC(RtlFillMemory,3) ++ (void *dest, SIZE_T length, UCHAR fill) ++{ ++ memset(dest, fill, length); ++} ++ ++wstdcall void WIN_FUNC(RtlMoveMemory,3) ++ (void *dest, const void *src, SIZE_T length) ++{ ++ memmove(dest, src, length); ++} ++ ++wstdcall LONG WIN_FUNC(RtlCompareString,3) ++ (const struct ansi_string *s1, const struct ansi_string *s2, ++ BOOLEAN case_insensitive) ++{ ++ unsigned int len; ++ LONG ret = 0; ++ const char *p1, *p2; ++ ++ ENTER2(""); ++ len = min(s1->length, s2->length); ++ p1 = s1->buf; ++ p2 = s2->buf; ++ if (case_insensitive) ++ while (!ret && len--) ++ ret = toupper(*p1++) - toupper(*p2++); ++ else ++ while (!ret && len--) ++ ret = *p1++ - *p2++; ++ if (!ret) ++ ret = s1->length - s2->length; ++ EXIT2(return ret); ++} ++ ++wstdcall LONG WIN_FUNC(RtlCompareUnicodeString,3) ++ (const struct unicode_string *s1, const struct unicode_string *s2, ++ BOOLEAN case_insensitive) ++{ ++ unsigned int len; ++ LONG ret = 0; ++ const wchar_t *p1, *p2; ++ ++ ENTER2(""); ++ ++ len = min(s1->length, s2->length) / sizeof(wchar_t); ++ p1 = s1->buf; ++ p2 = s2->buf; ++ if (case_insensitive) ++ while (!ret && len--) ++ ret = toupper((u8)*p1++) - toupper((u8)*p2++); ++ else ++ while (!ret && len--) ++ ret = (u8)*p1++ - (u8)*p2++; ++ if (!ret) ++ ret = s1->length - s2->length; ++ TRACE2("len: %d, ret: %d", len, ret); ++ EXIT2(return ret); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(RtlEqualString,3) ++ (const struct ansi_string *s1, const struct ansi_string *s2, ++ BOOLEAN case_insensitive) ++{ ++ ENTER1(""); ++ if (s1->length != s2->length) ++ return FALSE; ++ return !RtlCompareString(s1, s2, case_insensitive); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(RtlEqualUnicodeString,3) ++ (const struct unicode_string *s1, const struct unicode_string *s2, ++ BOOLEAN case_insensitive) ++{ ++ if (s1->length != s2->length) ++ return FALSE; ++ return !RtlCompareUnicodeString(s1, s2, case_insensitive); ++} ++ ++wstdcall void WIN_FUNC(RtlCopyUnicodeString,2) ++ (struct unicode_string *dst, struct unicode_string *src) ++{ ++ ENTER1("%p, %p", dst, src); ++ if (src && src->buf && dst->buf) { ++ dst->length = min(src->length, dst->max_length); ++ memcpy(dst->buf, src->buf, dst->length); ++ if (dst->length < dst->max_length) ++ dst->buf[dst->length / sizeof(dst->buf[0])] = 0; ++ } else ++ dst->length = 0; ++ EXIT1(return); ++} ++ ++wstdcall void WIN_FUNC(RtlCopyString,2) ++ (struct ansi_string *dst, struct ansi_string *src) ++{ ++ ENTER1("%p, %p", dst, src); ++ if (src && src->buf && dst->buf) { ++ dst->length = min(src->length, dst->max_length); ++ memcpy(dst->buf, src->buf, dst->length); ++ if (dst->length < dst->max_length) ++ dst->buf[dst->length] = 0; ++ } else ++ dst->length = 0; ++ EXIT1(return); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlAppendUnicodeToString,2) ++ (struct unicode_string *dst, wchar_t *src) ++{ ++ if (src) { ++ int len; ++ for (len = 0; src[len]; len++) ++ ; ++ if (dst->length + (len * sizeof(dst->buf[0])) > dst->max_length) ++ return STATUS_BUFFER_TOO_SMALL; ++ memcpy(&dst->buf[dst->length], src, len * sizeof(dst->buf[0])); ++ dst->length += len * sizeof(dst->buf[0]); ++ if (dst->max_length > dst->length) ++ dst->buf[dst->length / sizeof(dst->buf[0])] = 0; ++ } ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlAppendUnicodeStringToString,2) ++ (struct unicode_string *dst, struct unicode_string *src) ++{ ++ if (dst->max_length < src->length + dst->length) ++ return STATUS_BUFFER_TOO_SMALL; ++ if (src->length) { ++ memcpy(&dst->buf[dst->length], src->buf, src->length); ++ dst->length += src->length; ++ if (dst->max_length > dst->length) ++ dst->buf[dst->length / sizeof(dst->buf[0])] = 0; ++ } ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++wstdcall ULONG WIN_FUNC(RtlxAnsiStringToUnicodeSize,1) ++ (const struct ansi_string *string) ++{ ++ int i; ++ ++ for (i = 0; i < string->max_length && string->buf[i]; i++) ++ ; ++ return i * sizeof(wchar_t); ++} ++ ++wstdcall ULONG WIN_FUNC(RtlxUnicodeStringToAnsiSize,1) ++ (const struct unicode_string *string) ++{ ++ int i; ++ ++ for (i = 0; i < string->max_length && string->buf[i]; i++) ++ ; ++ return i; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlAnsiStringToUnicodeString,3) ++ (struct unicode_string *dst, const struct ansi_string *src, ++ BOOLEAN alloc) ++{ ++ int i, n; ++ ++ n = RtlxAnsiStringToUnicodeSize(src); ++ TRACE2("%d, %d, %d, %d, %p", n, dst->max_length, src->length, ++ src->max_length, src->buf); ++ if (alloc == TRUE) { ++#if 0 ++ if (n == 0) { ++ dst->length = dst->max_length = 0; ++ dst->buf = NULL; ++ EXIT2(return STATUS_SUCCESS); ++ } ++#endif ++ dst->max_length = n + sizeof(dst->buf[0]); ++ dst->buf = ExAllocatePoolWithTag(NonPagedPool, ++ dst->max_length, 0); ++ if (!dst->buf) { ++ dst->max_length = dst->length = 0; ++ EXIT2(return STATUS_NO_MEMORY); ++ } ++ } else if (dst->max_length < n) ++ EXIT2(return STATUS_BUFFER_TOO_SMALL); ++ ++ dst->length = n; ++ n /= sizeof(dst->buf[0]); ++ for (i = 0; i < n; i++) ++ dst->buf[i] = src->buf[i]; ++ if (i * sizeof(dst->buf[0]) < dst->max_length) ++ dst->buf[i] = 0; ++ TRACE2("dst: length: %d, max_length: %d, string: %p", ++ dst->length, dst->max_length, src->buf); ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlUnicodeStringToAnsiString,3) ++ (struct ansi_string *dst, const struct unicode_string *src, ++ BOOLEAN alloc) ++{ ++ int i, n; ++ ++ n = RtlxUnicodeStringToAnsiSize(src); ++ TRACE2("%d, %d, %d, %d, %p", n, dst->max_length, src->length, ++ src->max_length, src->buf); ++ if (alloc == TRUE) { ++#if 0 ++ if (n == 0) { ++ dst->length = dst->max_length = 0; ++ dst->buf = NULL; ++ EXIT2(return STATUS_SUCCESS); ++ } ++#endif ++ dst->max_length = n + sizeof(dst->buf[0]); ++ dst->buf = ExAllocatePoolWithTag(NonPagedPool, ++ dst->max_length, 0); ++ if (!dst->buf) { ++ dst->max_length = dst->length = 0; ++ EXIT1(return STATUS_NO_MEMORY); ++ } ++ } else if (dst->max_length < n) ++ EXIT2(return STATUS_BUFFER_TOO_SMALL); ++ ++ dst->length = n; ++ for (i = 0; i < n; i++) ++ dst->buf[i] = src->buf[i]; ++ if (i < dst->max_length) ++ dst->buf[i] = 0; ++ TRACE2("string: %p, len: %d(%d)", dst->buf, dst->length, ++ dst->max_length); ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlUnicodeStringToInteger,3) ++ (struct unicode_string *ustring, ULONG base, ULONG *value) ++{ ++ int i, sign = 1; ++ ULONG res; ++ typeof(ustring->buf) string; ++ ++ if (ustring->length == 0) { ++ *value = 0; ++ return STATUS_SUCCESS; ++ } ++ ++ string = ustring->buf; ++ i = 0; ++ while (i < (ustring->length / sizeof(*string)) && string[i] == ' ') ++ i++; ++ if (string[i] == '+') ++ i++; ++ else if (string[i] == '-') { ++ i++; ++ sign = -1; ++ } ++ if (base == 0) { ++ base = 10; ++ if (i <= ((ustring->length / sizeof(*string)) - 2) && ++ string[i] == '0') { ++ i++; ++ if (string[i] == 'b') { ++ base = 2; ++ i++; ++ } else if (string[i] == 'o') { ++ base = 8; ++ i++; ++ } else if (string[i] == 'x') { ++ base = 16; ++ i++; ++ } ++ } ++ } ++ if (!(base == 2 || base == 8 || base == 10 || base == 16)) ++ EXIT2(return STATUS_INVALID_PARAMETER); ++ ++ for (res = 0; i < (ustring->length / sizeof(*string)); i++) { ++ int v; ++ if (isdigit((char)string[i])) ++ v = string[i] - '0'; ++ else if (isxdigit((char)string[i])) ++ v = tolower((char)string[i]) - 'a' + 10; ++ else ++ v = base; ++ if (v >= base) ++ EXIT2(return STATUS_INVALID_PARAMETER); ++ res = res * base + v; ++ } ++ *value = sign * res; ++ EXIT3(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlCharToInteger,3) ++ (const char *string, ULONG base, ULONG *value) ++{ ++ int sign = 1; ++ ULONG res; ++ ++ if (!string || !value) ++ EXIT2(return STATUS_INVALID_PARAMETER); ++ while (*string == ' ') ++ string++; ++ if (*string == '+') ++ string++; ++ else if (*string == '-') { ++ string++; ++ sign = -1; ++ } ++ if (base == 0) { ++ base = 10; ++ if (*string == '0') { ++ string++; ++ if (*string == 'b') { ++ base = 2; ++ string++; ++ } else if (*string == 'o') { ++ base = 8; ++ string++; ++ } else if (*string == 'x') { ++ base = 16; ++ string++; ++ } ++ } ++ } ++ if (!(base == 2 || base == 8 || base == 10 || base == 16)) ++ EXIT2(return STATUS_INVALID_PARAMETER); ++ ++ for (res = 0; *string; string++) { ++ int v; ++ if (isdigit(*string)) ++ v = *string - '0'; ++ else if (isxdigit(*string)) ++ v = tolower(*string) - 'a' + 10; ++ else ++ v = base; ++ if (v >= base) ++ EXIT2(return STATUS_INVALID_PARAMETER); ++ res = res * base + v; ++ } ++ *value = sign * res; ++ EXIT3(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlIntegerToUnicodeString,3) ++ (ULONG value, ULONG base, struct unicode_string *ustring) ++{ ++ typeof(ustring->buf) buf = ustring->buf; ++ int i; ++ ++ if (base == 0) ++ base = 10; ++ if (!(base == 2 || base == 8 || base == 10 || base == 16)) ++ return STATUS_INVALID_PARAMETER; ++ for (i = 0; value && i < ustring->max_length / sizeof(*buf); i++) { ++ int r; ++ r = value % base; ++ value /= base; ++ if (r < 10) ++ buf[i] = r + '0'; ++ else ++ buf[i] = r + 'a' - 10; ++ } ++ if (value) ++ return STATUS_BUFFER_OVERFLOW; ++ ustring->length = i * sizeof(*buf); ++ return STATUS_SUCCESS; ++} ++ ++wstdcall LARGE_INTEGER WIN_FUNC(RtlConvertUlongToLargeInteger,1) ++ (ULONG ul) ++{ ++ LARGE_INTEGER li = ul; ++ return li; ++} ++ ++wfastcall USHORT WIN_FUNC(RtlUshortByteSwap,1) ++ (USHORT src) ++{ ++ return __swab16(src); ++} ++ ++wfastcall ULONG WIN_FUNC(RtlUlongByteSwap,1) ++ (ULONG src) ++{ ++ /* ULONG is 32 bits for both 32-bit and 64-bit architectures */ ++ return __swab32(src); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlUpcaseUnicodeString,3) ++ (struct unicode_string *dst, struct unicode_string *src, BOOLEAN alloc) ++{ ++ USHORT i, n; ++ ++ if (alloc) { ++ dst->buf = ExAllocatePoolWithTag(NonPagedPool, src->length, 0); ++ if (dst->buf) ++ dst->max_length = src->length; ++ else ++ EXIT2(return STATUS_NO_MEMORY); ++ } else { ++ if (dst->max_length < src->length) ++ EXIT2(return STATUS_BUFFER_OVERFLOW); ++ } ++ ++ n = src->length / sizeof(src->buf[0]); ++ for (i = 0; i < n; i++) ++ dst->buf[i] = toupper(src->buf[i]); ++ ++ dst->length = src->length; ++ EXIT3(return STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(RtlInitUnicodeString,2) ++ (struct unicode_string *dst, const wchar_t *src) ++{ ++ ENTER2("%p", dst); ++ if (dst == NULL) ++ EXIT1(return); ++ if (src == NULL) { ++ dst->max_length = dst->length = 0; ++ dst->buf = NULL; ++ } else { ++ int i; ++ for (i = 0; (char)src[i]; i++) ++ ; ++ dst->buf = (typeof(dst->buf))src; ++ dst->length = i * sizeof(dst->buf[0]); ++ dst->max_length = (i + 1) * sizeof(dst->buf[0]); ++ } ++ EXIT1(return); ++} ++ ++wstdcall void WIN_FUNC(RtlInitAnsiString,2) ++ (struct ansi_string *dst, const char *src) ++{ ++ ENTER2("%p", dst); ++ if (dst == NULL) ++ EXIT2(return); ++ if (src == NULL) { ++ dst->max_length = dst->length = 0; ++ dst->buf = NULL; ++ } else { ++ int i; ++ for (i = 0; src[i]; i++) ++ ; ++ dst->buf = (typeof(dst->buf))src; ++ dst->length = i; ++ dst->max_length = i + 1; ++ } ++ TRACE2("%p", dst->buf); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(RtlInitString,2) ++ (struct ansi_string *dst, const char *src) ++{ ++ ENTER2("%p", dst); ++ RtlInitAnsiString(dst, src); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(RtlFreeUnicodeString,1) ++ (struct unicode_string *string) ++{ ++ ENTER2("%p", string); ++ if (string == NULL) ++ return; ++ if (string->buf) ++ ExFreePool(string->buf); ++ string->length = string->max_length = 0; ++ string->buf = NULL; ++ return; ++} ++ ++wstdcall void WIN_FUNC(RtlFreeAnsiString,1) ++ (struct ansi_string *string) ++{ ++ ENTER2("%p", string); ++ if (string == NULL) ++ return; ++ if (string->buf) ++ ExFreePool(string->buf); ++ string->length = string->max_length = 0; ++ string->buf = NULL; ++ return; ++} ++ ++/* guid string is of the form: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */ ++wstdcall NTSTATUS WIN_FUNC(RtlGUIDFromString,2) ++ (struct unicode_string *guid_string, struct guid *guid) ++{ ++ struct ansi_string ansi; ++ NTSTATUS ret; ++ int i, j, k, l, m; ++ ++ ret = RtlUnicodeStringToAnsiString(&ansi, guid_string, TRUE); ++ if (ret != STATUS_SUCCESS) ++ return ret; ++ if (ansi.length != 37 || ansi.buf[0] != '{' || ++ ansi.buf[36] != '}' || ansi.buf[9] != '-' || ++ ansi.buf[14] != '-' || ansi.buf[19] != '-' || ++ ansi.buf[24] != '-') { ++ RtlFreeAnsiString(&ansi); ++ EXIT2(return STATUS_INVALID_PARAMETER); ++ } ++ memcpy(&guid->data4, &ansi.buf[29], sizeof(guid->data3)); ++ /* set end of data3 for scanf */ ++ ansi.buf[29] = 0; ++ if (sscanf(&ansi.buf[1], "%x", &i) == 1 && ++ sscanf(&ansi.buf[10], "%x", &j) == 1 && ++ sscanf(&ansi.buf[15], "%x", &k) == 1 && ++ sscanf(&ansi.buf[20], "%x", &l) == 1 && ++ sscanf(&ansi.buf[25], "%x", &m) == 1) { ++ guid->data1 = (i << 16) | (j < 8) | k; ++ guid->data2 = l; ++ guid->data3 = m; ++ ret = STATUS_SUCCESS; ++ } else ++ ret = STATUS_INVALID_PARAMETER; ++ RtlFreeAnsiString(&ansi); ++ return ret; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlQueryRegistryValues,5) ++ (ULONG relative, wchar_t *path, struct rtl_query_registry_table *tbl, ++ void *context, void *env) ++{ ++ struct ansi_string ansi; ++ struct unicode_string unicode; ++ NTSTATUS status, ret; ++ static int i = 0; ++ ++ ENTER3("%x, %p", relative, tbl); ++// TODO(); ++ ++ RtlInitUnicodeString(&unicode, path); ++ if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) == ++ STATUS_SUCCESS) { ++ TRACE2("%s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ ret = STATUS_SUCCESS; ++ for (; tbl->name; tbl++) { ++ RtlInitUnicodeString(&unicode, tbl->name); ++ if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) == ++ STATUS_SUCCESS) { ++ TRACE2("name: %s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ TRACE2("flags: %08X", tbl->flags); ++ if (tbl->flags == RTL_QUERY_REGISTRY_DIRECT) { ++ TRACE2("type: %08X", tbl->def_type); ++ if (tbl->def_type == REG_DWORD) { ++ /* Atheros USB driver needs this, but ++ * don't know where and how to get its ++ * value */ ++ if (tbl->def_data) { ++ TRACE2("def_data: %x", ++ *(int *)tbl->def_data); ++ *(DWORD *)tbl->context = 0x5f292a + i++; ++// *(DWORD *)tbl->def_data; ++ } else ++ *(DWORD *)tbl->context = 0x2345dbe; ++ } ++ } else { ++ void *data; ++ ULONG type, length; ++ ++ if (!tbl->query_func) { ++ ERROR("oops: no query_func"); ++ ret = STATUS_INVALID_PARAMETER; ++ break; ++ } ++ if (tbl->flags & RTL_QUERY_REGISTRY_NOVALUE) { ++ data = NULL; ++ type = REG_NONE; ++ length = 0; ++ } else { ++ data = tbl->def_data; ++ type = tbl->def_type; ++ length = tbl->def_length;; ++ } ++ TRACE2("calling query_func: %p", tbl->query_func); ++ status = LIN2WIN6(tbl->query_func, tbl->name, type, ++ data, length, context, env); ++ TRACE2("status: %08X", status); ++ if (status) { ++ if (status == STATUS_BUFFER_TOO_SMALL) ++ ret = STATUS_BUFFER_TOO_SMALL; ++ else ++ EXIT2(return STATUS_INVALID_PARAMETER); ++ } ++ } ++ } ++ EXIT3(return ret); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlWriteRegistryValue,6) ++ (ULONG relative, wchar_t *path, wchar_t *name, ULONG type, ++ void *data, ULONG length) ++{ ++ struct ansi_string ansi; ++ struct unicode_string unicode; ++ ++ ENTER3("%d", relative); ++ TODO(); ++ ++ RtlInitUnicodeString(&unicode, path); ++ if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) == ++ STATUS_SUCCESS) { ++ TRACE2("%s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ RtlInitUnicodeString(&unicode, name); ++ if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) == ++ STATUS_SUCCESS) { ++ TRACE2("%s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ EXIT5(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlDeleteRegistryValue,3) ++ (ULONG relative, wchar_t *path, wchar_t *name) ++{ ++ return STATUS_SUCCESS; ++} ++ ++wstdcall void WIN_FUNC(RtlAssert,4) ++ (char *failed_assertion, char *file_name, ULONG line_num, char *message) ++{ ++ ERROR("assertion '%s' failed at %s line %d%s", ++ failed_assertion, file_name, line_num, message ? message : ""); ++ return; ++} ++ ++wstdcall void WIN_FUNC(RtlUnwind,0) ++ (void) ++{ ++ TODO(); ++} ++ ++wstdcall void WIN_FUNC(RtlRaiseException,1) ++ (void *exception_record) ++{ ++ TODO(); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(RtlIsServicePackVersionInstalled,1) ++ (ULONG version) ++{ ++ /* Assume we have all service packs */ ++ TRACE1("version: %d", version); ++ return TRUE; ++} +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/usb.c linux-4.6-rc6-ndis/3rdparty/ndiswrapper/usb.c +--- linux-4.6-rc6/3rdparty/ndiswrapper/usb.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/usb.c 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,1496 @@ ++/* ++ * Copyright (C) 2004 Jan Kiszka ++ * Copyright (C) 2005 Giridhar Pemmasani ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include "ndis.h" ++#include "usb.h" ++#include "usb_exports.h" ++ ++#ifdef USB_DEBUG ++static unsigned int urb_id = 0; ++ ++#define DUMP_WRAP_URB(wrap_urb, dir) \ ++ USBTRACE("urb %p (%d) %s: buf: %p, len: %d, pipe: 0x%x, %d", \ ++ (wrap_urb)->urb, (wrap_urb)->id, \ ++ (dir == USB_DIR_OUT) ? "going down" : "coming back", \ ++ (wrap_urb)->urb->transfer_buffer, \ ++ (wrap_urb)->urb->transfer_buffer_length, \ ++ (wrap_urb)->urb->pipe, (wrap_urb)->urb->status) ++ ++#define DUMP_URB_BUFFER(urb, dir) \ ++ while (debug >= 2) { \ ++ int i; \ ++ char msg[20], *t; \ ++ if (!urb->transfer_buffer) \ ++ break; \ ++ if (!((usb_pipein(urb->pipe) && dir == USB_DIR_IN) || \ ++ (usb_pipeout(urb->pipe) && dir == USB_DIR_OUT))) \ ++ break; \ ++ t = msg; \ ++ t += sprintf(t, "%d: ", (urb)->actual_length); \ ++ for (i = 0; i < urb->actual_length && \ ++ t < &msg[sizeof(msg) - 4]; i++) \ ++ t += sprintf(t, "%02X ", \ ++ ((char *)urb->transfer_buffer)[i]); \ ++ *t = 0; \ ++ USBTRACE("%s", msg); \ ++ break; \ ++ } ++ ++#else ++ ++#define DUMP_WRAP_URB(wrap_urb, dir) (void)0 ++#define DUMP_URB_BUFFER(urb, dir) (void)0 ++ ++#endif ++ ++#define CUR_ALT_SETTING(intf) (intf)->cur_altsetting ++ ++#ifndef USB_CTRL_SET_TIMEOUT ++#define USB_CTRL_SET_TIMEOUT 5000 ++#endif ++ ++#ifndef USB_CTRL_GET_TIMEOUT ++#define USB_CTRL_GET_TIMEOUT 5000 ++#endif ++ ++#ifndef URB_NO_TRANSFER_DMA_MAP ++#define URB_NO_TRANSFER_DMA_MAP 0 ++#endif ++ ++/* wrap_urb->flags */ ++/* transfer_buffer for urb is allocated; free it in wrap_free_urb */ ++#define WRAP_URB_COPY_BUFFER 0x01 ++ ++static inline int wrap_cancel_urb(struct wrap_urb *wrap_urb) ++{ ++ int ret; ++ USBTRACE("%p, %p, %d", wrap_urb, wrap_urb->urb, wrap_urb->state); ++ if (wrap_urb->state != URB_SUBMITTED) ++ USBEXIT(return -1); ++ ret = usb_unlink_urb(wrap_urb->urb); ++ USBTRACE("ret: %d", ret); ++ if (ret == -EINPROGRESS) ++ return 0; ++ else { ++ WARNING("unlink failed: %d", ret); ++ return ret; ++ } ++} ++ ++#define URB_STATUS(wrap_urb) (wrap_urb->urb->status) ++ ++static struct nt_list wrap_urb_complete_list; ++static spinlock_t wrap_urb_complete_list_lock; ++ ++static struct work_struct wrap_urb_complete_work; ++static void wrap_urb_complete_worker(struct work_struct *dummy); ++ ++static void kill_all_urbs(struct wrap_device *wd, int complete) ++{ ++ struct nt_list *ent; ++ struct wrap_urb *wrap_urb; ++ KIRQL irql; ++ ++ USBTRACE("%d", wd->usb.num_alloc_urbs); ++ while (1) { ++ IoAcquireCancelSpinLock(&irql); ++ ent = RemoveHeadList(&wd->usb.wrap_urb_list); ++ IoReleaseCancelSpinLock(irql); ++ if (!ent) ++ break; ++ wrap_urb = container_of(ent, struct wrap_urb, list); ++ if (wrap_urb->state == URB_SUBMITTED) { ++ WARNING("Windows driver %s didn't free urb: %p", ++ wd->driver->name, wrap_urb->urb); ++ if (!complete) ++ wrap_urb->urb->complete = NULL; ++ usb_kill_urb(wrap_urb->urb); ++ } ++ USBTRACE("%p, %p", wrap_urb, wrap_urb->urb); ++ usb_free_urb(wrap_urb->urb); ++ kfree(wrap_urb); ++ } ++ wd->usb.num_alloc_urbs = 0; ++} ++ ++/* for a given Linux urb status code, return corresponding NT urb status */ ++static USBD_STATUS wrap_urb_status(int urb_status) ++{ ++ switch (urb_status) { ++ case 0: ++ return USBD_STATUS_SUCCESS; ++ case -EPROTO: ++ return USBD_STATUS_TIMEOUT; ++ case -EILSEQ: ++ return USBD_STATUS_CRC; ++ case -EPIPE: ++ return USBD_STATUS_INVALID_PIPE_HANDLE; ++ case -ECOMM: ++ return USBD_STATUS_DATA_OVERRUN; ++ case -ENOSR: ++ return USBD_STATUS_DATA_UNDERRUN; ++ case -EOVERFLOW: ++ return USBD_STATUS_BABBLE_DETECTED; ++ case -EREMOTEIO: ++ return USBD_STATUS_ERROR_SHORT_TRANSFER;; ++ case -ENODEV: ++ case -ESHUTDOWN: ++ case -ENOENT: ++ return USBD_STATUS_DEVICE_GONE; ++ case -ENOMEM: ++ return USBD_STATUS_NO_MEMORY; ++ case -EINVAL: ++ return USBD_STATUS_REQUEST_FAILED; ++ default: ++ return USBD_STATUS_NOT_SUPPORTED; ++ } ++} ++ ++/* for a given USBD_STATUS, return its corresponding NTSTATUS (for irp) */ ++static NTSTATUS nt_urb_irp_status(USBD_STATUS nt_urb_status) ++{ ++ switch (nt_urb_status) { ++ case USBD_STATUS_SUCCESS: ++ return STATUS_SUCCESS; ++ case USBD_STATUS_DEVICE_GONE: ++ return STATUS_DEVICE_REMOVED; ++ case USBD_STATUS_PENDING: ++ return STATUS_PENDING; ++ case USBD_STATUS_NOT_SUPPORTED: ++ return STATUS_NOT_IMPLEMENTED; ++ case USBD_STATUS_NO_MEMORY: ++ return STATUS_NO_MEMORY; ++ case USBD_STATUS_REQUEST_FAILED: ++ return STATUS_NOT_SUPPORTED; ++ default: ++ return STATUS_FAILURE; ++ } ++} ++ ++static void wrap_free_urb(struct urb *urb) ++{ ++ struct wrap_urb *wrap_urb = urb->context; ++ struct irp *irp = wrap_urb->irp; ++ struct wrap_device *wd = IRP_WRAP_DEVICE(irp); ++ ++ USBTRACE("freeing urb: %p", urb); ++ irp->cancel_routine = NULL; ++ IRP_WRAP_URB(irp) = NULL; ++ if (wrap_urb->flags & WRAP_URB_COPY_BUFFER) { ++ USBTRACE("freeing DMA buffer for URB: %p %p", ++ urb, urb->transfer_buffer); ++ usb_free_coherent(wd->usb.udev, urb->transfer_buffer_length, ++ urb->transfer_buffer, urb->transfer_dma); ++ } ++ kfree(urb->setup_packet); ++ if (wd->usb.num_alloc_urbs > MAX_ALLOCATED_URBS) { ++ IoAcquireCancelSpinLock(&irp->cancel_irql); ++ RemoveEntryList(&wrap_urb->list); ++ wd->usb.num_alloc_urbs--; ++ IoReleaseCancelSpinLock(irp->cancel_irql); ++ usb_free_urb(urb); ++ kfree(wrap_urb); ++ } else { ++ wrap_urb->state = URB_FREE; ++ wrap_urb->flags = 0; ++ wrap_urb->irp = NULL; ++ } ++ return; ++} ++ ++void wrap_suspend_urbs(struct wrap_device *wd) ++{ ++ /* TODO: do we need to cancel urbs? */ ++ USBTRACE("%p, %d", wd, wd->usb.num_alloc_urbs); ++} ++ ++void wrap_resume_urbs(struct wrap_device *wd) ++{ ++ /* TODO: do we need to resubmit urbs? */ ++ USBTRACE("%p, %d", wd, wd->usb.num_alloc_urbs); ++} ++ ++wstdcall void wrap_cancel_irp(struct device_object *dev_obj, struct irp *irp) ++{ ++ struct urb *urb; ++ struct wrap_urb *wrap_urb = IRP_WRAP_URB(irp); ++ ++ /* NB: this function is called holding Cancel spinlock */ ++ USBENTER("irp: %p", irp); ++ urb = wrap_urb->urb; ++ USBTRACE("canceling urb %p", urb); ++ if (wrap_cancel_urb(IRP_WRAP_URB(irp))) { ++ irp->cancel = FALSE; ++ ERROR("urb %p can't be canceled: %d", urb, wrap_urb->state); ++ } else ++ USBTRACE("urb %p canceled", urb); ++ IoReleaseCancelSpinLock(irp->cancel_irql); ++ return; ++} ++WIN_FUNC_DECL(wrap_cancel_irp,2) ++ ++static struct urb *wrap_alloc_urb(struct irp *irp, unsigned int pipe, ++ void *buf, unsigned int buf_len) ++{ ++ struct urb *urb; ++ gfp_t alloc_flags; ++ struct wrap_urb *wrap_urb; ++ struct wrap_device *wd; ++ ++ USBENTER("irp: %p", irp); ++ wd = IRP_WRAP_DEVICE(irp); ++ ++ /* Don't interfere with URB cleanup by the kernel */ ++ if (test_bit(HW_DISABLED, &wd->hw_status)) ++ return NULL; ++ ++ alloc_flags = irql_gfp(); ++ IoAcquireCancelSpinLock(&irp->cancel_irql); ++ urb = NULL; ++ nt_list_for_each_entry(wrap_urb, &wd->usb.wrap_urb_list, list) { ++ if (cmpxchg(&wrap_urb->state, URB_FREE, ++ URB_ALLOCATED) == URB_FREE) { ++ urb = wrap_urb->urb; ++ /* Clean URB but keep the refcount */ ++ memset((char *)urb + sizeof(urb->kref), 0, ++ sizeof(*urb) - sizeof(urb->kref)); ++ break; ++ } ++ } ++ if (!urb) { ++ IoReleaseCancelSpinLock(irp->cancel_irql); ++ wrap_urb = kzalloc(sizeof(*wrap_urb), alloc_flags); ++ if (!wrap_urb) { ++ WARNING("couldn't allocate memory"); ++ return NULL; ++ } ++ urb = usb_alloc_urb(0, alloc_flags); ++ if (!urb) { ++ WARNING("couldn't allocate urb"); ++ kfree(wrap_urb); ++ return NULL; ++ } ++ IoAcquireCancelSpinLock(&irp->cancel_irql); ++ wrap_urb->urb = urb; ++ wrap_urb->state = URB_ALLOCATED; ++ InsertTailList(&wd->usb.wrap_urb_list, &wrap_urb->list); ++ wd->usb.num_alloc_urbs++; ++ } ++ ++#ifdef URB_ASYNC_UNLINK ++ urb->transfer_flags |= URB_ASYNC_UNLINK; ++#elif defined(USB_ASYNC_UNLINK) ++ urb->transfer_flags |= USB_ASYNC_UNLINK; ++#endif ++ urb->context = wrap_urb; ++ wrap_urb->irp = irp; ++ IRP_WRAP_URB(irp) = wrap_urb; ++ /* called as Windows function */ ++ irp->cancel_routine = WIN_FUNC_PTR(wrap_cancel_irp,2); ++ IoReleaseCancelSpinLock(irp->cancel_irql); ++ USBTRACE("urb: %p", urb); ++ ++ urb->transfer_buffer_length = buf_len; ++ if (buf_len && buf && (!virt_addr_valid(buf) ++#if defined(CONFIG_HIGHMEM) || defined(CONFIG_HIGHMEM4G) ++ || PageHighMem(virt_to_page(buf)) ++#endif ++ )) { ++ urb->transfer_buffer = ++ usb_alloc_coherent(wd->usb.udev, buf_len, alloc_flags, ++ &urb->transfer_dma); ++ if (!urb->transfer_buffer) { ++ WARNING("couldn't allocate dma buf"); ++ IoAcquireCancelSpinLock(&irp->cancel_irql); ++ irp->cancel_routine = NULL; ++ wrap_urb->state = URB_FREE; ++ wrap_urb->irp = NULL; ++ IRP_WRAP_URB(irp) = NULL; ++ IoReleaseCancelSpinLock(irp->cancel_irql); ++ return NULL; ++ } ++ if (urb->transfer_dma) ++ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++ wrap_urb->flags |= WRAP_URB_COPY_BUFFER; ++ if (usb_pipeout(pipe)) ++ memcpy(urb->transfer_buffer, buf, buf_len); ++ USBTRACE("DMA buf for urb %p: %p", urb, urb->transfer_buffer); ++ } else ++ urb->transfer_buffer = buf; ++ return urb; ++} ++ ++static USBD_STATUS wrap_submit_urb(struct irp *irp) ++{ ++ int ret; ++ struct wrap_urb *wrap_urb = IRP_WRAP_URB(irp); ++ struct urb *urb = wrap_urb->urb; ++ union nt_urb *nt_urb = IRP_URB(irp); ++ ++#ifdef USB_DEBUG ++ if (wrap_urb->state != URB_ALLOCATED) { ++ ERROR("urb %p is in wrong state: %d", ++ urb, wrap_urb->state); ++ NT_URB_STATUS(nt_urb) = USBD_STATUS_REQUEST_FAILED; ++ return NT_URB_STATUS(nt_urb); ++ } ++ wrap_urb->id = pre_atomic_add(urb_id, 1); ++#endif ++ DUMP_WRAP_URB(IRP_WRAP_URB(irp), USB_DIR_OUT); ++ irp->io_status.status = STATUS_PENDING; ++ irp->io_status.info = 0; ++ NT_URB_STATUS(nt_urb) = USBD_STATUS_PENDING; ++ IoMarkIrpPending(irp); ++ DUMP_URB_BUFFER(urb, USB_DIR_OUT); ++ USBTRACE("%p", urb); ++ wrap_urb->state = URB_SUBMITTED; ++ ret = usb_submit_urb(urb, irql_gfp()); ++ if (ret) { ++ USBTRACE("ret: %d", ret); ++ wrap_free_urb(urb); ++ /* we assume that IRP was not in pending state before */ ++ IoUnmarkIrpPending(irp); ++ NT_URB_STATUS(nt_urb) = wrap_urb_status(ret); ++ USBEXIT(return NT_URB_STATUS(nt_urb)); ++ } else ++ USBEXIT(return USBD_STATUS_PENDING); ++} ++ ++static void wrap_urb_complete(struct urb *urb ISR_PT_REGS_PARAM_DECL) ++{ ++ struct irp *irp; ++ struct wrap_urb *wrap_urb; ++ ++ wrap_urb = urb->context; ++ USBTRACE("%p (%p) completed", wrap_urb, urb); ++ irp = wrap_urb->irp; ++ DUMP_WRAP_URB(wrap_urb, USB_DIR_IN); ++ irp->cancel_routine = NULL; ++#ifdef USB_DEBUG ++ if (wrap_urb->state != URB_SUBMITTED) { ++ WARNING("urb %p in wrong state: %d (%d)", urb, wrap_urb->state, ++ urb->status); ++ return; ++ } ++#endif ++ wrap_urb->state = URB_COMPLETED; ++ spin_lock(&wrap_urb_complete_list_lock); ++ InsertTailList(&wrap_urb_complete_list, &wrap_urb->complete_list); ++ spin_unlock(&wrap_urb_complete_list_lock); ++ queue_work(ntos_wq, &wrap_urb_complete_work); ++} ++ ++/* one worker for all devices */ ++static void wrap_urb_complete_worker(struct work_struct *dummy) ++{ ++ struct irp *irp; ++ struct urb *urb; ++ struct usbd_bulk_or_intr_transfer *bulk_int_tx; ++ struct usbd_vendor_or_class_request *vc_req; ++ union nt_urb *nt_urb; ++ struct wrap_urb *wrap_urb; ++ struct nt_list *ent; ++ unsigned long flags; ++ ++ USBENTER(""); ++ while (1) { ++ spin_lock_irqsave(&wrap_urb_complete_list_lock, flags); ++ ent = RemoveHeadList(&wrap_urb_complete_list); ++ spin_unlock_irqrestore(&wrap_urb_complete_list_lock, flags); ++ if (!ent) ++ break; ++ wrap_urb = container_of(ent, struct wrap_urb, complete_list); ++ urb = wrap_urb->urb; ++#ifdef USB_DEBUG ++ if (wrap_urb->state != URB_COMPLETED && ++ wrap_urb->state != URB_INT_UNLINKED) ++ WARNING("urb %p in wrong state: %d", ++ urb, wrap_urb->state); ++#endif ++ irp = wrap_urb->irp; ++ DUMP_IRP(irp); ++ nt_urb = IRP_URB(irp); ++ USBTRACE("urb: %p, nt_urb: %p, status: %d", ++ urb, nt_urb, urb->status); ++ switch (urb->status) { ++ case 0: ++ /* successfully transferred */ ++ irp->io_status.info = urb->actual_length; ++ if (nt_urb->header.function == ++ URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER) { ++ bulk_int_tx = &nt_urb->bulk_int_transfer; ++ bulk_int_tx->transfer_buffer_length = ++ urb->actual_length; ++ DUMP_URB_BUFFER(urb, USB_DIR_IN); ++ if ((wrap_urb->flags & WRAP_URB_COPY_BUFFER) && ++ usb_pipein(urb->pipe)) ++ memcpy(bulk_int_tx->transfer_buffer, ++ urb->transfer_buffer, ++ urb->actual_length); ++ } else { // vendor or class request ++ vc_req = &nt_urb->vendor_class_request; ++ vc_req->transfer_buffer_length = ++ urb->actual_length; ++ DUMP_URB_BUFFER(urb, USB_DIR_IN); ++ if ((wrap_urb->flags & WRAP_URB_COPY_BUFFER) && ++ usb_pipein(urb->pipe)) ++ memcpy(vc_req->transfer_buffer, ++ urb->transfer_buffer, ++ urb->actual_length); ++ } ++ NT_URB_STATUS(nt_urb) = USBD_STATUS_SUCCESS; ++ irp->io_status.status = STATUS_SUCCESS; ++ break; ++ case -ENOENT: ++ case -ECONNRESET: ++ /* urb canceled */ ++ irp->io_status.info = 0; ++ TRACE2("urb %p canceled", urb); ++ NT_URB_STATUS(nt_urb) = USBD_STATUS_SUCCESS; ++ irp->io_status.status = STATUS_CANCELLED; ++ break; ++ default: ++ TRACE2("irp: %p, urb: %p, status: %d/%d", ++ irp, urb, urb->status, wrap_urb->state); ++ irp->io_status.info = 0; ++ NT_URB_STATUS(nt_urb) = wrap_urb_status(urb->status); ++ irp->io_status.status = ++ nt_urb_irp_status(NT_URB_STATUS(nt_urb)); ++ break; ++ } ++ wrap_free_urb(urb); ++ IoCompleteRequest(irp, IO_NO_INCREMENT); ++ } ++ USBEXIT(return); ++} ++ ++static USBD_STATUS wrap_bulk_or_intr_trans(struct irp *irp) ++{ ++ struct usb_endpoint_descriptor *pipe_handle; ++ struct urb *urb; ++ unsigned int pipe; ++ struct usbd_bulk_or_intr_transfer *bulk_int_tx; ++ USBD_STATUS status; ++ struct wrap_device *wd = IRP_WRAP_DEVICE(irp); ++ struct usb_device *udev = wd->usb.udev; ++ union nt_urb *nt_urb = IRP_URB(irp); ++ ++ bulk_int_tx = &nt_urb->bulk_int_transfer; ++ pipe_handle = bulk_int_tx->pipe_handle; ++ USBTRACE("flags: 0x%x, length: %u, buffer: %p, handle: %p", ++ bulk_int_tx->transfer_flags, ++ bulk_int_tx->transfer_buffer_length, ++ bulk_int_tx->transfer_buffer, pipe_handle); ++ ++ if (USBD_IS_BULK_PIPE(pipe_handle)) { ++ if (bulk_int_tx->transfer_flags & USBD_TRANSFER_DIRECTION_IN) ++ pipe = usb_rcvbulkpipe(udev, ++ pipe_handle->bEndpointAddress); ++ else ++ pipe = usb_sndbulkpipe(udev, ++ pipe_handle->bEndpointAddress); ++ } else { ++ if (bulk_int_tx->transfer_flags & USBD_TRANSFER_DIRECTION_IN) ++ pipe = usb_rcvintpipe(udev, ++ pipe_handle->bEndpointAddress); ++ else ++ pipe = usb_sndintpipe(udev, ++ pipe_handle->bEndpointAddress); ++ } ++ ++ DUMP_IRP(irp); ++ urb = wrap_alloc_urb(irp, pipe, bulk_int_tx->transfer_buffer, ++ bulk_int_tx->transfer_buffer_length); ++ if (!urb) { ++ ERROR("couldn't allocate urb"); ++ return USBD_STATUS_NO_MEMORY; ++ } ++ if (usb_pipein(pipe) && ++ (!(bulk_int_tx->transfer_flags & USBD_SHORT_TRANSFER_OK))) { ++ USBTRACE("short not ok"); ++ urb->transfer_flags |= URB_SHORT_NOT_OK; ++ } ++ if (usb_pipebulk(pipe)) { ++ usb_fill_bulk_urb(urb, udev, pipe, urb->transfer_buffer, ++ bulk_int_tx->transfer_buffer_length, ++ wrap_urb_complete, urb->context); ++ USBTRACE("submitting bulk urb %p on pipe 0x%x (ep 0x%x)", ++ urb, urb->pipe, pipe_handle->bEndpointAddress); ++ } else { ++ usb_fill_int_urb(urb, udev, pipe, urb->transfer_buffer, ++ bulk_int_tx->transfer_buffer_length, ++ wrap_urb_complete, urb->context, ++ pipe_handle->bInterval); ++ USBTRACE("submitting interrupt urb %p on pipe 0x%x (ep 0x%x), " ++ "intvl: %d", urb, urb->pipe, ++ pipe_handle->bEndpointAddress, pipe_handle->bInterval); ++ } ++ status = wrap_submit_urb(irp); ++ USBTRACE("status: %08X", status); ++ USBEXIT(return status); ++} ++ ++static USBD_STATUS wrap_vendor_or_class_req(struct irp *irp) ++{ ++ u8 req_type; ++ unsigned int pipe; ++ struct usbd_vendor_or_class_request *vc_req; ++ USBD_STATUS status; ++ struct urb *urb; ++ struct usb_ctrlrequest *dr; ++ struct wrap_device *wd = IRP_WRAP_DEVICE(irp); ++ struct usb_device *udev = wd->usb.udev; ++ union nt_urb *nt_urb = IRP_URB(irp); ++ ++ vc_req = &nt_urb->vendor_class_request; ++ USBTRACE("bits: %x, req: %x, val: %08x, index: %08x, flags: %x," ++ "buf: %p, len: %d", vc_req->reserved_bits, vc_req->request, ++ vc_req->value, vc_req->index, vc_req->transfer_flags, ++ vc_req->transfer_buffer, vc_req->transfer_buffer_length); ++ ++ USBTRACE("%x", nt_urb->header.function); ++ switch (nt_urb->header.function) { ++ case URB_FUNCTION_VENDOR_DEVICE: ++ req_type = USB_TYPE_VENDOR | USB_RECIP_DEVICE; ++ break; ++ case URB_FUNCTION_VENDOR_INTERFACE: ++ req_type = USB_TYPE_VENDOR | USB_RECIP_INTERFACE; ++ break; ++ case URB_FUNCTION_VENDOR_ENDPOINT: ++ req_type = USB_TYPE_VENDOR | USB_RECIP_ENDPOINT; ++ break; ++ case URB_FUNCTION_VENDOR_OTHER: ++ req_type = USB_TYPE_VENDOR | USB_RECIP_OTHER; ++ break; ++ case URB_FUNCTION_CLASS_DEVICE: ++ req_type = USB_TYPE_CLASS | USB_RECIP_DEVICE; ++ break; ++ case URB_FUNCTION_CLASS_INTERFACE: ++ req_type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; ++ break; ++ case URB_FUNCTION_CLASS_ENDPOINT: ++ req_type = USB_TYPE_CLASS | USB_RECIP_ENDPOINT; ++ break; ++ case URB_FUNCTION_CLASS_OTHER: ++ req_type = USB_TYPE_CLASS | USB_RECIP_OTHER; ++ break; ++ default: ++ ERROR("unknown request type: %x", nt_urb->header.function); ++ req_type = 0; ++ break; ++ } ++ ++ req_type |= vc_req->reserved_bits; ++ USBTRACE("req type: %08x", req_type); ++ ++ if (vc_req->transfer_flags & USBD_TRANSFER_DIRECTION_IN) { ++ pipe = usb_rcvctrlpipe(udev, 0); ++ req_type |= USB_DIR_IN; ++ USBTRACE("pipe: %x, dir in", pipe); ++ } else { ++ pipe = usb_sndctrlpipe(udev, 0); ++ req_type |= USB_DIR_OUT; ++ USBTRACE("pipe: %x, dir out", pipe); ++ } ++ urb = wrap_alloc_urb(irp, pipe, vc_req->transfer_buffer, ++ vc_req->transfer_buffer_length); ++ if (!urb) { ++ ERROR("couldn't allocate urb"); ++ return USBD_STATUS_NO_MEMORY; ++ } ++ ++ if (usb_pipein(pipe) && ++ (!(vc_req->transfer_flags & USBD_SHORT_TRANSFER_OK))) { ++ USBTRACE("short not ok"); ++ urb->transfer_flags |= URB_SHORT_NOT_OK; ++ } ++ ++ dr = kzalloc(sizeof(*dr), irql_gfp()); ++ if (!dr) { ++ ERROR("couldn't allocate memory"); ++ wrap_free_urb(urb); ++ return USBD_STATUS_NO_MEMORY; ++ } ++ dr->bRequestType = req_type; ++ dr->bRequest = vc_req->request; ++ dr->wValue = cpu_to_le16(vc_req->value); ++ dr->wIndex = cpu_to_le16((u16)vc_req->index); ++ dr->wLength = cpu_to_le16((u16)urb->transfer_buffer_length); ++ ++ usb_fill_control_urb(urb, udev, pipe, (unsigned char *)dr, ++ urb->transfer_buffer, urb->transfer_buffer_length, ++ wrap_urb_complete, urb->context); ++ status = wrap_submit_urb(irp); ++ USBTRACE("status: %08X", status); ++ USBEXIT(return status); ++} ++ ++static USBD_STATUS wrap_reset_pipe(struct usb_device *udev, struct irp *irp) ++{ ++ int ret; ++ union nt_urb *nt_urb; ++ struct usb_endpoint_descriptor *pipe_handle; ++ unsigned int pipe1, pipe2; ++ ++ nt_urb = IRP_URB(irp); ++ pipe_handle = nt_urb->pipe_req.pipe_handle; ++ /* TODO: not clear if both directions should be cleared? */ ++ if (USBD_IS_BULK_PIPE(pipe_handle)) { ++ pipe1 = usb_rcvbulkpipe(udev, pipe_handle->bEndpointAddress); ++ pipe2 = usb_sndbulkpipe(udev, pipe_handle->bEndpointAddress); ++ } else if (USBD_IS_INT_PIPE(pipe_handle)) { ++ pipe1 = usb_rcvintpipe(udev, pipe_handle->bEndpointAddress); ++ pipe2 = pipe1; ++ } else { ++ WARNING("invalid pipe %d", pipe_handle->bEndpointAddress); ++ return USBD_STATUS_INVALID_PIPE_HANDLE; ++ } ++ USBTRACE("ep: %d, pipe: 0x%x", pipe_handle->bEndpointAddress, pipe1); ++ ret = usb_clear_halt(udev, pipe1); ++ if (ret) ++ USBTRACE("resetting pipe %d failed: %d", pipe1, ret); ++ if (pipe2 != pipe1) { ++ ret = usb_clear_halt(udev, pipe2); ++ if (ret) ++ USBTRACE("resetting pipe %d failed: %d", pipe2, ret); ++ } ++// return wrap_urb_status(ret); ++ return USBD_STATUS_SUCCESS; ++} ++ ++static USBD_STATUS wrap_abort_pipe(struct usb_device *udev, struct irp *irp) ++{ ++ union nt_urb *nt_urb; ++ struct usb_endpoint_descriptor *pipe_handle; ++ struct wrap_urb *wrap_urb; ++ struct wrap_device *wd; ++ KIRQL irql; ++ ++ wd = IRP_WRAP_DEVICE(irp); ++ nt_urb = IRP_URB(irp); ++ pipe_handle = nt_urb->pipe_req.pipe_handle; ++ USBENTER("%p, %x", irp, pipe_handle->bEndpointAddress); ++ IoAcquireCancelSpinLock(&irql); ++ nt_list_for_each_entry(wrap_urb, &wd->usb.wrap_urb_list, list) { ++ USBTRACE("%p, %p, %d, %x, %x", wrap_urb, wrap_urb->urb, ++ wrap_urb->state, wrap_urb->urb->pipe, ++ usb_pipeendpoint(wrap_urb->urb->pipe)); ++ /* for WG111T driver, urbs for endpoint 0 should also ++ * be canceled */ ++ if ((usb_pipeendpoint(wrap_urb->urb->pipe) == ++ pipe_handle->bEndpointAddress) || ++ (usb_pipeendpoint(wrap_urb->urb->pipe) == 0)) { ++ if (wrap_cancel_urb(wrap_urb) == 0) ++ USBTRACE("canceled wrap_urb: %p", wrap_urb); ++ } ++ } ++ IoReleaseCancelSpinLock(irql); ++ NT_URB_STATUS(nt_urb) = USBD_STATUS_CANCELED; ++ USBEXIT(return USBD_STATUS_SUCCESS); ++} ++ ++static USBD_STATUS wrap_set_clear_feature(struct usb_device *udev, ++ struct irp *irp) ++{ ++ union nt_urb *nt_urb; ++ struct urb_control_feature_request *feat_req; ++ int ret = 0; ++ __u8 request, type; ++ __u16 feature; ++ ++ nt_urb = IRP_URB(irp); ++ feat_req = &nt_urb->feat_req; ++ feature = feat_req->feature_selector; ++ switch (nt_urb->header.function) { ++ case URB_FUNCTION_SET_FEATURE_TO_DEVICE: ++ request = USB_REQ_SET_FEATURE; ++ type = USB_DT_DEVICE; ++ break; ++ case URB_FUNCTION_SET_FEATURE_TO_INTERFACE: ++ request = USB_REQ_SET_FEATURE; ++ type = USB_DT_INTERFACE; ++ break; ++ case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT: ++ request = USB_REQ_SET_FEATURE; ++ type = USB_DT_ENDPOINT; ++ break; ++ case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE: ++ request = USB_REQ_CLEAR_FEATURE; ++ type = USB_DT_DEVICE; ++ break; ++ case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE: ++ request = USB_REQ_CLEAR_FEATURE; ++ type = USB_DT_INTERFACE; ++ break; ++ case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT: ++ request = USB_REQ_CLEAR_FEATURE; ++ type = USB_DT_ENDPOINT; ++ break; ++ default: ++ WARNING("invalid function: %x", nt_urb->header.function); ++ NT_URB_STATUS(nt_urb) = USBD_STATUS_NOT_SUPPORTED; ++ return NT_URB_STATUS(nt_urb); ++ } ++ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), request, type, ++ feature, feat_req->index, NULL, 0, 1000); ++ NT_URB_STATUS(nt_urb) = wrap_urb_status(ret); ++ USBEXIT(return NT_URB_STATUS(nt_urb)); ++} ++ ++static USBD_STATUS wrap_get_status_request(struct usb_device *udev, ++ struct irp *irp) ++{ ++ union nt_urb *nt_urb; ++ struct urb_control_get_status_request *status_req; ++ int ret = 0; ++ __u8 type; ++ ++ nt_urb = IRP_URB(irp); ++ status_req = &nt_urb->status_req; ++ switch (nt_urb->header.function) { ++ case URB_FUNCTION_GET_STATUS_FROM_DEVICE: ++ type = USB_RECIP_DEVICE; ++ break; ++ case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: ++ type = USB_RECIP_INTERFACE; ++ break; ++ case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: ++ type = USB_RECIP_ENDPOINT; ++ break; ++ default: ++ WARNING("invalid function: %x", nt_urb->header.function); ++ NT_URB_STATUS(nt_urb) = USBD_STATUS_NOT_SUPPORTED; ++ return NT_URB_STATUS(nt_urb); ++ } ++ assert(status_req->transfer_buffer_length == sizeof(u16)); ++ ret = usb_get_status(udev, type, status_req->index, ++ status_req->transfer_buffer); ++ if (ret >= 0) { ++ assert(ret <= status_req->transfer_buffer_length); ++ status_req->transfer_buffer_length = ret; ++ NT_URB_STATUS(nt_urb) = USBD_STATUS_SUCCESS; ++ } else ++ NT_URB_STATUS(nt_urb) = wrap_urb_status(ret); ++ USBEXIT(return NT_URB_STATUS(nt_urb)); ++} ++ ++static void set_intf_pipe_info(struct wrap_device *wd, ++ struct usb_interface *usb_intf, ++ struct usbd_interface_information *intf) ++{ ++ int i; ++ struct usb_endpoint_descriptor *ep; ++ struct usbd_pipe_information *pipe; ++ ++ for (i = 0; i < CUR_ALT_SETTING(usb_intf)->desc.bNumEndpoints; i++) { ++ ep = &(CUR_ALT_SETTING(usb_intf)->endpoint[i]).desc; ++ if (i >= intf->bNumEndpoints) { ++ ERROR("intf %p has only %d endpoints, " ++ "ignoring endpoints above %d", ++ intf, intf->bNumEndpoints, i); ++ break; ++ } ++ pipe = &intf->pipes[i]; ++ ++ if (pipe->flags & USBD_PF_CHANGE_MAX_PACKET) ++ USBTRACE("pkt_sz: %d: %d", pipe->wMaxPacketSize, ++ pipe->max_tx_size); ++ USBTRACE("driver wants max_tx_size to %d", ++ pipe->max_tx_size); ++ ++ pipe->wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize); ++ pipe->bEndpointAddress = ep->bEndpointAddress; ++ pipe->type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; ++ if (pipe->type == UsbdPipeTypeInterrupt) { ++ /* Windows and Linux differ in how the ++ * bInterval is interpreted */ ++ /* for low speed: ++ interval (Windows) -> frames per ms (Linux) ++ 0 to 15 -> 8 ++ 16 to 35 -> 16 ++ 36 to 255 -> 32 ++ ++ for full speed: interval -> frames per ms ++ 1 -> 1 ++ 2 to 3 -> 2 ++ 4 to 7 -> 4 ++ 8 to 15 -> 8 ++ 16 to 31 -> 16 ++ 32 to 255 -> 32 ++ ++ for high speed: interval -> microframes ++ 1 -> 1 ++ 2 -> 2 ++ 3 -> 4 ++ 4 -> 8 ++ 5 -> 16 ++ 6 -> 32 ++ 7 to 255 -> 32 ++ */ ++ if (wd->usb.udev->speed == USB_SPEED_LOW) ++ pipe->bInterval = ep->bInterval + 5; ++ else if (wd->usb.udev->speed == USB_SPEED_FULL) ++ pipe->bInterval = ep->bInterval; ++ else { ++ int j, k; ++ for (j = k = 1; j < ep->bInterval; k++) ++ j *= 2; ++ pipe->bInterval = k; ++ } ++ } ++ pipe->handle = ep; ++ USBTRACE("%d: ep 0x%x, type %d, pkt_sz %d, intv %d (%d)," ++ "type: %d, handle %p", i, ep->bEndpointAddress, ++ ep->bmAttributes, pipe->wMaxPacketSize, ep->bInterval, ++ pipe->bInterval, pipe->type, pipe->handle); ++ } ++} ++ ++static USBD_STATUS wrap_select_configuration(struct wrap_device *wd, ++ union nt_urb *nt_urb, ++ struct irp *irp) ++{ ++ int i, ret; ++ struct usbd_select_configuration *sel_conf; ++ struct usb_device *udev; ++ struct usbd_interface_information *intf; ++ struct usb_config_descriptor *config; ++ struct usb_interface *usb_intf; ++ ++ udev = wd->usb.udev; ++ sel_conf = &nt_urb->select_conf; ++ config = sel_conf->config; ++ USBTRACE("%p", config); ++ if (config == NULL) { ++ kill_all_urbs(wd, 1); ++ ret = usb_reset_configuration(udev); ++ return wrap_urb_status(ret); ++ } ++ ++ USBTRACE("conf: %d, type: %d, length: %d, numif: %d, attr: %08x", ++ config->bConfigurationValue, config->bDescriptorType, ++ config->wTotalLength, config->bNumInterfaces, ++ config->bmAttributes); ++ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), ++ USB_REQ_SET_CONFIGURATION, 0, ++ config->bConfigurationValue, 0, ++ NULL, 0, USB_CTRL_SET_TIMEOUT); ++ if (ret < 0) { ++ ERROR("ret: %d", ret); ++ return wrap_urb_status(ret); ++ } ++ sel_conf->handle = udev->actconfig; ++ intf = &sel_conf->intf; ++ for (i = 0; i < config->bNumInterfaces && intf->bLength > 0; ++ i++, intf = (((void *)intf) + intf->bLength)) { ++ ++ USBTRACE("intf: %d, alt setting: %d", ++ intf->bInterfaceNumber, intf->bAlternateSetting); ++ ret = usb_set_interface(udev, intf->bInterfaceNumber, ++ intf->bAlternateSetting); ++ if (ret < 0) { ++ ERROR("failed with %d", ret); ++ return wrap_urb_status(ret); ++ } ++ usb_intf = usb_ifnum_to_if(udev, intf->bInterfaceNumber); ++ if (!usb_intf) { ++ ERROR("couldn't obtain ifnum"); ++ return USBD_STATUS_REQUEST_FAILED; ++ } ++ USBTRACE("intf: %p, num ep: %d", intf, intf->bNumEndpoints); ++ set_intf_pipe_info(wd, usb_intf, intf); ++ } ++ return USBD_STATUS_SUCCESS; ++} ++ ++static USBD_STATUS wrap_select_interface(struct wrap_device *wd, ++ union nt_urb *nt_urb, ++ struct irp *irp) ++{ ++ int ret; ++ struct usbd_select_interface *sel_intf; ++ struct usb_device *udev; ++ struct usbd_interface_information *intf; ++ struct usb_interface *usb_intf; ++ ++ udev = wd->usb.udev; ++ sel_intf = &nt_urb->select_intf; ++ intf = &sel_intf->intf; ++ ++ ret = usb_set_interface(udev, intf->bInterfaceNumber, ++ intf->bAlternateSetting); ++ if (ret < 0) { ++ ERROR("failed with %d", ret); ++ return wrap_urb_status(ret); ++ } ++ usb_intf = usb_ifnum_to_if(udev, intf->bInterfaceNumber); ++ if (!usb_intf) { ++ ERROR("couldn't get interface information"); ++ return USBD_STATUS_REQUEST_FAILED; ++ } ++ USBTRACE("intf: %p, num ep: %d", usb_intf, intf->bNumEndpoints); ++ set_intf_pipe_info(wd, usb_intf, intf); ++ return USBD_STATUS_SUCCESS; ++} ++ ++static int wrap_usb_get_string(struct usb_device *udev, unsigned short langid, ++ unsigned char index, void *buf, int size) ++{ ++ int i, ret; ++ /* if langid is 0, return array of languages supported in ++ * buf */ ++ for (i = 0; i < 3; i++) { ++ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), ++ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, ++ (USB_DT_STRING << 8) + index, langid, ++ buf, size, USB_CTRL_GET_TIMEOUT); ++ if (ret > 0 || ret == -EPIPE) ++ break; ++ } ++ return ret; ++} ++ ++static USBD_STATUS wrap_get_descriptor(struct wrap_device *wd, ++ union nt_urb *nt_urb, struct irp *irp) ++{ ++ struct usbd_control_descriptor_request *control_desc; ++ int ret = 0; ++ struct usb_device *udev; ++ ++ udev = wd->usb.udev; ++ control_desc = &nt_urb->control_desc; ++ USBTRACE("desctype = %d, descindex = %d, transfer_buffer = %p," ++ "transfer_buffer_length = %d", control_desc->desc_type, ++ control_desc->index, control_desc->transfer_buffer, ++ control_desc->transfer_buffer_length); ++ ++ if (control_desc->desc_type == USB_DT_STRING) { ++ USBTRACE("langid: %x", control_desc->language_id); ++ ret = wrap_usb_get_string(udev, control_desc->language_id, ++ control_desc->index, ++ control_desc->transfer_buffer, ++ control_desc->transfer_buffer_length); ++ } else { ++ ret = usb_get_descriptor(udev, control_desc->desc_type, ++ control_desc->index, ++ control_desc->transfer_buffer, ++ control_desc->transfer_buffer_length); ++ } ++ if (ret < 0) { ++ USBTRACE("request %d failed: %d", control_desc->desc_type, ret); ++ control_desc->transfer_buffer_length = 0; ++ return wrap_urb_status(ret); ++ } else { ++ USBTRACE("ret: %08x", ret); ++ control_desc->transfer_buffer_length = ret; ++ irp->io_status.info = ret; ++ return USBD_STATUS_SUCCESS; ++ } ++} ++ ++static USBD_STATUS wrap_process_nt_urb(struct irp *irp) ++{ ++ USBD_STATUS status; ++ struct wrap_device *wd = IRP_WRAP_DEVICE(irp); ++ struct usb_device *udev = wd->usb.udev; ++ union nt_urb *nt_urb = IRP_URB(irp); ++ ++ USBENTER("nt_urb = %p, irp = %p, length = %d, function = %x", ++ nt_urb, irp, nt_urb->header.length, nt_urb->header.function); ++ ++ if (test_bit(HW_DISABLED, &wd->hw_status)) { ++ status = USBD_STATUS_DEVICE_GONE; ++ NT_URB_STATUS(nt_urb) = status; ++ return status; ++ } ++ ++ DUMP_IRP(irp); ++ switch (nt_urb->header.function) { ++ /* bulk/int and vendor/class urbs are submitted to ++ * Linux USB core; if the call is successful, urb's ++ * completion worker will return IRP later */ ++ case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: ++ USBTRACE("submitting bulk/int irp: %p", irp); ++ status = wrap_bulk_or_intr_trans(irp); ++ break; ++ ++ case URB_FUNCTION_VENDOR_DEVICE: ++ case URB_FUNCTION_VENDOR_INTERFACE: ++ case URB_FUNCTION_VENDOR_ENDPOINT: ++ case URB_FUNCTION_VENDOR_OTHER: ++ case URB_FUNCTION_CLASS_DEVICE: ++ case URB_FUNCTION_CLASS_INTERFACE: ++ case URB_FUNCTION_CLASS_ENDPOINT: ++ case URB_FUNCTION_CLASS_OTHER: ++ USBTRACE("submitting vendor/class irp: %p", irp); ++ status = wrap_vendor_or_class_req(irp); ++ break; ++ ++ /* rest are synchronous */ ++ case URB_FUNCTION_SELECT_CONFIGURATION: ++ status = wrap_select_configuration(wd, nt_urb, irp); ++ NT_URB_STATUS(nt_urb) = status; ++ break; ++ ++ case URB_FUNCTION_SELECT_INTERFACE: ++ status = wrap_select_interface(wd, nt_urb, irp); ++ NT_URB_STATUS(nt_urb) = status; ++ break; ++ ++ case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: ++ status = wrap_get_descriptor(wd, nt_urb, irp); ++ NT_URB_STATUS(nt_urb) = status; ++ break; ++ ++ case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL: ++ status = wrap_reset_pipe(udev, irp); ++ NT_URB_STATUS(nt_urb) = status; ++ break; ++ ++ case URB_FUNCTION_ABORT_PIPE: ++ status = wrap_abort_pipe(udev, irp); ++ break; ++ ++ case URB_FUNCTION_SET_FEATURE_TO_DEVICE: ++ case URB_FUNCTION_SET_FEATURE_TO_INTERFACE: ++ case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT: ++ case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE: ++ case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE: ++ case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT: ++ status = wrap_set_clear_feature(udev, irp); ++ break; ++ ++ case URB_FUNCTION_GET_STATUS_FROM_DEVICE: ++ case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: ++ case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: ++ status = wrap_get_status_request(udev, irp); ++ break; ++ ++ default: ++ ERROR("function %x not implemented", nt_urb->header.function); ++ status = NT_URB_STATUS(nt_urb) = USBD_STATUS_NOT_SUPPORTED; ++ break; ++ } ++ USBTRACE("status: %08X", status); ++ return status; ++} ++ ++static USBD_STATUS wrap_reset_port(struct irp *irp) ++{ ++ int ret, lock = 0; ++ struct wrap_device *wd; ++ ++ wd = IRP_WRAP_DEVICE(irp); ++ USBENTER("%p, %p", wd, wd->usb.udev); ++ lock = usb_lock_device_for_reset(wd->usb.udev, wd->usb.intf); ++ if (lock < 0) { ++ WARNING("locking failed: %d", lock); ++// return wrap_urb_status(lock); ++ return USBD_STATUS_SUCCESS; ++ } ++ ret = usb_reset_device(wd->usb.udev); ++ if (ret < 0) ++ USBTRACE("reset failed: %d", ret); ++ /* TODO: should reconfigure? */ ++ if (lock) ++ usb_unlock_device(wd->usb.udev); ++// return wrap_urb_status(ret); ++ return USBD_STATUS_SUCCESS; ++} ++ ++static USBD_STATUS wrap_get_port_status(struct irp *irp) ++{ ++ struct wrap_device *wd; ++ ULONG *status; ++ enum usb_device_state state; ++ ++ wd = IRP_WRAP_DEVICE(irp); ++ USBENTER("%p, %p", wd, wd->usb.udev); ++ status = IoGetCurrentIrpStackLocation(irp)->params.others.arg1; ++ state = wd->usb.udev->state; ++ if (state != USB_STATE_NOTATTACHED && ++ state != USB_STATE_SUSPENDED) { ++ *status |= USBD_PORT_CONNECTED; ++ if (state == USB_STATE_CONFIGURED) ++ *status |= USBD_PORT_ENABLED; ++ } ++ USBTRACE("state: %d, *status: %08X", state, *status); ++ return USBD_STATUS_SUCCESS; ++} ++ ++NTSTATUS wrap_submit_irp(struct device_object *pdo, struct irp *irp) ++{ ++ struct io_stack_location *irp_sl; ++ struct wrap_device *wd; ++ USBD_STATUS status; ++ struct usbd_idle_callback *idle_callback; ++ ++ USBENTER("%p, %p", pdo, irp); ++ wd = pdo->reserved; ++ if (wd->usb.intf == NULL) { ++ USBTRACE("%p", irp); ++ irp->io_status.status = STATUS_DEVICE_REMOVED; ++ irp->io_status.info = 0; ++ USBEXIT(return STATUS_DEVICE_REMOVED); ++ } ++ IRP_WRAP_DEVICE(irp) = wd; ++ irp_sl = IoGetCurrentIrpStackLocation(irp); ++ switch (irp_sl->params.dev_ioctl.code) { ++ case IOCTL_INTERNAL_USB_SUBMIT_URB: ++ status = wrap_process_nt_urb(irp); ++ break; ++ case IOCTL_INTERNAL_USB_RESET_PORT: ++ status = wrap_reset_port(irp); ++ break; ++ case IOCTL_INTERNAL_USB_GET_PORT_STATUS: ++ status = wrap_get_port_status(irp); ++ break; ++ case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: ++ idle_callback = irp_sl->params.dev_ioctl.type3_input_buf; ++ (void)idle_callback; ++ USBTRACE("suspend function: %p", idle_callback->callback); ++ status = USBD_STATUS_NOT_SUPPORTED; ++ break; ++ default: ++ ERROR("ioctl %08X NOT IMPLEMENTED", ++ irp_sl->params.dev_ioctl.code); ++ status = USBD_STATUS_NOT_SUPPORTED; ++ break; ++ } ++ ++ USBTRACE("status: %08X", status); ++ if (status == USBD_STATUS_PENDING) { ++ /* don't touch this IRP - it may have been already ++ * completed/returned */ ++ return STATUS_PENDING; ++ } else { ++ irp->io_status.status = nt_urb_irp_status(status); ++ if (status != USBD_STATUS_SUCCESS) ++ irp->io_status.info = 0; ++ USBEXIT(return irp->io_status.status); ++ } ++} ++ ++/* TODO: The example on msdn in reference section suggests that second ++ * argument should be an array of usbd_interface_information, but ++ * description and examples elsewhere suggest that it should be ++ * usbd_interface_list_entry structre. Which is correct? */ ++ ++wstdcall union nt_urb *WIN_FUNC(USBD_CreateConfigurationRequestEx,2) ++ (struct usb_config_descriptor *config, ++ struct usbd_interface_list_entry *intf_list) ++{ ++ int size, i, n; ++ struct usbd_interface_information *intf; ++ struct usbd_pipe_information *pipe; ++ struct usb_interface_descriptor *intf_desc; ++ struct usbd_select_configuration *select_conf; ++ ++ USBENTER("config = %p, intf_list = %p", config, intf_list); ++ ++ /* calculate size required; select_conf already has space for ++ * one intf structure */ ++ size = sizeof(*select_conf) - sizeof(*intf); ++ for (n = 0; n < config->bNumInterfaces; n++) { ++ i = intf_list[n].intf_desc->bNumEndpoints; ++ /* intf already has space for one pipe */ ++ size += sizeof(*intf) + (i - 1) * sizeof(*pipe); ++ } ++ /* don't use kmalloc - driver frees it with ExFreePool */ ++ select_conf = ExAllocatePoolWithTag(NonPagedPool, size, ++ POOL_TAG('L', 'U', 'S', 'B')); ++ if (!select_conf) { ++ WARNING("couldn't allocate memory"); ++ return NULL; ++ } ++ memset(select_conf, 0, size); ++ intf = &select_conf->intf; ++ select_conf->handle = config; ++ for (n = 0; n < config->bNumInterfaces && intf_list[n].intf_desc; n++) { ++ /* initialize 'intf' fields in intf_list so they point ++ * to appropriate entry; these may be read/written by ++ * driver after this function returns */ ++ intf_list[n].intf = intf; ++ intf_desc = intf_list[n].intf_desc; ++ ++ i = intf_desc->bNumEndpoints; ++ intf->bLength = sizeof(*intf) + (i - 1) * sizeof(*pipe); ++ ++ intf->bInterfaceNumber = intf_desc->bInterfaceNumber; ++ intf->bAlternateSetting = intf_desc->bAlternateSetting; ++ intf->bInterfaceClass = intf_desc->bInterfaceClass; ++ intf->bInterfaceSubClass = intf_desc->bInterfaceSubClass; ++ intf->bInterfaceProtocol = intf_desc->bInterfaceProtocol; ++ intf->bNumEndpoints = intf_desc->bNumEndpoints; ++ ++ pipe = &intf->pipes[0]; ++ for (i = 0; i < intf->bNumEndpoints; i++) { ++ memset(&pipe[i], 0, sizeof(*pipe)); ++ pipe[i].max_tx_size = ++ USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE; ++ } ++ intf->handle = intf_desc; ++ intf = (((void *)intf) + intf->bLength); ++ } ++ select_conf->header.function = URB_FUNCTION_SELECT_CONFIGURATION; ++ select_conf->header.length = size; ++ select_conf->config = config; ++ USBEXIT(return (union nt_urb *)select_conf); ++} ++ ++WIN_SYMBOL_MAP("_USBD_CreateConfigurationRequestEx@8", USBD_CreateConfigurationRequestEx) ++ ++wstdcall struct usb_interface_descriptor * ++WIN_FUNC(USBD_ParseConfigurationDescriptorEx,7) ++ (struct usb_config_descriptor *config, void *start, ++ LONG bInterfaceNumber, LONG bAlternateSetting, LONG bInterfaceClass, ++ LONG bInterfaceSubClass, LONG bInterfaceProtocol) ++{ ++ void *pos; ++ struct usb_interface_descriptor *intf; ++ ++ USBENTER("config = %p, start = %p, ifnum = %d, alt_setting = %d," ++ " class = %d, subclass = %d, proto = %d", config, start, ++ bInterfaceNumber, bAlternateSetting, bInterfaceClass, ++ bInterfaceSubClass, bInterfaceProtocol); ++ ++ for (pos = start; ++ pos < ((void *)config + le16_to_cpu(config->wTotalLength)); ++ pos += intf->bLength) { ++ ++ intf = pos; ++ ++ if ((intf->bDescriptorType == USB_DT_INTERFACE) && ++ ((bInterfaceNumber == -1) || ++ (intf->bInterfaceNumber == bInterfaceNumber)) && ++ ((bAlternateSetting == -1) || ++ (intf->bAlternateSetting == bAlternateSetting)) && ++ ((bInterfaceClass == -1) || ++ (intf->bInterfaceClass == bInterfaceClass)) && ++ ((bInterfaceSubClass == -1) || ++ (intf->bInterfaceSubClass == bInterfaceSubClass)) && ++ ((bInterfaceProtocol == -1) || ++ (intf->bInterfaceProtocol == bInterfaceProtocol))) { ++ USBTRACE("selected interface = %p", intf); ++ USBEXIT(return intf); ++ } ++ } ++ USBEXIT(return NULL); ++} ++ ++WIN_SYMBOL_MAP("_USBD_ParseConfigurationDescriptorEx@28", USBD_ParseConfigurationDescriptorEx) ++ ++wstdcall union nt_urb *WIN_FUNC(USBD_CreateConfigurationRequest,2) ++ (struct usb_config_descriptor *config, USHORT *size) ++{ ++ union nt_urb *nt_urb; ++ struct usbd_interface_list_entry intf_list[2]; ++ struct usb_interface_descriptor *intf_desc; ++ ++ USBENTER("config = %p, urb_size = %p", config, size); ++ ++ intf_desc = USBD_ParseConfigurationDescriptorEx(config, config, -1, -1, ++ -1, -1, -1); ++ intf_list[0].intf_desc = intf_desc; ++ intf_list[0].intf = NULL; ++ intf_list[1].intf_desc = NULL; ++ intf_list[1].intf = NULL; ++ nt_urb = USBD_CreateConfigurationRequestEx(config, intf_list); ++ if (!nt_urb) ++ return NULL; ++ ++ *size = nt_urb->select_conf.header.length; ++ USBEXIT(return nt_urb); ++} ++ ++wstdcall struct usb_interface_descriptor * ++WIN_FUNC(USBD_ParseConfigurationDescriptor,3) ++ (struct usb_config_descriptor *config, UCHAR bInterfaceNumber, ++ UCHAR bAlternateSetting) ++{ ++ return USBD_ParseConfigurationDescriptorEx(config, config, ++ bInterfaceNumber, ++ bAlternateSetting, ++ -1, -1, -1); ++} ++ ++wstdcall struct usb_descriptor_header *WIN_FUNC(USBD_ParseDescriptors,4) ++ (void *buf, ULONG length, struct usb_descriptor_header *descr, ++ LONG type) ++{ ++ while ((void *)descr < buf + length) { ++ if (descr->bDescriptorType == type) ++ return descr; ++ if (descr->bLength == 0) ++ break; ++ descr = (void *)descr + descr->bLength; ++ } ++ USBEXIT(return NULL); ++} ++ ++WIN_SYMBOL_MAP("_USBD_ParseDescriptors@16", USBD_ParseDescriptors) ++ ++wstdcall void WIN_FUNC(USBD_GetUSBDIVersion,1) ++ (struct usbd_version_info *version_info) ++{ ++ /* this function is obsolete in Windows XP */ ++ if (version_info) { ++ version_info->usbdi_version = USBDI_VERSION_XP; ++ /* TODO: how do we get this correctly? */ ++ version_info->supported_usb_version = 0x110; ++ } ++ USBEXIT(return); ++} ++ ++wstdcall void ++USBD_InterfaceGetUSBDIVersion(void *context, ++ struct usbd_version_info *version_info, ++ ULONG *hcd_capa) ++{ ++ struct wrap_device *wd = context; ++ ++ if (version_info) { ++ version_info->usbdi_version = USBDI_VERSION_XP; ++ if (wd->usb.udev->speed == USB_SPEED_HIGH) ++ version_info->supported_usb_version = 0x200; ++ else ++ version_info->supported_usb_version = 0x110; ++ } ++ *hcd_capa = USB_HCD_CAPS_SUPPORTS_RT_THREADS; ++ USBEXIT(return); ++} ++ ++wstdcall BOOLEAN USBD_InterfaceIsDeviceHighSpeed(void *context) ++{ ++ struct wrap_device *wd = context; ++ ++ USBTRACE("wd: %p", wd); ++ if (wd->usb.udev->speed == USB_SPEED_HIGH) ++ USBEXIT(return TRUE); ++ else ++ USBEXIT(return FALSE); ++} ++ ++wstdcall void USBD_InterfaceReference(void *context) ++{ ++ USBTRACE("%p", context); ++ TODO(); ++} ++ ++wstdcall void USBD_InterfaceDereference(void *context) ++{ ++ USBTRACE("%p", context); ++ TODO(); ++} ++ ++wstdcall NTSTATUS USBD_InterfaceQueryBusTime(void *context, ULONG *frame) ++{ ++ struct wrap_device *wd = context; ++ ++ *frame = usb_get_current_frame_number(wd->usb.udev); ++ USBEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS USBD_InterfaceSubmitIsoOutUrb(void *context, ++ union nt_urb *nt_urb) ++{ ++ /* TODO: implement this */ ++ TODO(); ++ USBEXIT(return STATUS_NOT_IMPLEMENTED); ++} ++ ++wstdcall NTSTATUS ++USBD_InterfaceQueryBusInformation(void *context, ULONG level, void *buf, ++ ULONG *buf_length, ULONG *buf_actual_length) ++{ ++#if 0 ++ struct wrap_device *wd = context; ++ struct usb_bus *bus = wd->usb.udev->bus; ++ struct usb_bus_information_level *bus_info = buf; ++#endif ++ ++ TODO(); ++ USBEXIT(return STATUS_NOT_IMPLEMENTED); ++} ++ ++wstdcall NTSTATUS ++USBD_InterfaceLogEntry(void *context, ULONG driver_tag, ULONG enum_tag, ++ ULONG p1, ULONG p2) ++{ ++ ERROR("%p, %x, %x, %x, %x", context, driver_tag, enum_tag, p1, p2); ++ USBEXIT(return STATUS_SUCCESS); ++} ++ ++NTSTATUS ++usb_query_interface(struct wrap_device *wd, struct io_stack_location *irp_sl) ++{ ++ struct usbd_bus_interface_usbdi *intf = ++ (struct usbd_bus_interface_usbdi *) ++ irp_sl->params.query_intf.intf; ++ ++ TRACE2("type: %x, size: %d, version: %d", ++ irp_sl->params.query_intf.type->data1, ++ irp_sl->params.query_intf.size, ++ irp_sl->params.query_intf.version); ++ intf->Context = wd; ++ intf->InterfaceReference = ++ WIN_FUNC_PTR(USBD_InterfaceReference, 1); ++ intf->InterfaceDereference = ++ WIN_FUNC_PTR(USBD_InterfaceDereference, 1); ++ intf->GetUSBDIVersion = ++ WIN_FUNC_PTR(USBD_InterfaceGetUSBDIVersion, 3); ++ intf->QueryBusTime = ++ WIN_FUNC_PTR(USBD_InterfaceQueryBusTime, 2); ++ intf->SubmitIsoOutUrb = ++ WIN_FUNC_PTR(USBD_InterfaceSubmitIsoOutUrb, 2); ++ intf->QueryBusInformation = ++ WIN_FUNC_PTR(USBD_InterfaceQueryBusInformation, 5); ++ if (irp_sl->params.query_intf.version >= USB_BUSIF_USBDI_VERSION_1) ++ intf->IsDeviceHighSpeed = ++ WIN_FUNC_PTR(USBD_InterfaceIsDeviceHighSpeed, 1); ++ if (irp_sl->params.query_intf.version >= USB_BUSIF_USBDI_VERSION_2) ++ intf->LogEntry = WIN_FUNC_PTR(USBD_InterfaceLogEntry, 5); ++ return STATUS_SUCCESS; ++} ++ ++int usb_init(void) ++{ ++ InitializeListHead(&wrap_urb_complete_list); ++ spin_lock_init(&wrap_urb_complete_list_lock); ++ INIT_WORK(&wrap_urb_complete_work, wrap_urb_complete_worker); ++#ifdef USB_DEBUG ++ urb_id = 0; ++#endif ++ return 0; ++} ++ ++void usb_exit(void) ++{ ++ USBEXIT(return); ++} ++ ++int usb_init_device(struct wrap_device *wd) ++{ ++ InitializeListHead(&wd->usb.wrap_urb_list); ++ wd->usb.num_alloc_urbs = 0; ++ USBEXIT(return 0); ++} ++ ++void usb_exit_device(struct wrap_device *wd) ++{ ++ kill_all_urbs(wd, 0); ++ USBEXIT(return); ++} +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/usb.h linux-4.6-rc6-ndis/3rdparty/ndiswrapper/usb.h +--- linux-4.6-rc6/3rdparty/ndiswrapper/usb.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/usb.h 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,360 @@ ++/* ++ * Copyright (C) 2004 Jan Kiszka ++ * Copyright (C) 2005 Giridhar Pemmasani ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _USB_H_ ++#define _USB_H_ ++ ++#include "ntoskernel.h" ++ ++#define IOCTL_INTERNAL_USB_SUBMIT_URB 0x00220003 ++#define IOCTL_INTERNAL_USB_RESET_PORT 0x00220007 ++#define IOCTL_INTERNAL_USB_GET_PORT_STATUS 0x00220013 ++#define IOCTL_INTERNAL_USB_CYCLE_PORT 0x0022001F ++#define IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION 0x00220027 ++ ++#define URB_FUNCTION_SELECT_CONFIGURATION 0x0000 ++#define URB_FUNCTION_SELECT_INTERFACE 0x0001 ++#define URB_FUNCTION_ABORT_PIPE 0x0002 ++#define URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL 0x0003 ++#define URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL 0x0004 ++#define URB_FUNCTION_GET_FRAME_LENGTH 0x0005 ++#define URB_FUNCTION_SET_FRAME_LENGTH 0x0006 ++#define URB_FUNCTION_GET_CURRENT_FRAME_NUMBER 0x0007 ++#define URB_FUNCTION_CONTROL_TRANSFER 0x0008 ++#define URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER 0x0009 ++#define URB_FUNCTION_ISOCH_TRANSFER 0x000A ++#define URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE 0x000B ++#define URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE 0x000C ++#define URB_FUNCTION_SET_FEATURE_TO_DEVICE 0x000D ++#define URB_FUNCTION_SET_FEATURE_TO_INTERFACE 0x000E ++#define URB_FUNCTION_SET_FEATURE_TO_ENDPOINT 0x000F ++#define URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE 0x0010 ++#define URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE 0x0011 ++#define URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT 0x0012 ++#define URB_FUNCTION_GET_STATUS_FROM_DEVICE 0x0013 ++#define URB_FUNCTION_GET_STATUS_FROM_INTERFACE 0x0014 ++#define URB_FUNCTION_GET_STATUS_FROM_ENDPOINT 0x0015 ++#define URB_FUNCTION_RESERVED_0X0016 0x0016 ++#define URB_FUNCTION_VENDOR_DEVICE 0x0017 ++#define URB_FUNCTION_VENDOR_INTERFACE 0x0018 ++#define URB_FUNCTION_VENDOR_ENDPOINT 0x0019 ++#define URB_FUNCTION_CLASS_DEVICE 0x001A ++#define URB_FUNCTION_CLASS_INTERFACE 0x001B ++#define URB_FUNCTION_CLASS_ENDPOINT 0x001C ++#define URB_FUNCTION_RESERVE_0X001D 0x001D ++#define URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL 0x001E ++#define URB_FUNCTION_CLASS_OTHER 0x001F ++#define URB_FUNCTION_VENDOR_OTHER 0x0020 ++#define URB_FUNCTION_GET_STATUS_FROM_OTHER 0x0021 ++#define URB_FUNCTION_CLEAR_FEATURE_TO_OTHER 0x0022 ++#define URB_FUNCTION_SET_FEATURE_TO_OTHER 0x0023 ++#define URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT 0x0024 ++#define URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT 0x0025 ++#define URB_FUNCTION_GET_CONFIGURATION 0x0026 ++#define URB_FUNCTION_GET_INTERFACE 0x0027 ++#define URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE 0x0028 ++#define URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE 0x0029 ++#define URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR 0x002A ++#define URB_FUNCTION_RESERVE_0X002B 0x002B ++#define URB_FUNCTION_RESERVE_0X002C 0x002C ++#define URB_FUNCTION_RESERVE_0X002D 0x002D ++#define URB_FUNCTION_RESERVE_0X002E 0x002E ++#define URB_FUNCTION_RESERVE_0X002F 0x002F ++// USB 2.0 calls start at 0x0030 ++#define URB_FUNCTION_SYNC_RESET_PIPE 0x0030 ++#define URB_FUNCTION_SYNC_CLEAR_STALL 0x0031 ++#define URB_FUNCTION_CONTROL_TRANSFER_EX 0x0032 ++ ++#define USBD_PF_CHANGE_MAX_PACKET 0x00000001 ++ ++#define USBD_TRANSFER_DIRECTION_OUT 0 ++#define USBD_TRANSFER_DIRECTION_IN 1 ++ ++#define USBD_SHORT_TRANSFER_OK 0x00000002 ++#define USBD_START_ISO_TRANSFER_ASAP 0x00000004 ++#define USBD_DEFAULT_PIPE_TRANSFER 0x00000008 ++ ++#define USBD_TRANSFER_DIRECTION(flags) \ ++ ((flags) & USBD_TRANSFER_DIRECTION_IN) ++ ++enum pipe_type {UsbdPipeTypeControl = USB_ENDPOINT_XFER_CONTROL, ++ UsbdPipeTypeIsochronous = USB_ENDPOINT_XFER_ISOC, ++ UsbdPipeTypeBulk = USB_ENDPOINT_XFER_BULK, ++ UsbdPipeTypeInterrupt = USB_ENDPOINT_XFER_INT}; ++ ++#define USBD_IS_BULK_PIPE(pipe_handle) \ ++ (((pipe_handle)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) \ ++ == USB_ENDPOINT_XFER_BULK) ++ ++#define USBD_IS_INT_PIPE(pipe_handle) \ ++ (((pipe_handle)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) \ ++ == USB_ENDPOINT_XFER_INT) ++ ++#define USBD_PORT_ENABLED 0x00000001 ++#define USBD_PORT_CONNECTED 0x00000002 ++ ++typedef LONG USBD_STATUS; ++ ++#define USBD_STATUS_SUCCESS 0x0 ++#define USBD_STATUS_PENDING 0x40000000 ++#define USBD_STATUS_CANCELED 0x00010000 ++ ++#define USBD_STATUS_CRC 0xC0000001 ++#define USBD_STATUS_BTSTUFF 0xC0000002 ++#define USBD_STATUS_DATA_TOGGLE_MISMATCH 0xC0000003 ++#define USBD_STATUS_STALL_PID 0xC0000004 ++#define USBD_STATUS_DEV_NOT_RESPONDING 0xC0000005 ++#define USBD_STATUS_PID_CHECK_FAILURE 0xC0000006 ++#define USBD_STATUS_UNEXPECTED_PID 0xC0000007 ++#define USBD_STATUS_DATA_OVERRUN 0xC0000008 ++#define USBD_STATUS_DATA_UNDERRUN 0xC0000009 ++#define USBD_STATUS_RESERVED1 0xC000000A ++#define USBD_STATUS_RESERVED2 0xC000000B ++#define USBD_STATUS_BUFFER_OVERRUN 0xC000000C ++#define USBD_STATUS_BUFFER_UNDERRUN 0xC000000D ++#define USBD_STATUS_NOT_ACCESSED 0xC000000F ++#define USBD_STATUS_FIFO 0xC0000010 ++#define USBD_STATUS_XACT_ERROR 0xC0000011 ++#define USBD_STATUS_BABBLE_DETECTED 0xC0000012 ++#define USBD_STATUS_DATA_BUFFER_ERROR 0xC0000013 ++ ++#define USBD_STATUS_NOT_SUPPORTED 0xC0000E00 ++#define USBD_STATUS_BUFFER_TOO_SMALL 0xC0003000 ++#define USBD_STATUS_TIMEOUT 0xC0006000 ++#define USBD_STATUS_DEVICE_GONE 0xC0007000 ++ ++#define USBD_STATUS_NO_MEMORY 0x80000100 ++#define USBD_STATUS_INVALID_URB_FUNCTION 0x80000200 ++#define USBD_STATUS_INVALID_PARAMETER 0x80000300 ++#define USBD_STATUS_REQUEST_FAILED 0x80000500 ++#define USBD_STATUS_INVALID_PIPE_HANDLE 0x80000600 ++#define USBD_STATUS_ERROR_SHORT_TRANSFER 0x80000900 ++ ++#define USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE PAGE_SIZE ++ ++struct urb_hcd_area { ++ void *reserved8[8]; ++}; ++ ++struct usbd_pipe_information { ++ USHORT wMaxPacketSize; ++ UCHAR bEndpointAddress; ++ UCHAR bInterval; ++ enum pipe_type type; ++ struct usb_endpoint_descriptor *handle; ++ ULONG max_tx_size; ++ ULONG flags; ++}; ++ ++struct usbd_interface_information { ++ USHORT bLength; ++ UCHAR bInterfaceNumber; ++ UCHAR bAlternateSetting; ++ UCHAR bInterfaceClass; ++ UCHAR bInterfaceSubClass; ++ UCHAR bInterfaceProtocol; ++ UCHAR reserved; ++ void *handle; ++ ULONG bNumEndpoints; ++ struct usbd_pipe_information pipes[1]; ++}; ++ ++struct usbd_interface_list_entry { ++ struct usb_interface_descriptor *intf_desc; ++ struct usbd_interface_information *intf; ++}; ++ ++struct nt_urb_header { ++ USHORT length; ++ USHORT function; ++ USBD_STATUS status; ++ void *usbd_dev_handle; ++ ULONG usbd_flags; ++}; ++ ++struct usbd_select_interface { ++ struct nt_urb_header header; ++ void *handle; ++ struct usbd_interface_information intf; ++}; ++ ++struct usbd_select_configuration { ++ struct nt_urb_header header; ++ struct usb_config_descriptor *config; ++ void *handle; ++ struct usbd_interface_information intf; ++}; ++ ++struct usbd_control_descriptor_request { ++ struct nt_urb_header header; ++ void *reserved; ++ ULONG reserved0; ++ ULONG transfer_buffer_length; ++ void *transfer_buffer; ++ struct mdl *mdl; ++ union nt_urb *urb_link; ++ struct urb_hcd_area hca; ++ USHORT reserved1; ++ UCHAR index; ++ UCHAR desc_type; ++ USHORT language_id; ++ USHORT reserved2; ++}; ++ ++struct usbd_bulk_or_intr_transfer { ++ struct nt_urb_header header; ++ struct usb_endpoint_descriptor *pipe_handle; ++ ULONG transfer_flags; ++ ULONG transfer_buffer_length; ++ void *transfer_buffer; ++ struct mdl *mdl; ++ union nt_urb *urb_link; ++ struct urb_hcd_area hca; ++}; ++ ++struct usbd_pipe_request { ++ struct nt_urb_header header; ++ struct usb_endpoint_descriptor *pipe_handle; ++}; ++ ++struct usbd_vendor_or_class_request { ++ struct nt_urb_header header; ++ void *reserved; ++ ULONG transfer_flags; ++ ULONG transfer_buffer_length; ++ void *transfer_buffer; ++ struct mdl *mdl; ++ union nt_urb *link; ++ struct urb_hcd_area hca; ++ UCHAR reserved_bits; ++ UCHAR request; ++ USHORT value; ++ USHORT index; ++ USHORT reserved1; ++}; ++ ++struct urb_control_feature_request { ++ struct nt_urb_header header; ++ void *reserved; ++ ULONG reserved2; ++ ULONG reserved3; ++ void *reserved4; ++ struct mdl *reserved5; ++ union nt_urb *link; ++ struct urb_hcd_area hca; ++ USHORT reserved0; ++ USHORT feature_selector; ++ USHORT index; ++ USHORT reserved1; ++}; ++ ++struct urb_control_get_status_request { ++ struct nt_urb_header header; ++ void *reserved; ++ ULONG reserved0; ++ ULONG transfer_buffer_length; ++ void *transfer_buffer; ++ struct mdl *mdl; ++ union nt_urb *link; ++ struct urb_hcd_area hca; ++ UCHAR reserved1[4]; ++ USHORT index; ++ USHORT reserved2; ++}; ++ ++struct usbd_iso_packet_desc { ++ ULONG offset; ++ ULONG length; ++ USBD_STATUS status; ++}; ++ ++struct usbd_isochronous_transfer { ++ struct nt_urb_header header; ++ struct usb_endpoint_descriptor *pipe_handle; ++ ULONG transfer_flags; ++ ULONG transfer_buffer_length; ++ void *transfer_buffer; ++ struct mdl *mdl; ++ union nt_urb *urb_link; ++ struct urb_hcd_area hca; ++ ULONG start_frame; ++ ULONG number_of_packets; ++ ULONG error_count; ++ struct usbd_iso_packet_desc iso_packet[1]; ++}; ++ ++union nt_urb { ++ struct nt_urb_header header; ++ struct usbd_select_interface select_intf; ++ struct usbd_select_configuration select_conf; ++ struct usbd_bulk_or_intr_transfer bulk_int_transfer; ++ struct usbd_control_descriptor_request control_desc; ++ struct usbd_vendor_or_class_request vendor_class_request; ++ struct usbd_isochronous_transfer isochronous; ++ struct usbd_pipe_request pipe_req; ++ struct urb_control_feature_request feat_req; ++ struct urb_control_get_status_request status_req; ++}; ++ ++struct usbd_bus_interface_usbdi { ++ USHORT Size; ++ USHORT Version; ++ void *Context; ++ void *InterfaceReference; ++ void *InterfaceDereference; ++ void *GetUSBDIVersion; ++ void *QueryBusTime; ++ void *SubmitIsoOutUrb; ++ void *QueryBusInformation; ++ /* version 1 and above have following field */ ++ void *IsDeviceHighSpeed; ++ /* version 2 (and above) have following field */ ++ void *LogEntry; ++}; ++ ++struct usbd_bus_information_level { ++ ULONG TotalBandwidth; ++ ULONG ConsumedBandwidth; ++ /* level 1 and above have following fields */ ++ ULONG ControllerNameLength; ++ wchar_t ControllerName[1]; ++}; ++ ++#define USBDI_VERSION_XP 0x00000500 // Windows XP ++#define USB_HCD_CAPS_SUPPORTS_RT_THREADS 0x00000001 ++#define USB_BUSIF_USBDI_VERSION_0 0x0000 ++#define USB_BUSIF_USBDI_VERSION_1 0x0001 ++#define USB_BUSIF_USBDI_VERSION_2 0x0002 ++ ++struct usbd_version_info { ++ ULONG usbdi_version; ++ ULONG supported_usb_version; ++}; ++ ++struct usbd_idle_callback { ++ void *callback; ++ void *context; ++}; ++ ++#define NT_URB_STATUS(nt_urb) ((nt_urb)->header.status) ++ ++NTSTATUS wrap_submit_irp(struct device_object *pdo, struct irp *irp); ++void wrap_suspend_urbs(struct wrap_device *wd); ++void wrap_resume_urbs(struct wrap_device *wd); ++NTSTATUS usb_query_interface(struct wrap_device *wd, ++ struct io_stack_location *irp_sl); ++ ++#endif /* USB_H */ +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/win2lin_stubs.S linux-4.6-rc6-ndis/3rdparty/ndiswrapper/win2lin_stubs.S +--- linux-4.6-rc6/3rdparty/ndiswrapper/win2lin_stubs.S 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/win2lin_stubs.S 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,253 @@ ++/* ++ * Copyright (C) 2005 Karl Vogel, Giridhar Pemmasani ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include ++ ++#ifdef CONFIG_X86_64 ++ ++/* ++# Windows <---> Linux register usage conversion when calling functions ++# V = Volatile ++# NV = Non Volatile (needs to be saved) ++# ++# Win Lin ++# --------------------------------------- ++# Rax Return V Return V ++# Rbx NV NV ++# Rcx Arg1 V Arg4 V ++# Rdx Arg2 V Arg3 V ++# Rsi NV Arg2 V ++# Rdi NV Arg1 V ++# Rsp NV NV ++# Rbp NV NV ++# R8 Arg3 V Arg5 V ++# R9 Arg4 V Arg6 V ++# R10 V V ++# R11 V V ++# R12 NV NV ++# R13 NV NV ++# R14 NV NV ++# R15 NV NV ++# ++# In addition, Linux uses %rax to indicate number of SSE registers used ++# when variadic functions are called. Since there is no way to obtain this ++# from Windows, for now, we just assume this is 0 (hence %rax is cleared). ++# ++# Windows pushes arguments 5 and higher onto stack in case of integer ++# variables and 4 and higher in case of floating point variables (passed ++# in SSE registers). ++ ++In a windows function, the stackframe/registers look like this: ++ ++# 0x0048 .... ++# 0x0040 arg8 ++# 0x0038 arg7 ++# 0x0030 arg6 ++# 0x0028 arg5 ++# 0x0020 shadow/spill space for arg4 ++# 0x0018 shadow/spill space for arg3 ++# 0x0010 shadow/spill space for arg2 ++# 0x0008 shadow/spill space for arg1 ++# 0x0000 ret ++ ++# register spill space is same irrespective of number of arguments - even ++# if Windows function takes less than 4 arguments, 32 bytes above return ++# address is reserved for the function ++ ++In Linux it should look like: ++ ++# 0x0018 .... ++# 0x0010 arg8 ++# 0x0008 arg7 ++# 0x0000 ret ++ ++*/ ++ ++ .text ++ ++#define LINUX_REG_ARGS 6 ++#define LOOP_THRESHOLD 9 ++#define WORD_BYTES 8 ++ ++/* ++ * %rsi and %rdi must be saved because they are not saved by Linux calls, but ++ * Windows callers expect them to be saved. %rbp is saved to create a stack ++ * frame, which can help with debugging. We need to reserve space for an odd ++ * number of registers anyway to keep 16-bit alignment of the stack (one more ++ * position is used by the return address). ++ */ ++#define SAVED_REGS 3 ++ ++/* ++ * When calling the Linux function, several registers are saved on the stack. ++ * When passing more than 6 arguments, arguments starting with argument 7 are ++ * pushed to the stack as well. ++ * ++ * We also need to allocate an additional word on the stack to keep it aligned ++ * to the 16-bit boundary if the number of saved arguments plus one (for the ++ * return address) is odd. ++ */ ++ ++/* ++ * Number of arguments we pass on stack to the Linux function. ++ * The value of true is -1 in assembler, so we multiply it by another true ++ * value. ++ */ ++#define stack_args(argc) \ ++ ((0 < 1) * (argc > LINUX_REG_ARGS) * (argc - LINUX_REG_ARGS)) ++ ++/* Full required change of stack pointer, in words */ ++#define stack_words_raw(argc) (stack_args(argc) + SAVED_REGS + 1) ++ ++/* Full actual change of stack pointer, in words (must be even) */ ++#define stack_words_aligned(argc) ((stack_words_raw(argc) + 1) & ~1) ++ ++/* Space allocated for Linux arguments on stack */ ++#define stack_space(argc) \ ++ ((stack_words_aligned(argc) - SAVED_REGS - 1) * WORD_BYTES) ++ ++/* ++ * win2lin_win_arg(N, ARGC) gives the address of the Windows argument N out of ++ * total ARGC after the stack has been prepared for the Linux function call. ++ * ++ * When called from Windows, the Nth argument is at (N * 8)(%rsp). We add the ++ * stack space allocated by the Linux function to compensate for %rsp change. ++ * ++ * Don't call with N less than 5! ++ */ ++#define win2lin_win_arg(n, argc) \ ++ ((n + SAVED_REGS) * WORD_BYTES + stack_space(argc))(%rsp) ++ ++/* ++ * win2lin_lin_arg(N) gives the address of the Nth Linux argument on the extra ++ * Linux stack frame. When more than 6 arguments are used, %rsp points to the ++ * 7th argument. The Nth argument is therefore at ((N - 7) * 8)(%rsp). ++ * ++ * Don't call with N less than 7! ++ */ ++#define win2lin_lin_arg(n) ((n - 1 - LINUX_REG_ARGS) * WORD_BYTES)(%rsp) ++ ++/* Declare function LONGNAME, call function SHORTNAME with ARGC arguments */ ++.macro win2linm longname, shortname, argc ++ .type \longname, @function ++ ENTRY(\longname) ++ ++ /* Create a call frame - it's optional, but good for debugging */ ++ .cfi_startproc ++ push %rbp ++ .cfi_def_cfa %rsp, 2 * WORD_BYTES ++ .cfi_offset %rbp, -2 * WORD_BYTES ++ mov %rsp, %rbp ++ .cfi_def_cfa %rbp, 2 * WORD_BYTES ++ ++ /* ++ * Registers %rdi and %rsi are volatile on Linux, but not on Windows, ++ * so save them on the stack. ++ */ ++ push %rsi ++ push %rdi ++ ++ /* Allocate extra stack space for arguments 7 and up */ ++ sub $stack_space(\argc), %rsp ++ ++ /* ++ * Copy arguments 7 and up. We do it early, before %rdi and %rsi ++ * are used for arguments 1 and 2, so we don't have to save them. ++ * We still need to save %rcx if using a string copy. ++ */ ++ .if (\argc < LOOP_THRESHOLD) ++ /* If a few arguments, copy them individually through %r11 */ ++ .if (\argc >= 7) ++ mov win2lin_win_arg(7, \argc), %r11 ++ mov %r11, win2lin_lin_arg(7) ++ .endif ++ .if (\argc >= 8) ++ mov win2lin_win_arg(8, \argc), %r11 ++ mov %r11, win2lin_lin_arg(8) ++ .endif ++ .else ++ /* If there are many arguments, copy them in a loop */ ++ /* Save arg1 to %r11 */ ++ mov %rcx, %r11 ++ /* Source and destination */ ++ lea win2lin_win_arg(LINUX_REG_ARGS + 1, \argc), %rsi ++ lea win2lin_lin_arg(LINUX_REG_ARGS + 1), %rdi ++ /* Number of arguments to copy (%ecx zero-extends to %rcx) */ ++ mov $(\argc - LINUX_REG_ARGS), %ecx ++ rep movsq ++ /* Restore arg1 directly to %rdi */ ++ mov %r11, %rdi ++ .endif ++ ++ /* ++ * Argument 1 - %rcx on Windows, %rdi on Linux ++ * Micro-optimization - if we used loop, arg1 is already in %rdi ++ */ ++ .if (\argc >= 1) && (\argc < LOOP_THRESHOLD) ++ mov %rcx, %rdi ++ .endif ++ ++ /* Argument 2 - %rdx on Windows, %rsi on Linux */ ++ .if (\argc >= 2) ++ mov %rdx, %rsi ++ .endif ++ ++ /* Argument 3 - %r8 on Windows, %rdx on Linux */ ++ .if (\argc >= 3) ++ mov %r8, %rdx ++ .endif ++ ++ /* Argument 4 - %r9 on Windows, %rcx on Linux */ ++ .if (\argc >= 4) ++ mov %r9, %rcx ++ .endif ++ ++ /* Argument 5 - first argument on stack on Windows, %r8 Linux */ ++ .if (\argc >= 5) ++ mov win2lin_win_arg(5, \argc), %r8 ++ .endif ++ ++ /* Argument 6 - second argument on stack on Windows, %r9 Linux */ ++ .if (\argc >= 6) ++ mov win2lin_win_arg(6, \argc), %r9 ++ .endif ++ ++ /* %rax on Linux is the number of arguments in SSE registers (zero) */ ++ xor %rax, %rax ++ ++ /* Call the function */ ++ call \shortname ++ ++ /* Free stack space for arguments 7 and up */ ++ add $stack_space(\argc), %rsp ++ ++ /* Restore saved registers */ ++ pop %rdi ++ pop %rsi ++ ++ /* Return to Windows code */ ++ leave ++ .cfi_def_cfa %rsp, WORD_BYTES ++ .cfi_restore %rbp ++ ret ++ .cfi_endproc ++ .size \longname, (. - \longname) ++.endm ++ ++#define win2lin(name, argc) win2linm win2lin_ ## name ## _ ## argc, name, argc ++ ++#include "win2lin_stubs.h" ++ ++#endif /* CONFIG_X86_64 */ +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/winnt_types.h linux-4.6-rc6-ndis/3rdparty/ndiswrapper/winnt_types.h +--- linux-4.6-rc6/3rdparty/ndiswrapper/winnt_types.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/winnt_types.h 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,1701 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _WINNT_TYPES_H_ ++#define _WINNT_TYPES_H_ ++ ++#define TRUE 1 ++#define FALSE 0 ++ ++#define PASSIVE_LEVEL 0 ++#define APC_LEVEL 1 ++#define DISPATCH_LEVEL 2 ++#define DEVICE_LEVEL_BASE 4 ++ ++/* soft interrupts / bottom-half's are disabled at SOFT_IRQL */ ++#define SOFT_IRQL (DEVICE_LEVEL_BASE + 1) ++#define DIRQL (DEVICE_LEVEL_BASE + 2) ++ ++#define STATUS_WAIT_0 0 ++#define STATUS_SUCCESS 0 ++#define STATUS_ALERTED 0x00000101 ++#define STATUS_TIMEOUT 0x00000102 ++#define STATUS_PENDING 0x00000103 ++#define STATUS_FAILURE 0xC0000001 ++#define STATUS_NOT_IMPLEMENTED 0xC0000002 ++#define STATUS_INVALID_PARAMETER 0xC000000D ++#define STATUS_INVALID_DEVICE_REQUEST 0xC0000010 ++#define STATUS_MORE_PROCESSING_REQUIRED 0xC0000016 ++#define STATUS_ACCESS_DENIED 0xC0000022 ++#define STATUS_BUFFER_TOO_SMALL 0xC0000023 ++#define STATUS_OBJECT_NAME_INVALID 0xC0000023 ++#define STATUS_MUTANT_NOT_OWNED 0xC0000046 ++#define STATUS_RESOURCES 0xC000009A ++#define STATUS_DELETE_PENDING 0xC0000056 ++#define STATUS_INSUFFICIENT_RESOURCES 0xC000009A ++#define STATUS_NOT_SUPPORTED 0xC00000BB ++#define STATUS_INVALID_PARAMETER_2 0xC00000F0 ++#define STATUS_NO_MEMORY 0xC0000017 ++#define STATUS_CANCELLED 0xC0000120 ++#define STATUS_DEVICE_REMOVED 0xC00002B6 ++#define STATUS_DEVICE_NOT_CONNECTED 0xC000009D ++ ++#define STATUS_BUFFER_OVERFLOW 0x80000005 ++ ++#define SL_PENDING_RETURNED 0x01 ++#define SL_INVOKE_ON_CANCEL 0x20 ++#define SL_INVOKE_ON_SUCCESS 0x40 ++#define SL_INVOKE_ON_ERROR 0x80 ++ ++#define IRP_MJ_CREATE 0x00 ++#define IRP_MJ_CREATE_NAMED_PIPE 0x01 ++#define IRP_MJ_CLOSE 0x02 ++#define IRP_MJ_READ 0x03 ++#define IRP_MJ_WRITE 0x04 ++ ++#define IRP_MJ_DEVICE_CONTROL 0x0E ++#define IRP_MJ_INTERNAL_DEVICE_CONTROL 0x0F ++#define IRP_MJ_POWER 0x16 ++#define IRP_MJ_SYSTEM_CONTROL 0x0E ++#define IRP_MJ_PNP 0x1b ++#define IRP_MJ_MAXIMUM_FUNCTION 0x1b ++ ++#define IRP_MN_WAIT_WAKE 0x00 ++#define IRP_MN_POWER_SEQUENCE 0x01 ++#define IRP_MN_SET_POWER 0x02 ++#define IRP_MN_QUERY_POWER 0x03 ++ ++#define IRP_MN_REGINFO 0x08 ++#define IRP_MN_REGINFO_EX 0x0b ++ ++#define IRP_MN_START_DEVICE 0x00 ++#define IRP_MN_QUERY_REMOVE_DEVICE 0x01 ++#define IRP_MN_REMOVE_DEVICE 0x02 ++#define IRP_MN_CANCEL_REMOVE_DEVICE 0x03 ++#define IRP_MN_STOP_DEVICE 0x04 ++#define IRP_MN_QUERY_STOP_DEVICE 0x05 ++#define IRP_MN_CANCEL_STOP_DEVICE 0x06 ++#define IRP_MN_QUERY_DEVICE_RELATIONS 0x07 ++#define IRP_MN_QUERY_INTERFACE 0x08 ++ ++#define IRP_BUFFERED_IO 0x00000010 ++#define IRP_DEALLOCATE_BUFFER 0x00000020 ++#define IRP_INPUT_OPERATION 0x00000040 ++ ++#define IRP_DEFFER_IO_COMPLETION 0x00000800 ++ ++#define THREAD_WAIT_OBJECTS 3 ++#define MAX_WAIT_OBJECTS 64 ++ ++#define LOW_PRIORITY 0 ++#define LOW_REALTIME_PRIORITY 16 ++#define HIGH_PRIORITY 31 ++#define MAXIMUM_PRIORITY 32 ++ ++#define PROCESSOR_FEATURE_MAX 64 ++ ++#define IO_NO_INCREMENT 0 ++ ++#define WMIREG_ACTION_REGISTER 1 ++#define WMIREG_ACTION_DEREGISTER 2 ++#define WMIREG_ACTION_REREGISTER 3 ++#define WMIREG_ACTION_UPDATE_GUIDS 4 ++ ++#define WMIREGISTER 0 ++#define WMIUPDATE 1 ++ ++#ifdef CONFIG_X86_64 ++#define wstdcall ++#define wfastcall ++#define noregparm ++#define regparm3 ++ ++#define KI_USER_SHARED_DATA 0xfffff78000000000UL ++ ++#else ++ ++#define noregparm __attribute__((regparm(0))) ++#define regparm3 __attribute__((regparm(3))) ++#define wstdcall __attribute__((__stdcall__, regparm(0))) ++#if defined(__GNUC__) && ((__GNUC__ == 3 && __GNUC_MINOR__ > 3) || __GNUC__ > 3) ++#undef fastcall ++#define wfastcall __attribute__((fastcall)) ++#else ++#error "gcc 3.4 or newer should be used for compiling this module" ++#endif ++ ++#define KI_USER_SHARED_DATA 0xffdf0000 ++ ++#endif ++ ++typedef u8 BOOLEAN; ++typedef u8 BYTE; ++typedef u8 *LPBYTE; ++typedef s8 CHAR; ++typedef u8 UCHAR; ++typedef s16 SHORT; ++typedef u16 USHORT; ++typedef u16 WORD; ++typedef s32 INT; ++typedef u32 UINT; ++typedef u32 DWORD; ++typedef s32 LONG; ++typedef u32 ULONG; ++typedef s64 LONGLONG; ++typedef u64 ULONGLONG; ++typedef u64 ULONGULONG; ++typedef u64 ULONG64; ++ ++typedef CHAR CCHAR; ++typedef USHORT wchar_t; ++typedef SHORT CSHORT; ++typedef LONGLONG LARGE_INTEGER; ++ ++typedef LONG NTSTATUS; ++ ++typedef LONG KPRIORITY; ++typedef LARGE_INTEGER PHYSICAL_ADDRESS; ++typedef UCHAR KIRQL; ++typedef CHAR KPROCESSOR_MODE; ++ ++/* ULONG_PTR is 32 bits on 32-bit platforms and 64 bits on 64-bit ++ * platform, which is same as 'unsigned long' in Linux */ ++typedef unsigned long ULONG_PTR; ++ ++typedef size_t SIZE_T; ++typedef ULONG_PTR KAFFINITY; ++typedef ULONG ACCESS_MASK; ++ ++typedef ULONG_PTR PFN_NUMBER; ++typedef ULONG SECURITY_INFORMATION; ++ ++/* non-negative numbers indicate success */ ++#define NT_SUCCESS(status) ((NTSTATUS)(status) >= 0) ++ ++struct ansi_string { ++ USHORT length; ++ USHORT max_length; ++ char *buf; ++}; ++ ++struct unicode_string { ++ USHORT length; ++ USHORT max_length; ++ wchar_t *buf; ++}; ++ ++struct nt_slist { ++ struct nt_slist *next; ++}; ++ ++#ifdef CONFIG_X86_64 ++/* it is not clear how nt_slist_head is used to store pointer to ++ * slists and depth; here we assume 'align' field is used to store ++ * depth and 'region' field is used to store slist pointers */ ++struct nt_slist_head { ++ union { ++ USHORT depth; ++ ULONGLONG align; ++ }; ++ union { ++ ULONGLONG region; ++ struct nt_slist *next; ++ }; ++} __attribute__((aligned(16))); ++typedef struct nt_slist_head nt_slist_header; ++#else ++union nt_slist_head { ++ ULONGLONG align; ++ struct { ++ struct nt_slist *next; ++ USHORT depth; ++ USHORT sequence; ++ }; ++}; ++typedef union nt_slist_head nt_slist_header; ++#endif ++ ++struct nt_list { ++ struct nt_list *next; ++ struct nt_list *prev; ++}; ++ ++typedef ULONG_PTR NT_SPIN_LOCK; ++ ++enum kdpc_importance {LowImportance, MediumImportance, HighImportance}; ++ ++struct kdpc; ++typedef void (*DPC)(struct kdpc *kdpc, void *ctx, void *arg1, ++ void *arg2) wstdcall; ++struct kdpc { ++ SHORT type; ++ UCHAR nr_cpu; ++ UCHAR importance; ++ struct nt_list list; ++ DPC func; ++ void *ctx; ++ void *arg1; ++ void *arg2; ++ union { ++ NT_SPIN_LOCK *lock; ++ /* 'lock' is not used; 'queued' represents whether ++ * kdpc is queued or not */ ++ int queued; ++ }; ++}; ++ ++enum pool_type { ++ NonPagedPool, PagedPool, NonPagedPoolMustSucceed, DontUseThisType, ++ NonPagedPoolCacheAligned, PagedPoolCacheAligned, ++ NonPagedPoolCacheAlignedMustS, MaxPoolType, ++ NonPagedPoolSession = 32, ++ PagedPoolSession = NonPagedPoolSession + 1, ++ NonPagedPoolMustSucceedSession = PagedPoolSession + 1, ++ DontUseThisTypeSession = NonPagedPoolMustSucceedSession + 1, ++ NonPagedPoolCacheAlignedSession = DontUseThisTypeSession + 1, ++ PagedPoolCacheAlignedSession = NonPagedPoolCacheAlignedSession + 1, ++ NonPagedPoolCacheAlignedMustSSession = PagedPoolCacheAlignedSession + 1 ++}; ++ ++enum memory_caching_type_orig { ++ MmFrameBufferCached = 2 ++}; ++ ++enum memory_caching_type { ++ MmNonCached = FALSE, MmCached = TRUE, ++ MmWriteCombined = MmFrameBufferCached, MmHardwareCoherentCached, ++ MmNonCachedUnordered, MmUSWCCached, MmMaximumCacheType ++}; ++ ++enum lock_operation { ++ IoReadAccess, IoWriteAccess, IoModifyAccess ++}; ++ ++enum mode { ++ KernelMode, UserMode, MaximumMode ++}; ++ ++struct mdl { ++ struct mdl *next; ++ CSHORT size; ++ CSHORT flags; ++ /* NdisFreeBuffer doesn't pass pool, so we store pool in ++ * unused field 'process' */ ++ union { ++ void *process; ++ void *pool; ++ }; ++ void *mappedsystemva; ++ void *startva; ++ ULONG bytecount; ++ ULONG byteoffset; ++}; ++ ++#define MDL_MAPPED_TO_SYSTEM_VA 0x0001 ++#define MDL_PAGES_LOCKED 0x0002 ++#define MDL_SOURCE_IS_NONPAGED_POOL 0x0004 ++#define MDL_ALLOCATED_FIXED_SIZE 0x0008 ++#define MDL_PARTIAL 0x0010 ++#define MDL_PARTIAL_HAS_BEEN_MAPPED 0x0020 ++#define MDL_IO_PAGE_READ 0x0040 ++#define MDL_WRITE_OPERATION 0x0080 ++#define MDL_PARENT_MAPPED_SYSTEM_VA 0x0100 ++#define MDL_FREE_EXTRA_PTES 0x0200 ++#define MDL_IO_SPACE 0x0800 ++#define MDL_NETWORK_HEADER 0x1000 ++#define MDL_MAPPING_CAN_FAIL 0x2000 ++#define MDL_ALLOCATED_MUST_SUCCEED 0x4000 ++ ++#define MDL_POOL_ALLOCATED 0x0400 ++#define MDL_CACHE_ALLOCATED 0x8000 ++ ++#define PAGE_START(ptr) ((void *)((ULONG_PTR)(ptr) & ~(PAGE_SIZE - 1))) ++#define BYTE_OFFSET(ptr) ((ULONG)((ULONG_PTR)(ptr) & (PAGE_SIZE - 1))) ++ ++#define MmGetMdlByteCount(mdl) ((mdl)->bytecount) ++#define MmGetMdlVirtualAddress(mdl) ((mdl)->startva + (mdl)->byteoffset) ++#define MmGetMdlByteOffset(mdl) ((mdl)->byteoffset) ++#define MmGetSystemAddressForMdl(mdl) ((mdl)->mappedsystemva) ++#define MmGetSystemAddressForMdlSafe(mdl, priority) ((mdl)->mappedsystemva) ++#define MmGetMdlPfnArray(mdl) ((PFN_NUMBER *)(mdl + 1)) ++#define MmInitializeMdl(mdl, baseva, length) \ ++do { \ ++ (mdl)->next = NULL; \ ++ (mdl)->size = MmSizeOfMdl(baseva, length); \ ++ (mdl)->flags = 0; \ ++ (mdl)->startva = PAGE_START(baseva); \ ++ (mdl)->byteoffset = BYTE_OFFSET(baseva); \ ++ (mdl)->bytecount = length; \ ++ (mdl)->mappedsystemva = baseva; \ ++ TRACE4("%p %p %p %d %d", (mdl), baseva, (mdl)->startva, \ ++ (mdl)->byteoffset, length); \ ++} while (0) ++ ++struct kdevice_queue_entry { ++ struct nt_list list; ++ ULONG sort_key; ++ BOOLEAN inserted; ++}; ++ ++struct kdevice_queue { ++ USHORT type; ++ USHORT size; ++ struct nt_list list; ++ NT_SPIN_LOCK lock; ++ BOOLEAN busy; ++}; ++ ++struct wait_context_block { ++ struct kdevice_queue_entry wait_queue_entry; ++ void *device_routine; ++ void *device_context; ++ ULONG num_regs; ++ void *device_object; ++ void *current_irp; ++ void *buffer_chaining_dpc; ++}; ++ ++struct wait_block { ++ struct nt_list list; ++ struct task_struct *thread; ++ void *object; ++ int *wait_done; ++ USHORT wait_key; ++ USHORT wait_type; ++}; ++ ++struct dispatcher_header { ++ UCHAR type; ++ UCHAR absolute; ++ UCHAR size; ++ UCHAR inserted; ++ LONG signal_state; ++ struct nt_list wait_blocks; ++}; ++ ++enum event_type { ++ NotificationEvent, ++ SynchronizationEvent, ++}; ++ ++enum timer_type { ++ NotificationTimer = NotificationEvent, ++ SynchronizationTimer = SynchronizationEvent, ++}; ++ ++enum dh_type { ++ NotificationObject = NotificationEvent, ++ SynchronizationObject = SynchronizationEvent, ++ MutexObject, ++ SemaphoreObject, ++ ThreadObject, ++}; ++ ++enum wait_type { ++ WaitAll, WaitAny ++}; ++ ++/* objects that use dispatcher_header have it as the first field, so ++ * whenever we need to initialize dispatcher_header, we can convert ++ * that object into a nt_event and access dispatcher_header */ ++struct nt_event { ++ struct dispatcher_header dh; ++}; ++ ++struct wrap_timer; ++ ++#define WRAP_TIMER_MAGIC 47697249 ++ ++struct nt_timer { ++ struct dispatcher_header dh; ++ /* We can't fit Linux timer in this structure. Instead of ++ * padding the nt_timer structure, we replace due_time field ++ * with *wrap_timer and allocate memory for it when nt_timer is ++ * initialized */ ++ union { ++ ULONGLONG due_time; ++ struct wrap_timer *wrap_timer; ++ }; ++ struct nt_list nt_timer_list; ++ struct kdpc *kdpc; ++ union { ++ LONG period; ++ LONG wrap_timer_magic; ++ }; ++}; ++ ++struct nt_mutex { ++ struct dispatcher_header dh; ++ struct nt_list list; ++ struct task_struct *owner_thread; ++ BOOLEAN abandoned; ++ BOOLEAN apc_disable; ++}; ++ ++struct nt_semaphore { ++ struct dispatcher_header dh; ++ LONG limit; ++}; ++ ++struct nt_thread { ++ struct dispatcher_header dh; ++ /* the rest in Windows is a long structure; since this ++ * structure is opaque to drivers, we just define what we ++ * need */ ++ int pid; ++ NTSTATUS status; ++ struct task_struct *task; ++ struct nt_list irps; ++ NT_SPIN_LOCK lock; ++ KPRIORITY prio; ++}; ++ ++#define set_object_type(dh, type) ((dh)->type = (type)) ++#define is_notify_object(dh) ((dh)->type == NotificationObject) ++#define is_synch_object(dh) ((dh)->type == SynchronizationObject) ++#define is_mutex_object(dh) ((dh)->type == MutexObject) ++#define is_semaphore_object(dh) ((dh)->type == SemaphoreObject) ++#define is_nt_thread_object(dh) ((dh)->type == ThreadObject) ++ ++#define IO_TYPE_ADAPTER 1 ++#define IO_TYPE_CONTROLLER 2 ++#define IO_TYPE_DEVICE 3 ++#define IO_TYPE_DRIVER 4 ++#define IO_TYPE_FILE 5 ++#define IO_TYPE_IRP 6 ++#define IO_TYPE_DEVICE_OBJECT_EXTENSION 13 ++ ++struct irp; ++struct dev_obj_ext; ++struct driver_object; ++ ++struct device_object { ++ CSHORT type; ++ USHORT size; ++ LONG ref_count; ++ struct driver_object *drv_obj; ++ struct device_object *next; ++ struct device_object *attached; ++ struct irp *current_irp; ++ void *io_timer; ++ ULONG flags; ++ ULONG characteristics; ++ void *vpb; ++ void *dev_ext; ++ CCHAR stack_count; ++ union { ++ struct nt_list queue_list; ++ struct wait_context_block wcb; ++ } queue; ++ ULONG align_req; ++ struct kdevice_queue dev_queue; ++ struct kdpc dpc; ++ ULONG active_threads; ++ void *security_desc; ++ struct nt_event lock; ++ USHORT sector_size; ++ USHORT spare1; ++ struct dev_obj_ext *dev_obj_ext; ++ void *reserved; ++}; ++ ++struct dev_obj_ext { ++ CSHORT type; ++ CSHORT size; ++ struct device_object *dev_obj; ++ struct device_object *attached_to; ++}; ++ ++struct io_status_block { ++ union { ++ NTSTATUS status; ++ void *pointer; ++ }; ++ ULONG_PTR info; ++}; ++ ++#ifdef CONFIG_X86_64 ++struct io_status_block32 { ++ NTSTATUS status; ++ ULONG info; ++}; ++#endif ++ ++#define DEVICE_TYPE ULONG ++ ++struct driver_extension; ++ ++typedef NTSTATUS driver_dispatch_t(struct device_object *dev_obj, ++ struct irp *irp) wstdcall; ++ ++struct driver_object { ++ CSHORT type; ++ CSHORT size; ++ struct device_object *dev_obj; ++ ULONG flags; ++ void *start; ++ ULONG driver_size; ++ void *section; ++ struct driver_extension *drv_ext; ++ struct unicode_string name; ++ struct unicode_string *hardware_database; ++ void *fast_io_dispatch; ++ void *init; ++ void *start_io; ++ void (*unload)(struct driver_object *driver) wstdcall; ++ driver_dispatch_t *major_func[IRP_MJ_MAXIMUM_FUNCTION + 1]; ++}; ++ ++struct driver_extension { ++ struct driver_object *drv_obj; ++ NTSTATUS (*add_device)(struct driver_object *drv_obj, ++ struct device_object *dev_obj); ++ ULONG count; ++ struct unicode_string service_key_name; ++ struct nt_list custom_ext; ++}; ++ ++struct custom_ext { ++ struct nt_list list; ++ void *client_id; ++}; ++ ++struct wrap_bin_file; ++ ++struct file_object { ++ CSHORT type; ++ CSHORT size; ++ struct device_object *dev_obj; ++ void *volume_parameter_block; ++ void *fs_context; ++ void *fs_context2; ++ void *section_object_pointer; ++ void *private_cache_map; ++ NTSTATUS final_status; ++ union { ++ struct file_object *related_file_object; ++ struct wrap_bin_file *wrap_bin_file; ++ }; ++ BOOLEAN lock_operation; ++ BOOLEAN delete_pending; ++ BOOLEAN read_access; ++ BOOLEAN write_access; ++ BOOLEAN delete_access; ++ BOOLEAN shared_read; ++ BOOLEAN shared_write; ++ BOOLEAN shared_delete; ++ ULONG flags; ++ struct unicode_string _name_; ++ LARGE_INTEGER current_byte_offset; ++ ULONG waiters; ++ ULONG busy; ++ void *last_lock; ++ struct nt_event lock; ++ struct nt_event event; ++ void *completion_context; ++}; ++ ++#ifdef CONFIG_X86_64 ++#define POINTER_ALIGN __attribute__((aligned(8))) ++#else ++#define POINTER_ALIGN ++#endif ++ ++#define CACHE_ALIGN __attribute__((aligned(128))) ++ ++enum system_power_state { ++ PowerSystemUnspecified = 0, ++ PowerSystemWorking, PowerSystemSleeping1, PowerSystemSleeping2, ++ PowerSystemSleeping3, PowerSystemHibernate, PowerSystemShutdown, ++ PowerSystemMaximum, ++}; ++ ++enum device_power_state { ++ PowerDeviceUnspecified = 0, ++ PowerDeviceD0, PowerDeviceD1, PowerDeviceD2, PowerDeviceD3, ++ PowerDeviceMaximum, ++}; ++ ++union power_state { ++ enum system_power_state system_state; ++ enum device_power_state device_state; ++}; ++ ++enum power_state_type { ++ SystemPowerState = 0, DevicePowerState, ++}; ++ ++enum power_action { ++ PowerActionNone = 0, ++ PowerActionReserved, PowerActionSleep, PowerActionHibernate, ++ PowerActionShutdown, PowerActionShutdownReset, PowerActionShutdownOff, ++ PowerActionWarmEject, ++}; ++ ++struct guid { ++ ULONG data1; ++ USHORT data2; ++ USHORT data3; ++ UCHAR data4[8]; ++}; ++ ++struct nt_interface { ++ USHORT size; ++ USHORT version; ++ void *context; ++ void (*reference)(void *context) wstdcall; ++ void (*dereference)(void *context) wstdcall; ++}; ++ ++enum interface_type { ++ InterfaceTypeUndefined = -1, Internal, Isa, Eisa, MicroChannel, ++ TurboChannel, PCIBus, VMEBus, NuBus, PCMCIABus, CBus, MPIBus, ++ MPSABus, ProcessorInternal, InternalPowerBus, PNPISABus, ++ PNPBus, MaximumInterfaceType, ++}; ++ ++#define CmResourceTypeNull 0 ++#define CmResourceTypePort 1 ++#define CmResourceTypeInterrupt 2 ++#define CmResourceTypeMemory 3 ++#define CmResourceTypeDma 4 ++#define CmResourceTypeDeviceSpecific 5 ++#define CmResourceTypeBusNumber 6 ++#define CmResourceTypeMaximum 7 ++ ++#define CmResourceTypeNonArbitrated 128 ++#define CmResourceTypeConfigData 128 ++#define CmResourceTypeDevicePrivate 129 ++#define CmResourceTypePcCardConfig 130 ++#define CmResourceTypeMfCardConfig 131 ++ ++enum cm_share_disposition { ++ CmResourceShareUndetermined = 0, CmResourceShareDeviceExclusive, ++ CmResourceShareDriverExclusive, CmResourceShareShared ++}; ++ ++#define CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE 0 ++#define CM_RESOURCE_INTERRUPT_LATCHED 1 ++#define CM_RESOURCE_MEMORY_READ_WRITE 0x0000 ++#define CM_RESOURCE_MEMORY_READ_ONLY 0x0001 ++#define CM_RESOURCE_MEMORY_WRITE_ONLY 0x0002 ++#define CM_RESOURCE_MEMORY_PREFETCHABLE 0x0004 ++ ++#define CM_RESOURCE_MEMORY_COMBINEDWRITE 0x0008 ++#define CM_RESOURCE_MEMORY_24 0x0010 ++#define CM_RESOURCE_MEMORY_CACHEABLE 0x0020 ++ ++#define CM_RESOURCE_PORT_MEMORY 0x0000 ++#define CM_RESOURCE_PORT_IO 0x0001 ++#define CM_RESOURCE_PORT_10_BIT_DECODE 0x0004 ++#define CM_RESOURCE_PORT_12_BIT_DECODE 0x0008 ++#define CM_RESOURCE_PORT_16_BIT_DECODE 0x0010 ++#define CM_RESOURCE_PORT_POSITIVE_DECODE 0x0020 ++#define CM_RESOURCE_PORT_PASSIVE_DECODE 0x0040 ++#define CM_RESOURCE_PORT_WINDOW_DECODE 0x0080 ++ ++#define CM_RESOURCE_DMA_8 0x0000 ++#define CM_RESOURCE_DMA_16 0x0001 ++#define CM_RESOURCE_DMA_32 0x0002 ++#define CM_RESOURCE_DMA_8_AND_16 0x0004 ++#define CM_RESOURCE_DMA_BUS_MASTER 0x0008 ++#define CM_RESOURCE_DMA_TYPE_A 0x0010 ++#define CM_RESOURCE_DMA_TYPE_B 0x0020 ++#define CM_RESOURCE_DMA_TYPE_F 0x0040 ++ ++#define MAX_RESOURCES 20 ++ ++#pragma pack(push,4) ++struct cm_partial_resource_descriptor { ++ UCHAR type; ++ UCHAR share; ++ USHORT flags; ++ union { ++ struct { ++ PHYSICAL_ADDRESS start; ++ ULONG length; ++ } generic; ++ struct { ++ PHYSICAL_ADDRESS start; ++ ULONG length; ++ } port; ++ struct { ++ ULONG level; ++ ULONG vector; ++ KAFFINITY affinity; ++ } interrupt; ++ struct { ++ PHYSICAL_ADDRESS start; ++ ULONG length; ++ } memory; ++ struct { ++ ULONG channel; ++ ULONG port; ++ ULONG reserved1; ++ } dma; ++ struct { ++ ULONG data[3]; ++ } device_private; ++ struct { ++ ULONG start; ++ ULONG length; ++ ULONG reserved; ++ } bus_number; ++ struct { ++ ULONG data_size; ++ ULONG reserved1; ++ ULONG reserved2; ++ } device_specific_data; ++ } u; ++}; ++#pragma pack(pop) ++ ++struct cm_partial_resource_list { ++ USHORT version; ++ USHORT revision; ++ ULONG count; ++ struct cm_partial_resource_descriptor partial_descriptors[1]; ++}; ++ ++struct cm_full_resource_descriptor { ++ enum interface_type interface_type; ++ ULONG bus_number; ++ struct cm_partial_resource_list partial_resource_list; ++}; ++ ++struct cm_resource_list { ++ ULONG count; ++ struct cm_full_resource_descriptor list[1]; ++}; ++ ++enum file_info_class { ++ FileDirectoryInformation = 1, ++ FileBasicInformation = 4, ++ FileStandardInformation = 5, ++ FileNameInformation = 9, ++ FilePositionInformation = 14, ++ FileAlignmentInformation = 17, ++ FileNetworkOpenInformation = 34, ++ FileAttributeTagInformation = 35, ++ FileMaximumInformation = 41, ++}; ++ ++enum fs_info_class { ++ FileFsVolumeInformation = 1, ++ /* ... */ ++ FileFsMaximumInformation = 9, ++}; ++ ++enum device_relation_type { ++ BusRelations, EjectionRelations, PowerRelations, RemovalRelations, ++ TargetDeviceRelation, SingleBusRelations, ++}; ++ ++enum bus_query_id_type { ++ BusQueryDeviceID = 0, BusQueryHardwareIDs = 1, ++ BusQueryCompatibleIDs = 2, BusQueryInstanceID = 3, ++ BusQueryDeviceSerialNumber = 4, ++}; ++ ++enum device_text_type { ++ DeviceTextDescription = 0, DeviceTextLocationInformation = 1, ++}; ++ ++enum device_usage_notification_type { ++ DeviceUsageTypeUndefined, DeviceUsageTypePaging, ++ DeviceUsageTypeHibernation, DevbiceUsageTypeDumpFile, ++}; ++ ++#define METHOD_BUFFERED 0 ++#define METHOD_IN_DIRECT 1 ++#define METHOD_OUT_DIRECT 2 ++#define METHOD_NEITHER 3 ++ ++#define CTL_CODE(dev_type, func, method, access) \ ++ (((dev_type) << 16) | ((access) << 14) | ((func) << 2) | (method)) ++ ++#define IO_METHOD_FROM_CTL_CODE(code) (code & 0x3) ++ ++#ifndef CONFIG_X86_64 ++#pragma pack(push,4) ++#endif ++struct io_stack_location { ++ UCHAR major_fn; ++ UCHAR minor_fn; ++ UCHAR flags; ++ UCHAR control; ++ union { ++ struct { ++ void *security_context; ++ ULONG options; ++ USHORT POINTER_ALIGN file_attributes; ++ USHORT share_access; ++ ULONG POINTER_ALIGN ea_length; ++ } create; ++ struct { ++ ULONG length; ++ ULONG POINTER_ALIGN key; ++ LARGE_INTEGER byte_offset; ++ } read; ++ struct { ++ ULONG length; ++ ULONG POINTER_ALIGN key; ++ LARGE_INTEGER byte_offset; ++ } write; ++ struct { ++ ULONG length; ++ enum file_info_class POINTER_ALIGN file_info_class; ++ } query_file; ++ struct { ++ ULONG length; ++ enum file_info_class POINTER_ALIGN file_info_class; ++ struct file_object *file_object; ++ union { ++ struct { ++ BOOLEAN replace_if_exists; ++ BOOLEAN advance_only; ++ }; ++ ULONG cluster_count; ++ void *delete_handle; ++ }; ++ } set_file; ++ struct { ++ ULONG length; ++ enum fs_info_class POINTER_ALIGN fs_info_class; ++ } query_volume; ++ struct { ++ ULONG output_buf_len; ++ ULONG POINTER_ALIGN input_buf_len; ++ ULONG POINTER_ALIGN code; ++ void *type3_input_buf; ++ } dev_ioctl; ++ struct { ++ SECURITY_INFORMATION security_info; ++ ULONG POINTER_ALIGN length; ++ } query_security; ++ struct { ++ SECURITY_INFORMATION security_info; ++ void *security_descriptor; ++ } set_security; ++ struct { ++ void *vpb; ++ struct device_object *device_object; ++ } mount_volume; ++ struct { ++ void *vpb; ++ struct device_object *device_object; ++ } verify_volume; ++ struct { ++ void *srb; ++ } scsi; ++ struct { ++ enum device_relation_type type; ++ } query_device_relations; ++ struct { ++ const struct guid *type; ++ USHORT size; ++ USHORT version; ++ struct nt_interface *intf; ++ void *intf_data; ++ } query_intf; ++ struct { ++ void *capabilities; ++ } device_capabilities; ++ struct { ++ void *io_resource_requirement_list; ++ } filter_resource_requirements; ++ struct { ++ ULONG which_space; ++ void *buffer; ++ ULONG offset; ++ ULONG POINTER_ALIGN length; ++ } read_write_config; ++ struct { ++ BOOLEAN lock; ++ } set_lock; ++ struct { ++ enum bus_query_id_type id_type; ++ } query_id; ++ struct { ++ enum device_text_type device_text_type; ++ ULONG POINTER_ALIGN locale_id; ++ } query_device_text; ++ struct { ++ BOOLEAN in_path; ++ BOOLEAN reserved[3]; ++ enum device_usage_notification_type POINTER_ALIGN type; ++ } usage_notification; ++ struct { ++ enum system_power_state power_state; ++ } wait_wake; ++ struct { ++ void *power_sequence; ++ } power_sequence; ++ struct { ++ ULONG sys_context; ++ enum power_state_type POINTER_ALIGN type; ++ union power_state POINTER_ALIGN state; ++ enum power_action POINTER_ALIGN shutdown_type; ++ } power; ++ struct { ++ struct cm_resource_list *allocated_resources; ++ struct cm_resource_list *allocated_resources_translated; ++ } start_device; ++ struct { ++ ULONG_PTR provider_id; ++ void *data_path; ++ ULONG buf_len; ++ void *buf; ++ } wmi; ++ struct { ++ void *arg1; ++ void *arg2; ++ void *arg3; ++ void *arg4; ++ } others; ++ } params; ++ struct device_object *dev_obj; ++ struct file_object *file_obj; ++ NTSTATUS (*completion_routine)(struct device_object *, ++ struct irp *, void *) wstdcall; ++ void *context; ++}; ++#ifndef CONFIG_X86_64 ++#pragma pack(pop) ++#endif ++ ++struct kapc { ++ CSHORT type; ++ CSHORT size; ++ ULONG spare0; ++ struct nt_thread *thread; ++ struct nt_list list; ++ void *kernele_routine; ++ void *rundown_routine; ++ void *normal_routine; ++ void *normal_context; ++ void *sys_arg1; ++ void *sys_arg2; ++ CCHAR apc_state_index; ++ KPROCESSOR_MODE apc_mode; ++ BOOLEAN inserted; ++}; ++ ++#define IRP_NOCACHE 0x00000001 ++#define IRP_SYNCHRONOUS_API 0x00000004 ++#define IRP_ASSOCIATED_IRP 0x00000008 ++ ++enum urb_state { ++ URB_INVALID = 1, URB_ALLOCATED, URB_SUBMITTED, ++ URB_COMPLETED, URB_FREE, URB_SUSPEND, URB_INT_UNLINKED }; ++ ++struct wrap_urb { ++ struct nt_list list; ++ enum urb_state state; ++ struct nt_list complete_list; ++ unsigned int flags; ++ struct urb *urb; ++ struct irp *irp; ++#ifdef USB_DEBUG ++ unsigned int id; ++#endif ++}; ++ ++struct irp { ++ SHORT type; ++ USHORT size; ++ struct mdl *mdl; ++ ULONG flags; ++ union { ++ struct irp *master_irp; ++ LONG irp_count; ++ void *system_buffer; ++ } associated_irp; ++ struct nt_list thread_list; ++ struct io_status_block io_status; ++ KPROCESSOR_MODE requestor_mode; ++ BOOLEAN pending_returned; ++ CHAR stack_count; ++ CHAR current_location; ++ BOOLEAN cancel; ++ KIRQL cancel_irql; ++ CCHAR apc_env; ++ UCHAR alloc_flags; ++ struct io_status_block *user_status; ++ struct nt_event *user_event; ++ union { ++ struct { ++ void *user_apc_routine; ++ void *user_apc_context; ++ } async_params; ++ LARGE_INTEGER alloc_size; ++ } overlay; ++ void (*cancel_routine)(struct device_object *, struct irp *) wstdcall; ++ void *user_buf; ++ union { ++ struct { ++ union { ++ struct kdevice_queue_entry dev_q_entry; ++ struct { ++ void *driver_context[4]; ++ }; ++ }; ++ void *thread; ++ char *aux_buf; ++ struct { ++ struct nt_list list; ++ union { ++ struct io_stack_location *csl; ++ ULONG packet_type; ++ }; ++ }; ++ struct file_object *file_object; ++ } overlay; ++ union { ++ struct kapc apc; ++ /* space for apc is used for ndiswrapper ++ * specific fields */ ++ struct { ++ struct wrap_urb *wrap_urb; ++ struct wrap_device *wrap_device; ++ }; ++ }; ++ void *completion_key; ++ } tail; ++}; ++ ++#define IoSizeOfIrp(stack_count) \ ++ ((USHORT)(sizeof(struct irp) + \ ++ ((stack_count) * sizeof(struct io_stack_location)))) ++#define IoGetCurrentIrpStackLocation(irp) \ ++ (irp)->tail.overlay.csl ++#define IoGetNextIrpStackLocation(irp) \ ++ (IoGetCurrentIrpStackLocation(irp) - 1) ++#define IoGetPreviousIrpStackLocation(irp) \ ++ (IoGetCurrentIrpStackLocation(irp) + 1) ++ ++#define IoSetNextIrpStackLocation(irp) \ ++do { \ ++ KIRQL _irql_; \ ++ IoAcquireCancelSpinLock(&_irql_); \ ++ (irp)->current_location--; \ ++ IoGetCurrentIrpStackLocation(irp)--; \ ++ IoReleaseCancelSpinLock(_irql_); \ ++} while (0) ++ ++#define IoSkipCurrentIrpStackLocation(irp) \ ++do { \ ++ KIRQL _irql_; \ ++ IoAcquireCancelSpinLock(&_irql_); \ ++ (irp)->current_location++; \ ++ IoGetCurrentIrpStackLocation(irp)++; \ ++ IoReleaseCancelSpinLock(_irql_); \ ++} while (0) ++ ++static inline void ++IoCopyCurrentIrpStackLocationToNext(struct irp *irp) ++{ ++ struct io_stack_location *next; ++ next = IoGetNextIrpStackLocation(irp); ++ memcpy(next, IoGetCurrentIrpStackLocation(irp), ++ offsetof(struct io_stack_location, completion_routine)); ++ next->control = 0; ++} ++ ++static inline void ++IoSetCompletionRoutine(struct irp *irp, void *routine, void *context, ++ BOOLEAN success, BOOLEAN error, BOOLEAN cancel) ++{ ++ struct io_stack_location *irp_sl = IoGetNextIrpStackLocation(irp); ++ irp_sl->completion_routine = routine; ++ irp_sl->context = context; ++ irp_sl->control = 0; ++ if (success) ++ irp_sl->control |= SL_INVOKE_ON_SUCCESS; ++ if (error) ++ irp_sl->control |= SL_INVOKE_ON_ERROR; ++ if (cancel) ++ irp_sl->control |= SL_INVOKE_ON_CANCEL; ++} ++ ++#define IoMarkIrpPending(irp) \ ++ (IoGetCurrentIrpStackLocation((irp))->control |= SL_PENDING_RETURNED) ++#define IoUnmarkIrpPending(irp) \ ++ (IoGetCurrentIrpStackLocation((irp))->control &= ~SL_PENDING_RETURNED) ++ ++#define IRP_SL(irp, n) (((struct io_stack_location *)((irp) + 1)) + (n)) ++#define IRP_DRIVER_CONTEXT(irp) (irp)->tail.overlay.driver_context ++#define IoIrpThread(irp) ((irp)->tail.overlay.thread) ++ ++#define IRP_URB(irp) \ ++ (union nt_urb *)(IoGetCurrentIrpStackLocation(irp)->params.others.arg1) ++ ++#define IRP_WRAP_DEVICE(irp) (irp)->tail.wrap_device ++#define IRP_WRAP_URB(irp) (irp)->tail.wrap_urb ++ ++struct wmi_guid_reg_info { ++ struct guid *guid; ++ ULONG instance_count; ++ ULONG flags; ++}; ++ ++struct wmilib_context { ++ ULONG guid_count; ++ struct wmi_guid_reg_info *guid_list; ++ void *query_wmi_reg_info; ++ void *query_wmi_data_block; ++ void *set_wmi_data_block; ++ void *set_wmi_data_item; ++ void *execute_wmi_method; ++ void *wmi_function_control; ++}; ++ ++enum key_value_information_class { ++ KeyValueBasicInformation, KeyValueFullInformation, ++ KeyValuePartialInformation, KeyValueFullInformationAlign64, ++ KeyValuePartialInformationAlign64 ++}; ++ ++struct file_name_info { ++ ULONG length; ++ wchar_t *name; ++}; ++ ++struct file_std_info { ++ LARGE_INTEGER alloc_size; ++ LARGE_INTEGER eof; ++ ULONG num_links; ++ BOOLEAN delete_pending; ++ BOOLEAN dir; ++}; ++ ++enum nt_obj_type { ++ NT_OBJ_EVENT = 10, NT_OBJ_MUTEX, NT_OBJ_THREAD, NT_OBJ_TIMER, ++ NT_OBJ_SEMAPHORE, ++}; ++ ++enum common_object_type { ++ OBJECT_TYPE_NONE, OBJECT_TYPE_DEVICE, OBJECT_TYPE_DRIVER, ++ OBJECT_TYPE_NT_THREAD, OBJECT_TYPE_FILE, OBJECT_TYPE_CALLBACK, ++}; ++ ++struct common_object_header { ++ struct nt_list list; ++ enum common_object_type type; ++ UINT size; ++ UINT ref_count; ++ BOOLEAN close_in_process; ++ BOOLEAN permanent; ++ struct unicode_string name; ++}; ++ ++#define OBJECT_TO_HEADER(object) \ ++ (struct common_object_header *)((void *)(object) - \ ++ sizeof(struct common_object_header)) ++#define OBJECT_SIZE(size) \ ++ ((size) + sizeof(struct common_object_header)) ++#define HEADER_TO_OBJECT(hdr) \ ++ ((void *)(hdr) + sizeof(struct common_object_header)) ++#define HANDLE_TO_OBJECT(handle) HEADER_TO_OBJECT(handle) ++#define HANDLE_TO_HEADER(handle) (handle) ++ ++enum work_queue_type { ++ CriticalWorkQueue, DelayedWorkQueue, HyperCriticalWorkQueue, ++ MaximumWorkQueue ++}; ++ ++typedef void (*NTOS_WORK_FUNC)(void *arg1, void *arg2) wstdcall; ++ ++struct io_workitem { ++ enum work_queue_type type; ++ struct device_object *dev_obj; ++ NTOS_WORK_FUNC worker_routine; ++ void *context; ++}; ++ ++struct io_workitem_entry { ++ struct nt_list list; ++ struct io_workitem *io_workitem; ++}; ++ ++enum mm_page_priority { ++ LowPagePriority, NormalPagePriority = 16, HighPagePriority = 32 ++}; ++ ++enum kinterrupt_mode { ++ LevelSensitive, Latched ++}; ++ ++enum ntos_wait_reason { ++ Executive, FreePage, PageIn, PoolAllocation, DelayExecution, ++ Suspended, UserRequest, WrExecutive, WrFreePage, WrPageIn, ++ WrPoolAllocation, WrDelayExecution, WrSuspended, WrUserRequest, ++ WrEventPair, WrQueue, WrLpcReceive, WrLpcReply, WrVirtualMemory, ++ WrPageOut, WrRendezvous, Spare2, Spare3, Spare4, Spare5, Spare6, ++ WrKernel, MaximumWaitReason ++}; ++ ++typedef enum ntos_wait_reason KWAIT_REASON; ++ ++typedef void *LOOKASIDE_ALLOC_FUNC(enum pool_type pool_type, ++ SIZE_T size, ULONG tag) wstdcall; ++typedef void LOOKASIDE_FREE_FUNC(void *) wstdcall; ++ ++struct npaged_lookaside_list { ++ nt_slist_header head; ++ USHORT depth; ++ USHORT maxdepth; ++ ULONG totalallocs; ++ union { ++ ULONG allocmisses; ++ ULONG allochits; ++ } u1; ++ ULONG totalfrees; ++ union { ++ ULONG freemisses; ++ ULONG freehits; ++ } u2; ++ enum pool_type pool_type; ++ ULONG tag; ++ ULONG size; ++ LOOKASIDE_ALLOC_FUNC *alloc_func; ++ LOOKASIDE_FREE_FUNC *free_func; ++ struct nt_list list; ++ ULONG lasttotallocs; ++ union { ++ ULONG lastallocmisses; ++ ULONG lastallochits; ++ } u3; ++ ULONG pad[2]; ++#ifndef CONFIG_X86_64 ++ NT_SPIN_LOCK obsolete; ++#endif ++} ++#ifdef CONFIG_X86_64 ++CACHE_ALIGN ++#endif ++; ++ ++enum device_registry_property { ++ DevicePropertyDeviceDescription, DevicePropertyHardwareID, ++ DevicePropertyCompatibleIDs, DevicePropertyBootConfiguration, ++ DevicePropertyBootConfigurationTranslated, ++ DevicePropertyClassName, DevicePropertyClassGuid, ++ DevicePropertyDriverKeyName, DevicePropertyManufacturer, ++ DevicePropertyFriendlyName, DevicePropertyLocationInformation, ++ DevicePropertyPhysicalDeviceObjectName, DevicePropertyBusTypeGuid, ++ DevicePropertyLegacyBusType, DevicePropertyBusNumber, ++ DevicePropertyEnumeratorName, DevicePropertyAddress, ++ DevicePropertyUINumber, DevicePropertyInstallState, ++ DevicePropertyRemovalPolicy ++}; ++ ++enum trace_information_class { ++ TraceIdClass, TraceHandleClass, TraceEnableFlagsClass, ++ TraceEnableLevelClass, GlobalLoggerHandleClass, EventLoggerHandleClass, ++ AllLoggerHandlesClass, TraceHandleByNameClass ++}; ++ ++struct kinterrupt; ++typedef BOOLEAN (*PKSERVICE_ROUTINE)(struct kinterrupt *interrupt, ++ void *context) wstdcall; ++typedef BOOLEAN (*PKSYNCHRONIZE_ROUTINE)(void *context) wstdcall; ++ ++struct kinterrupt { ++ ULONG vector; ++ KAFFINITY cpu_mask; ++ NT_SPIN_LOCK lock; ++ NT_SPIN_LOCK *actual_lock; ++ BOOLEAN shared; ++ BOOLEAN save_fp; ++ union { ++ CHAR processor_number; ++#ifdef CONFIG_DEBUG_SHIRQ ++ CHAR enabled; ++#endif ++ } u; ++ PKSERVICE_ROUTINE isr; ++ void *isr_ctx; ++ struct nt_list list; ++ KIRQL irql; ++ KIRQL synch_irql; ++ enum kinterrupt_mode mode; ++}; ++ ++struct time_fields { ++ CSHORT year; ++ CSHORT month; ++ CSHORT day; ++ CSHORT hour; ++ CSHORT minute; ++ CSHORT second; ++ CSHORT milliseconds; ++ CSHORT weekday; ++}; ++ ++struct object_attributes { ++ ULONG length; ++ void *root_dir; ++ struct unicode_string *name; ++ ULONG attributes; ++ void *security_descr; ++ void *security_qos; ++}; ++ ++typedef void (*PCALLBACK_FUNCTION)(void *context, void *arg1, ++ void *arg2) wstdcall; ++ ++struct callback_object; ++struct callback_func { ++ PCALLBACK_FUNCTION func; ++ void *context; ++ struct nt_list list; ++ struct callback_object *object; ++}; ++ ++struct callback_object { ++ NT_SPIN_LOCK lock; ++ struct nt_list list; ++ struct nt_list callback_funcs; ++ BOOLEAN allow_multiple_callbacks; ++ struct object_attributes *attributes; ++}; ++ ++enum section_inherit { ++ ViewShare = 1, ViewUnmap = 2 ++}; ++ ++struct ksystem_time { ++ ULONG low_part; ++ LONG high1_time; ++ LONG high2_time; ++}; ++ ++enum nt_product_type { ++ nt_product_win_nt = 1, nt_product_lan_man_nt, nt_product_server ++}; ++ ++enum alt_arch_type { ++ arch_type_standard, arch_type_nex98x86, end_alternatives ++}; ++ ++struct kuser_shared_data { ++ ULONG tick_count; ++ ULONG tick_count_multiplier; ++ volatile struct ksystem_time interrupt_time; ++ volatile struct ksystem_time system_time; ++ volatile struct ksystem_time time_zone_bias; ++ USHORT image_number_low; ++ USHORT image_number_high; ++ wchar_t nt_system_root[260]; ++ ULONG max_stack_trace_depth; ++ ULONG crypto_exponent; ++ ULONG time_zone_id; ++ ULONG large_page_min; ++ ULONG reserved2[7]; ++ enum nt_product_type nt_product_type; ++ BOOLEAN product_type_is_valid; ++ ULONG nt_major_version; ++ ULONG nt_minor_version; ++ BOOLEAN processor_features[PROCESSOR_FEATURE_MAX]; ++ ULONG reserved1; ++ ULONG reserved3; ++ volatile LONG time_slip; ++ enum alt_arch_type alt_arch_type; ++ LARGE_INTEGER system_expiration_date; ++ ULONG suite_mask; ++ BOOLEAN kdbg_enabled; ++ volatile ULONG active_console; ++ volatile ULONG dismount_count; ++ ULONG com_plus_package; ++ ULONG last_system_rite_event_tick_count; ++ ULONG num_phys_pages; ++ BOOLEAN safe_boot_mode; ++ ULONG trace_log; ++ ULONGLONG fill0; ++ ULONGLONG sys_call[4]; ++ union { ++ volatile struct ksystem_time tick_count; ++ volatile ULONG64 tick_count_quad; ++ } tick; ++}; ++ ++#define REG_NONE (0) ++#define REG_SZ (1) ++#define REG_EXPAND_SZ (2) ++#define REG_BINARY (3) ++#define REG_DWORD (4) ++ ++#define RTL_REGISTRY_ABSOLUTE 0 ++#define RTL_REGISTRY_SERVICES 1 ++#define RTL_REGISTRY_CONTROL 2 ++#define RTL_REGISTRY_WINDOWS_NT 3 ++#define RTL_REGISTRY_DEVICEMAP 4 ++#define RTL_REGISTRY_USER 5 ++#define RTL_REGISTRY_MAXIMUM 6 ++#define RTL_REGISTRY_HANDLE 0x40000000 ++#define RTL_REGISTRY_OPTIONAL 0x80000000 ++ ++#define RTL_QUERY_REGISTRY_SUBKEY 0x00000001 ++#define RTL_QUERY_REGISTRY_TOPKEY 0x00000002 ++#define RTL_QUERY_REGISTRY_REQUIRED 0x00000004 ++#define RTL_QUERY_REGISTRY_NOVALUE 0x00000008 ++#define RTL_QUERY_REGISTRY_NOEXPAND 0x00000010 ++#define RTL_QUERY_REGISTRY_DIRECT 0x00000020 ++#define RTL_QUERY_REGISTRY_DELETE 0x00000040 ++ ++typedef NTSTATUS (*PRTL_QUERY_REGISTRY_ROUTINE)(wchar_t *name, ULONG type, ++ void *data, ULONG length, ++ void *context, ++ void *entry) wstdcall; ++ ++struct rtl_query_registry_table { ++ PRTL_QUERY_REGISTRY_ROUTINE query_func; ++ ULONG flags; ++ wchar_t *name; ++ void *context; ++ ULONG def_type; ++ void *def_data; ++ ULONG def_length; ++}; ++ ++struct io_remove_lock { ++ BOOLEAN removed; ++ BOOLEAN reserved[3]; ++ LONG io_count; ++ struct nt_event remove_event; ++}; ++ ++struct io_error_log_packet { ++ UCHAR major_fn_code; ++ UCHAR retry_count; ++ USHORT dump_data_size; ++ USHORT nr_of_strings; ++ USHORT string_offset; ++ USHORT event_category; ++ NTSTATUS error_code; ++ ULONG unique_error_value; ++ NTSTATUS final_status; ++ ULONG sequence_number; ++ ULONG io_control_code; ++ LARGE_INTEGER device_offset; ++ ULONG dump_data[1]; ++}; ++ ++/* some of the functions below are slightly different from DDK's ++ * implementation; e.g., Insert functions return appropriate ++ * pointer */ ++ ++/* instead of using Linux's lists, we implement list manipulation ++ * functions because nt_list is used by drivers and we don't want to ++ * worry about Linux's list being different from nt_list (right now ++ * they are same, but in future they could be different) */ ++ ++static inline void InitializeListHead(struct nt_list *head) ++{ ++ head->next = head->prev = head; ++} ++ ++static inline BOOLEAN IsListEmpty(struct nt_list *head) ++{ ++ if (head == head->next) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++static inline void RemoveEntryList(struct nt_list *entry) ++{ ++ entry->prev->next = entry->next; ++ entry->next->prev = entry->prev; ++} ++ ++static inline struct nt_list *RemoveHeadList(struct nt_list *head) ++{ ++ struct nt_list *entry; ++ ++ entry = head->next; ++ if (entry == head) ++ return NULL; ++ else { ++ RemoveEntryList(entry); ++ return entry; ++ } ++} ++ ++static inline struct nt_list *RemoveTailList(struct nt_list *head) ++{ ++ struct nt_list *entry; ++ ++ entry = head->prev; ++ if (entry == head) ++ return NULL; ++ else { ++ RemoveEntryList(entry); ++ return entry; ++ } ++} ++ ++static inline void InsertListEntry(struct nt_list *entry, struct nt_list *prev, ++ struct nt_list *next) ++{ ++ next->prev = entry; ++ entry->next = next; ++ entry->prev = prev; ++ prev->next = entry; ++} ++ ++static inline struct nt_list *InsertHeadList(struct nt_list *head, ++ struct nt_list *entry) ++{ ++ struct nt_list *ret; ++ ++ if (IsListEmpty(head)) ++ ret = NULL; ++ else ++ ret = head->next; ++ ++ InsertListEntry(entry, head, head->next); ++ return ret; ++} ++ ++static inline struct nt_list *InsertTailList(struct nt_list *head, ++ struct nt_list *entry) ++{ ++ struct nt_list *ret; ++ ++ if (IsListEmpty(head)) ++ ret = NULL; ++ else ++ ret = head->prev; ++ ++ InsertListEntry(entry, head->prev, head); ++ return ret; ++} ++ ++#define nt_list_for_each(pos, head) \ ++ for (pos = (head)->next; pos != (head); pos = pos->next) ++ ++#define nt_list_for_each_entry(pos, head, member) \ ++ for (pos = container_of((head)->next, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = container_of(pos->member.next, typeof(*pos), member)) ++ ++#define nt_list_for_each_safe(pos, n, head) \ ++ for (pos = (head)->next, n = pos->next; pos != (head); \ ++ pos = n, n = pos->next) ++ ++/* device object flags */ ++#define DO_VERIFY_VOLUME 0x00000002 ++#define DO_BUFFERED_IO 0x00000004 ++#define DO_EXCLUSIVE 0x00000008 ++#define DO_DIRECT_IO 0x00000010 ++#define DO_MAP_IO_BUFFER 0x00000020 ++#define DO_DEVICE_HAS_NAME 0x00000040 ++#define DO_DEVICE_INITIALIZING 0x00000080 ++#define DO_SYSTEM_BOOT_PARTITION 0x00000100 ++#define DO_LONG_TERM_REQUESTS 0x00000200 ++#define DO_NEVER_LAST_DEVICE 0x00000400 ++#define DO_SHUTDOWN_REGISTERED 0x00000800 ++#define DO_BUS_ENUMERATED_DEVICE 0x00001000 ++#define DO_POWER_PAGABLE 0x00002000 ++#define DO_POWER_INRUSH 0x00004000 ++#define DO_LOW_PRIORITY_FILESYSTEM 0x00010000 ++ ++/* Various supported device types (used with IoCreateDevice()) */ ++ ++#define FILE_DEVICE_BEEP 0x00000001 ++#define FILE_DEVICE_CD_ROM 0x00000002 ++#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 ++#define FILE_DEVICE_CONTROLLER 0x00000004 ++#define FILE_DEVICE_DATALINK 0x00000005 ++#define FILE_DEVICE_DFS 0x00000006 ++#define FILE_DEVICE_DISK 0x00000007 ++#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 ++#define FILE_DEVICE_FILE_SYSTEM 0x00000009 ++#define FILE_DEVICE_INPORT_PORT 0x0000000A ++#define FILE_DEVICE_KEYBOARD 0x0000000B ++#define FILE_DEVICE_MAILSLOT 0x0000000C ++#define FILE_DEVICE_MIDI_IN 0x0000000D ++#define FILE_DEVICE_MIDI_OUT 0x0000000E ++#define FILE_DEVICE_MOUSE 0x0000000F ++#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010 ++#define FILE_DEVICE_NAMED_PIPE 0x00000011 ++#define FILE_DEVICE_NETWORK 0x00000012 ++#define FILE_DEVICE_NETWORK_BROWSER 0x00000013 ++#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 ++#define FILE_DEVICE_NULL 0x00000015 ++#define FILE_DEVICE_PARALLEL_PORT 0x00000016 ++#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017 ++#define FILE_DEVICE_PRINTER 0x00000018 ++#define FILE_DEVICE_SCANNER 0x00000019 ++#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001A ++#define FILE_DEVICE_SERIAL_PORT 0x0000001B ++#define FILE_DEVICE_SCREEN 0x0000001C ++#define FILE_DEVICE_SOUND 0x0000001D ++#define FILE_DEVICE_STREAMS 0x0000001E ++#define FILE_DEVICE_TAPE 0x0000001F ++#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 ++#define FILE_DEVICE_TRANSPORT 0x00000021 ++#define FILE_DEVICE_UNKNOWN 0x00000022 ++#define FILE_DEVICE_VIDEO 0x00000023 ++#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 ++#define FILE_DEVICE_WAVE_IN 0x00000025 ++#define FILE_DEVICE_WAVE_OUT 0x00000026 ++#define FILE_DEVICE_8042_PORT 0x00000027 ++#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 ++#define FILE_DEVICE_BATTERY 0x00000029 ++#define FILE_DEVICE_BUS_EXTENDER 0x0000002A ++#define FILE_DEVICE_MODEM 0x0000002B ++#define FILE_DEVICE_VDM 0x0000002C ++#define FILE_DEVICE_MASS_STORAGE 0x0000002D ++#define FILE_DEVICE_SMB 0x0000002E ++#define FILE_DEVICE_KS 0x0000002F ++#define FILE_DEVICE_CHANGER 0x00000030 ++#define FILE_DEVICE_SMARTCARD 0x00000031 ++#define FILE_DEVICE_ACPI 0x00000032 ++#define FILE_DEVICE_DVD 0x00000033 ++#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034 ++#define FILE_DEVICE_DFS_FILE_SYSTEM 0x00000035 ++#define FILE_DEVICE_DFS_VOLUME 0x00000036 ++#define FILE_DEVICE_SERENUM 0x00000037 ++#define FILE_DEVICE_TERMSRV 0x00000038 ++#define FILE_DEVICE_KSEC 0x00000039 ++#define FILE_DEVICE_FIPS 0x0000003A ++ ++/* Device characteristics */ ++ ++#define FILE_REMOVABLE_MEDIA 0x00000001 ++#define FILE_READ_ONLY_DEVICE 0x00000002 ++#define FILE_FLOPPY_DISKETTE 0x00000004 ++#define FILE_WRITE_ONCE_MEDIA 0x00000008 ++#define FILE_REMOTE_DEVICE 0x00000010 ++#define FILE_DEVICE_IS_MOUNTED 0x00000020 ++#define FILE_VIRTUAL_VOLUME 0x00000040 ++#define FILE_AUTOGENERATED_DEVICE_NAME 0x00000080 ++#define FILE_DEVICE_SECURE_OPEN 0x00000100 ++ ++#define FILE_READ_DATA 0x0001 ++#define FILE_WRITE_DATA 0x0002 ++ ++#define FILE_SUPERSEDED 0x00000000 ++#define FILE_OPENED 0x00000001 ++#define FILE_CREATED 0x00000002 ++#define FILE_OVERWRITTEN 0x00000003 ++#define FILE_EXISTS 0x00000004 ++#define FILE_DOES_NOT_EXIST 0x00000005 ++ ++ ++#endif /* WINNT_TYPES_H */ +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/workqueue.c linux-4.6-rc6-ndis/3rdparty/ndiswrapper/workqueue.c +--- linux-4.6-rc6/3rdparty/ndiswrapper/workqueue.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/workqueue.c 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,279 @@ ++/* ++ * Copyright (C) 2006 Giridhar Pemmasani ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include "ntoskernel.h" ++ ++struct workqueue_thread { ++ spinlock_t lock; ++ struct task_struct *task; ++ struct completion *completion; ++ char name[16]; ++ int pid; ++ /* whether any work_structs pending? <0 implies quit */ ++ s8 pending; ++ /* list of work_structs pending */ ++ struct list_head work_list; ++}; ++ ++struct workq_thread_data { ++ struct workqueue_struct *workq; ++ int index; ++}; ++ ++struct wrap_workqueue_struct { ++ u8 singlethread; ++ u8 qon; ++ int num_cpus; ++ struct workqueue_thread threads[0]; ++}; ++ ++static void wrap_destroy_wq_on(struct workqueue_struct *workq, int cpu); ++ ++static int workq_thread(void *data) ++{ ++ struct workq_thread_data *thread_data = data; ++ struct workqueue_thread *thread; ++ struct workqueue_struct *workq; ++ struct work_struct *work; ++ ++ workq = thread_data->workq; ++ thread = &workq->threads[thread_data->index]; ++ WORKTRACE("%p, %d, %p", workq, thread_data->index, thread); ++ strncpy(thread->name, current->comm, sizeof(thread->name)); ++ ++ daemonize(thread->name); ++ set_user_nice(current, -5); ++ ++ if (thread->task != current) { ++ WARNING("invalid task: %p, %p", thread->task, current); ++ thread->task = current; ++ } ++ thread->pid = current->pid; ++ complete(xchg(&thread->completion, NULL)); ++ WORKTRACE("%s (%d) started", thread->name, thread->pid); ++ while (1) { ++ if (wait_condition(thread->pending, 0, TASK_INTERRUPTIBLE) < 0) { ++ /* TODO: deal with signal */ ++ WARNING("signal not blocked?"); ++ flush_signals(current); ++ continue; ++ } ++ while (1) { ++ struct list_head *entry; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&thread->lock, flags); ++ if (list_empty(&thread->work_list)) { ++ struct completion *completion; ++ if (thread->pending < 0) { ++ spin_unlock_irqrestore(&thread->lock, ++ flags); ++ goto out; ++ } ++ thread->pending = 0; ++ completion = thread->completion; ++ thread->completion = NULL; ++ spin_unlock_irqrestore(&thread->lock, flags); ++ if (completion) ++ complete(completion); ++ break; ++ } ++ entry = thread->work_list.next; ++ work = list_entry(entry, struct work_struct, list); ++ if (xchg(&work->thread, NULL)) ++ list_del(entry); ++ else ++ work = NULL; ++ spin_unlock_irqrestore(&thread->lock, flags); ++ DBG_BLOCK(4) { ++ WORKTRACE("%p, %p", work, thread); ++ } ++ if (work) ++ work->func(work->data); ++ } ++ } ++ ++out: ++ WORKTRACE("%s exiting", thread->name); ++ thread->pid = 0; ++ return 0; ++} ++ ++static int wrap_queue_work_on(struct workqueue_struct *workq, ++ struct work_struct *work, int cpu) ++{ ++ struct workqueue_thread *thread = &workq->threads[cpu]; ++ unsigned long flags; ++ int ret; ++ ++ assert(thread->pid > 0); ++ DBG_BLOCK(4) { ++ WORKTRACE("%p, %d", workq, cpu); ++ } ++ spin_lock_irqsave(&thread->lock, flags); ++ if (work->thread) ++ ret = 0; ++ else { ++ work->thread = thread; ++ list_add_tail(&work->list, &thread->work_list); ++ thread->pending = 1; ++ wake_up_process(thread->task); ++ ret = 1; ++ } ++ spin_unlock_irqrestore(&thread->lock, flags); ++ return ret; ++} ++ ++int wrap_queue_work(struct workqueue_struct *workq, struct work_struct *work) ++{ ++ if (num_online_cpus() == 1 || workq->singlethread) ++ return wrap_queue_work_on(workq, work, 0); ++ else { ++ typeof(workq->qon) qon; ++ /* work is queued on threads in a round-robin fashion */ ++ do { ++ qon = workq->qon % workq->num_cpus; ++ atomic_inc_var(workq->qon); ++ } while (!workq->threads[qon].pid); ++ return wrap_queue_work_on(workq, work, qon); ++ } ++} ++ ++void wrap_cancel_work(struct work_struct *work) ++{ ++ struct workqueue_thread *thread; ++ unsigned long flags; ++ ++ WORKTRACE("%p", work); ++ if ((thread = xchg(&work->thread, NULL))) { ++ WORKTRACE("%p", thread); ++ spin_lock_irqsave(&thread->lock, flags); ++ list_del(&work->list); ++ spin_unlock_irqrestore(&thread->lock, flags); ++ } ++} ++ ++struct workqueue_struct *wrap_create_wq(const char *name, u8 singlethread, ++ u8 freeze) ++{ ++ struct completion started; ++ struct workqueue_struct *workq; ++ int i, n; ++ ++ if (singlethread) ++ n = 1; ++ else ++ n = num_online_cpus(); ++ workq = kzalloc(sizeof(*workq) + n * sizeof(workq->threads[0]), ++ GFP_KERNEL); ++ if (!workq) { ++ WARNING("couldn't allocate memory"); ++ return NULL; ++ } ++ WORKTRACE("%p", workq); ++ workq->singlethread = singlethread; ++ init_completion(&started); ++ for_each_online_cpu(i) { ++ struct workq_thread_data thread_data; ++ spin_lock_init(&workq->threads[i].lock); ++ INIT_LIST_HEAD(&workq->threads[i].work_list); ++ reinit_completion(&started); ++ workq->threads[i].completion = &started; ++ thread_data.workq = workq; ++ thread_data.index = i; ++ WORKTRACE("%p, %d, %p", workq, i, &workq->threads[i]); ++ workq->threads[i].task = ++ kthread_create(workq_thread, &thread_data, ++ "%s/%d", name, i); ++ if (IS_ERR(workq->threads[i].task)) { ++ int j; ++ for (j = 0; j < i; j++) ++ wrap_destroy_wq_on(workq, j); ++ kfree(workq); ++ WARNING("couldn't start thread %s", name); ++ return NULL; ++ } ++#ifdef PF_NOFREEZE ++ if (!freeze) ++ workq->threads[i].task->flags |= PF_NOFREEZE; ++#endif ++ kthread_bind(workq->threads[i].task, i); ++ workq->num_cpus = max(workq->num_cpus, i); ++ wake_up_process(workq->threads[i].task); ++ wait_for_completion(&started); ++ WORKTRACE("%s, %d: %p, %d", name, i, ++ workq, workq->threads[i].pid); ++ if (singlethread) ++ break; ++ } ++ workq->num_cpus++; ++ return workq; ++} ++ ++static void wrap_flush_wq_on(struct workqueue_struct *workq, int cpu) ++{ ++ struct workqueue_thread *thread = &workq->threads[cpu]; ++ struct completion done; ++ ++ WORKTRACE("%p: %d, %s", workq, cpu, thread->name); ++ init_completion(&done); ++ thread->completion = &done; ++ thread->pending = 1; ++ wake_up_process(thread->task); ++ wait_for_completion(&done); ++ return; ++} ++ ++void wrap_flush_wq(struct workqueue_struct *workq) ++{ ++ int i, n; ++ ++ WORKTRACE("%p", workq); ++ if (workq->singlethread) ++ n = 1; ++ else ++ n = num_online_cpus(); ++ for (i = 0; i < n; i++) ++ wrap_flush_wq_on(workq, i); ++} ++ ++static void wrap_destroy_wq_on(struct workqueue_struct *workq, int cpu) ++{ ++ struct workqueue_thread *thread = &workq->threads[cpu]; ++ ++ WORKTRACE("%p: %d, %s", workq, cpu, thread->name); ++ if (!thread->pid) ++ return; ++ thread->pending = -1; ++ wake_up_process(thread->task); ++ while (thread->pid) { ++ WORKTRACE("%d", thread->pid); ++ schedule(); ++ } ++} ++ ++void wrap_destroy_wq(struct workqueue_struct *workq) ++{ ++ int i, n; ++ ++ WORKTRACE("%p", workq); ++ if (workq->singlethread) ++ n = 1; ++ else ++ n = num_online_cpus(); ++ for (i = 0; i < n; i++) ++ wrap_destroy_wq_on(workq, i); ++ kfree(workq); ++} +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/wrapmem.c linux-4.6-rc6-ndis/3rdparty/ndiswrapper/wrapmem.c +--- linux-4.6-rc6/3rdparty/ndiswrapper/wrapmem.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/wrapmem.c 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,366 @@ ++/* ++ * Copyright (C) 2006 Giridhar Pemmasani ++ * ++ * 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. ++ * ++ */ ++ ++#define _WRAPMEM_C_ ++ ++#include "ntoskernel.h" ++#include "wrapmem.h" ++ ++struct slack_alloc_info { ++ struct nt_list list; ++ size_t size; ++}; ++ ++#if ALLOC_DEBUG > 1 ++static struct nt_list allocs; ++#endif ++ ++static struct nt_list slack_allocs; ++static spinlock_t alloc_lock; ++ ++#if ALLOC_DEBUG ++const char *alloc_type_name[ALLOC_TYPE_MAX] = { ++ "kmalloc_atomic", ++ "kmalloc_nonatomic", ++ "vmalloc_atomic", ++ "vmalloc_nonatomic", ++ "kmalloc_slack", ++ "pages" ++}; ++ ++struct alloc_info { ++ enum alloc_type type; ++ size_t size; ++#if ALLOC_DEBUG > 1 ++ struct nt_list list; ++ const char *file; ++ int line; ++ ULONG tag; ++#endif ++}; ++ ++static atomic_t alloc_sizes[ALLOC_TYPE_MAX]; ++#endif ++ ++/* allocate memory and add it to list of allocated pointers; if a ++ * driver doesn't free this memory for any reason (buggy driver or we ++ * allocate space behind driver's back since we need more space than ++ * corresponding Windows structure provides etc.), this gets freed ++ * automatically when module is unloaded ++ */ ++void *slack_kmalloc(size_t size) ++{ ++ struct slack_alloc_info *info; ++ ++ ENTER4("size = %zu", size); ++ info = kmalloc(size + sizeof(*info), irql_gfp()); ++ if (!info) ++ return NULL; ++ info->size = size; ++ spin_lock_bh(&alloc_lock); ++ InsertTailList(&slack_allocs, &info->list); ++ spin_unlock_bh(&alloc_lock); ++#if ALLOC_DEBUG ++ atomic_add(size, &alloc_sizes[ALLOC_TYPE_SLACK]); ++#endif ++ TRACE4("%p, %p", info, info + 1); ++ EXIT4(return info + 1); ++} ++ ++/* free pointer and remove from list of allocated pointers */ ++void slack_kfree(void *ptr) ++{ ++ struct slack_alloc_info *info; ++ ++ ENTER4("%p", ptr); ++ info = ptr - sizeof(*info); ++ spin_lock_bh(&alloc_lock); ++ RemoveEntryList(&info->list); ++ spin_unlock_bh(&alloc_lock); ++#if ALLOC_DEBUG ++ atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]); ++#endif ++ kfree(info); ++ EXIT4(return); ++} ++ ++void *slack_kzalloc(size_t size) ++{ ++ void *ptr = slack_kmalloc(size); ++ if (ptr) ++ memset(ptr, 0, size); ++ return ptr; ++} ++ ++#if ALLOC_DEBUG ++void *wrap_kmalloc(size_t size, gfp_t flags, const char *file, int line) ++{ ++ struct alloc_info *info; ++ ++ info = kmalloc(size + sizeof(*info), flags); ++ if (!info) ++ return NULL; ++ if (flags & GFP_ATOMIC) ++ info->type = ALLOC_TYPE_KMALLOC_ATOMIC; ++ else ++ info->type = ALLOC_TYPE_KMALLOC_NON_ATOMIC; ++ info->size = size; ++ atomic_add(size, &alloc_sizes[info->type]); ++#if ALLOC_DEBUG > 1 ++ info->file = file; ++ info->line = line; ++ info->tag = 0; ++ spin_lock_bh(&alloc_lock); ++ InsertTailList(&allocs, &info->list); ++ spin_unlock_bh(&alloc_lock); ++#endif ++ TRACE4("%p", info + 1); ++ return info + 1; ++} ++ ++void *wrap_kzalloc(size_t size, gfp_t flags, const char *file, int line) ++{ ++ void *ptr = wrap_kmalloc(size, flags, file, line); ++ if (ptr) ++ memset(ptr, 0, size); ++ return ptr; ++} ++ ++void wrap_kfree(void *ptr) ++{ ++ struct alloc_info *info; ++ ++ TRACE4("%p", ptr); ++ if (!ptr) ++ return; ++ info = ptr - sizeof(*info); ++ atomic_sub(info->size, &alloc_sizes[info->type]); ++#if ALLOC_DEBUG > 1 ++ spin_lock_bh(&alloc_lock); ++ RemoveEntryList(&info->list); ++ spin_unlock_bh(&alloc_lock); ++ if (!(info->type == ALLOC_TYPE_KMALLOC_ATOMIC || ++ info->type == ALLOC_TYPE_KMALLOC_NON_ATOMIC)) { ++ WARNING("invalid type: %d", info->type); ++ return; ++ } ++#endif ++ kfree(info); ++} ++ ++void *wrap_vmalloc(unsigned long size, const char *file, int line) ++{ ++ struct alloc_info *info; ++ ++ info = vmalloc(size + sizeof(*info)); ++ if (!info) ++ return NULL; ++ info->type = ALLOC_TYPE_VMALLOC_NON_ATOMIC; ++ info->size = size; ++ atomic_add(size, &alloc_sizes[info->type]); ++#if ALLOC_DEBUG > 1 ++ info->file = file; ++ info->line = line; ++ info->tag = 0; ++ spin_lock_bh(&alloc_lock); ++ InsertTailList(&allocs, &info->list); ++ spin_unlock_bh(&alloc_lock); ++#endif ++ return info + 1; ++} ++ ++void *wrap__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot, ++ const char *file, int line) ++{ ++ struct alloc_info *info; ++ ++ info = __vmalloc(size + sizeof(*info), gfp_mask, prot); ++ if (!info) ++ return NULL; ++ if (gfp_mask & GFP_ATOMIC) ++ info->type = ALLOC_TYPE_VMALLOC_ATOMIC; ++ else ++ info->type = ALLOC_TYPE_VMALLOC_NON_ATOMIC; ++ info->size = size; ++ atomic_add(size, &alloc_sizes[info->type]); ++#if ALLOC_DEBUG > 1 ++ info->file = file; ++ info->line = line; ++ info->tag = 0; ++ spin_lock_bh(&alloc_lock); ++ InsertTailList(&allocs, &info->list); ++ spin_unlock_bh(&alloc_lock); ++#endif ++ return info + 1; ++} ++ ++void wrap_vfree(void *ptr) ++{ ++ struct alloc_info *info; ++ ++ info = ptr - sizeof(*info); ++ atomic_sub(info->size, &alloc_sizes[info->type]); ++#if ALLOC_DEBUG > 1 ++ spin_lock_bh(&alloc_lock); ++ RemoveEntryList(&info->list); ++ spin_unlock_bh(&alloc_lock); ++ if (!(info->type == ALLOC_TYPE_VMALLOC_ATOMIC || ++ info->type == ALLOC_TYPE_VMALLOC_NON_ATOMIC)) { ++ WARNING("invalid type: %d", info->type); ++ return; ++ } ++#endif ++ vfree(info); ++} ++ ++void *wrap_alloc_pages(gfp_t flags, unsigned int size, ++ const char *file, int line) ++{ ++ struct alloc_info *info; ++ ++ size += sizeof(*info); ++ info = (struct alloc_info *)__get_free_pages(flags, get_order(size)); ++ if (!info) ++ return NULL; ++ info->type = ALLOC_TYPE_PAGES; ++ info->size = size; ++ atomic_add(size, &alloc_sizes[info->type]); ++#if ALLOC_DEBUG > 1 ++ info->file = file; ++ info->line = line; ++ info->tag = 0; ++ spin_lock_bh(&alloc_lock); ++ InsertTailList(&allocs, &info->list); ++ spin_unlock_bh(&alloc_lock); ++#endif ++ return info + 1; ++} ++ ++void wrap_free_pages(unsigned long ptr, int order) ++{ ++ struct alloc_info *info; ++ ++ info = (void *)ptr - sizeof(*info); ++ atomic_sub(info->size, &alloc_sizes[info->type]); ++#if ALLOC_DEBUG > 1 ++ spin_lock_bh(&alloc_lock); ++ RemoveEntryList(&info->list); ++ spin_unlock_bh(&alloc_lock); ++ if (info->type != ALLOC_TYPE_PAGES) { ++ WARNING("invalid type: %d", info->type); ++ return; ++ } ++#endif ++ free_pages((unsigned long)info, get_order(info->size)); ++} ++ ++#if ALLOC_DEBUG > 1 ++void *wrap_ExAllocatePoolWithTag(enum pool_type pool_type, SIZE_T size, ++ ULONG tag, const char *file, int line) ++{ ++ void *addr; ++ struct alloc_info *info; ++ ++ ENTER4("pool_type: %d, size: %zu, tag: %u", pool_type, size, tag); ++ addr = (ExAllocatePoolWithTag)(pool_type, size, tag); ++ if (!addr) ++ return NULL; ++ info = addr - sizeof(*info); ++ info->file = file; ++ info->line = line; ++ info->tag = tag; ++ EXIT4(return addr); ++} ++#endif ++ ++int alloc_size(enum alloc_type type) ++{ ++ if ((int)type >= 0 && type < ALLOC_TYPE_MAX) ++ return atomic_read(&alloc_sizes[type]); ++ else ++ return -EINVAL; ++} ++ ++#endif // ALLOC_DEBUG ++ ++int wrapmem_init(void) ++{ ++#if ALLOC_DEBUG > 1 ++ InitializeListHead(&allocs); ++#endif ++ InitializeListHead(&slack_allocs); ++ spin_lock_init(&alloc_lock); ++ return 0; ++} ++ ++void wrapmem_exit(void) ++{ ++#if ALLOC_DEBUG ++ enum alloc_type type; ++#endif ++ struct nt_list *ent; ++ ++ /* free all pointers on the slack list */ ++ while (1) { ++ struct slack_alloc_info *info; ++ spin_lock_bh(&alloc_lock); ++ ent = RemoveHeadList(&slack_allocs); ++ spin_unlock_bh(&alloc_lock); ++ if (!ent) ++ break; ++ info = container_of(ent, struct slack_alloc_info, list); ++#if ALLOC_DEBUG ++ atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]); ++#endif ++ kfree(info); ++ } ++#if ALLOC_DEBUG ++ for (type = 0; type < ALLOC_TYPE_MAX; type++) { ++ int n = atomic_read(&alloc_sizes[type]); ++ if (n) ++ WARNING("%d bytes of memory in %s leaking", n, ++ alloc_type_name[type]); ++ } ++ ++#if ALLOC_DEBUG > 1 ++ while (1) { ++ struct alloc_info *info; ++ ++ spin_lock_bh(&alloc_lock); ++ ent = RemoveHeadList(&allocs); ++ spin_unlock_bh(&alloc_lock); ++ if (!ent) ++ break; ++ info = container_of(ent, struct alloc_info, list); ++ atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]); ++ printk(KERN_DEBUG DRIVER_NAME ++ ": %s:%d leaked %zd bytes at %p (%s, tag 0x%08X)\n", ++ info->file, info->line, info->size, info + 1, ++ alloc_type_name[info->type], info->tag); ++ if (info->type == ALLOC_TYPE_KMALLOC_ATOMIC || ++ info->type == ALLOC_TYPE_KMALLOC_NON_ATOMIC) ++ kfree(info); ++ else if (info->type == ALLOC_TYPE_VMALLOC_ATOMIC || ++ info->type == ALLOC_TYPE_VMALLOC_NON_ATOMIC) ++ vfree(info); ++ else if (info->type == ALLOC_TYPE_PAGES) ++ free_pages((unsigned long)info, get_order(info->size)); ++ else ++ WARNING("invalid type: %d; not freed", info->type); ++ } ++#endif ++#endif ++ return; ++} +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/wrapmem.h linux-4.6-rc6-ndis/3rdparty/ndiswrapper/wrapmem.h +--- linux-4.6-rc6/3rdparty/ndiswrapper/wrapmem.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/wrapmem.h 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,97 @@ ++/* ++ * Copyright (C) 2006 Giridhar Pemmasani ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _WRAPMEM_H_ ++#define _WRAPMEM_H_ ++ ++/* ++ * Set ALLOC_DEBUG to 1 to show information about memory used by both ++ * ndiswrapper and Windows driver in /proc/net/ndiswrapper/debug ++ * This will also show memory leaks (memory allocated but not freed) when ++ * ndiswrapper module is unloaded. ++ * ++ * Set ALLOC_DEBUG to 2 to see details about every leaking allocation. ++*/ ++ ++#ifndef ALLOC_DEBUG ++#define ALLOC_DEBUG 0 ++#endif ++ ++int wrapmem_init(void); ++void wrapmem_exit(void); ++void *slack_kmalloc(size_t size); ++void *slack_kzalloc(size_t size); ++void slack_kfree(void *ptr); ++ ++#if ALLOC_DEBUG ++enum alloc_type { ALLOC_TYPE_KMALLOC_ATOMIC, ++ ALLOC_TYPE_KMALLOC_NON_ATOMIC, ++ ALLOC_TYPE_VMALLOC_ATOMIC, ALLOC_TYPE_VMALLOC_NON_ATOMIC, ++ ALLOC_TYPE_SLACK, ALLOC_TYPE_PAGES, ALLOC_TYPE_MAX }; ++ ++extern const char *alloc_type_name[ALLOC_TYPE_MAX]; ++ ++void *wrap_kmalloc(size_t size, gfp_t flags, const char *file, int line); ++void *wrap_kzalloc(size_t size, gfp_t flags, const char *file, int line); ++void wrap_kfree(void *ptr); ++void *wrap_vmalloc(unsigned long size, const char *file, int line); ++void *wrap__vmalloc(unsigned long size, gfp_t flags, pgprot_t prot, ++ const char *file, int line); ++void wrap_vfree(void *ptr); ++void *wrap_alloc_pages(gfp_t flags, unsigned int size, ++ const char *file, int line); ++void wrap_free_pages(unsigned long ptr, int order); ++int alloc_size(enum alloc_type type); ++ ++#if ALLOC_DEBUG > 1 ++void *wrap_ExAllocatePoolWithTag(enum pool_type pool_type, SIZE_T size, ++ ULONG tag, const char *file, int line); ++#define ExAllocatePoolWithTag(pool_type, size, tag) \ ++ wrap_ExAllocatePoolWithTag(pool_type, size, tag, __FILE__, __LINE__) ++#endif ++ ++#ifndef _WRAPMEM_C_ ++#undef kmalloc ++#undef kzalloc ++#undef kfree ++#undef vmalloc ++#undef __vmalloc ++#undef vfree ++#define kmalloc(size, flags) \ ++ wrap_kmalloc(size, flags, __FILE__, __LINE__) ++#define kzalloc(size, flags) \ ++ wrap_kzalloc(size, flags, __FILE__, __LINE__) ++#define vmalloc(size) \ ++ wrap_vmalloc(size, __FILE__, __LINE__) ++#define __vmalloc(size, flags, prot) \ ++ wrap__vmalloc(size, flags, prot, __FILE__, __LINE__) ++#define kfree(ptr) wrap_kfree(ptr) ++#define vfree(ptr) wrap_vfree(ptr) ++ ++#define wrap_get_free_pages(flags, size) \ ++ wrap_alloc_pages(flags, size, __FILE__, __LINE__) ++#undef free_pages ++#define free_pages(ptr, order) wrap_free_pages(ptr, order) ++ ++#endif // _WRAPMEM_C_ ++ ++#else ++ ++#define wrap_get_free_pages(flags, size) \ ++ (void *)__get_free_pages(flags, get_order(size)) ++ ++#endif // ALLOC_DEBUG ++ ++#endif +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/wrapndis.c linux-4.6-rc6-ndis/3rdparty/ndiswrapper/wrapndis.c +--- linux-4.6-rc6/3rdparty/ndiswrapper/wrapndis.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/wrapndis.c 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,2186 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include "ndis.h" ++#include "iw_ndis.h" ++#include "pnp.h" ++#include "loader.h" ++#include "wrapndis.h" ++#include "wrapper.h" ++ ++/* Functions callable from the NDIS driver */ ++wstdcall NTSTATUS NdisDispatchDeviceControl(struct device_object *fdo, ++ struct irp *irp); ++wstdcall NTSTATUS NdisDispatchPnp(struct device_object *fdo, struct irp *irp); ++wstdcall NTSTATUS NdisDispatchPower(struct device_object *fdo, struct irp *irp); ++ ++struct workqueue_struct *wrapndis_wq; ++ ++static int set_packet_filter(struct ndis_device *wnd, ++ ULONG packet_filter); ++static void add_iw_stats_timer(struct ndis_device *wnd); ++static void del_iw_stats_timer(struct ndis_device *wnd); ++static NDIS_STATUS ndis_start_device(struct ndis_device *wnd); ++static int ndis_remove_device(struct ndis_device *wnd); ++static void set_multicast_list(struct ndis_device *wnd); ++static int ndis_net_dev_open(struct net_device *net_dev); ++static int ndis_net_dev_close(struct net_device *net_dev); ++ ++/* MiniportReset */ ++NDIS_STATUS mp_reset(struct ndis_device *wnd) ++{ ++ NDIS_STATUS res; ++ struct miniport *mp; ++ BOOLEAN reset_address; ++ KIRQL irql; ++ ++ ENTER2("wnd: %p", wnd); ++ mutex_lock(&wnd->tx_ring_mutex); ++ mutex_lock(&wnd->ndis_req_mutex); ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ prepare_wait_condition(wnd->ndis_req_task, wnd->ndis_req_done, 0); ++ WARNING("%s is being reset", wnd->net_dev->name); ++ irql = serialize_lock_irql(wnd); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ res = LIN2WIN2(mp->reset, &reset_address, wnd->nmb->mp_ctx); ++ serialize_unlock_irql(wnd, irql); ++ ++ TRACE2("%08X, %08X", res, reset_address); ++ if (res == NDIS_STATUS_PENDING) { ++ /* wait for NdisMResetComplete */ ++ if (wait_condition((wnd->ndis_req_done > 0), 0, ++ TASK_INTERRUPTIBLE) < 0) ++ res = NDIS_STATUS_FAILURE; ++ else { ++ res = wnd->ndis_req_status; ++ reset_address = wnd->ndis_req_done - 1; ++ } ++ TRACE2("%08X, %08X", res, reset_address); ++ } ++ mutex_unlock(&wnd->ndis_req_mutex); ++ if (res == NDIS_STATUS_SUCCESS && reset_address) { ++ set_packet_filter(wnd, wnd->packet_filter); ++ set_multicast_list(wnd); ++ } ++ mutex_unlock(&wnd->tx_ring_mutex); ++ EXIT3(return res); ++} ++ ++/* MiniportRequest(Query/Set)Information */ ++NDIS_STATUS mp_request(enum ndis_request_type request, ++ struct ndis_device *wnd, ndis_oid oid, ++ void *buf, ULONG buflen, ULONG *written, ULONG *needed) ++{ ++ NDIS_STATUS res; ++ ULONG w, n; ++ struct miniport *mp; ++ KIRQL irql; ++ ++ mutex_lock(&wnd->ndis_req_mutex); ++ if (!written) ++ written = &w; ++ if (!needed) ++ needed = &n; ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ prepare_wait_condition(wnd->ndis_req_task, wnd->ndis_req_done, 0); ++ irql = serialize_lock_irql(wnd); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ switch (request) { ++ case NdisRequestQueryInformation: ++ TRACE2("%p, %08X, %p", mp->queryinfo, oid, wnd->nmb->mp_ctx); ++ res = LIN2WIN6(mp->queryinfo, wnd->nmb->mp_ctx, oid, buf, ++ buflen, written, needed); ++ break; ++ case NdisRequestSetInformation: ++ TRACE2("%p, %08X, %p", mp->setinfo, oid, wnd->nmb->mp_ctx); ++ res = LIN2WIN6(mp->setinfo, wnd->nmb->mp_ctx, oid, buf, ++ buflen, written, needed); ++ break; ++ default: ++ WARNING("invalid request %d, %08X", request, oid); ++ res = NDIS_STATUS_NOT_SUPPORTED; ++ break; ++ } ++ serialize_unlock_irql(wnd, irql); ++ TRACE2("%08X, %08X", res, oid); ++ if (res == NDIS_STATUS_PENDING) { ++ /* wait for NdisMQueryInformationComplete */ ++ if (wait_condition((wnd->ndis_req_done > 0), 0, ++ TASK_INTERRUPTIBLE) < 0) ++ res = NDIS_STATUS_FAILURE; ++ else ++ res = wnd->ndis_req_status; ++ TRACE2("%08X, %08X", res, oid); ++ } ++ mutex_unlock(&wnd->ndis_req_mutex); ++ DBG_BLOCK(2) { ++ if (res || needed) ++ TRACE2("%08X, %d, %d, %d", res, buflen, *written, ++ *needed); ++ } ++ EXIT3(return res); ++} ++ ++/* MiniportPnPEventNotify */ ++static NDIS_STATUS mp_pnp_event(struct ndis_device *wnd, ++ enum ndis_device_pnp_event event, ++ ULONG power_profile) ++{ ++ struct miniport *mp; ++ ++ ENTER1("%p, %d", wnd, event); ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ if (!mp->pnp_event_notify) { ++ TRACE1("Windows driver %s doesn't support " ++ "MiniportPnpEventNotify", wnd->wd->driver->name); ++ return NDIS_STATUS_FAILURE; ++ } ++ /* RNDIS driver doesn't like to be notified if device is ++ * already halted */ ++ if (!test_bit(HW_INITIALIZED, &wnd->wd->hw_status)) ++ EXIT1(return NDIS_STATUS_SUCCESS); ++ switch (event) { ++ case NdisDevicePnPEventSurpriseRemoved: ++ TRACE1("%u, %p", ++ (wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK), ++ mp->pnp_event_notify); ++ if ((wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK) && ++ !test_bit(HW_DISABLED, &wnd->wd->hw_status) && ++ mp->pnp_event_notify) { ++ TRACE1("calling surprise_removed"); ++ LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx, ++ NdisDevicePnPEventSurpriseRemoved, NULL, 0); ++ } else ++ TRACE1("Windows driver %s doesn't support " ++ "MiniportPnpEventNotify for safe unplugging", ++ wnd->wd->driver->name); ++ return NDIS_STATUS_SUCCESS; ++ case NdisDevicePnPEventPowerProfileChanged: ++ if (power_profile) ++ power_profile = NdisPowerProfileAcOnLine; ++ LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx, ++ NdisDevicePnPEventPowerProfileChanged, ++ &power_profile, sizeof(power_profile)); ++ return NDIS_STATUS_SUCCESS; ++ default: ++ WARNING("event %d not yet implemented", event); ++ return NDIS_STATUS_SUCCESS; ++ } ++} ++ ++/* MiniportInitialize */ ++static NDIS_STATUS mp_init(struct ndis_device *wnd) ++{ ++ NDIS_STATUS error_status, status; ++ UINT medium_index; ++ enum ndis_medium medium_array[] = {NdisMedium802_3}; ++ struct miniport *mp; ++ ++ ENTER1("irql: %d", current_irql()); ++ if (test_bit(HW_INITIALIZED, &wnd->wd->hw_status)) { ++ WARNING("device %p already initialized!", wnd); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ if (!wnd->wd->driver->ndis_driver || ++ !wnd->wd->driver->ndis_driver->mp.init) { ++ WARNING("assuming WDM (non-NDIS) driver"); ++ EXIT1(return NDIS_STATUS_NOT_RECOGNIZED); ++ } ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ status = LIN2WIN6(mp->init, &error_status, &medium_index, medium_array, ++ ARRAY_SIZE(medium_array), wnd->nmb, wnd->nmb); ++ TRACE1("init returns: %08X, irql: %d", status, current_irql()); ++ if (status != NDIS_STATUS_SUCCESS) { ++ WARNING("couldn't initialize device: %08X", status); ++ EXIT1(return NDIS_STATUS_FAILURE); ++ } ++ ++ /* Wait a little to let card power up otherwise ifup might ++ * fail after boot */ ++ sleep_hz(HZ / 5); ++ status = mp_pnp_event(wnd, NdisDevicePnPEventPowerProfileChanged, ++ NdisPowerProfileAcOnLine); ++ if (status != NDIS_STATUS_SUCCESS) ++ TRACE1("setting power failed: %08X", status); ++ set_bit(HW_INITIALIZED, &wnd->wd->hw_status); ++ /* the description about NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND is ++ * misleading/confusing */ ++ status = mp_query(wnd, OID_PNP_CAPABILITIES, ++ &wnd->pnp_capa, sizeof(wnd->pnp_capa)); ++ if (status == NDIS_STATUS_SUCCESS) { ++ TRACE1("%d, %d", wnd->pnp_capa.wakeup.min_magic_packet_wakeup, ++ wnd->pnp_capa.wakeup.min_pattern_wakeup); ++ wnd->attributes |= NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND; ++ status = mp_query_int(wnd, OID_PNP_ENABLE_WAKE_UP, ++ &wnd->ndis_wolopts); ++ TRACE1("%08X, %x", status, wnd->ndis_wolopts); ++ } else if (status == NDIS_STATUS_NOT_SUPPORTED) ++ wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND; ++ TRACE1("%d", wnd->pnp_capa.wakeup.min_magic_packet_wakeup); ++ /* although some NDIS drivers support suspend, Linux kernel ++ * has issues with suspending USB devices */ ++ if (wrap_is_usb_bus(wnd->wd->dev_bus)) { ++ wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND; ++ wnd->ndis_wolopts = 0; ++ } ++ mp_set_int(wnd, OID_802_11_POWER_MODE, NDIS_POWER_OFF); ++ EXIT1(return NDIS_STATUS_SUCCESS); ++} ++ ++/* MiniportHalt */ ++static void mp_halt(struct ndis_device *wnd) ++{ ++ struct miniport *mp; ++ ++ ENTER1("%p", wnd); ++ if (!test_and_clear_bit(HW_INITIALIZED, &wnd->wd->hw_status)) { ++ WARNING("device %p is not initialized - not halting", wnd); ++ return; ++ } ++ hangcheck_del(wnd); ++ del_iw_stats_timer(wnd); ++#ifdef CONFIG_WIRELESS_EXT ++ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan && ++ wrap_is_pci_bus(wnd->wd->dev_bus)) { ++ mutex_unlock(&wnd->ndis_req_mutex); ++ disassociate(wnd, 0); ++ mutex_lock(&wnd->ndis_req_mutex); ++ } ++#endif ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ TRACE1("halt: %p", mp->mp_halt); ++ LIN2WIN1(mp->mp_halt, wnd->nmb->mp_ctx); ++ /* if a driver doesn't call NdisMDeregisterInterrupt during ++ * halt, deregister it now */ ++ if (wnd->mp_interrupt) ++ NdisMDeregisterInterrupt(wnd->mp_interrupt); ++ /* cancel any timers left by buggy windows driver; also free ++ * the memory for timers */ ++ while (1) { ++ struct nt_slist *slist; ++ struct wrap_timer *wrap_timer; ++ ++ spin_lock_bh(&ntoskernel_lock); ++ if ((slist = wnd->wrap_timer_slist.next)) ++ wnd->wrap_timer_slist.next = slist->next; ++ spin_unlock_bh(&ntoskernel_lock); ++ TIMERTRACE("%p", slist); ++ if (!slist) ++ break; ++ wrap_timer = container_of(slist, struct wrap_timer, slist); ++ wrap_timer->repeat = 0; ++ /* ktimer that this wrap_timer is associated to can't ++ * be touched, as it may have been freed by the driver ++ * already */ ++ if (del_timer_sync(&wrap_timer->timer)) ++ WARNING("Buggy Windows driver left timer %p " ++ "running", wrap_timer->nt_timer); ++ memset(wrap_timer, 0, sizeof(*wrap_timer)); ++ kfree(wrap_timer); ++ } ++ EXIT1(return); ++} ++ ++static NDIS_STATUS mp_set_power_state(struct ndis_device *wnd, ++ enum ndis_power_state state) ++{ ++ NDIS_STATUS status; ++ ++ TRACE1("%d", state); ++ if (state == NdisDeviceStateD0) { ++ status = NDIS_STATUS_SUCCESS; ++ mutex_unlock(&wnd->ndis_req_mutex); ++ if (test_and_clear_bit(HW_HALTED, &wnd->wd->hw_status)) { ++ status = mp_init(wnd); ++ if (status == NDIS_STATUS_SUCCESS) { ++ set_packet_filter(wnd, wnd->packet_filter); ++ set_multicast_list(wnd); ++ } ++ } else if (test_and_clear_bit(HW_SUSPENDED, ++ &wnd->wd->hw_status)) { ++ status = mp_set_int(wnd, OID_PNP_SET_POWER, state); ++ if (status != NDIS_STATUS_SUCCESS) ++ WARNING("%s: setting power to state %d failed? " ++ "%08X", wnd->net_dev->name, state, ++ status); ++ } else ++ return NDIS_STATUS_FAILURE; ++ ++ if (wrap_is_pci_bus(wnd->wd->dev_bus)) { ++ pci_enable_wake(wnd->wd->pci.pdev, PCI_D3hot, 0); ++ pci_enable_wake(wnd->wd->pci.pdev, PCI_D3cold, 0); ++ } ++ if (status == NDIS_STATUS_SUCCESS) { ++ mutex_unlock(&wnd->tx_ring_mutex); ++ netif_device_attach(wnd->net_dev); ++ hangcheck_add(wnd); ++ add_iw_stats_timer(wnd); ++ } else ++ WARNING("%s: couldn't set power to state %d; device not" ++ " resumed", wnd->net_dev->name, state); ++ EXIT1(return status); ++ } else { ++ mutex_lock(&wnd->tx_ring_mutex); ++ netif_device_detach(wnd->net_dev); ++ hangcheck_del(wnd); ++ del_iw_stats_timer(wnd); ++ status = NDIS_STATUS_NOT_SUPPORTED; ++ if (wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND) { ++ status = mp_set_int(wnd, OID_PNP_ENABLE_WAKE_UP, ++ wnd->ndis_wolopts); ++ TRACE2("0x%x, 0x%x", status, wnd->ndis_wolopts); ++ if (status == NDIS_STATUS_SUCCESS && ++ wrap_is_pci_bus(wnd->wd->dev_bus)) { ++ if (wnd->ndis_wolopts) ++ wnd->wd->pci.wake_state = ++ PowerDeviceD3; ++ else ++ wnd->wd->pci.wake_state = ++ PowerDeviceUnspecified; ++ } else ++ WARNING("couldn't set wake-on-lan options: " ++ "0x%x, %08X", wnd->ndis_wolopts, status); ++ status = mp_set_int(wnd, OID_PNP_SET_POWER, state); ++ if (status == NDIS_STATUS_SUCCESS) ++ set_bit(HW_SUSPENDED, &wnd->wd->hw_status); ++ else ++ WARNING("suspend failed: %08X", status); ++ } ++ if (status != NDIS_STATUS_SUCCESS) { ++ WARNING("%s does not support power management; " ++ "halting the device", wnd->net_dev->name); ++ mp_halt(wnd); ++ set_bit(HW_HALTED, &wnd->wd->hw_status); ++ status = STATUS_SUCCESS; ++ } ++ mutex_lock(&wnd->ndis_req_mutex); ++ EXIT1(return status); ++ } ++} ++ ++static int ndis_set_mac_address(struct net_device *dev, void *p) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ struct sockaddr *addr = p; ++ struct ndis_configuration_parameter param; ++ struct unicode_string key; ++ struct ansi_string ansi; ++ NDIS_STATUS res; ++ unsigned char mac_string[2 * ETH_ALEN + 1]; ++ mac_address mac; ++ ++ memcpy(mac, addr->sa_data, sizeof(mac)); ++ memset(mac_string, 0, sizeof(mac_string)); ++ res = snprintf(mac_string, sizeof(mac_string), MACSTR, MAC2STR(mac)); ++ if (res != (sizeof(mac_string) - 1)) ++ EXIT1(return -EINVAL); ++ TRACE1("new mac: %s", mac_string); ++ ++ RtlInitAnsiString(&ansi, mac_string); ++ if (RtlAnsiStringToUnicodeString(¶m.data.string, &ansi, ++ TRUE) != STATUS_SUCCESS) ++ EXIT1(return -EINVAL); ++ ++ param.type = NdisParameterString; ++ RtlInitAnsiString(&ansi, "NetworkAddress"); ++ if (RtlAnsiStringToUnicodeString(&key, &ansi, TRUE) != STATUS_SUCCESS) { ++ RtlFreeUnicodeString(¶m.data.string); ++ EXIT1(return -EINVAL); ++ } ++ NdisWriteConfiguration(&res, wnd->nmb, &key, ¶m); ++ RtlFreeUnicodeString(&key); ++ RtlFreeUnicodeString(¶m.data.string); ++ ++ if (res != NDIS_STATUS_SUCCESS) ++ EXIT1(return -EFAULT); ++ if (ndis_reinit(wnd) == NDIS_STATUS_SUCCESS) { ++ res = mp_query(wnd, OID_802_3_CURRENT_ADDRESS, ++ mac, sizeof(mac)); ++ if (res == NDIS_STATUS_SUCCESS) { ++ TRACE1("mac:" MACSTRSEP, MAC2STR(mac)); ++ memcpy(dev->dev_addr, mac, sizeof(mac)); ++ } else ++ ERROR("couldn't get mac address: %08X", res); ++ } ++ EXIT1(return 0); ++} ++ ++static int setup_tx_sg_list(struct ndis_device *wnd, struct sk_buff *skb, ++ struct ndis_packet_oob_data *oob_data) ++{ ++ struct ndis_sg_element *sg_element; ++ struct ndis_sg_list *sg_list; ++ int i; ++ ++ ENTER3("%p, %d", skb, skb_shinfo(skb)->nr_frags); ++ if (skb_shinfo(skb)->nr_frags <= 1) { ++ sg_element = &oob_data->wrap_tx_sg_list.elements[0]; ++ sg_element->address = ++ PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, skb->data, ++ skb->len, PCI_DMA_TODEVICE); ++ sg_element->length = skb->len; ++ oob_data->wrap_tx_sg_list.nent = 1; ++ oob_data->ext.info[ScatterGatherListPacketInfo] = ++ &oob_data->wrap_tx_sg_list; ++ TRACE3("%llx, %u", sg_element->address, sg_element->length); ++ return 0; ++ } ++ sg_list = kmalloc(sizeof(*sg_list) + ++ (skb_shinfo(skb)->nr_frags + 1) * sizeof(*sg_element), ++ GFP_ATOMIC); ++ if (!sg_list) ++ return -ENOMEM; ++ sg_list->nent = skb_shinfo(skb)->nr_frags + 1; ++ TRACE3("%p, %d", sg_list, sg_list->nent); ++ sg_element = sg_list->elements; ++ sg_element->length = skb_headlen(skb); ++ sg_element->address = ++ PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, skb->data, ++ skb_headlen(skb), PCI_DMA_TODEVICE); ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { ++ skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; ++ sg_element++; ++ sg_element->length = frag->size; ++ sg_element->address = ++ pci_map_page(wnd->wd->pci.pdev, skb_frag_page(frag), ++ frag->page_offset, frag->size, ++ PCI_DMA_TODEVICE); ++ TRACE3("%llx, %u", sg_element->address, sg_element->length); ++ } ++ oob_data->ext.info[ScatterGatherListPacketInfo] = sg_list; ++ return 0; ++} ++ ++static void free_tx_sg_list(struct ndis_device *wnd, ++ struct ndis_packet_oob_data *oob_data) ++{ ++ int i; ++ struct ndis_sg_element *sg_element; ++ struct ndis_sg_list *sg_list = ++ oob_data->ext.info[ScatterGatherListPacketInfo]; ++ sg_element = sg_list->elements; ++ TRACE3("%p, %d", sg_list, sg_list->nent); ++ PCI_DMA_UNMAP_SINGLE(wnd->wd->pci.pdev, sg_element->address, ++ sg_element->length, PCI_DMA_TODEVICE); ++ if (sg_list->nent == 1) ++ EXIT3(return); ++ for (i = 1; i < sg_list->nent; i++, sg_element++) { ++ TRACE3("%llx, %u", sg_element->address, sg_element->length); ++ pci_unmap_page(wnd->wd->pci.pdev, sg_element->address, ++ sg_element->length, PCI_DMA_TODEVICE); ++ } ++ TRACE3("%p", sg_list); ++ kfree(sg_list); ++} ++ ++static struct ndis_packet *alloc_tx_packet(struct ndis_device *wnd, ++ struct sk_buff *skb) ++{ ++ struct ndis_packet *packet; ++ ndis_buffer *buffer; ++ struct ndis_packet_oob_data *oob_data; ++ NDIS_STATUS status; ++ ++ NdisAllocatePacket(&status, &packet, wnd->tx_packet_pool); ++ if (status != NDIS_STATUS_SUCCESS) ++ return NULL; ++ NdisAllocateBuffer(&status, &buffer, wnd->tx_buffer_pool, ++ skb->data, skb->len); ++ if (status != NDIS_STATUS_SUCCESS) { ++ NdisFreePacket(packet); ++ return NULL; ++ } ++ packet->private.buffer_head = buffer; ++ packet->private.buffer_tail = buffer; ++ ++ oob_data = NDIS_PACKET_OOB_DATA(packet); ++ oob_data->tx_skb = skb; ++ if (wnd->sg_dma_size) { ++ if (setup_tx_sg_list(wnd, skb, oob_data)) { ++ NdisFreeBuffer(buffer); ++ NdisFreePacket(packet); ++ return NULL; ++ } ++ } ++ if (skb->ip_summed == CHECKSUM_PARTIAL) { ++ struct ndis_tcp_ip_checksum_packet_info csum; ++ int protocol; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21) ++ protocol = ntohs(skb->protocol); ++#else ++ protocol = skb->nh.iph->protocol; ++#endif ++ csum.value = 0; ++ csum.tx.v4 = 1; ++ if (protocol == IPPROTO_TCP) ++ csum.tx.tcp = 1; ++ else if (protocol == IPPROTO_UDP) ++ csum.tx.udp = 1; ++// csum->tx.ip = 1; ++ packet->private.flags |= NDIS_PROTOCOL_ID_TCP_IP; ++ oob_data->ext.info[TcpIpChecksumPacketInfo] = ++ (void *)(ULONG_PTR)csum.value; ++ } ++ DBG_BLOCK(4) { ++ dump_bytes(__func__, skb->data, skb->len); ++ } ++ TRACE4("%p, %p, %p", packet, buffer, skb); ++ return packet; ++} ++ ++void free_tx_packet(struct ndis_device *wnd, struct ndis_packet *packet, ++ NDIS_STATUS status) ++{ ++ ndis_buffer *buffer; ++ struct ndis_packet_oob_data *oob_data; ++ struct sk_buff *skb; ++ struct ndis_packet_pool *pool; ++ ++ assert_irql(_irql_ <= DISPATCH_LEVEL); ++ assert(packet->private.packet_flags); ++ oob_data = NDIS_PACKET_OOB_DATA(packet); ++ skb = oob_data->tx_skb; ++ buffer = packet->private.buffer_head; ++ TRACE4("%p, %p, %p, %08X", packet, buffer, skb, status); ++ if (status == NDIS_STATUS_SUCCESS) { ++ pre_atomic_add(wnd->net_stats.tx_bytes, packet->private.len); ++ atomic_inc_var(wnd->net_stats.tx_packets); ++ } else { ++ TRACE1("packet dropped: %08X", status); ++ atomic_inc_var(wnd->net_stats.tx_dropped); ++ } ++ if (wnd->sg_dma_size) ++ free_tx_sg_list(wnd, oob_data); ++ NdisFreeBuffer(buffer); ++ dev_kfree_skb_any(skb); ++ pool = packet->private.pool; ++ NdisFreePacket(packet); ++ if (netif_queue_stopped(wnd->net_dev) && ++ ((pool->max_descr - pool->num_used_descr) >= ++ (wnd->max_tx_packets / 4))) { ++ set_bit(NETIF_WAKEQ, &wnd->ndis_pending_work); ++ queue_work(wrapndis_wq, &wnd->ndis_work); ++ } ++ EXIT4(return); ++} ++ ++/* MiniportSend and MiniportSendPackets */ ++/* this function is called holding tx_ring_mutex. start and n are such ++ * that start + n < TX_RING_SIZE; i.e., packets don't wrap around ++ * ring */ ++static u8 mp_tx_packets(struct ndis_device *wnd, u8 start, u8 n) ++{ ++ NDIS_STATUS res; ++ struct miniport *mp; ++ struct ndis_packet *packet; ++ u8 sent; ++ KIRQL irql; ++ ++ ENTER3("%d, %d", start, n); ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ if (mp->send_packets) { ++ if (deserialized_driver(wnd)) { ++ LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx, ++ &wnd->tx_ring[start], n); ++ sent = n; ++ } else { ++ irql = serialize_lock_irql(wnd); ++ LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx, ++ &wnd->tx_ring[start], n); ++ serialize_unlock_irql(wnd, irql); ++ for (sent = 0; sent < n && wnd->tx_ok; sent++) { ++ struct ndis_packet_oob_data *oob_data; ++ packet = wnd->tx_ring[start + sent]; ++ oob_data = NDIS_PACKET_OOB_DATA(packet); ++ switch ((res = ++ xchg(&oob_data->status, ++ NDIS_STATUS_NOT_RECOGNIZED))) { ++ case NDIS_STATUS_SUCCESS: ++ free_tx_packet(wnd, packet, ++ NDIS_STATUS_SUCCESS); ++ break; ++ case NDIS_STATUS_PENDING: ++ break; ++ case NDIS_STATUS_RESOURCES: ++ wnd->tx_ok = 0; ++ /* resubmit this packet and ++ * the rest when resources ++ * become available */ ++ sent--; ++ break; ++ case NDIS_STATUS_FAILURE: ++ free_tx_packet(wnd, packet, ++ NDIS_STATUS_FAILURE); ++ break; ++ default: ++ ERROR("%p: invalid status: %08X", ++ packet, res); ++ free_tx_packet(wnd, packet, ++ oob_data->status); ++ break; ++ } ++ TRACE3("%p, %d", packet, res); ++ } ++ } ++ TRACE3("sent: %d(%d)", sent, n); ++ } else { ++ for (sent = 0; sent < n && wnd->tx_ok; sent++) { ++ struct ndis_packet_oob_data *oob_data; ++ packet = wnd->tx_ring[start + sent]; ++ oob_data = NDIS_PACKET_OOB_DATA(packet); ++ oob_data->status = NDIS_STATUS_NOT_RECOGNIZED; ++ irql = serialize_lock_irql(wnd); ++ res = LIN2WIN3(mp->send, wnd->nmb->mp_ctx, ++ packet, packet->private.flags); ++ serialize_unlock_irql(wnd, irql); ++ switch (res) { ++ case NDIS_STATUS_SUCCESS: ++ free_tx_packet(wnd, packet, res); ++ break; ++ case NDIS_STATUS_PENDING: ++ break; ++ case NDIS_STATUS_RESOURCES: ++ wnd->tx_ok = 0; ++ /* resend this packet when resources ++ * become available */ ++ sent--; ++ break; ++ case NDIS_STATUS_FAILURE: ++ free_tx_packet(wnd, packet, res); ++ break; ++ default: ++ ERROR("packet %p: invalid status: %08X", ++ packet, res); ++ break; ++ } ++ } ++ } ++ EXIT3(return sent); ++} ++ ++static void tx_worker(struct work_struct *work) ++{ ++ struct ndis_device *wnd; ++ s8 n; ++ ++ wnd = container_of(work, struct ndis_device, tx_work); ++ ENTER3("tx_ok %d", wnd->tx_ok); ++ while (wnd->tx_ok) { ++ mutex_lock(&wnd->tx_ring_mutex); ++ spin_lock_bh(&wnd->tx_ring_lock); ++ n = wnd->tx_ring_end - wnd->tx_ring_start; ++ TRACE3("%d, %d, %d", wnd->tx_ring_start, wnd->tx_ring_end, n); ++ /* end == start if either ring is empty or full; in ++ * the latter case is_tx_ring_full is set */ ++ if (n == 0) { ++ if (wnd->is_tx_ring_full) ++ n = TX_RING_SIZE - wnd->tx_ring_start; ++ else { ++ spin_unlock_bh(&wnd->tx_ring_lock); ++ mutex_unlock(&wnd->tx_ring_mutex); ++ break; ++ } ++ } else if (n < 0) ++ n = TX_RING_SIZE - wnd->tx_ring_start; ++ spin_unlock_bh(&wnd->tx_ring_lock); ++ if (unlikely(n > wnd->max_tx_packets)) ++ n = wnd->max_tx_packets; ++ n = mp_tx_packets(wnd, wnd->tx_ring_start, n); ++ if (n) { ++ wnd->net_dev->trans_start = jiffies; ++ wnd->tx_ring_start = ++ (wnd->tx_ring_start + n) % TX_RING_SIZE; ++ wnd->is_tx_ring_full = 0; ++ } ++ mutex_unlock(&wnd->tx_ring_mutex); ++ TRACE3("%d, %d, %d", wnd->tx_ring_start, wnd->tx_ring_end, n); ++ } ++ EXIT3(return); ++} ++ ++static int tx_skbuff(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ struct ndis_packet *packet; ++ ++ packet = alloc_tx_packet(wnd, skb); ++ if (!packet) { ++ TRACE2("couldn't allocate packet"); ++ netif_tx_lock(dev); ++ netif_stop_queue(dev); ++ netif_tx_unlock(dev); ++ return NETDEV_TX_BUSY; ++ } ++ spin_lock(&wnd->tx_ring_lock); ++ wnd->tx_ring[wnd->tx_ring_end++] = packet; ++ if (wnd->tx_ring_end == TX_RING_SIZE) ++ wnd->tx_ring_end = 0; ++ if (wnd->tx_ring_end == wnd->tx_ring_start) { ++ netif_tx_lock(dev); ++ wnd->is_tx_ring_full = 1; ++ netif_stop_queue(dev); ++ netif_tx_unlock(dev); ++ } ++ spin_unlock(&wnd->tx_ring_lock); ++ TRACE4("ring: %d, %d", wnd->tx_ring_start, wnd->tx_ring_end); ++ queue_work(wrapndis_wq, &wnd->tx_work); ++ return NETDEV_TX_OK; ++} ++ ++static int set_packet_filter(struct ndis_device *wnd, ULONG packet_filter) ++{ ++ NDIS_STATUS res; ++ ++ while (1) { ++ res = mp_set_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, ++ packet_filter); ++ if (res == NDIS_STATUS_SUCCESS) ++ break; ++ TRACE2("couldn't set filter 0x%08x", packet_filter); ++ /* NDIS_PACKET_TYPE_PROMISCUOUS may not work with 802.11 */ ++ if (packet_filter & NDIS_PACKET_TYPE_PROMISCUOUS) { ++ packet_filter &= ~NDIS_PACKET_TYPE_PROMISCUOUS; ++ continue; ++ } ++ if (packet_filter & NDIS_PACKET_TYPE_ALL_LOCAL) { ++ packet_filter &= ~NDIS_PACKET_TYPE_ALL_LOCAL; ++ continue; ++ } ++ if (packet_filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) { ++ packet_filter &= ~NDIS_PACKET_TYPE_ALL_FUNCTIONAL; ++ continue; ++ } ++ if (packet_filter & NDIS_PACKET_TYPE_MULTICAST) { ++ packet_filter &= ~NDIS_PACKET_TYPE_MULTICAST; ++ packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; ++ continue; ++ } ++ if (packet_filter & NDIS_PACKET_TYPE_ALL_MULTICAST) { ++ packet_filter &= ~NDIS_PACKET_TYPE_ALL_MULTICAST; ++ continue; ++ } ++ break; ++ } ++ ++ wnd->packet_filter = packet_filter; ++ res = mp_query_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, &packet_filter); ++ if (packet_filter != wnd->packet_filter) { ++ WARNING("filter not set: 0x%08x, 0x%08x", ++ packet_filter, wnd->packet_filter); ++ wnd->packet_filter = packet_filter; ++ } ++ if (wnd->packet_filter) ++ EXIT3(return 0); ++ else ++ EXIT3(return -1); ++} ++ ++void set_media_state(struct ndis_device *wnd, enum ndis_media_state state) ++{ ++ struct net_device *net_dev = wnd->net_dev; ++ ++ ENTER2("state: 0x%x, carrier %d", state, netif_carrier_ok(net_dev)); ++ switch (state) { ++ case NdisMediaStateConnected: ++ if (netif_carrier_ok(net_dev)) ++ return; ++ netif_carrier_on(net_dev); ++ wnd->tx_ok = 1; ++ if (netif_queue_stopped(net_dev)) ++ netif_wake_queue(net_dev); ++ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) { ++ set_bit(LINK_STATUS_ON, &wnd->ndis_pending_work); ++ queue_work(wrapndis_wq, &wnd->ndis_work); ++ } ++ break; ++ case NdisMediaStateDisconnected: ++ if (!netif_carrier_ok(net_dev)) ++ return; ++ netif_carrier_off(net_dev); ++ netif_stop_queue(net_dev); ++ wnd->tx_ok = 0; ++ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) { ++ memset(&wnd->essid, 0, sizeof(wnd->essid)); ++ set_bit(LINK_STATUS_OFF, &wnd->ndis_pending_work); ++ queue_work(wrapndis_wq, &wnd->ndis_work); ++ } ++ break; ++ default: ++ WARNING("invalid media state: 0x%x", state); ++ break; ++ } ++} ++ ++static int ndis_net_dev_init(struct net_device *net_dev) ++{ ++ struct ndis_device *wnd = netdev_priv(net_dev); ++ ++ ENTER1("%p", wnd); ++ wrap_procfs_add_ndis_device(wnd); ++ EXIT1(return 0); ++} ++ ++static void ndis_net_dev_uninit(struct net_device *net_dev) ++{ ++ struct ndis_device *wnd = netdev_priv(net_dev); ++ ++ ENTER1("%p", wnd); ++ wrap_procfs_remove_ndis_device(wnd); ++ EXIT1(return); ++} ++ ++static int ndis_net_dev_open(struct net_device *net_dev) ++{ ++ int status, res; ++ struct ndis_device *wnd = netdev_priv(net_dev); ++ ++ ENTER1("%p", wnd); ++ res = mp_query_int(wnd, OID_GEN_MEDIA_CONNECT_STATUS, &status); ++ if (res == NDIS_STATUS_SUCCESS && status >= NdisMediaStateConnected && ++ status <= NdisMediaStateDisconnected) ++ set_media_state(wnd, status); ++ netif_start_queue(net_dev); ++ netif_poll_enable(net_dev); ++ EXIT1(return 0); ++} ++ ++static int ndis_net_dev_close(struct net_device *net_dev) ++{ ++ ENTER1("%p", netdev_priv(net_dev)); ++ netif_poll_disable(net_dev); ++ netif_tx_disable(net_dev); ++ EXIT1(return 0); ++} ++ ++static int ndis_change_mtu(struct net_device *net_dev, int mtu) ++{ ++ struct ndis_device *wnd = netdev_priv(net_dev); ++ int max; ++ ++ if (mtu < ETH_ZLEN) ++ return -EINVAL; ++ if (mp_query_int(wnd, OID_GEN_MAXIMUM_TOTAL_SIZE, &max) != ++ NDIS_STATUS_SUCCESS) ++ return -EOPNOTSUPP; ++ TRACE1("%d", max); ++ max -= ETH_HLEN; ++ if (max <= ETH_ZLEN) ++ return -EINVAL; ++ if (mtu + ETH_HLEN > max) ++ return -EINVAL; ++ net_dev->mtu = mtu; ++ return 0; ++} ++ ++#ifdef CONFIG_NET_POLL_CONTROLLER ++static void ndis_poll_controller(struct net_device *dev) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ++ disable_irq(dev->irq); ++ ndis_isr(wnd->mp_interrupt->kinterrupt, wnd->mp_interrupt); ++ enable_irq(dev->irq); ++} ++#endif ++ ++/* called from BH context */ ++static struct net_device_stats *ndis_get_stats(struct net_device *dev) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ return &wnd->net_stats; ++} ++ ++/* called from BH context */ ++static void ndis_set_multicast_list(struct net_device *dev) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ set_bit(SET_MULTICAST_LIST, &wnd->ndis_pending_work); ++ queue_work(wrapndis_wq, &wnd->ndis_work); ++} ++ ++/* called from BH context */ ++struct iw_statistics *get_iw_stats(struct net_device *dev) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ return &wnd->iw_stats; ++} ++ ++static void update_iw_stats(struct ndis_device *wnd) ++{ ++ struct iw_statistics *iw_stats = &wnd->iw_stats; ++ struct ndis_wireless_stats ndis_stats; ++ NDIS_STATUS res; ++ ndis_rssi rssi; ++ int qual; ++ ++ ENTER2("%p", wnd); ++ if (wnd->iw_stats_enabled == FALSE || !netif_carrier_ok(wnd->net_dev)) { ++ memset(iw_stats, 0, sizeof(*iw_stats)); ++ EXIT2(return); ++ } ++ res = mp_query(wnd, OID_802_11_RSSI, &rssi, sizeof(rssi)); ++ if (res == NDIS_STATUS_SUCCESS) ++ iw_stats->qual.level = rssi; ++ ++ qual = 100 * (rssi - WL_NOISE) / (WL_SIGMAX - WL_NOISE); ++ if (qual < 0) ++ qual = 0; ++ else if (qual > 100) ++ qual = 100; ++ ++ iw_stats->qual.noise = WL_NOISE; ++ iw_stats->qual.qual = qual; ++ ++ res = mp_query(wnd, OID_802_11_STATISTICS, ++ &ndis_stats, sizeof(ndis_stats)); ++ if (res != NDIS_STATUS_SUCCESS) ++ EXIT2(return); ++ iw_stats->discard.retries = (unsigned long)ndis_stats.retry + ++ (unsigned long)ndis_stats.multi_retry; ++ iw_stats->discard.misc = (unsigned long)ndis_stats.fcs_err + ++ (unsigned long)ndis_stats.rtss_fail + ++ (unsigned long)ndis_stats.ack_fail + ++ (unsigned long)ndis_stats.frame_dup; ++ ++ EXIT2(return); ++} ++ ++static void set_multicast_list(struct ndis_device *wnd) ++{ ++ struct net_device *net_dev; ++ ULONG packet_filter; ++ NDIS_STATUS res; ++ ++ net_dev = wnd->net_dev; ++ packet_filter = wnd->packet_filter; ++ ++ TRACE2("0x%08x", packet_filter); ++ if (net_dev->flags & IFF_PROMISC) { ++ packet_filter |= NDIS_PACKET_TYPE_PROMISCUOUS | ++ NDIS_PACKET_TYPE_ALL_LOCAL; ++ } else if (net_dev->flags & IFF_ALLMULTI || ++ netdev_mc_count(net_dev) > wnd->multicast_size) { ++ packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; ++ TRACE2("0x%08x", packet_filter); ++ } else if (netdev_mc_count(net_dev) > 0) { ++ int i, size; ++ char *buf; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) ++ struct netdev_hw_addr *ha; ++#else ++ struct dev_mc_list *mclist; ++#endif ++ size = min(wnd->multicast_size, netdev_mc_count(net_dev)); ++ TRACE2("%d, %d", wnd->multicast_size, netdev_mc_count(net_dev)); ++ buf = kmalloc(size * ETH_ALEN, GFP_KERNEL); ++ if (!buf) { ++ WARNING("couldn't allocate memory"); ++ EXIT2(return); ++ } ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) ++ i = 0; ++ netdev_for_each_mc_addr(ha, net_dev) { ++ if (i >= size) ++ break; ++ memcpy(buf + i * ETH_ALEN, ha->addr, ETH_ALEN); ++ TRACE2(MACSTRSEP, MAC2STR(ha->addr)); ++ i++; ++ } ++#else ++ mclist = net_dev->mc_list; ++ for (i = 0; i < size && mclist; mclist = mclist->next) { ++ if (mclist->dmi_addrlen != ETH_ALEN) ++ continue; ++ memcpy(buf + i * ETH_ALEN, mclist->dmi_addr, ETH_ALEN); ++ TRACE2(MACSTRSEP, MAC2STR(mclist->dmi_addr)); ++ i++; ++ } ++#endif ++ res = mp_set(wnd, OID_802_3_MULTICAST_LIST, buf, i * ETH_ALEN); ++ if (res == NDIS_STATUS_SUCCESS && i > 0) ++ packet_filter |= NDIS_PACKET_TYPE_MULTICAST; ++ else ++ packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; ++ kfree(buf); ++ } ++ TRACE2("0x%08x", packet_filter); ++ res = set_packet_filter(wnd, packet_filter); ++ if (res) ++ TRACE1("couldn't set packet filter (%08X)", res); ++ EXIT2(return); ++} ++ ++static void link_status_off(struct ndis_device *wnd) ++{ ++#ifdef CONFIG_WIRELESS_EXT ++ union iwreq_data wrqu; ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.ap_addr.sa_family = ARPHRD_ETHER; ++ wireless_send_event(wnd->net_dev, SIOCGIWAP, &wrqu, NULL); ++#endif ++ EXIT2(return); ++} ++ ++static void link_status_on(struct ndis_device *wnd) ++{ ++#ifdef CONFIG_WIRELESS_EXT ++ struct ndis_assoc_info *ndis_assoc_info; ++ union iwreq_data wrqu; ++ NDIS_STATUS res; ++ const int assoc_size = sizeof(*ndis_assoc_info) + IW_CUSTOM_MAX + 32; ++#endif ++ ++ ENTER2(""); ++#ifdef CONFIG_WIRELESS_EXT ++ memset(&wrqu, 0, sizeof(wrqu)); ++ ndis_assoc_info = kzalloc(assoc_size, GFP_KERNEL); ++ if (!ndis_assoc_info) { ++ ERROR("couldn't allocate memory"); ++ goto send_assoc_event; ++ } ++ res = mp_query(wnd, OID_802_11_ASSOCIATION_INFORMATION, ++ ndis_assoc_info, assoc_size); ++ if (res) { ++ TRACE2("query assoc_info failed (%08X)", res); ++ kfree(ndis_assoc_info); ++ goto send_assoc_event; ++ } ++ TRACE2("%u, 0x%x, %u, 0x%x, %u", ndis_assoc_info->length, ++ ndis_assoc_info->req_ies, ndis_assoc_info->req_ie_length, ++ ndis_assoc_info->resp_ies, ndis_assoc_info->resp_ie_length); ++ if (ndis_assoc_info->req_ie_length > 0) { ++ wrqu.data.length = ndis_assoc_info->req_ie_length; ++ wireless_send_event(wnd->net_dev, IWEVASSOCREQIE, &wrqu, ++ ((char *)ndis_assoc_info) + ++ ndis_assoc_info->offset_req_ies); ++ } ++ if (ndis_assoc_info->resp_ie_length > 0) { ++ wrqu.data.length = ndis_assoc_info->resp_ie_length; ++ wireless_send_event(wnd->net_dev, IWEVASSOCRESPIE, &wrqu, ++ ((char *)ndis_assoc_info) + ++ ndis_assoc_info->offset_resp_ies); ++ } ++ kfree(ndis_assoc_info); ++ ++send_assoc_event: ++ get_ap_address(wnd, wrqu.ap_addr.sa_data); ++ wrqu.ap_addr.sa_family = ARPHRD_ETHER; ++ TRACE2(MACSTRSEP, MAC2STR(wrqu.ap_addr.sa_data)); ++ wireless_send_event(wnd->net_dev, SIOCGIWAP, &wrqu, NULL); ++#endif ++ EXIT2(return); ++} ++ ++static void iw_stats_timer_proc(unsigned long data) ++{ ++ struct ndis_device *wnd = (struct ndis_device *)data; ++ ++ ENTER2("%d", wnd->iw_stats_interval); ++ if (wnd->iw_stats_interval > 0) { ++ set_bit(COLLECT_IW_STATS, &wnd->ndis_pending_work); ++ queue_work(wrapndis_wq, &wnd->ndis_work); ++ } ++ mod_timer(&wnd->iw_stats_timer, jiffies + wnd->iw_stats_interval); ++} ++ ++static void add_iw_stats_timer(struct ndis_device *wnd) ++{ ++ if (wnd->physical_medium != NdisPhysicalMediumWirelessLan) ++ return; ++ if (wnd->iw_stats_interval < 0) ++ wnd->iw_stats_interval *= -1; ++ wnd->iw_stats_timer.data = (unsigned long)wnd; ++ wnd->iw_stats_timer.function = iw_stats_timer_proc; ++ mod_timer(&wnd->iw_stats_timer, jiffies + wnd->iw_stats_interval); ++} ++ ++static void del_iw_stats_timer(struct ndis_device *wnd) ++{ ++ ENTER2("%d", wnd->iw_stats_interval); ++ wnd->iw_stats_interval *= -1; ++ del_timer_sync(&wnd->iw_stats_timer); ++ EXIT2(return); ++} ++ ++static void hangcheck_proc(unsigned long data) ++{ ++ struct ndis_device *wnd = (struct ndis_device *)data; ++ ++ ENTER3("%d", wnd->hangcheck_interval); ++ if (wnd->hangcheck_interval > 0) { ++ set_bit(HANGCHECK, &wnd->ndis_pending_work); ++ queue_work(wrapndis_wq, &wnd->ndis_work); ++ } ++ mod_timer(&wnd->hangcheck_timer, jiffies + wnd->hangcheck_interval); ++ EXIT3(return); ++} ++ ++void hangcheck_add(struct ndis_device *wnd) ++{ ++ if (!wnd->wd->driver->ndis_driver->mp.hangcheck || ++ hangcheck_interval < 0) ++ EXIT2(return); ++ ++ if (hangcheck_interval > 0) ++ wnd->hangcheck_interval = hangcheck_interval * HZ; ++ if (wnd->hangcheck_interval < 0) ++ wnd->hangcheck_interval *= -1; ++ wnd->hangcheck_timer.data = (unsigned long)wnd; ++ wnd->hangcheck_timer.function = hangcheck_proc; ++ mod_timer(&wnd->hangcheck_timer, jiffies + wnd->hangcheck_interval); ++ EXIT2(return); ++} ++ ++void hangcheck_del(struct ndis_device *wnd) ++{ ++ ENTER2("%d", wnd->hangcheck_interval); ++ if (wnd->hangcheck_interval > 0) ++ wnd->hangcheck_interval *= -1; ++ del_timer_sync(&wnd->hangcheck_timer); ++ EXIT2(return); ++} ++ ++/* worker procedure to take care of setting/checking various states */ ++static void wrapndis_worker(struct work_struct *work) ++{ ++ struct ndis_device *wnd; ++ ++ wnd = container_of(work, struct ndis_device, ndis_work); ++ WORKTRACE("0x%lx", wnd->ndis_pending_work); ++ ++ if (test_and_clear_bit(NETIF_WAKEQ, &wnd->ndis_pending_work)) { ++ netif_tx_lock_bh(wnd->net_dev); ++ netif_wake_queue(wnd->net_dev); ++ netif_tx_unlock_bh(wnd->net_dev); ++ } ++ ++ if (test_and_clear_bit(LINK_STATUS_OFF, &wnd->ndis_pending_work)) ++ link_status_off(wnd); ++ ++ if (test_and_clear_bit(LINK_STATUS_ON, &wnd->ndis_pending_work)) ++ link_status_on(wnd); ++ ++ if (test_and_clear_bit(COLLECT_IW_STATS, &wnd->ndis_pending_work)) ++ update_iw_stats(wnd); ++ ++ if (test_and_clear_bit(SET_MULTICAST_LIST, ++ &wnd->ndis_pending_work)) ++ set_multicast_list(wnd); ++ ++ if (test_and_clear_bit(HANGCHECK, &wnd->ndis_pending_work)) { ++ struct miniport *mp; ++ BOOLEAN reset; ++ KIRQL irql; ++ ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ irql = serialize_lock_irql(wnd); ++ reset = LIN2WIN1(mp->hangcheck, wnd->nmb->mp_ctx); ++ serialize_unlock_irql(wnd, irql); ++ if (reset) { ++ TRACE2("%s needs reset", wnd->net_dev->name); ++ mp_reset(wnd); ++ } ++ } ++ WORKEXIT(return); ++} ++ ++NDIS_STATUS ndis_reinit(struct ndis_device *wnd) ++{ ++ NDIS_STATUS status; ++ ++ wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND; ++ status = mp_set_power_state(wnd, NdisDeviceStateD3); ++ if (status != NDIS_STATUS_SUCCESS) { ++ ERROR("halting device %s failed: %08X", wnd->net_dev->name, ++ status); ++ return status; ++ } ++ status = mp_set_power_state(wnd, NdisDeviceStateD0); ++ if (status != NDIS_STATUS_SUCCESS) ++ ERROR("starting device %s failed: %08X", wnd->net_dev->name, ++ status); ++ return status; ++} ++ ++#ifdef CONFIG_WIRELESS_EXT ++static void get_encryption_capa(struct ndis_device *wnd, char *buf, ++ const int buf_len) ++{ ++ int i, mode; ++ NDIS_STATUS res; ++ struct ndis_assoc_info ndis_assoc_info; ++ struct ndis_add_key ndis_key; ++ struct ndis_capability *c; ++ ++ ENTER1("%p", wnd); ++ /* set network type to g, b, or a, in that order */ ++ res = mp_query(wnd, OID_802_11_NETWORK_TYPES_SUPPORTED, buf, buf_len); ++ if (res == NDIS_STATUS_SUCCESS) { ++ struct network_type_list *net_types; ++ unsigned long types = 0; ++ net_types = (typeof(net_types))buf; ++ for (i = 0; i < net_types->num; i++) { ++ TRACE2("%d", net_types->types[i]); ++ set_bit(net_types->types[i], &types); ++ } ++ if (test_bit(Ndis802_11OFDM24, &types)) ++ mode = Ndis802_11OFDM24; ++ else if (test_bit(Ndis802_11DS, &types)) ++ mode = Ndis802_11DS; ++ else if (test_bit(Ndis802_11OFDM5, &types)) ++ mode = Ndis802_11OFDM5; ++ else ++ mode = Ndis802_11DS; ++ mp_set_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE, mode); ++ } ++ /* check if WEP is supported */ ++ if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104, ++ IW_AUTH_CIPHER_NONE) == 0 && ++ get_ndis_encr_mode(wnd) == Ndis802_11Encryption1KeyAbsent) ++ set_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr); ++ ++ /* check if WPA is supported */ ++ if (set_ndis_auth_mode(wnd, Ndis802_11AuthModeWPA) == 0 && ++ get_ndis_auth_mode(wnd) == Ndis802_11AuthModeWPA) ++ set_bit(Ndis802_11AuthModeWPA, &wnd->capa.encr); ++ else ++ EXIT1(return); ++ ++ if (set_ndis_auth_mode(wnd, Ndis802_11AuthModeWPAPSK) == 0 && ++ get_ndis_auth_mode(wnd) == Ndis802_11AuthModeWPAPSK) ++ set_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.encr); ++ ++ /* check for highest encryption */ ++ mode = 0; ++ if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_CCMP, ++ IW_AUTH_CIPHER_NONE) == 0 && ++ (i = get_ndis_encr_mode(wnd)) > 0 && ++ (i == Ndis802_11Encryption3KeyAbsent || ++ i == Ndis802_11Encryption3Enabled)) ++ mode = Ndis802_11Encryption3Enabled; ++ else if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_TKIP, ++ IW_AUTH_CIPHER_NONE) == 0 && ++ (i = get_ndis_encr_mode(wnd)) > 0 && ++ (i == Ndis802_11Encryption2KeyAbsent || ++ i == Ndis802_11Encryption2Enabled)) ++ mode = Ndis802_11Encryption2Enabled; ++ else if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104, ++ IW_AUTH_CIPHER_NONE) == 0 && ++ (i = get_ndis_encr_mode(wnd)) > 0 && ++ (i == Ndis802_11Encryption1KeyAbsent || ++ i == Ndis802_11Encryption1Enabled)) ++ mode = Ndis802_11Encryption1Enabled; ++ ++ TRACE1("mode: %d", mode); ++ if (mode == 0) ++ EXIT1(return); ++ set_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr); ++ if (mode == Ndis802_11Encryption1Enabled) ++ EXIT1(return); ++ ++ ndis_key.length = 32; ++ ndis_key.index = 0xC0000001; ++ ndis_key.struct_size = sizeof(ndis_key); ++ res = mp_set(wnd, OID_802_11_ADD_KEY, &ndis_key, ndis_key.struct_size); ++ TRACE2("%08X, %zu", res, sizeof(ndis_key)); ++ if (res && res != NDIS_STATUS_INVALID_DATA) ++ EXIT1(return); ++ res = mp_query(wnd, OID_802_11_ASSOCIATION_INFORMATION, ++ &ndis_assoc_info, sizeof(ndis_assoc_info)); ++ TRACE1("%08X", res); ++ if (res == NDIS_STATUS_NOT_SUPPORTED) ++ EXIT1(return); ++ ++ set_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr); ++ if (mode == Ndis802_11Encryption3Enabled) ++ set_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr); ++ /* not all drivers support OID_802_11_CAPABILITY, so we don't ++ * know for sure if driver support WPA or WPAPSK; assume ++ * WPAPSK */ ++ set_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.auth); ++ wnd->max_pmkids = 1; ++ ++ memset(buf, 0, buf_len); ++ c = (struct ndis_capability *)buf; ++ res = mp_query(wnd, OID_802_11_CAPABILITY, buf, buf_len); ++ if (!(res == NDIS_STATUS_SUCCESS && c->version == 2)) ++ EXIT1(return); ++ wnd->max_pmkids = c->num_PMKIDs; ++ ++ for (i = 0; i < c->num_auth_encr_pair; i++) { ++ struct ndis_auth_encr_pair *ae; ++ ++ ae = &c->auth_encr_pair[i]; ++ if ((char *)(ae + 1) > buf + buf_len) ++ break; ++ switch (ae->auth_mode) { ++ case Ndis802_11AuthModeOpen: ++ case Ndis802_11AuthModeShared: ++ case Ndis802_11AuthModeWPA: ++ case Ndis802_11AuthModeWPAPSK: ++ case Ndis802_11AuthModeWPANone: ++ case Ndis802_11AuthModeWPA2: ++ case Ndis802_11AuthModeWPA2PSK: ++ set_bit(ae->auth_mode, &wnd->capa.auth); ++ break; ++ default: ++ WARNING("unknown auth_mode: %d", ae->auth_mode); ++ break; ++ } ++ switch (ae->encr_mode) { ++ case Ndis802_11EncryptionDisabled: ++ case Ndis802_11Encryption1Enabled: ++ case Ndis802_11Encryption2Enabled: ++ case Ndis802_11Encryption3Enabled: ++ set_bit(ae->encr_mode, &wnd->capa.encr); ++ break; ++ default: ++ WARNING("unknown encr_mode: %d", ae->encr_mode); ++ break; ++ } ++ } ++ EXIT1(return); ++} ++#endif ++ ++wstdcall NTSTATUS NdisDispatchDeviceControl(struct device_object *fdo, ++ struct irp *irp) ++{ ++ struct ndis_device *wnd; ++ ++ TRACE3("fdo: %p", fdo); ++ /* for now, we don't have anything interesting here, so pass it ++ * down to bus driver */ ++ wnd = fdo->reserved; ++ return IoPassIrpDown(wnd->nmb->pdo, irp); ++} ++WIN_FUNC_DECL(NdisDispatchDeviceControl,2) ++ ++wstdcall NTSTATUS NdisDispatchPower(struct device_object *fdo, struct irp *irp) ++{ ++ struct io_stack_location *irp_sl; ++ struct ndis_device *wnd; ++ enum ndis_power_state state; ++ NTSTATUS status; ++ NDIS_STATUS ndis_status; ++ ++ irp_sl = IoGetCurrentIrpStackLocation(irp); ++ wnd = fdo->reserved; ++ IOTRACE("fdo: %p, fn: %d:%d, wnd: %p", fdo, irp_sl->major_fn, ++ irp_sl->minor_fn, wnd); ++ if ((irp_sl->params.power.type == SystemPowerState && ++ irp_sl->params.power.state.system_state > PowerSystemWorking) || ++ (irp_sl->params.power.type == DevicePowerState && ++ irp_sl->params.power.state.device_state > PowerDeviceD0)) ++ state = NdisDeviceStateD3; ++ else ++ state = NdisDeviceStateD0; ++ switch (irp_sl->minor_fn) { ++ case IRP_MN_SET_POWER: ++ if (state == NdisDeviceStateD0) { ++ status = IoSyncForwardIrp(wnd->nmb->pdo, irp); ++ if (status != STATUS_SUCCESS) ++ break; ++ ndis_status = mp_set_power_state(wnd, state); ++ if (ndis_status != NDIS_STATUS_SUCCESS) ++ WARNING("couldn't set power to %d: %08X", ++ state, ndis_status); ++ TRACE2("%s: device resumed", wnd->net_dev->name); ++ irp->io_status.status = status = STATUS_SUCCESS; ++ IoCompleteRequest(irp, IO_NO_INCREMENT); ++ break; ++ } else { ++ ndis_status = mp_set_power_state(wnd, state); ++ /* TODO: handle error case */ ++ if (ndis_status != NDIS_STATUS_SUCCESS) ++ WARNING("setting power to %d failed: %08X", ++ state, ndis_status); ++ status = IoAsyncForwardIrp(wnd->nmb->pdo, irp); ++ } ++ break; ++ case IRP_MN_QUERY_POWER: ++ if (wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND) { ++ ndis_status = mp_query(wnd, OID_PNP_QUERY_POWER, ++ &state, sizeof(state)); ++ TRACE2("%d, %08X", state, ndis_status); ++ /* this OID must always succeed */ ++ if (ndis_status != NDIS_STATUS_SUCCESS) ++ TRACE1("query power returns %08X", ndis_status); ++ irp->io_status.status = STATUS_SUCCESS; ++ } else ++ irp->io_status.status = STATUS_SUCCESS; ++ status = IoPassIrpDown(wnd->nmb->pdo, irp); ++ break; ++ case IRP_MN_WAIT_WAKE: ++ case IRP_MN_POWER_SEQUENCE: ++ /* TODO: implement WAIT_WAKE */ ++ status = IoPassIrpDown(wnd->nmb->pdo, irp); ++ break; ++ default: ++ status = IoPassIrpDown(wnd->nmb->pdo, irp); ++ break; ++ } ++ IOEXIT(return status); ++} ++WIN_FUNC_DECL(NdisDispatchPower,2) ++ ++wstdcall NTSTATUS NdisDispatchPnp(struct device_object *fdo, struct irp *irp) ++{ ++ struct io_stack_location *irp_sl; ++ struct ndis_device *wnd; ++ struct device_object *pdo; ++ NTSTATUS status; ++ ++ IOTRACE("fdo: %p, irp: %p", fdo, irp); ++ irp_sl = IoGetCurrentIrpStackLocation(irp); ++ wnd = fdo->reserved; ++ pdo = wnd->nmb->pdo; ++ switch (irp_sl->minor_fn) { ++ case IRP_MN_START_DEVICE: ++ status = IoSyncForwardIrp(pdo, irp); ++ if (status != STATUS_SUCCESS) ++ break; ++ if (ndis_start_device(wnd) == NDIS_STATUS_SUCCESS) ++ status = STATUS_SUCCESS; ++ else ++ status = STATUS_FAILURE; ++ irp->io_status.status = status; ++ IoCompleteRequest(irp, IO_NO_INCREMENT); ++ break; ++ case IRP_MN_QUERY_STOP_DEVICE: ++ /* TODO: implement in NDIS */ ++ status = IoPassIrpDown(wnd->nmb->pdo, irp); ++ break; ++ case IRP_MN_STOP_DEVICE: ++ mp_halt(wnd); ++ irp->io_status.status = STATUS_SUCCESS; ++ status = IoAsyncForwardIrp(pdo, irp); ++ break; ++ case IRP_MN_REMOVE_DEVICE: ++ TRACE1("%s", wnd->net_dev->name); ++ mp_pnp_event(wnd, NdisDevicePnPEventSurpriseRemoved, 0); ++ if (ndis_remove_device(wnd)) { ++ status = STATUS_FAILURE; ++ break; ++ } ++ /* wnd is already freed */ ++ status = IoAsyncForwardIrp(pdo, irp); ++ IoDetachDevice(fdo); ++ IoDeleteDevice(fdo); ++ break; ++ default: ++ status = IoAsyncForwardIrp(pdo, irp); ++ break; ++ } ++ IOTRACE("status: %08X", status); ++ IOEXIT(return status); ++} ++WIN_FUNC_DECL(NdisDispatchPnp,2) ++ ++static void set_task_offload(struct ndis_device *wnd, void *buf, ++ const int buf_size) ++{ ++ struct ndis_task_offload_header *task_offload_header; ++ struct ndis_task_offload *task_offload; ++ struct ndis_task_tcp_ip_checksum *csum = NULL; ++ struct ndis_task_tcp_large_send *tso = NULL; ++ NDIS_STATUS status; ++ ++ memset(buf, 0, buf_size); ++ task_offload_header = buf; ++ task_offload_header->version = NDIS_TASK_OFFLOAD_VERSION; ++ task_offload_header->size = sizeof(*task_offload_header); ++ task_offload_header->encap_format.flags.fixed_header_size = 1; ++ task_offload_header->encap_format.header_size = sizeof(struct ethhdr); ++ task_offload_header->encap_format.encap = IEEE_802_3_Encapsulation; ++ status = mp_query(wnd, OID_TCP_TASK_OFFLOAD, buf, buf_size); ++ TRACE1("%08X", status); ++ if (status != NDIS_STATUS_SUCCESS) ++ EXIT1(return); ++ if (task_offload_header->offset_first_task == 0) ++ EXIT1(return); ++ task_offload = ((void *)task_offload_header + ++ task_offload_header->offset_first_task); ++ while (1) { ++ TRACE1("%d, %d", task_offload->version, task_offload->task); ++ switch (task_offload->task) { ++ case TcpIpChecksumNdisTask: ++ csum = (void *)task_offload->task_buf; ++ break; ++ case TcpLargeSendNdisTask: ++ tso = (void *)task_offload->task_buf; ++ break; ++ default: ++ TRACE1("%d", task_offload->task); ++ break; ++ } ++ if (task_offload->offset_next_task == 0) ++ break; ++ task_offload = (void *)task_offload + ++ task_offload->offset_next_task; ++ } ++ if (tso) ++ TRACE1("%u, %u, %d, %d", tso->max_size, tso->min_seg_count, ++ tso->tcp_opts, tso->ip_opts); ++ if (!csum) ++ EXIT1(return); ++ TRACE1("%08x, %08x", csum->v4_tx.value, csum->v4_rx.value); ++ task_offload_header->encap_format.flags.fixed_header_size = 1; ++ task_offload_header->encap_format.header_size = sizeof(struct ethhdr); ++ task_offload_header->offset_first_task = sizeof(*task_offload_header); ++ task_offload = ((void *)task_offload_header + ++ task_offload_header->offset_first_task); ++ task_offload->offset_next_task = 0; ++ task_offload->size = sizeof(*task_offload); ++ task_offload->task = TcpIpChecksumNdisTask; ++ memcpy(task_offload->task_buf, csum, sizeof(*csum)); ++ task_offload->task_buf_length = sizeof(*csum); ++ status = mp_set(wnd, OID_TCP_TASK_OFFLOAD, task_offload_header, ++ sizeof(*task_offload_header) + ++ sizeof(*task_offload) + sizeof(*csum)); ++ TRACE1("%08X", status); ++ if (status != NDIS_STATUS_SUCCESS) ++ EXIT2(return); ++ wnd->tx_csum = csum->v4_tx; ++ if (csum->v4_tx.tcp_csum && csum->v4_tx.udp_csum) { ++ if (csum->v4_tx.ip_csum) { ++ wnd->net_dev->features |= NETIF_F_HW_CSUM; ++ TRACE1("hw checksum enabled"); ++ } else { ++ wnd->net_dev->features |= NETIF_F_IP_CSUM; ++ TRACE1("IP checksum enabled"); ++ } ++ if (wnd->sg_dma_size) ++ wnd->net_dev->features |= NETIF_F_SG; ++ } ++ wnd->rx_csum = csum->v4_rx; ++ EXIT1(return); ++} ++ ++static void get_supported_oids(struct ndis_device *wnd) ++{ ++ NDIS_STATUS res; ++ int i, n, needed; ++ ndis_oid *oids; ++ ++ res = mp_query_info(wnd, OID_GEN_SUPPORTED_LIST, NULL, 0, NULL, ++ &needed); ++ if (!(res == NDIS_STATUS_BUFFER_TOO_SHORT || ++ res == NDIS_STATUS_INVALID_LENGTH)) ++ EXIT1(return); ++ oids = kmalloc(needed, GFP_KERNEL); ++ if (!oids) { ++ TRACE1("couldn't allocate memory"); ++ EXIT1(return); ++ } ++ res = mp_query(wnd, OID_GEN_SUPPORTED_LIST, oids, needed); ++ if (res) { ++ TRACE1("failed: %08X", res); ++ kfree(oids); ++ EXIT1(return); ++ } ++ for (i = 0, n = needed / sizeof(*oids); i < n; i++) { ++ TRACE1("oid: %08X", oids[i]); ++ /* if a wireless device didn't say so for ++ * OID_GEN_PHYSICAL_MEDIUM (they should, but in case) */ ++ if (wnd->physical_medium != NdisPhysicalMediumWirelessLan && ++ oids[i] == OID_802_11_SSID) ++ wnd->physical_medium = NdisPhysicalMediumWirelessLan; ++ } ++ kfree(oids); ++ EXIT1(return); ++} ++ ++static void ndis_get_drvinfo(struct net_device *dev, ++ struct ethtool_drvinfo *info) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 2); ++ strcat(info->driver, "+"); ++ strncat(info->driver, wnd->wd->driver->name, ++ sizeof(info->driver) - strlen(DRIVER_NAME) - 1); ++ strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 2); ++ strcat(info->version, "+"); ++ strncat(info->version, wnd->wd->driver->version, ++ sizeof(info->version) - strlen(DRIVER_VERSION) - 1); ++ if (wrap_is_pci_bus(wnd->wd->dev_bus)) ++ strncpy(info->bus_info, pci_name(wnd->wd->pci.pdev), ++ sizeof(info->bus_info) - 1); ++#ifdef ENABLE_USB ++ else ++ usb_make_path(wnd->wd->usb.udev, info->bus_info, ++ sizeof(info->bus_info) - 1); ++#endif ++ return; ++} ++ ++static u32 ndis_get_link(struct net_device *dev) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ return netif_carrier_ok(wnd->net_dev); ++} ++ ++static void ndis_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ++ wol->supported = 0; ++ wol->wolopts = 0; ++ if (!(wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND)) ++ EXIT2(return); ++ if (!wrap_is_pci_bus(wnd->wd->dev_bus)) ++ EXIT2(return); ++ /* we always suspend to D3 */ ++ if (wnd->pnp_capa.wakeup.min_magic_packet_wakeup < NdisDeviceStateD3) ++ return; ++ wol->supported |= WAKE_MAGIC; ++ if (wnd->ndis_wolopts & NDIS_PNP_WAKE_UP_MAGIC_PACKET) ++ wol->wolopts |= WAKE_MAGIC; ++ return; ++} ++ ++static int ndis_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ++ if (!(wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND)) ++ return -EOPNOTSUPP; ++ if (wnd->pnp_capa.wakeup.min_magic_packet_wakeup < NdisDeviceStateD3) ++ EXIT2(return -EOPNOTSUPP); ++ TRACE2("0x%x", wol->wolopts); ++ if (wol->wolopts & WAKE_MAGIC) { ++ wnd->ndis_wolopts |= NDIS_PNP_WAKE_UP_MAGIC_PACKET; ++ if (wol->wolopts != WAKE_MAGIC) ++ WARNING("ignored wake-on-lan options: 0x%x", ++ wol->wolopts & ~WAKE_MAGIC); ++ } else if (!wol->wolopts) ++ wnd->ndis_wolopts = 0; ++ else ++ return -EOPNOTSUPP; ++ TRACE2("0x%x", wnd->ndis_wolopts); ++ return 0; ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) ++static u32 ndis_get_tx_csum(struct net_device *dev) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ if (wnd->tx_csum.tcp_csum && wnd->tx_csum.udp_csum) ++ return 1; ++ else ++ return 0; ++} ++ ++static u32 ndis_get_rx_csum(struct net_device *dev) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ if (wnd->rx_csum.value) ++ return 1; ++ else ++ return 0; ++} ++ ++static int ndis_set_tx_csum(struct net_device *dev, u32 data) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ++ if (data && (wnd->tx_csum.value == 0)) ++ return -EOPNOTSUPP; ++ ++ if (wnd->tx_csum.ip_csum) ++ ethtool_op_set_tx_hw_csum(dev, data); ++ else ++ ethtool_op_set_tx_csum(dev, data); ++ return 0; ++} ++ ++static int ndis_set_rx_csum(struct net_device *dev, u32 data) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ++ if (data && (wnd->tx_csum.value == 0)) ++ return -EOPNOTSUPP; ++ ++ /* TODO: enable/disable rx csum through NDIS */ ++ return 0; ++} ++ ++static u32 ndis_get_sg(struct net_device *dev) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ if (wnd->sg_dma_size) ++ return ethtool_op_get_sg(dev); ++ else ++ return 0; ++} ++ ++static int ndis_set_sg(struct net_device *dev, u32 data) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ if (wnd->sg_dma_size) ++ return ethtool_op_set_sg(dev, data); ++ else ++ return -EOPNOTSUPP; ++} ++#endif ++ ++static struct ethtool_ops ndis_ethtool_ops = { ++ .get_drvinfo = ndis_get_drvinfo, ++ .get_link = ndis_get_link, ++ .get_wol = ndis_get_wol, ++ .set_wol = ndis_set_wol, ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) ++ .get_tx_csum = ndis_get_tx_csum, ++ .get_rx_csum = ndis_get_rx_csum, ++ .set_tx_csum = ndis_set_tx_csum, ++ .set_rx_csum = ndis_set_rx_csum, ++ .get_sg = ndis_get_sg, ++ .set_sg = ndis_set_sg, ++#endif ++}; ++ ++static int notifier_event(struct notifier_block *notifier, unsigned long event, ++ void *ptr) ++{ ++ struct net_device *net_dev = netdev_notifier_info_to_dev(ptr); ++ ++ ENTER2("0x%lx", event); ++ if (net_dev->ethtool_ops == &ndis_ethtool_ops ++ && event == NETDEV_CHANGENAME) { ++ struct ndis_device *wnd = netdev_priv(net_dev); ++ ++ /* called with rtnl lock held, so no need to lock */ ++ if (likely(wnd->procfs_iface)) { ++ printk(KERN_INFO "%s: interface renamed to '%s'\n", ++ DRIVER_NAME, net_dev->name); ++ wrap_procfs_remove_ndis_device(wnd); ++ wrap_procfs_add_ndis_device(wnd); ++ } ++ } ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block netdev_notifier = { ++ .notifier_call = notifier_event, ++}; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) ++static const struct net_device_ops ndis_netdev_ops = { ++ .ndo_init = ndis_net_dev_init, ++ .ndo_uninit = ndis_net_dev_uninit, ++ .ndo_open = ndis_net_dev_open, ++ .ndo_stop = ndis_net_dev_close, ++ .ndo_start_xmit = tx_skbuff, ++ .ndo_change_mtu = ndis_change_mtu, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) ++ .ndo_set_rx_mode = ndis_set_multicast_list, ++#else ++ .ndo_set_multicast_list = ndis_set_multicast_list, ++#endif ++ .ndo_set_mac_address = ndis_set_mac_address, ++ .ndo_get_stats = ndis_get_stats, ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ .ndo_poll_controller = ndis_poll_controller, ++#endif ++}; ++#endif ++ ++static NDIS_STATUS ndis_start_device(struct ndis_device *wnd) ++{ ++ struct wrap_device *wd; ++ struct net_device *net_dev; ++ NDIS_STATUS status; ++ char *buf; ++ const int buf_len = 256; ++ mac_address mac; ++ struct transport_header_offset *tx_header_offset; ++ int n; ++ ++ ENTER2("%d", in_atomic()); ++ status = mp_init(wnd); ++ if (status == NDIS_STATUS_NOT_RECOGNIZED) ++ EXIT1(return NDIS_STATUS_SUCCESS); ++ if (status != NDIS_STATUS_SUCCESS) ++ EXIT1(return status); ++ wd = wnd->wd; ++ net_dev = wnd->net_dev; ++ ++ get_supported_oids(wnd); ++ memset(mac, 0, sizeof(mac)); ++ status = mp_query(wnd, OID_802_3_CURRENT_ADDRESS, mac, sizeof(mac)); ++ if (memcmp(mac, "\x00\x00\x00\x00\x00\x00", sizeof(mac)) == 0) { ++ status = mp_query(wnd, OID_802_3_PERMANENT_ADDRESS, mac, ++ sizeof(mac)); ++ if (status != NDIS_STATUS_SUCCESS) { ++ ERROR("couldn't get mac address: %08X", status); ++ goto err_start; ++ } ++ } ++ TRACE1("mac:" MACSTRSEP, MAC2STR(mac)); ++ memcpy(net_dev->dev_addr, mac, ETH_ALEN); ++ ++ strncpy(net_dev->name, if_name, IFNAMSIZ - 1); ++ net_dev->name[IFNAMSIZ - 1] = 0; ++ ++ wnd->packet_filter = NDIS_PACKET_TYPE_DIRECTED | ++ NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_MULTICAST; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) ++ net_dev->netdev_ops = &ndis_netdev_ops; ++#else ++ net_dev->init = ndis_net_dev_init; ++ net_dev->uninit = ndis_net_dev_uninit; ++ net_dev->open = ndis_net_dev_open; ++ net_dev->hard_start_xmit = tx_skbuff; ++ net_dev->stop = ndis_net_dev_close; ++ net_dev->get_stats = ndis_get_stats; ++ net_dev->change_mtu = ndis_change_mtu; ++ net_dev->set_multicast_list = ndis_set_multicast_list; ++ net_dev->set_mac_address = ndis_set_mac_address; ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ net_dev->poll_controller = ndis_poll_controller; ++#endif ++#endif ++#ifdef CONFIG_WIRELESS_EXT ++ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) { ++ net_dev->wireless_handlers = &ndis_handler_def; ++ } ++#endif ++ net_dev->ethtool_ops = &ndis_ethtool_ops; ++ if (wnd->mp_interrupt) ++ net_dev->irq = wnd->mp_interrupt->irq; ++ net_dev->mem_start = wnd->mem_start; ++ net_dev->mem_end = wnd->mem_end; ++ status = mp_query_int(wnd, OID_802_3_MAXIMUM_LIST_SIZE, ++ &wnd->multicast_size); ++ if (status != NDIS_STATUS_SUCCESS || wnd->multicast_size < 0) ++ wnd->multicast_size = 0; ++ if (wnd->multicast_size > 0) ++ net_dev->flags |= IFF_MULTICAST; ++ else ++ net_dev->flags &= ~IFF_MULTICAST; ++ ++ buf = kmalloc(buf_len, GFP_KERNEL); ++ if (!buf) { ++ WARNING("couldn't allocate memory"); ++ goto err_start; ++ } ++ ++ set_task_offload(wnd, buf, buf_len); ++#ifdef NETIF_F_LLTX ++ net_dev->features |= NETIF_F_LLTX; ++#endif ++ ++ if (register_netdev(net_dev)) { ++ ERROR("cannot register net device %s", net_dev->name); ++ goto err_register; ++ } ++ memset(buf, 0, buf_len); ++ status = mp_query(wnd, OID_GEN_VENDOR_DESCRIPTION, buf, buf_len); ++ if (status != NDIS_STATUS_SUCCESS) { ++ WARNING("couldn't get vendor information: 0x%x", status); ++ buf[0] = 0; ++ } ++ wnd->drv_ndis_version = n = 0; ++ mp_query_int(wnd, OID_GEN_DRIVER_VERSION, &wnd->drv_ndis_version); ++ mp_query_int(wnd, OID_GEN_VENDOR_DRIVER_VERSION, &n); ++ ++ printk(KERN_INFO "%s: ethernet device " MACSTRSEP " using %sNDIS " ++ "driver: %s, version: 0x%x, NDIS version: 0x%x, vendor: '%s', " ++ "%s\n", net_dev->name, MAC2STR(net_dev->dev_addr), ++ deserialized_driver(wnd) ? "" : "serialized ", ++ wd->driver->name, n, wnd->drv_ndis_version, buf, ++ wd->conf_file_name); ++ ++ if (deserialized_driver(wnd)) { ++ /* deserialized drivers don't have a limit, but we ++ * keep max at TX_RING_SIZE */ ++ wnd->max_tx_packets = TX_RING_SIZE; ++ } else { ++ status = mp_query_int(wnd, OID_GEN_MAXIMUM_SEND_PACKETS, ++ &wnd->max_tx_packets); ++ if (status != NDIS_STATUS_SUCCESS) ++ wnd->max_tx_packets = 1; ++ if (wnd->max_tx_packets > TX_RING_SIZE) ++ wnd->max_tx_packets = TX_RING_SIZE; ++ } ++ TRACE2("maximum send packets: %d", wnd->max_tx_packets); ++ NdisAllocatePacketPoolEx(&status, &wnd->tx_packet_pool, ++ wnd->max_tx_packets, 0, ++ PROTOCOL_RESERVED_SIZE_IN_PACKET); ++ if (status != NDIS_STATUS_SUCCESS) { ++ ERROR("couldn't allocate packet pool"); ++ goto packet_pool_err; ++ } ++ NdisAllocateBufferPool(&status, &wnd->tx_buffer_pool, ++ wnd->max_tx_packets + 4); ++ if (status != NDIS_STATUS_SUCCESS) { ++ ERROR("couldn't allocate buffer pool"); ++ goto buffer_pool_err; ++ } ++ TRACE1("pool: %p", wnd->tx_buffer_pool); ++ ++ if (mp_query_int(wnd, OID_GEN_MAXIMUM_TOTAL_SIZE, &n) == ++ NDIS_STATUS_SUCCESS && n > ETH_HLEN) ++ ndis_change_mtu(wnd->net_dev, n - ETH_HLEN); ++ ++ if (mp_query_int(wnd, OID_GEN_MAC_OPTIONS, &n) == NDIS_STATUS_SUCCESS) ++ TRACE2("mac options supported: 0x%x", n); ++ ++ tx_header_offset = (typeof(tx_header_offset))buf; ++ tx_header_offset->protocol_type = NDIS_PROTOCOL_ID_TCP_IP; ++ tx_header_offset->header_offset = sizeof(ETH_HLEN); ++ status = mp_set(wnd, OID_GEN_TRANSPORT_HEADER_OFFSET, ++ tx_header_offset, sizeof(*tx_header_offset)); ++ TRACE2("%08X", status); ++ ++ status = mp_query_int(wnd, OID_GEN_PHYSICAL_MEDIUM, ++ &wnd->physical_medium); ++ if (status != NDIS_STATUS_SUCCESS) ++ wnd->physical_medium = NdisPhysicalMediumUnspecified; ++ ++#ifdef CONFIG_WIRELESS_EXT ++ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) { ++ mp_set_int(wnd, OID_802_11_POWER_MODE, NDIS_POWER_OFF); ++ get_encryption_capa(wnd, buf, buf_len); ++ TRACE1("capabilities = %ld", wnd->capa.encr); ++ printk(KERN_INFO "%s: encryption modes supported: " ++ "%s%s%s%s%s%s%s\n", net_dev->name, ++ test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr) ? ++ "WEP" : "none", ++ ++ test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr) ? ++ "; TKIP with WPA" : "", ++ test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ? ++ ", WPA2" : "", ++ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ? ++ ", WPA2-PSK" : "", ++ ++ test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr) ? ++ "; AES/CCMP with WPA" : "", ++ test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ? ++ ", WPA2" : "", ++ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ? ++ ", WPA2-PSK" : ""); ++ ++ set_default_iw_params(wnd); ++ } ++#endif ++ kfree(buf); ++ hangcheck_add(wnd); ++ add_iw_stats_timer(wnd); ++ EXIT1(return NDIS_STATUS_SUCCESS); ++ ++buffer_pool_err: ++ wnd->tx_buffer_pool = NULL; ++ if (wnd->tx_packet_pool) { ++ NdisFreePacketPool(wnd->tx_packet_pool); ++ wnd->tx_packet_pool = NULL; ++ } ++packet_pool_err: ++ unregister_netdev(net_dev); ++ wnd->max_tx_packets = 0; ++err_register: ++ kfree(buf); ++err_start: ++ mp_halt(wnd); ++ EXIT1(return NDIS_STATUS_FAILURE); ++} ++ ++static int ndis_remove_device(struct ndis_device *wnd) ++{ ++ s8 tx_pending; ++ int our_mutex; ++ ++ /* prevent setting essid during disassociation */ ++ memset(&wnd->essid, 0, sizeof(wnd->essid)); ++ wnd->tx_ok = 0; ++ netif_carrier_off(wnd->net_dev); ++ if (wnd->max_tx_packets) ++ unregister_netdev(wnd->net_dev); ++ /* if device is suspended, but resume failed, tx_ring_mutex ++ * may already be locked */ ++ our_mutex = mutex_trylock(&wnd->tx_ring_mutex); ++ if (!our_mutex) ++ WARNING("couldn't obtain tx_ring_mutex"); ++ spin_lock_bh(&wnd->tx_ring_lock); ++ tx_pending = wnd->tx_ring_end - wnd->tx_ring_start; ++ if (tx_pending < 0) ++ tx_pending += TX_RING_SIZE; ++ else if (tx_pending == 0 && wnd->is_tx_ring_full) ++ tx_pending = TX_RING_SIZE - 1; ++ wnd->is_tx_ring_full = 0; ++ /* throw away pending packets */ ++ while (tx_pending-- > 0) { ++ struct ndis_packet *packet; ++ ++ packet = wnd->tx_ring[wnd->tx_ring_start]; ++ free_tx_packet(wnd, packet, NDIS_STATUS_CLOSING); ++ wnd->tx_ring_start = (wnd->tx_ring_start + 1) % TX_RING_SIZE; ++ } ++ spin_unlock_bh(&wnd->tx_ring_lock); ++ if (our_mutex) ++ mutex_unlock(&wnd->tx_ring_mutex); ++ mp_halt(wnd); ++ ndis_exit_device(wnd); ++ ++ if (wnd->tx_packet_pool) { ++ NdisFreePacketPool(wnd->tx_packet_pool); ++ wnd->tx_packet_pool = NULL; ++ } ++ if (wnd->tx_buffer_pool) { ++ NdisFreeBufferPool(wnd->tx_buffer_pool); ++ wnd->tx_buffer_pool = NULL; ++ } ++ kfree(wnd->pmkids); ++ printk(KERN_INFO "%s: device %s removed\n", DRIVER_NAME, ++ wnd->net_dev->name); ++ kfree(wnd->nmb); ++ free_netdev(wnd->net_dev); ++ EXIT2(return 0); ++} ++ ++static NTSTATUS ndis_add_device(struct driver_object *drv_obj, ++ struct device_object *pdo) ++{ ++ struct device_object *fdo; ++ struct ndis_mp_block *nmb; ++ NTSTATUS status; ++ struct ndis_device *wnd; ++ struct net_device *net_dev; ++ struct wrap_device *wd; ++ unsigned long i; ++ ++ ENTER2("%p, %p", drv_obj, pdo); ++ if (strlen(if_name) >= IFNAMSIZ) { ++ ERROR("interface name '%s' is too long", if_name); ++ return STATUS_INVALID_PARAMETER; ++ } ++ net_dev = alloc_etherdev(sizeof(*wnd)); ++ if (!net_dev) { ++ ERROR("couldn't allocate device"); ++ return STATUS_RESOURCES; ++ } ++ wd = pdo->reserved; ++ if (wrap_is_pci_bus(wd->dev_bus)) ++ SET_NETDEV_DEV(net_dev, &wd->pci.pdev->dev); ++ if (wrap_is_usb_bus(wd->dev_bus)) ++ SET_NETDEV_DEV(net_dev, &wd->usb.intf->dev); ++ status = IoCreateDevice(drv_obj, 0, NULL, FILE_DEVICE_UNKNOWN, 0, ++ FALSE, &fdo); ++ if (status != STATUS_SUCCESS) { ++ free_netdev(net_dev); ++ EXIT2(return status); ++ } ++ wnd = netdev_priv(net_dev); ++ TRACE1("wnd: %p", wnd); ++ ++ nmb = kmalloc(sizeof(*nmb), GFP_KERNEL); ++ if (!nmb) { ++ WARNING("couldn't allocate memory"); ++ IoDeleteDevice(fdo); ++ free_netdev(net_dev); ++ return STATUS_RESOURCES; ++ } ++#if DEBUG >= 6 ++ /* poison nmb so if a driver accesses uninitialized pointers, we ++ * know what it is */ ++ for (i = 0; i < sizeof(*nmb) / sizeof(unsigned long); i++) ++ ((unsigned long *)nmb)[i] = i + 0x8a3fc1; ++#endif ++ ++ wnd->nmb = nmb; ++ nmb->wnd = wnd; ++ nmb->pdo = pdo; ++ wnd->wd = wd; ++ wnd->net_dev = net_dev; ++ fdo->reserved = wnd; ++ nmb->fdo = fdo; ++ if (ndis_init_device(wnd)) { ++ IoDeleteDevice(fdo); ++ kfree(nmb); ++ free_netdev(net_dev); ++ EXIT1(return STATUS_RESOURCES); ++ } ++ nmb->next_device = IoAttachDeviceToDeviceStack(fdo, pdo); ++ spin_lock_init(&wnd->tx_ring_lock); ++ mutex_init(&wnd->tx_ring_mutex); ++ mutex_init(&wnd->ndis_req_mutex); ++ wnd->ndis_req_done = 0; ++ INIT_WORK(&wnd->tx_work, tx_worker); ++ wnd->tx_ring_start = 0; ++ wnd->tx_ring_end = 0; ++ wnd->is_tx_ring_full = 0; ++ wnd->capa.encr = 0; ++ wnd->capa.auth = 0; ++ wnd->attributes = 0; ++ wnd->dma_map_count = 0; ++ wnd->dma_map_addr = NULL; ++ wnd->nick[0] = 0; ++ init_timer(&wnd->hangcheck_timer); ++ wnd->scan_timestamp = 0; ++ init_timer(&wnd->iw_stats_timer); ++ wnd->iw_stats_interval = 10 * HZ; ++ wnd->ndis_pending_work = 0; ++ memset(&wnd->essid, 0, sizeof(wnd->essid)); ++ memset(&wnd->encr_info, 0, sizeof(wnd->encr_info)); ++ wnd->infrastructure_mode = Ndis802_11Infrastructure; ++ INIT_WORK(&wnd->ndis_work, wrapndis_worker); ++ wnd->iw_stats_enabled = TRUE; ++ ++ TRACE1("nmb: %p, pdo: %p, fdo: %p, attached: %p, next: %p", ++ nmb, pdo, fdo, fdo->attached, nmb->next_device); ++ ++ /* dispatch routines are called as Windows functions */ ++ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) ++ drv_obj->major_func[i] = WIN_FUNC_PTR(IoPassIrpDown,2); ++ ++ drv_obj->major_func[IRP_MJ_PNP] = WIN_FUNC_PTR(NdisDispatchPnp,2); ++ drv_obj->major_func[IRP_MJ_POWER] = WIN_FUNC_PTR(NdisDispatchPower,2); ++ drv_obj->major_func[IRP_MJ_INTERNAL_DEVICE_CONTROL] = ++ WIN_FUNC_PTR(NdisDispatchDeviceControl,2); ++// drv_obj->major_func[IRP_MJ_DEVICE_CONTROL] = ++// WIN_FUNC_PTR(NdisDispatchDeviceControl,2); ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++int init_ndis_driver(struct driver_object *drv_obj) ++{ ++ ENTER1("%p", drv_obj); ++ drv_obj->drv_ext->add_device = ndis_add_device; ++ return 0; ++} ++ ++int wrapndis_init(void) ++{ ++ wrapndis_wq = create_singlethread_workqueue("wrapndis_wq"); ++ if (!wrapndis_wq) ++ EXIT1(return -ENOMEM); ++ TRACE1("wrapndis_wq: %p", wrapndis_wq); ++ register_netdevice_notifier(&netdev_notifier); ++ return 0; ++} ++ ++void wrapndis_exit(void) ++{ ++ unregister_netdevice_notifier(&netdev_notifier); ++ if (wrapndis_wq) ++ destroy_workqueue(wrapndis_wq); ++} +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/wrapndis.h linux-4.6-rc6-ndis/3rdparty/ndiswrapper/wrapndis.h +--- linux-4.6-rc6/3rdparty/ndiswrapper/wrapndis.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/wrapndis.h 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,86 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _WRAPNDIS_H_ ++#define _WRAPNDIS_H_ ++ ++#include "ndis.h" ++#include "pnp.h" ++ ++int wrapndis_init(void); ++void wrapndis_exit(void); ++ ++NDIS_STATUS mp_reset(struct ndis_device *wnd); ++ ++NDIS_STATUS mp_request(enum ndis_request_type request, ++ struct ndis_device *wnd, ndis_oid oid, ++ void *buf, ULONG buflen, ULONG *written, ULONG *needed); ++ ++static inline NDIS_STATUS mp_query_info(struct ndis_device *wnd, ++ ndis_oid oid, void *buf, ULONG buflen, ++ ULONG *written, ULONG *needed) ++{ ++ return mp_request(NdisRequestQueryInformation, wnd, oid, ++ buf, buflen, written, needed); ++} ++ ++static inline NDIS_STATUS mp_set_info(struct ndis_device *wnd, ++ ndis_oid oid, void *buf, ULONG buflen, ++ ULONG *written, ULONG *needed) ++{ ++ return mp_request(NdisRequestSetInformation, wnd, oid, ++ buf, buflen, written, needed); ++} ++ ++static inline NDIS_STATUS mp_query(struct ndis_device *wnd, ndis_oid oid, ++ void *buf, ULONG buflen) ++{ ++ return mp_request(NdisRequestQueryInformation, wnd, oid, ++ buf, buflen, NULL, NULL); ++} ++ ++static inline NDIS_STATUS mp_query_int(struct ndis_device *wnd, ++ ndis_oid oid, ULONG *data) ++{ ++ return mp_request(NdisRequestQueryInformation, wnd, oid, ++ data, sizeof(ULONG), NULL, NULL); ++} ++ ++static inline NDIS_STATUS mp_set(struct ndis_device *wnd, ndis_oid oid, ++ void *buf, ULONG buflen) ++{ ++ return mp_request(NdisRequestSetInformation, wnd, oid, ++ buf, buflen, NULL, NULL); ++} ++ ++static inline NDIS_STATUS mp_set_int(struct ndis_device *wnd, ++ ndis_oid oid, ULONG data) ++{ ++ return mp_request(NdisRequestSetInformation, wnd, oid, ++ &data, sizeof(ULONG), NULL, NULL); ++} ++ ++void free_tx_packet(struct ndis_device *wnd, struct ndis_packet *packet, ++ NDIS_STATUS status); ++int init_ndis_driver(struct driver_object *drv_obj); ++NDIS_STATUS ndis_reinit(struct ndis_device *wnd); ++void set_media_state(struct ndis_device *wnd, enum ndis_media_state state); ++ ++void hangcheck_add(struct ndis_device *wnd); ++void hangcheck_del(struct ndis_device *wnd); ++ ++struct iw_statistics *get_iw_stats(struct net_device *dev); ++ ++#endif +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/wrapper.c linux-4.6-rc6-ndis/3rdparty/ndiswrapper/wrapper.c +--- linux-4.6-rc6/3rdparty/ndiswrapper/wrapper.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/wrapper.c 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,111 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include "ndis.h" ++#include "iw_ndis.h" ++#include "loader.h" ++#include "pnp.h" ++#include "wrapper.h" ++ ++char *if_name = "wlan%d"; ++int proc_uid, proc_gid; ++int hangcheck_interval; ++static char *utils_version = UTILS_VERSION; ++int debug = DEBUG; ++ ++module_param(if_name, charp, 0400); ++MODULE_PARM_DESC(if_name, "Network interface name or template " ++ "(default: wlan%d)"); ++module_param(proc_uid, int, 0600); ++MODULE_PARM_DESC(proc_uid, "The uid of the files created in /proc " ++ "(default: 0)."); ++module_param(proc_gid, int, 0600); ++MODULE_PARM_DESC(proc_gid, "The gid of the files created in /proc " ++ "(default: 0)."); ++module_param(debug, int, 0600); ++MODULE_PARM_DESC(debug, "debug level"); ++ ++/* 0 - default value provided by NDIS driver, ++ * positive value - force hangcheck interval to that many seconds ++ * negative value - disable hangcheck ++ */ ++module_param(hangcheck_interval, int, 0600); ++MODULE_PARM_DESC(hangcheck_interval, "The interval, in seconds, for checking" ++ " if driver is hung. (default: 0)"); ++ ++module_param(utils_version, charp, 0400); ++MODULE_PARM_DESC(utils_version, "Compatible version of utils " ++ "(read only: " UTILS_VERSION ")"); ++ ++MODULE_AUTHOR("ndiswrapper team "); ++#ifdef MODULE_DESCRIPTION ++MODULE_DESCRIPTION("NDIS wrapper driver"); ++#endif ++#ifdef MODULE_VERSION ++MODULE_VERSION(DRIVER_VERSION); ++#endif ++MODULE_LICENSE("GPL"); ++ ++static void module_cleanup(void) ++{ ++ loader_exit(); ++ usb_exit(); ++ wrap_procfs_remove(); ++ wrapndis_exit(); ++ ndis_exit(); ++ ntoskernel_exit(); ++ wrapmem_exit(); ++} ++ ++static int __init wrapper_init(void) ++{ ++#ifdef TAINT_OOT_MODULE ++ add_taint(TAINT_OOT_MODULE, LOCKDEP_NOW_UNRELIABLE); ++#endif ++ printk(KERN_INFO "%s version %s loaded (smp=%s, preempt=%s)\n", ++ DRIVER_NAME, DRIVER_VERSION, ++#ifdef CONFIG_SMP ++ "yes" ++#else ++ "no" ++#endif ++ , ++#ifdef CONFIG_PREEMPT_RT ++ "rt" ++#elif defined(CONFIG_PREEMPT) ++ "yes" ++#else ++ "no" ++#endif ++ ); ++ ++ if (wrapmem_init() || ntoskernel_init() || ndis_init() || ++ wrapndis_init() || usb_init() || wrap_procfs_init() || ++ loader_init()) { ++ module_cleanup(); ++ ERROR("%s: initialization failed", DRIVER_NAME); ++ return -EINVAL; ++ } ++ EXIT1(return 0); ++} ++ ++static void __exit wrapper_exit(void) ++{ ++ ENTER1(""); ++ module_cleanup(); ++} ++ ++module_init(wrapper_init); ++module_exit(wrapper_exit); +diff -Nurp linux-4.6-rc6/3rdparty/ndiswrapper/wrapper.h linux-4.6-rc6-ndis/3rdparty/ndiswrapper/wrapper.h +--- linux-4.6-rc6/3rdparty/ndiswrapper/wrapper.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.6-rc6-ndis/3rdparty/ndiswrapper/wrapper.h 2016-05-01 18:25:43.000000000 +0300 +@@ -0,0 +1,24 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef WRAPPER_H ++#define WRAPPER_H ++ ++extern char *if_name; ++extern int proc_uid; ++extern int proc_gid; ++extern int hangcheck_interval; ++ ++#endif /* WRAPPER_H */ diff --git a/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-4.7-buildfix.patch b/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-4.7-buildfix.patch new file mode 100644 index 0000000000..6e984b38cb --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-4.7-buildfix.patch @@ -0,0 +1,20 @@ + +Add supprto for 4.7 series kernels. + +Signed-off-by: Thomas Backlund + +diff -urp linux/3rdparty/ndiswrapper.orig/wrapndis.c linux/3rdparty/ndiswrapper/wrapndis.c +--- linux/3rdparty/ndiswrapper.orig/wrapndis.c 2016-07-04 20:00:13.000000000 +0300 ++++ linux/3rdparty/ndiswrapper/wrapndis.c 2016-07-04 20:23:29.454819702 +0300 +@@ -704,7 +704,11 @@ static void tx_worker(struct work_struct + n = wnd->max_tx_packets; + n = mp_tx_packets(wnd, wnd->tx_ring_start, n); + if (n) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) + wnd->net_dev->trans_start = jiffies; ++#else ++ netif_trans_update(wnd->net_dev); ++#endif + wnd->tx_ring_start = + (wnd->tx_ring_start + n) % TX_RING_SIZE; + wnd->is_tx_ring_full = 0; diff --git a/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-Kconfig.patch b/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-Kconfig.patch new file mode 100644 index 0000000000..f7d26e620b --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-Kconfig.patch @@ -0,0 +1,7 @@ +--- linux-2.6.24.orig/3rdparty/ndiswrapper/Kconfig 1969-12-31 21:00:00.000000000 -0300 ++++ linux-2.6.24/3rdparty/ndiswrapper/Kconfig 2007-11-26 15:11:31.000000000 -0200 +@@ -0,0 +1,4 @@ ++ ++config NDISWRAPPER ++ tristate "NDIS driver wrapper support" ++ depends on PCI && USB && !X86_64_XEN diff --git a/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-Makefile-build-fix.patch b/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-Makefile-build-fix.patch new file mode 100644 index 0000000000..b44f4b2938 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-Makefile-build-fix.patch @@ -0,0 +1,45 @@ +--- linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/Makefile.orig 2013-11-28 21:42:10.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/Makefile 2013-11-30 21:41:19.550504380 +0200 +@@ -9,24 +9,10 @@ DISTFILES = \ + winnt_types.h workqueue.c wrapmem.c wrapmem.h wrapndis.c wrapndis.h \ + wrapper.c wrapper.h + +-# By default, we try to compile the modules for the currently running +-# kernel. But it's the first approximation, as we will re-read the +-# version from the kernel sources. +-KVERS_UNAME ?= $(shell uname -r) +- + # KBUILD is the path to the Linux kernel build tree. It is usually the + # same as the kernel source tree, except when the kernel was compiled in + # a separate directory. +-KBUILD ?= $(shell readlink -f /lib/modules/$(KVERS_UNAME)/build) +- +-ifeq (,$(KBUILD)) +-$(error Kernel build tree not found - please set KBUILD to configured kernel) +-endif +- +-KCONFIG := $(KBUILD)/.config +-ifeq (,$(wildcard $(KCONFIG))) +-$(error No .config found in $(KBUILD), please set KBUILD to configured kernel) +-endif ++KBUILD ?= $(srctree) + + ifneq (,$(wildcard $(KBUILD)/include/linux/version.h)) + ifneq (,$(wildcard $(KBUILD)/include/generated/uapi/linux/version.h)) +@@ -43,16 +29,9 @@ endif + ifeq (,$(wildcard $(VERSION_H))) + VERSION_H := $(KBUILD)/include/linux/version.h + endif +-ifeq (,$(wildcard $(VERSION_H))) +-$(error Please run 'make modules_prepare' in $(KBUILD)) +-endif + + KVERS := $(shell sed -ne 's/"//g;s/^\#define UTS_RELEASE //p' $(VERSION_H)) + +-ifeq (,$(KVERS)) +-$(error Cannot find UTS_RELEASE in $(VERSION_H), please report) +-endif +- + INST_DIR = /lib/modules/$(KVERS)/misc + + SRC_DIR=$(shell pwd) diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rfswitch-1.3.patch b/kernel/tools/perf/files/patches/mageia/3rd-rfswitch-1.3.patch new file mode 100644 index 0000000000..e87bf7e0df --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-rfswitch-1.3.patch @@ -0,0 +1,978 @@ + 3rdparty/rfswitch/FILES | 6 + 3rdparty/rfswitch/ISSUES | 28 +++ + 3rdparty/rfswitch/Kconfig | 22 ++ + 3rdparty/rfswitch/LICENSE | 339 +++++++++++++++++++++++++++++++++++++++++++++ + 3rdparty/rfswitch/Makefile | 119 +++++++++++++++ + 3rdparty/rfswitch/README | 44 +++++ + 3rdparty/rfswitch/av5100.c | 174 +++++++++++++++++++++++ + 3rdparty/rfswitch/pbe5.c | 205 +++++++++++++++++++++++++++ + 8 files changed, 937 insertions(+) +diff -Nurp linux-2.6.37/3rdparty/rfswitch/av5100.c linux-2.6.37.3rdparty/3rdparty/rfswitch/av5100.c +--- linux-2.6.37/3rdparty/rfswitch/av5100.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/rfswitch/av5100.c 2008-03-28 05:25:28.000000000 +0200 +@@ -0,0 +1,174 @@ ++/******************************************************************************* ++ ++ 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 ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define DRV_NAME "av5100" ++#define DRV_VERSION "1.3" ++#define DRV_DESCRIPTION "SW RF kill switch for Averatec 5100P" ++#define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" ++ ++static int radio = 1; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ ++MODULE_PARM(radio, "i"); ++ ++#else /* LINUX_VERSION_CODE < 2.6.0 */ ++ ++#include ++module_param(radio, int, 1); ++ ++#endif /* LINUX_VERSION_CODE < 2.6.0 */ ++ ++MODULE_PARM_DESC(radio, "controls state of radio (1=on, 0=off)"); ++ ++MODULE_DESCRIPTION(DRV_DESCRIPTION); ++MODULE_AUTHOR(DRV_COPYRIGHT); ++MODULE_LICENSE("GPL"); ++ ++#define AV5100_RADIO_ON (0xe0) ++#define AV5100_RADIO_OFF (0xe1) ++ ++static int av5100_radio = AV5100_RADIO_OFF; ++ ++static void av5100_set_radio(int state) ++{ ++ printk(KERN_INFO DRV_NAME ": Radio being turned %s\n", ++ (state == AV5100_RADIO_ON) ? "ON" : "OFF"); ++ outl(0x80020800, 0xcf8); ++ outb(0x6f, 0x0072); ++ outl(0x1800ffff, 0x1184); ++ outb(state, 0x00b2); ++ av5100_radio = state; ++} ++ ++ ++/* ++ * proc stuff ++ */ ++static struct proc_dir_entry *dir_base = NULL; ++ ++static int proc_set_radio(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ av5100_set_radio(buffer[0] == '0' ? AV5100_RADIO_OFF : AV5100_RADIO_ON); ++ ++ return count; ++} ++ ++static int proc_get_radio(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ ++ len += snprintf(page, count, DRV_NAME ": %d\n", ++ av5100_radio == AV5100_RADIO_OFF ? 0 : 1); ++ ++ *eof = 1; ++ return len; ++} ++ ++ ++static void av5100_proc_cleanup(void) ++{ ++ if (dir_base) { ++ remove_proc_entry("radio", dir_base); ++ remove_proc_entry(DRV_NAME, &proc_root); ++ dir_base = NULL; ++ } ++} ++ ++ ++static int av5100_proc_init(void) ++{ ++ struct proc_dir_entry *ent; ++ int err = 0; ++ ++ dir_base = create_proc_entry(DRV_NAME, S_IFDIR, &proc_root); ++ if (dir_base == NULL) { ++ printk(KERN_ERR DRV_NAME ": Unable to initialise /proc/" ++ DRV_NAME "\n"); ++ err = -ENOMEM; ++ goto fail; ++ } ++ ++ ++ ent = create_proc_entry("radio", S_IFREG | S_IRUGO | S_IWUSR, ++ dir_base); ++ if (ent) { ++ ent->read_proc = proc_get_radio; ++ ent->write_proc = proc_set_radio; ++ } else { ++ printk(KERN_ERR ++ "Unable to initialize /proc/" DRV_NAME "/radio\n"); ++ err = -ENOMEM; ++ goto fail; ++ } ++ ++ return 0; ++ ++ fail: ++ av5100_proc_cleanup(); ++ return err; ++} ++ ++/* ++ * module stuff ++ */ ++static int __init av5100_init(void) ++{ ++ av5100_proc_init(); ++ ++ av5100_set_radio((radio == 1) ? AV5100_RADIO_ON : AV5100_RADIO_OFF); ++ ++ return 0; ++} ++ ++static void __exit av5100_exit(void) ++{ ++ av5100_set_radio(AV5100_RADIO_OFF); ++ ++ av5100_proc_cleanup(); ++} ++ ++module_init(av5100_init); ++module_exit(av5100_exit); ++ ++/* ++ 1 2 3 4 5 6 7 ++12345678901234567890123456789012345678901234567890123456789012345678901234567890 ++*/ +diff -Nurp linux-2.6.37/3rdparty/rfswitch/FILES linux-2.6.37.3rdparty/3rdparty/rfswitch/FILES +--- linux-2.6.37/3rdparty/rfswitch/FILES 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/rfswitch/FILES 2004-07-09 07:44:19.000000000 +0300 +@@ -0,0 +1,6 @@ ++Makefile Used for building on 2.4, 2.6, internally and exteranlly ++ ++FILES This file ++ ++av5100.c Averatec 5100P SW Switch Module ++pbe5.c Packard Bell Easynote SW Switch Module +diff -Nurp linux-2.6.37/3rdparty/rfswitch/ISSUES linux-2.6.37.3rdparty/3rdparty/rfswitch/ISSUES +--- linux-2.6.37/3rdparty/rfswitch/ISSUES 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/rfswitch/ISSUES 2004-07-09 07:43:22.000000000 +0300 +@@ -0,0 +1,28 @@ ++ ++ISSUES ++------------ ----- ----- ---- --- -- - ++ ++No packets! - RF kill switch ++ ++If the module loads, but no packets are transferred you may have a SW based ++radio kill switch. All laptops have some capability to disable the radio ++via a button or switch. On some laptops that switch is physically tied to the ++IPW2100; simply toggling the switch should enable the radio. ++ ++On other laptops, the switch is a button that when pressed requires some ++software driver to send some hardware command to some other piece of hardware ++on the laptop, that then controls the radio. The driver currently has support ++for the Averatec 5100P laptop's SW switch. Support will be added for other ++laptop vendors as we become aware of them and figure out how to enable the ++radio. ++ ++To know if the radio is being disabled via the RF switch, perform the following: ++ ++% cat /proc/net/ipw2100/eth1/state ++Radio is disabled by RF switch ++ ++If it says that, then your RF switch is currently disabling the radio. The ++driver doesn't currently support switching back to the on state if you have a ++physical RF switch (the radio may turn on and packets will work, but the proc ++entry won't be updated) ++ +diff -Nurp linux-2.6.37/3rdparty/rfswitch/Kconfig linux-2.6.37.3rdparty/3rdparty/rfswitch/Kconfig +--- linux-2.6.37/3rdparty/rfswitch/Kconfig 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/rfswitch/Kconfig 2008-05-27 23:39:10.000000000 +0300 +@@ -0,0 +1,22 @@ ++menu "RF Switch" ++ depends on EXPERIMENTAL ++ ++config RFSWITCH ++ tristate "RF Switch" ++ depends on EXPERIMENTAL ++ ++config AVERATEC_5100P ++ tristate "averatec 5100P driver" ++ depends on RFSWITCH ++ ---help--- ++ This is an experimental driver for the wireless switch ++ of some laptops (usefull with some ipw2x00 cards) ++ ++config PACKARDBELL_E5 ++ tristate "pbe5 driver" ++ depends on RFSWITCH ++ ---help--- ++ This is an experimental driver for the wireless switch ++ of some laptops (usefull with some ipw2x00 cards) ++ ++endmenu +diff -Nurp linux-2.6.37/3rdparty/rfswitch/LICENSE linux-2.6.37.3rdparty/3rdparty/rfswitch/LICENSE +--- linux-2.6.37/3rdparty/rfswitch/LICENSE 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/rfswitch/LICENSE 2004-07-09 07:43:22.000000000 +0300 +@@ -0,0 +1,339 @@ ++ ++"This software program is licensed subject to the GNU General Public License ++(GPL). Version 2, June 1991, available at ++" ++ ++GNU General Public License ++ ++Version 2, June 1991 ++ ++Copyright (C) 1989, 1991 Free Software Foundation, Inc. ++59 Temple Place - Suite 330, Boston, MA 02111-1307, USA ++ ++Everyone is permitted to copy and distribute verbatim copies of this license ++document, but changing it is not allowed. ++ ++Preamble ++ ++The licenses for most software are designed to take away your freedom to ++share and change it. By contrast, the GNU General Public License is intended ++to guarantee your freedom to share and change free software--to make sure ++the software is free for all its users. This General Public License applies ++to most of the Free Software Foundation's software and to any other program ++whose authors commit to using it. (Some other Free Software Foundation ++software is covered by the GNU Library General Public License instead.) You ++can apply it to your programs, too. ++ ++When we speak of free software, we are referring to freedom, not price. Our ++General Public Licenses are designed to make sure that you have the freedom ++to distribute copies of free software (and charge for this service if you ++wish), that you receive source code or can get it if you want it, that you ++can change the software or use pieces of it in new free programs; and that ++you know you can do these things. ++ ++To protect your rights, we need to make restrictions that forbid anyone to ++deny you these rights or to ask you to surrender the rights. These ++restrictions translate to certain responsibilities for you if you distribute ++copies of the software, or if you modify it. ++ ++For example, if you distribute copies of such a program, whether gratis or ++for a fee, you must give the recipients all the rights that you have. You ++must make sure that they, too, receive or can get the source code. And you ++must show them these terms so they know their rights. ++ ++We protect your rights with two steps: (1) copyright the software, and (2) ++offer you this license which gives you legal permission to copy, distribute ++and/or modify the software. ++ ++Also, for each author's protection and ours, we want to make certain that ++everyone understands that there is no warranty for this free software. If ++the software is modified by someone else and passed on, we want its ++recipients to know that what they have is not the original, so that any ++problems introduced by others will not reflect on the original authors' ++reputations. ++ ++Finally, any free program is threatened constantly by software patents. We ++wish to avoid the danger that redistributors of a free program will ++individually obtain patent licenses, in effect making the program ++proprietary. To prevent this, we have made it clear that any patent must be ++licensed for everyone's free use or not licensed at all. ++ ++The precise terms and conditions for copying, distribution and modification ++follow. ++ ++TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ++ ++0. This License applies to any program or other work which contains a notice ++ placed by the copyright holder saying it may be distributed under the ++ terms of this General Public License. The "Program", below, refers to any ++ such program or work, and a "work based on the Program" means either the ++ Program or any derivative work under copyright law: that is to say, a ++ work containing the Program or a portion of it, either verbatim or with ++ modifications and/or translated into another language. (Hereinafter, ++ translation is included without limitation in the term "modification".) ++ Each licensee is addressed as "you". ++ ++ Activities other than copying, distribution and modification are not ++ covered by this License; they are outside its scope. The act of running ++ the Program is not restricted, and the output from the Program is covered ++ only if its contents constitute a work based on the Program (independent ++ of having been made by running the Program). Whether that is true depends ++ on what the Program does. ++ ++1. You may copy and distribute verbatim copies of the Program's source code ++ as you receive it, in any medium, provided that you conspicuously and ++ appropriately publish on each copy an appropriate copyright notice and ++ disclaimer of warranty; keep intact all the notices that refer to this ++ License and to the absence of any warranty; and give any other recipients ++ of the Program a copy of this License along with the Program. ++ ++ You may charge a fee for the physical act of transferring a copy, and you ++ may at your option offer warranty protection in exchange for a fee. ++ ++2. You may modify your copy or copies of the Program or any portion of it, ++ thus forming a work based on the Program, and copy and distribute such ++ modifications or work under the terms of Section 1 above, provided that ++ you also meet all of these conditions: ++ ++ * a) You must cause the modified files to carry prominent notices stating ++ that you changed the files and the date of any change. ++ ++ * b) You must cause any work that you distribute or publish, that in ++ whole or in part contains or is derived from the Program or any part ++ thereof, to be licensed as a whole at no charge to all third parties ++ under the terms of this License. ++ ++ * c) If the modified program normally reads commands interactively when ++ run, you must cause it, when started running for such interactive ++ use in the most ordinary way, to print or display an announcement ++ including an appropriate copyright notice and a notice that there is ++ no warranty (or else, saying that you provide a warranty) and that ++ users may redistribute the program under these conditions, and ++ telling the user how to view a copy of this License. (Exception: if ++ the Program itself is interactive but does not normally print such ++ an announcement, your work based on the Program is not required to ++ print an announcement.) ++ ++ These requirements apply to the modified work as a whole. If identifiable ++ sections of that work are not derived from the Program, and can be ++ reasonably considered independent and separate works in themselves, then ++ this License, and its terms, do not apply to those sections when you ++ distribute them as separate works. But when you distribute the same ++ sections as part of a whole which is a work based on the Program, the ++ distribution of the whole must be on the terms of this License, whose ++ permissions for other licensees extend to the entire whole, and thus to ++ each and every part regardless of who wrote it. ++ ++ Thus, it is not the intent of this section to claim rights or contest ++ your rights to work written entirely by you; rather, the intent is to ++ exercise the right to control the distribution of derivative or ++ collective works based on the Program. ++ ++ In addition, mere aggregation of another work not based on the Program ++ with the Program (or with a work based on the Program) on a volume of a ++ storage or distribution medium does not bring the other work under the ++ scope of this License. ++ ++3. You may copy and distribute the Program (or a work based on it, under ++ Section 2) in object code or executable form under the terms of Sections ++ 1 and 2 above provided that you also do one of the following: ++ ++ * a) Accompany it with the complete corresponding machine-readable source ++ code, which must be distributed under the terms of Sections 1 and 2 ++ above on a medium customarily used for software interchange; or, ++ ++ * b) Accompany it with a written offer, valid for at least three years, ++ to give any third party, for a charge no more than your cost of ++ physically performing source distribution, a complete machine- ++ readable copy of the corresponding source code, to be distributed ++ under the terms of Sections 1 and 2 above on a medium customarily ++ used for software interchange; or, ++ ++ * c) Accompany it with the information you received as to the offer to ++ distribute corresponding source code. (This alternative is allowed ++ only for noncommercial distribution and only if you received the ++ program in object code or executable form with such an offer, in ++ accord with Subsection b above.) ++ ++ The source code for a work means the preferred form of the work for ++ making modifications to it. For an executable work, complete source code ++ means all the source code for all modules it contains, plus any ++ associated interface definition files, plus the scripts used to control ++ compilation and installation of the executable. However, as a special ++ exception, the source code distributed need not include anything that is ++ normally distributed (in either source or binary form) with the major ++ components (compiler, kernel, and so on) of the operating system on which ++ the executable runs, unless that component itself accompanies the ++ executable. ++ ++ If distribution of executable or object code is made by offering access ++ to copy from a designated place, then offering equivalent access to copy ++ the source code from the same place counts as distribution of the source ++ code, even though third parties are not compelled to copy the source ++ along with the object code. ++ ++4. You may not copy, modify, sublicense, or distribute the Program except as ++ expressly provided under this License. Any attempt otherwise to copy, ++ modify, sublicense or distribute the Program is void, and will ++ automatically terminate your rights under this License. However, parties ++ who have received copies, or rights, from you under this License will not ++ have their licenses terminated so long as such parties remain in full ++ compliance. ++ ++5. You are not required to accept this License, since you have not signed ++ it. However, nothing else grants you permission to modify or distribute ++ the Program or its derivative works. These actions are prohibited by law ++ if you do not accept this License. Therefore, by modifying or ++ distributing the Program (or any work based on the Program), you ++ indicate your acceptance of this License to do so, and all its terms and ++ conditions for copying, distributing or modifying the Program or works ++ based on it. ++ ++6. Each time you redistribute the Program (or any work based on the ++ Program), the recipient automatically receives a license from the ++ original licensor to copy, distribute or modify the Program subject to ++ these terms and conditions. You may not impose any further restrictions ++ on the recipients' exercise of the rights granted herein. You are not ++ responsible for enforcing compliance by third parties to this License. ++ ++7. If, as a consequence of a court judgment or allegation of patent ++ infringement or for any other reason (not limited to patent issues), ++ conditions are imposed on you (whether by court order, agreement or ++ otherwise) that contradict the conditions of this License, they do not ++ excuse you from the conditions of this License. If you cannot distribute ++ so as to satisfy simultaneously your obligations under this License and ++ any other pertinent obligations, then as a consequence you may not ++ distribute the Program at all. For example, if a patent license would ++ not permit royalty-free redistribution of the Program by all those who ++ receive copies directly or indirectly through you, then the only way you ++ could satisfy both it and this License would be to refrain entirely from ++ distribution of the Program. ++ ++ If any portion of this section is held invalid or unenforceable under any ++ particular circumstance, the balance of the section is intended to apply ++ and the section as a whole is intended to apply in other circumstances. ++ ++ It is not the purpose of this section to induce you to infringe any ++ patents or other property right claims or to contest validity of any ++ such claims; this section has the sole purpose of protecting the ++ integrity of the free software distribution system, which is implemented ++ by public license practices. Many people have made generous contributions ++ to the wide range of software distributed through that system in ++ reliance on consistent application of that system; it is up to the ++ author/donor to decide if he or she is willing to distribute software ++ through any other system and a licensee cannot impose that choice. ++ ++ This section is intended to make thoroughly clear what is believed to be ++ a consequence of the rest of this License. ++ ++8. If the distribution and/or use of the Program is restricted in certain ++ countries either by patents or by copyrighted interfaces, the original ++ copyright holder who places the Program under this License may add an ++ explicit geographical distribution limitation excluding those countries, ++ so that distribution is permitted only in or among countries not thus ++ excluded. In such case, this License incorporates the limitation as if ++ written in the body of this License. ++ ++9. The Free Software Foundation may publish revised and/or new versions of ++ the General Public License from time to time. Such new versions will be ++ similar in spirit to the present version, but may differ in detail to ++ address new problems or concerns. ++ ++ Each version is given a distinguishing version number. If the Program ++ specifies a version number of this License which applies to it and "any ++ later version", you have the option of following the terms and ++ conditions either of that version or of any later version published by ++ the Free Software Foundation. If the Program does not specify a version ++ number of this License, you may choose any version ever published by the ++ Free Software Foundation. ++ ++10. If you wish to incorporate parts of the Program into other free programs ++ whose distribution conditions are different, write to the author to ask ++ for permission. For software which is copyrighted by the Free Software ++ Foundation, write to the Free Software Foundation; we sometimes make ++ exceptions for this. Our decision will be guided by the two goals of ++ preserving the free status of all derivatives of our free software and ++ of promoting the sharing and reuse of software generally. ++ ++ NO WARRANTY ++ ++11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY ++ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN ++ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES ++ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER ++ EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ++ ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH ++ YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL ++ NECESSARY SERVICING, REPAIR OR CORRECTION. ++ ++12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING ++ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR ++ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR ++ DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL ++ DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM ++ (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED ++ INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF ++ THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR ++ OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. ++ ++END OF TERMS AND CONDITIONS ++ ++How to Apply These Terms to Your New Programs ++ ++If you develop a new program, and you want it to be of the greatest ++possible use to the public, the best way to achieve this is to make it free ++software which everyone can redistribute and change under these terms. ++ ++To do so, attach the following notices to the program. It is safest to ++attach them to the start of each source file to most effectively convey the ++exclusion of warranty; and each file should have at least the "copyright" ++line and a pointer to where the full notice is found. ++ ++one line to give the program's name and an idea of what it does. ++Copyright (C) yyyy name of author ++ ++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. ++ ++Also add information on how to contact you by electronic and paper mail. ++ ++If the program is interactive, make it output a short notice like this when ++it starts in an interactive mode: ++ ++Gnomovision version 69, Copyright (C) year name of author Gnomovision comes ++with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free ++software, and you are welcome to redistribute it under certain conditions; ++type 'show c' for details. ++ ++The hypothetical commands 'show w' and 'show c' should show the appropriate ++parts of the General Public License. Of course, the commands you use may be ++called something other than 'show w' and 'show c'; they could even be ++mouse-clicks or menu items--whatever suits your program. ++ ++You should also get your employer (if you work as a programmer) or your ++school, if any, to sign a "copyright disclaimer" for the program, if ++necessary. Here is a sample; alter the names: ++ ++Yoyodyne, Inc., hereby disclaims all copyright interest in the program ++'Gnomovision' (which makes passes at compilers) written by James Hacker. ++ ++signature of Ty Coon, 1 April 1989 ++Ty Coon, President of Vice ++ ++This General Public License does not permit incorporating your program into ++proprietary programs. If your program is a subroutine library, you may ++consider it more useful to permit linking proprietary applications with the ++library. If this is what you want to do, use the GNU Library General Public ++License instead of this License. +diff -Nurp linux-2.6.37/3rdparty/rfswitch/Makefile linux-2.6.37.3rdparty/3rdparty/rfswitch/Makefile +--- linux-2.6.37/3rdparty/rfswitch/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/rfswitch/Makefile 2008-03-28 05:17:16.000000000 +0200 +@@ -0,0 +1,119 @@ ++# ++# Makefile for the SW RF Switch kernel modules ++# ++# NOTE: This make file can serve as both an external Makefile (launched ++# directly by the user), or as the sub-dir Makefile used by the kernel ++# build system. ++ ++ ++CONFIG_AVERATEC_5100P=m ++CONFIG_PACKARDBELL_E5=m ++ ++ ++ ++list-m := ++list-$(CONFIG_AVERATEC_5100P) += av5100 ++list-$(CONFIG_PACKARDBELL_E5) += pbe5 ++ ++ ++obj-$(CONFIG_AVERATEC_5100P) += av5100.o ++obj-$(CONFIG_PACKARDBELL_E5) += pbe5.o ++ ++# ++# Begin dual Makefile mode here. First we provide support for when we ++# are being invoked by the kernel build system ++# ++ifneq ($(KERNELRELEASE),) ++ ++ifneq ($(PATCHLEVEL),6) # If we are not on a 2.6, then do 2.4 specific things ++ ++O_TARGET := rfswitch.o ++ ++include $(TOPDIR)/Rules.make ++ ++endif # End if 2.4 specific settings ++ ++else ++# Here we begin the portion that is executed if the user invoked this Makefile ++# directly. ++ ++# KSRC should be set to the path to your sources ++# modules are installed into KMISC ++KVER := $(shell uname -r) ++KSRC := /lib/modules/$(KVER)/build ++KMISC := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ ++ ++# KSRC_OUTPUT should be overridden if you are using a 2.6 kernel that ++# has it's output sent elsewhere via KBUILD_OUTPUT= or O= ++KSRC_OUTPUT := $(KSRC) ++ ++# If we find Rules.make, we can assume we're using the old 2.4 style building ++OLDMAKE=$(wildcard $(KSRC)/Rules.make) ++PWD=$(shell pwd) ++ ++VERFILE := $(KSRC_OUTPUT)/include/linux/version.h ++KERNELRELEASE := $(shell \ ++ if [ -r $(VERFILE) ]; then \ ++ (cat $(VERFILE); echo UTS_RELEASE) | \ ++ $(CC) -I$(KSRC_OUTPUT) $(CFLAGS) -E - | \ ++ tail -n 1 | \ ++ xargs echo; \ ++ else \ ++ uname -r; \ ++ fi) ++ ++MODPATH := $(DESTDIR)/lib/modules/$(KERNELRELEASE) ++ ++all: modules ++ ++clean: ++ rm -f *.mod.c *.mod *.o *.ko .*.cmd .*.flags Modules.symvers ++ rm -rf $(PWD)/tmp ++ ++ ++ifeq ($(OLDMAKE),) ++ ++TMP=$(PWD)/tmp ++MODVERDIR=$(TMP)/.tmp_versions ++ ++modules: ++ifdef ($(KSRC_OUTPUT)/.tmp_versions) ++ mkdir -p $(MODVERDIR) ++ -cp $(KSRC_OUTPUT)/.tmp_versions/*.mod $(MODVERDIR) ++endif ++ifeq ($(KSRC),$(KSRC_OUTPUT)) # We're not outputting elsewhere ++ifdef ($(KSRC)/.tmp_versions) ++ -cp $(KSRC)/.tmp_versions/*.mod $(MODVERDIR) ++endif ++ $(MAKE) -C $(KSRC) SUBDIRS=$(PWD) MODVERDIR=$(MODVERDIR) modules ++else # We've got a kernel with seperate output, copy the config, and use O= ++ mkdir -p $(TMP) ++ cp $(KSRC_OUTPUT)/.config $(TMP) ++ $(MAKE) -C $(KSRC) SUBDIRS=$(PWD) MODVERDIR=$(MODVERDIR) O=$(PWD)/tmp modules ++endif ++ ++install: modules ++ install -d $(KMISC) ++ install -m 644 -c $(addsuffix .ko,$(list-m)) $(KMISC) ++ /sbin/depmod -a ++ ++ ++else # We're on 2.4, and things are slightly different ++ ++modules: ++ $(MAKE) -C $(KSRC) SUBDIRS=$(PWD) BUILD_DIR=$(PWD) modules ++ ++install: modules ++ install -d $(KMISC) ++ install -m 644 -c $(addsuffix .o,$(list-m)) $(KMISC) ++ /sbin/depmod -a ++ ++endif ++ ++uninstall: ++ cd $(KMISC) ++ rm -rf $(addsuffix .ko,$(list-m)) ++ cd - ++ /sbin/depmod -a ++ ++endif +diff -Nurp linux-2.6.37/3rdparty/rfswitch/pbe5.c linux-2.6.37.3rdparty/3rdparty/rfswitch/pbe5.c +--- linux-2.6.37/3rdparty/rfswitch/pbe5.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/rfswitch/pbe5.c 2008-03-28 05:25:16.000000000 +0200 +@@ -0,0 +1,205 @@ ++/******************************************************************************* ++ ++ 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. ++ ++ Author: ++ Pedro Ramalhais ++ ++ Based on: ++ av5100.c from http://ipw2100.sourceforge.net/ ++ ++*******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRV_NAME "pbe5" ++#define DRV_VERSION "1.3" ++#define DRV_DESCRIPTION "SW RF kill switch for Packard Bell EasyNote E5" ++#define DRV_AUTHOR "Pedro Ramalhais" ++#define DRV_LICENSE "GPL" ++ ++static int radio = 1; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ ++MODULE_PARM(radio, "i"); ++ ++#else /* LINUX_VERSION_CODE < 2.6.0 */ ++ ++#include ++module_param(radio, int, 1); ++ ++#endif /* LINUX_VERSION_CODE < 2.6.0 */ ++ ++MODULE_PARM_DESC(radio, "controls state of radio (1=on, 0=off)"); ++ ++MODULE_DESCRIPTION(DRV_DESCRIPTION); ++MODULE_AUTHOR(DRV_AUTHOR); ++MODULE_LICENSE(DRV_LICENSE); ++ ++/* ++ * NOTE: These values were obtained from disassembling the Icon.exe program ++ * installed in the Packard Bell EasyNote E5 laptop. The names were guessed, ++ * so don't rely on them. ++ */ ++#define PBE5_PORT_TOGGLE 0x0b3 ++#define PBE5_VALUE_TOGGLE_ON 0x01 ++#define PBE5_VALUE_TOGGLE_OFF 0x00 ++#define PBE5_PORT_APPLY 0x0b2 ++#define PBE5_VALUE_APPLY 0xef ++ ++// Some "booleans" =;-) ++#define PBE5_RADIO_OFF 0 ++#define PBE5_RADIO_ON 1 ++ ++static int pbe5_radio_status = PBE5_RADIO_ON; ++ ++unsigned char pbe5_get_radio(void) ++{ ++ unsigned char val = 0x00; ++ ++ val = inb(PBE5_PORT_TOGGLE); ++ ++ return val; ++} ++ ++static void pbe5_set_radio(int state_set) ++{ ++ pbe5_radio_status = pbe5_get_radio(); ++ ++ if (pbe5_radio_status != state_set) { ++ // Set the radio toggle register ++ outb(PBE5_VALUE_TOGGLE_ON, PBE5_PORT_TOGGLE); ++ // Commit the radio toggle register value ++ outb(PBE5_VALUE_APPLY, PBE5_PORT_APPLY); ++ // Update the radio status ++ pbe5_radio_status = pbe5_get_radio(); ++ ++ printk(KERN_INFO DRV_NAME ": Radio turned %s\n", ++ (state_set == PBE5_RADIO_ON) ? "ON" : "OFF"); ++ } else { ++ printk(KERN_INFO DRV_NAME ": Radio already %s\n", ++ (state_set == PBE5_RADIO_ON) ? "ON" : "OFF"); ++ } ++} ++ ++ ++/* ++ * proc stuff ++ */ ++static struct proc_dir_entry *dir_base = NULL; ++ ++static int proc_set_radio(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ pbe5_set_radio(buffer[0] == '0' ? PBE5_RADIO_OFF : PBE5_RADIO_ON); ++ ++ return count; ++} ++ ++static int proc_get_radio(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ ++ len += snprintf(page, count, DRV_NAME ": %d\n", ++ pbe5_radio_status == PBE5_RADIO_OFF ? 0 : 1); ++ ++ *eof = 1; ++ return len; ++} ++ ++ ++static void pbe5_proc_cleanup(void) ++{ ++ if (dir_base) { ++ remove_proc_entry("radio", dir_base); ++ remove_proc_entry(DRV_NAME, &proc_root); ++ dir_base = NULL; ++ } ++} ++ ++ ++static int pbe5_proc_init(void) ++{ ++ struct proc_dir_entry *ent; ++ int err = 0; ++ ++ dir_base = create_proc_entry(DRV_NAME, S_IFDIR, &proc_root); ++ if (dir_base == NULL) { ++ printk(KERN_ERR DRV_NAME ": Unable to initialise /proc/" ++ DRV_NAME "\n"); ++ err = -ENOMEM; ++ goto fail; ++ } ++ ++ ++ ent = create_proc_entry("radio", S_IFREG | S_IRUGO | S_IWUSR, ++ dir_base); ++ if (ent) { ++ ent->read_proc = proc_get_radio; ++ ent->write_proc = proc_set_radio; ++ } else { ++ printk(KERN_ERR ++ "Unable to initialize /proc/" DRV_NAME "/radio\n"); ++ err = -ENOMEM; ++ goto fail; ++ } ++ ++ return 0; ++ ++ fail: ++ pbe5_proc_cleanup(); ++ return err; ++} ++ ++/* ++ * module stuff ++ */ ++static int __init pbe5_init(void) ++{ ++ pbe5_proc_init(); ++ ++ pbe5_set_radio((radio == 1) ? PBE5_RADIO_ON : PBE5_RADIO_OFF); ++ ++ return 0; ++} ++ ++static void __exit pbe5_exit(void) ++{ ++ pbe5_set_radio(PBE5_RADIO_OFF); ++ ++ pbe5_proc_cleanup(); ++} ++ ++module_init(pbe5_init); ++module_exit(pbe5_exit); ++ ++/* ++ 1 2 3 4 5 6 7 ++12345678901234567890123456789012345678901234567890123456789012345678901234567890 ++*/ +diff -Nurp linux-2.6.37/3rdparty/rfswitch/README linux-2.6.37.3rdparty/3rdparty/rfswitch/README +--- linux-2.6.37/3rdparty/rfswitch/README 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/rfswitch/README 2004-07-09 17:26:20.000000000 +0300 +@@ -0,0 +1,44 @@ ++Radio Kill Switch ++------------ ----- ----- ---- --- -- - ++Most laptops provide the ability for the user to physically disable the radio. ++Some vendors have implemented this as a physical switch that requires no ++software to turn the radio off and on. On other laptops, however, the switch ++is controlled through a button being pressed and a software driver then making ++calls to turn the radio off and on. This is referred to as a "software based ++RF kill switch" ++ ++Currently this project provides modules for controlling the software RF kill ++switch on the Averatec 5100P and Packard Bell EasyNote E5. The code may work ++on other laptops, but these are the only models on which it has been tested. ++ ++To determine if you have a system that might be compatible with one of the ++provided SW RF Kill switch modules, you can run: ++ ++ ++ To check for the Packard Bell (to use module pbe) -- ++ ++ % dd if=/dev/mem bs=1 skip=983040 count=65535 2>/dev/null | strings | egrep "NEW-PC|Insyde Software MobilePRO BIOS" ++ ++ To check for the Averatec (to use module av5100) -- ++ ++ % dd if=/dev/mem bs=1 skip=983040 count=65535 2>/dev/null | strings | egrep "AVERATEC" ++ ++If you have one of those laptop models you can imply loading the av5100/pbe5 ++module and the radio will be toggled on and off. In addition, you can turn ++the driver on and off by writing either a 1 or 0 to /proc/av5100/radio or ++/proc/pbe5/radio. If you automatically load the av5100/pbe5 module when your ++system boots, you may wish to use the radio module parameter to control the ++state of the radio upon loading: ++ ++ modprobe av5100 radio=0 ++ modprobe pbe5 radio=0 ++ ++results in the module loading with the radio turned off. You can then turn the ++radio on by: ++ ++ echo 1 > /proc/av5100/radio ++ echo 1 > /proc/pbe5/radio ++ ++If you have a SW RF kill switch and can not use one of the above modules, ++please join us on IRC (irc.freenode.net) on channel #ipw2100 and someone may ++be able to help. diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rfswitch-3.0-buildfix.patch b/kernel/tools/perf/files/patches/mageia/3rd-rfswitch-3.0-buildfix.patch new file mode 100644 index 0000000000..7bfc2c64c1 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-rfswitch-3.0-buildfix.patch @@ -0,0 +1,19 @@ + +fix build with 3.0 + +Signed-off-by: Thomas Backlund + + 3rdparty/rfswitch/Makefile | 2 -- + 1 file changed, 2 deletions(-) + +--- a/3rdparty/rfswitch/Makefile.orig 2011-07-15 02:37:27.000000000 +0300 ++++ a/3rdparty/rfswitch/Makefile 2011-07-15 13:47:10.463914526 +0300 +@@ -29,8 +29,6 @@ ifneq ($(PATCHLEVEL),6) # If we are not + + O_TARGET := rfswitch.o + +-include $(TOPDIR)/Rules.make +- + endif # End if 2.4 specific settings + + else diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rfswitch-build-fix.patch b/kernel/tools/perf/files/patches/mageia/3rd-rfswitch-build-fix.patch new file mode 100644 index 0000000000..ab1c279ca3 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-rfswitch-build-fix.patch @@ -0,0 +1,51 @@ +Remove 'proc_root' usage + +Commit c74c120a21d87b0b6925ada5830d8cac21e852d9 (Linus's tree) removed +the export of 'proc_root' variable, because you can create on the proc's +root directory by passing NULL where you would pass 'proc_root'. + +Signed-off-by: Luiz Fernando N. Capitulino +Index: linux-2.6.25/3rdparty/rfswitch/av5100.c +=================================================================== +--- linux-2.6.25.orig/3rdparty/rfswitch/av5100.c ++++ linux-2.6.25/3rdparty/rfswitch/av5100.c +@@ -107,7 +107,7 @@ static void av5100_proc_cleanup(void) + { + if (dir_base) { + remove_proc_entry("radio", dir_base); +- remove_proc_entry(DRV_NAME, &proc_root); ++ remove_proc_entry(DRV_NAME, NULL); + dir_base = NULL; + } + } +@@ -118,7 +118,7 @@ static int av5100_proc_init(void) + struct proc_dir_entry *ent; + int err = 0; + +- dir_base = create_proc_entry(DRV_NAME, S_IFDIR, &proc_root); ++ dir_base = create_proc_entry(DRV_NAME, S_IFDIR, NULL); + if (dir_base == NULL) { + printk(KERN_ERR DRV_NAME ": Unable to initialise /proc/" + DRV_NAME "\n"); +Index: linux-2.6.25/3rdparty/rfswitch/pbe5.c +=================================================================== +--- linux-2.6.25.orig/3rdparty/rfswitch/pbe5.c ++++ linux-2.6.25/3rdparty/rfswitch/pbe5.c +@@ -138,7 +138,7 @@ static void pbe5_proc_cleanup(void) + { + if (dir_base) { + remove_proc_entry("radio", dir_base); +- remove_proc_entry(DRV_NAME, &proc_root); ++ remove_proc_entry(DRV_NAME, NULL); + dir_base = NULL; + } + } +@@ -149,7 +149,7 @@ static int pbe5_proc_init(void) + struct proc_dir_entry *ent; + int err = 0; + +- dir_base = create_proc_entry(DRV_NAME, S_IFDIR, &proc_root); ++ dir_base = create_proc_entry(DRV_NAME, S_IFDIR, NULL); + if (dir_base == NULL) { + printk(KERN_ERR DRV_NAME ": Unable to initialise /proc/" + DRV_NAME "\n"); diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8723bs-4.7-buildfix.patch b/kernel/tools/perf/files/patches/mageia/3rd-rtl8723bs-4.7-buildfix.patch new file mode 100644 index 0000000000..cbab5aae89 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-rtl8723bs-4.7-buildfix.patch @@ -0,0 +1,178 @@ + +Fix building with kernel-4.7 series. + +Signed-off-by: Thomas Backlund + + 3rdparty/rtl8723bs/os_dep/ioctl_cfg80211.c | 32 ++++++++++++++--------------- + 3rdparty/rtl8723bs/os_dep/wifi_regd.c | 6 ++--- + 2 files changed, 19 insertions(+), 19 deletions(-) + +diff -urp linux/3rdparty/rtl8723bs.orig/os_dep/ioctl_cfg80211.c linux/3rdparty/rtl8723bs/os_dep/ioctl_cfg80211.c +--- linux/3rdparty/rtl8723bs.orig/os_dep/ioctl_cfg80211.c 2016-07-04 20:00:13.000000000 +0300 ++++ linux/3rdparty/rtl8723bs/os_dep/ioctl_cfg80211.c 2016-07-04 20:37:45.054379270 +0300 +@@ -44,7 +44,7 @@ static const u32 rtw_cipher_suites[] = { + } + + #define CHAN2G(_channel, _freq, _flags) { \ +- .band = IEEE80211_BAND_2GHZ, \ ++ .band = NL80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_channel), \ + .flags = (_flags), \ +@@ -120,13 +120,13 @@ static void rtw_2g_rates_init(struct iee + } + + static struct ieee80211_supported_band *rtw_spt_band_alloc( +- enum ieee80211_band band ++ enum nl80211_band band + ) + { + struct ieee80211_supported_band *spt_band = NULL; + int n_channels, n_bitrates; + +- if (band == IEEE80211_BAND_2GHZ) ++ if (band == NL80211_BAND_2GHZ) + { + n_channels = RTW_2G_CHANNELS_NUM; + n_bitrates = RTW_G_RATES_NUM; +@@ -150,7 +150,7 @@ static struct ieee80211_supported_band * + spt_band->n_channels = n_channels; + spt_band->n_bitrates = n_bitrates; + +- if (band == IEEE80211_BAND_2GHZ) ++ if (band == NL80211_BAND_2GHZ) + { + rtw_2g_channels_init(spt_band->channels); + rtw_2g_rates_init(spt_band->bitrates); +@@ -170,7 +170,7 @@ static void rtw_spt_band_free(struct iee + if (!spt_band) + return; + +- if (spt_band->band == IEEE80211_BAND_2GHZ) ++ if (spt_band->band == NL80211_BAND_2GHZ) + { + size = sizeof(struct ieee80211_supported_band) + + sizeof(struct ieee80211_channel)*RTW_2G_CHANNELS_NUM +@@ -232,7 +232,7 @@ static int rtw_ieee80211_channel_to_freq + { + /* see 802.11 17.3.8.3.2 and Annex J + * there are overlapping channel numbers in 5GHz and 2GHz bands */ +- if (band == IEEE80211_BAND_2GHZ) { ++ if (band == NL80211_BAND_2GHZ) { + if (chan == 14) + return 2484; + else if (chan < 14) +@@ -336,7 +336,7 @@ struct cfg80211_bss *rtw_cfg80211_inform + + + channel = pnetwork->network.Configuration.DSConfig; +- freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); ++ freq = rtw_ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ); + + notify_channel = ieee80211_get_channel(wiphy, freq); + +@@ -420,7 +420,7 @@ int rtw_cfg80211_check_bss(struct adapte + if (!(pnetwork) || !(padapter->rtw_wdev)) + return false; + +- freq = rtw_ieee80211_channel_to_frequency(pnetwork->Configuration.DSConfig, IEEE80211_BAND_2GHZ); ++ freq = rtw_ieee80211_channel_to_frequency(pnetwork->Configuration.DSConfig, NL80211_BAND_2GHZ); + + notify_channel = ieee80211_get_channel(padapter->rtw_wdev->wiphy, freq); + bss = cfg80211_get_bss(padapter->rtw_wdev->wiphy, notify_channel, +@@ -542,7 +542,7 @@ check_bss: + u32 freq; + u16 channel = cur_network->network.Configuration.DSConfig; + +- freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); ++ freq = rtw_ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ); + + notify_channel = ieee80211_get_channel(wiphy, freq); + +@@ -3064,7 +3064,7 @@ void rtw_cfg80211_rx_action(struct adapt + else + DBG_871X("RTW_Rx:category(%u), action(%u)\n", category, action); + +- freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); ++ freq = rtw_ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ); + + rtw_cfg80211_rx_mgmt(adapter, freq, 0, frame, frame_len, GFP_ATOMIC); + } +@@ -3311,7 +3311,7 @@ static int cfg80211_rtw_sched_scan_stop( + } + #endif /* CONFIG_PNO_SUPPORT */ + +-static void rtw_cfg80211_init_ht_capab(struct ieee80211_sta_ht_cap *ht_cap, enum ieee80211_band band, u8 rf_type) ++static void rtw_cfg80211_init_ht_capab(struct ieee80211_sta_ht_cap *ht_cap, enum nl80211_band band, u8 rf_type) + { + + #define MAX_BIT_RATE_40MHZ_MCS15 300 /* Mbps */ +@@ -3335,7 +3335,7 @@ static void rtw_cfg80211_init_ht_capab(s + ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + + /* +- *hw->wiphy->bands[IEEE80211_BAND_2GHZ] ++ *hw->wiphy->bands[NL80211_BAND_2GHZ] + *base on ant_num + *rx_mask: RX mask + *if rx_ant = 1 rx_mask[0]= 0xff;==>MCS0-MCS7 +@@ -3379,9 +3379,9 @@ void rtw_cfg80211_init_wiphy(struct adap + DBG_8192C("%s:rf_type =%d\n", __func__, rf_type); + + { +- bands = wiphy->bands[IEEE80211_BAND_2GHZ]; ++ bands = wiphy->bands[NL80211_BAND_2GHZ]; + if (bands) +- rtw_cfg80211_init_ht_capab(&bands->ht_cap, IEEE80211_BAND_2GHZ, rf_type); ++ rtw_cfg80211_init_ht_capab(&bands->ht_cap, NL80211_BAND_2GHZ, rf_type); + } + + /* init regulary domain */ +@@ -3417,7 +3417,7 @@ static void rtw_cfg80211_preinit_wiphy(s + wiphy->n_cipher_suites = ARRAY_SIZE(rtw_cipher_suites); + + /* if (padapter->registrypriv.wireless_mode & WIRELESS_11G) */ +- wiphy->bands[IEEE80211_BAND_2GHZ] = rtw_spt_band_alloc(IEEE80211_BAND_2GHZ); ++ wiphy->bands[NL80211_BAND_2GHZ] = rtw_spt_band_alloc(NL80211_BAND_2GHZ); + + wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + wiphy->flags |= WIPHY_FLAG_OFFCHAN_TX | WIPHY_FLAG_HAVE_AP_SME; +@@ -3564,7 +3564,7 @@ void rtw_wdev_free(struct wireless_dev * + if (!wdev) + return; + +- rtw_spt_band_free(wdev->wiphy->bands[IEEE80211_BAND_2GHZ]); ++ rtw_spt_band_free(wdev->wiphy->bands[NL80211_BAND_2GHZ]); + + wiphy_free(wdev->wiphy); + +diff -urp linux/3rdparty/rtl8723bs.orig/os_dep/wifi_regd.c linux/3rdparty/rtl8723bs/os_dep/wifi_regd.c +--- linux/3rdparty/rtl8723bs.orig/os_dep/wifi_regd.c 2016-07-04 20:00:13.000000000 +0300 ++++ linux/3rdparty/rtl8723bs/os_dep/wifi_regd.c 2016-07-04 20:35:31.427278665 +0300 +@@ -105,7 +105,7 @@ static int rtw_ieee80211_channel_to_freq + /* see 802.11 17.3.8.3.2 and Annex J + * there are overlapping channel numbers in 5GHz and 2GHz bands */ + +- /* IEEE80211_BAND_2GHZ */ ++ /* NL80211_BAND_2GHZ */ + if (chan == 14) + return 2484; + else if (chan < 14) +@@ -128,7 +128,7 @@ static void _rtw_reg_apply_flags(struct + u32 freq; + + /* all channels disable */ +- for (i = 0; i < IEEE80211_NUM_BANDS; i++) { ++ for (i = 0; i < NUM_NL80211_BANDS; i++) { + sband = wiphy->bands[i]; + + if (sband) { +@@ -146,7 +146,7 @@ static void _rtw_reg_apply_flags(struct + channel = channel_set[i].ChannelNum; + freq = + rtw_ieee80211_channel_to_frequency(channel, +- IEEE80211_BAND_2GHZ); ++ NL80211_BAND_2GHZ); + + ch = ieee80211_get_channel(wiphy, freq); + if (ch) { diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8723bs.patch b/kernel/tools/perf/files/patches/mageia/3rd-rtl8723bs.patch new file mode 100644 index 0000000000..5e355dd01c --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-rtl8723bs.patch @@ -0,0 +1,112390 @@ + +From https://github.com/hadess/rtl8723bs + +Tpomost commit: + +commit 9750337e13af3e3870fabd5c3dd9d170bd0953e4 +Author: Larry Finger +Date: Mon Nov 9 12:00:56 2015 -0600 + + rtl8723bs: Remove extraneous variable + + Signed-off-by: Larry Finger + + +Signed-off-by: Thomas Backlund + + 3rdparty/rtl8723bs/Kconfig | 11 + 3rdparty/rtl8723bs/Makefile | 250 + 3rdparty/rtl8723bs/core/rtw_ap.c | 2479 +++++++ + 3rdparty/rtl8723bs/core/rtw_btcoex.c | 253 + 3rdparty/rtl8723bs/core/rtw_cmd.c | 2322 ++++++ + 3rdparty/rtl8723bs/core/rtw_debug.c | 1477 ++++ + 3rdparty/rtl8723bs/core/rtw_eeprom.c | 375 + + 3rdparty/rtl8723bs/core/rtw_efuse.c | 654 + + 3rdparty/rtl8723bs/core/rtw_ieee80211.c | 1488 ++++ + 3rdparty/rtl8723bs/core/rtw_io.c | 203 + 3rdparty/rtl8723bs/core/rtw_ioctl_set.c | 736 ++ + 3rdparty/rtl8723bs/core/rtw_mlme.c | 3331 +++++++++ + 3rdparty/rtl8723bs/core/rtw_mlme_ext.c | 7376 ++++++++++++++++++++++ + 3rdparty/rtl8723bs/core/rtw_odm.c | 195 + 3rdparty/rtl8723bs/core/rtw_pwrctrl.c | 1521 ++++ + 3rdparty/rtl8723bs/core/rtw_recv.c | 2931 ++++++++ + 3rdparty/rtl8723bs/core/rtw_rf.c | 66 + 3rdparty/rtl8723bs/core/rtw_security.c | 2486 +++++++ + 3rdparty/rtl8723bs/core/rtw_sta_mgt.c | 646 + + 3rdparty/rtl8723bs/core/rtw_wlan_util.c | 2542 +++++++ + 3rdparty/rtl8723bs/core/rtw_xmit.c | 3263 +++++++++ + 3rdparty/rtl8723bs/hal/Hal8723BPwrSeq.c | 115 + 3rdparty/rtl8723bs/hal/Hal8723BReg.h | 442 + + 3rdparty/rtl8723bs/hal/HalBtc8723b1Ant.c | 3547 ++++++++++ + 3rdparty/rtl8723bs/hal/HalBtc8723b1Ant.h | 243 + 3rdparty/rtl8723bs/hal/HalBtc8723b2Ant.c | 4077 ++++++++++++ + 3rdparty/rtl8723bs/hal/HalBtc8723b2Ant.h | 205 + 3rdparty/rtl8723bs/hal/HalBtcOutSrc.h | 706 ++ + 3rdparty/rtl8723bs/hal/HalHWImg8723B_BB.c | 612 + + 3rdparty/rtl8723bs/hal/HalHWImg8723B_BB.h | 48 + 3rdparty/rtl8723bs/hal/HalHWImg8723B_MAC.c | 275 + 3rdparty/rtl8723bs/hal/HalHWImg8723B_MAC.h | 28 + 3rdparty/rtl8723bs/hal/HalHWImg8723B_RF.c | 638 + + 3rdparty/rtl8723bs/hal/HalHWImg8723B_RF.h | 49 + 3rdparty/rtl8723bs/hal/HalPhyRf.c | 394 + + 3rdparty/rtl8723bs/hal/HalPhyRf.h | 75 + 3rdparty/rtl8723bs/hal/HalPhyRf_8723B.c | 2171 ++++++ + 3rdparty/rtl8723bs/hal/HalPhyRf_8723B.h | 100 + 3rdparty/rtl8723bs/hal/HalPwrSeqCmd.c | 166 + 3rdparty/rtl8723bs/hal/Mp_Precomp.h | 33 + 3rdparty/rtl8723bs/hal/hal_btcoex.c | 1754 +++++ + 3rdparty/rtl8723bs/hal/hal_com.c | 1464 ++++ + 3rdparty/rtl8723bs/hal/hal_com_phycfg.c | 3582 ++++++++++ + 3rdparty/rtl8723bs/hal/hal_intf.c | 478 + + 3rdparty/rtl8723bs/hal/hal_phy.c | 272 + 3rdparty/rtl8723bs/hal/hal_sdio.c | 106 + 3rdparty/rtl8723bs/hal/odm.c | 1630 ++++ + 3rdparty/rtl8723bs/hal/odm.h | 1558 ++++ + 3rdparty/rtl8723bs/hal/odm_AntDiv.c | 74 + 3rdparty/rtl8723bs/hal/odm_AntDiv.h | 38 + 3rdparty/rtl8723bs/hal/odm_CfoTracking.c | 275 + 3rdparty/rtl8723bs/hal/odm_CfoTracking.h | 48 + 3rdparty/rtl8723bs/hal/odm_DIG.c | 1104 +++ + 3rdparty/rtl8723bs/hal/odm_DIG.h | 263 + 3rdparty/rtl8723bs/hal/odm_DynamicBBPowerSaving.c | 107 + 3rdparty/rtl8723bs/hal/odm_DynamicBBPowerSaving.h | 46 + 3rdparty/rtl8723bs/hal/odm_DynamicTxPower.c | 32 + 3rdparty/rtl8723bs/hal/odm_DynamicTxPower.h | 40 + 3rdparty/rtl8723bs/hal/odm_EdcaTurboCheck.c | 187 + 3rdparty/rtl8723bs/hal/odm_EdcaTurboCheck.h | 41 + 3rdparty/rtl8723bs/hal/odm_HWConfig.c | 608 + + 3rdparty/rtl8723bs/hal/odm_HWConfig.h | 179 + 3rdparty/rtl8723bs/hal/odm_NoiseMonitor.c | 172 + 3rdparty/rtl8723bs/hal/odm_NoiseMonitor.h | 44 + 3rdparty/rtl8723bs/hal/odm_PathDiv.c | 34 + 3rdparty/rtl8723bs/hal/odm_PathDiv.h | 29 + 3rdparty/rtl8723bs/hal/odm_RTL8723B.c | 49 + 3rdparty/rtl8723bs/hal/odm_RTL8723B.h | 22 + 3rdparty/rtl8723bs/hal/odm_RegConfig8723B.c | 189 + 3rdparty/rtl8723bs/hal/odm_RegConfig8723B.h | 80 + 3rdparty/rtl8723bs/hal/odm_RegDefine11N.h | 172 + 3rdparty/rtl8723bs/hal/odm_debug.c | 52 + 3rdparty/rtl8723bs/hal/odm_debug.h | 154 + 3rdparty/rtl8723bs/hal/odm_interface.h | 60 + 3rdparty/rtl8723bs/hal/odm_precomp.h | 60 + 3rdparty/rtl8723bs/hal/odm_reg.h | 103 + 3rdparty/rtl8723bs/hal/odm_types.h | 102 + 3rdparty/rtl8723bs/hal/rtl8723b_cmd.c | 2412 +++++++ + 3rdparty/rtl8723bs/hal/rtl8723b_dm.c | 314 + 3rdparty/rtl8723bs/hal/rtl8723b_hal_init.c | 4844 ++++++++++++++ + 3rdparty/rtl8723bs/hal/rtl8723b_phycfg.c | 1070 +++ + 3rdparty/rtl8723bs/hal/rtl8723b_rf6052.c | 241 + 3rdparty/rtl8723bs/hal/rtl8723b_rxdesc.c | 87 + 3rdparty/rtl8723bs/hal/rtl8723bs_recv.c | 528 + + 3rdparty/rtl8723bs/hal/rtl8723bs_xmit.c | 652 + + 3rdparty/rtl8723bs/hal/sdio_halinit.c | 1959 +++++ + 3rdparty/rtl8723bs/hal/sdio_ops.c | 1262 +++ + 3rdparty/rtl8723bs/include/Hal8192CPhyReg.h | 1126 +++ + 3rdparty/rtl8723bs/include/Hal8723BPhyCfg.h | 128 + 3rdparty/rtl8723bs/include/Hal8723BPhyReg.h | 77 + 3rdparty/rtl8723bs/include/Hal8723BPwrSeq.h | 232 + 3rdparty/rtl8723bs/include/HalPwrSeqCmd.h | 132 + 3rdparty/rtl8723bs/include/HalVerDef.h | 127 + 3rdparty/rtl8723bs/include/autoconf.h | 67 + 3rdparty/rtl8723bs/include/basic_types.h | 209 + 3rdparty/rtl8723bs/include/cmd_osdep.h | 26 + 3rdparty/rtl8723bs/include/drv_conf.h | 37 + 3rdparty/rtl8723bs/include/drv_types.h | 720 ++ + 3rdparty/rtl8723bs/include/drv_types_sdio.h | 39 + 3rdparty/rtl8723bs/include/ethernet.h | 22 + 3rdparty/rtl8723bs/include/hal_btcoex.h | 68 + 3rdparty/rtl8723bs/include/hal_com.h | 309 + 3rdparty/rtl8723bs/include/hal_com_h2c.h | 293 + 3rdparty/rtl8723bs/include/hal_com_phycfg.h | 275 + 3rdparty/rtl8723bs/include/hal_com_reg.h | 1725 +++++ + 3rdparty/rtl8723bs/include/hal_data.h | 485 + + 3rdparty/rtl8723bs/include/hal_intf.h | 410 + + 3rdparty/rtl8723bs/include/hal_pg.h | 81 + 3rdparty/rtl8723bs/include/hal_phy.h | 183 + 3rdparty/rtl8723bs/include/hal_phy_reg.h | 25 + 3rdparty/rtl8723bs/include/hal_sdio.h | 26 + 3rdparty/rtl8723bs/include/ieee80211.h | 1345 ++++ + 3rdparty/rtl8723bs/include/ioctl_cfg80211.h | 132 + 3rdparty/rtl8723bs/include/mlme_osdep.h | 27 + 3rdparty/rtl8723bs/include/osdep_intf.h | 88 + 3rdparty/rtl8723bs/include/osdep_service.h | 281 + 3rdparty/rtl8723bs/include/osdep_service_linux.h | 178 + 3rdparty/rtl8723bs/include/recv_osdep.h | 48 + 3rdparty/rtl8723bs/include/rtl8192c_recv.h | 50 + 3rdparty/rtl8723bs/include/rtl8192c_rf.h | 39 + 3rdparty/rtl8723bs/include/rtl8723b_cmd.h | 199 + 3rdparty/rtl8723bs/include/rtl8723b_dm.h | 41 + 3rdparty/rtl8723bs/include/rtl8723b_hal.h | 279 + 3rdparty/rtl8723bs/include/rtl8723b_recv.h | 144 + 3rdparty/rtl8723bs/include/rtl8723b_rf.h | 26 + 3rdparty/rtl8723bs/include/rtl8723b_spec.h | 262 + 3rdparty/rtl8723bs/include/rtl8723b_xmit.h | 458 + + 3rdparty/rtl8723bs/include/rtw_ap.h | 47 + 3rdparty/rtl8723bs/include/rtw_beamforming.h | 135 + 3rdparty/rtl8723bs/include/rtw_br_ext.h | 63 + 3rdparty/rtl8723bs/include/rtw_btcoex.h | 64 + 3rdparty/rtl8723bs/include/rtw_byteorder.h | 24 + 3rdparty/rtl8723bs/include/rtw_cmd.h | 980 ++ + 3rdparty/rtl8723bs/include/rtw_debug.h | 355 + + 3rdparty/rtl8723bs/include/rtw_eeprom.h | 128 + 3rdparty/rtl8723bs/include/rtw_efuse.h | 132 + 3rdparty/rtl8723bs/include/rtw_event.h | 117 + 3rdparty/rtl8723bs/include/rtw_ht.h | 118 + 3rdparty/rtl8723bs/include/rtw_io.h | 373 + + 3rdparty/rtl8723bs/include/rtw_ioctl.h | 80 + 3rdparty/rtl8723bs/include/rtw_ioctl_set.h | 41 + 3rdparty/rtl8723bs/include/rtw_mlme.h | 695 ++ + 3rdparty/rtl8723bs/include/rtw_mlme_ext.h | 888 ++ + 3rdparty/rtl8723bs/include/rtw_mp.h | 512 + + 3rdparty/rtl8723bs/include/rtw_odm.h | 36 + 3rdparty/rtl8723bs/include/rtw_pwrctrl.h | 375 + + 3rdparty/rtl8723bs/include/rtw_qos.h | 27 + 3rdparty/rtl8723bs/include/rtw_recv.h | 553 + + 3rdparty/rtl8723bs/include/rtw_rf.h | 159 + 3rdparty/rtl8723bs/include/rtw_security.h | 440 + + 3rdparty/rtl8723bs/include/rtw_version.h | 2 + 3rdparty/rtl8723bs/include/rtw_wifi_regd.h | 28 + 3rdparty/rtl8723bs/include/rtw_xmit.h | 528 + + 3rdparty/rtl8723bs/include/sdio_hal.h | 28 + 3rdparty/rtl8723bs/include/sdio_ops.h | 49 + 3rdparty/rtl8723bs/include/sdio_ops_linux.h | 40 + 3rdparty/rtl8723bs/include/sdio_osintf.h | 24 + 3rdparty/rtl8723bs/include/sta_info.h | 392 + + 3rdparty/rtl8723bs/include/wifi.h | 1158 +++ + 3rdparty/rtl8723bs/include/wlan_bssdef.h | 278 + 3rdparty/rtl8723bs/include/xmit_osdep.h | 54 + 3rdparty/rtl8723bs/os_dep/ioctl_cfg80211.c | 3599 ++++++++++ + 3rdparty/rtl8723bs/os_dep/ioctl_linux.c | 5820 +++++++++++++++++ + 3rdparty/rtl8723bs/os_dep/mlme_linux.c | 206 + 3rdparty/rtl8723bs/os_dep/os_intfs.c | 1916 +++++ + 3rdparty/rtl8723bs/os_dep/osdep_service.c | 481 + + 3rdparty/rtl8723bs/os_dep/recv_linux.c | 366 + + 3rdparty/rtl8723bs/os_dep/rtw_proc.c | 786 ++ + 3rdparty/rtl8723bs/os_dep/rtw_proc.h | 45 + 3rdparty/rtl8723bs/os_dep/sdio_intf.c | 725 ++ + 3rdparty/rtl8723bs/os_dep/sdio_ops_linux.c | 599 + + 3rdparty/rtl8723bs/os_dep/wifi_regd.c | 218 + 3rdparty/rtl8723bs/os_dep/xmit_linux.c | 298 + 173 files changed, 111507 insertions(+) + +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_ap.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_ap.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_ap.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_ap.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,2479 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTW_AP_C_ ++ ++#include ++#include ++ ++extern unsigned char RTW_WPA_OUI[]; ++extern unsigned char WMM_OUI[]; ++extern unsigned char WPS_OUI[]; ++extern unsigned char P2P_OUI[]; ++extern unsigned char WFD_OUI[]; ++ ++void init_mlme_ap_info(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ ++ ++ spin_lock_init(&pmlmepriv->bcn_update_lock); ++ ++ /* for ACL */ ++ _rtw_init_queue(&pacl_list->acl_node_q); ++ ++ /* pmlmeext->bstart_bss = false; */ ++ ++ start_ap_mode(padapter); ++} ++ ++void free_mlme_ap_info(struct adapter *padapter) ++{ ++ struct sta_info *psta = NULL; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ /* stop_ap_mode(padapter); */ ++ ++ pmlmepriv->update_bcn = false; ++ pmlmeext->bstart_bss = false; ++ ++ rtw_sta_flush(padapter); ++ ++ pmlmeinfo->state = _HW_STATE_NOLINK_; ++ ++ /* free_assoc_sta_resources */ ++ rtw_free_all_stainfo(padapter); ++ ++ /* free bc/mc sta_info */ ++ psta = rtw_get_bcmc_stainfo(padapter); ++ rtw_free_stainfo(padapter, psta); ++} ++ ++static void update_BCNTIM(struct adapter *padapter) ++{ ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *pnetwork_mlmeext = &(pmlmeinfo->network); ++ unsigned char *pie = pnetwork_mlmeext->IEs; ++ ++ /* DBG_871X("%s\n", __func__); */ ++ ++ /* update TIM IE */ ++ /* if (pstapriv->tim_bitmap) */ ++ if (true) ++ { ++ u8 *p, *dst_ie, *premainder_ie = NULL, *pbackup_remainder_ie = NULL; ++ __le16 tim_bitmap_le; ++ uint offset, tmp_len, tim_ielen, tim_ie_offset, remainder_ielen; ++ ++ tim_bitmap_le = cpu_to_le16(pstapriv->tim_bitmap); ++ ++ p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, _TIM_IE_, &tim_ielen, pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_); ++ if (p != NULL && tim_ielen>0) ++ { ++ tim_ielen += 2; ++ ++ premainder_ie = p+tim_ielen; ++ ++ tim_ie_offset = (sint)(p -pie); ++ ++ remainder_ielen = pnetwork_mlmeext->IELength - tim_ie_offset - tim_ielen; ++ ++ /* append TIM IE from dst_ie offset */ ++ dst_ie = p; ++ } ++ else ++ { ++ tim_ielen = 0; ++ ++ /* calucate head_len */ ++ offset = _FIXED_IE_LENGTH_; ++ ++ /* get ssid_ie len */ ++ p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SSID_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_)); ++ if (p != NULL) ++ offset += tmp_len+2; ++ ++ /* get supported rates len */ ++ p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_)); ++ if (p != NULL) ++ { ++ offset += tmp_len+2; ++ } ++ ++ /* DS Parameter Set IE, len =3 */ ++ offset += 3; ++ ++ premainder_ie = pie + offset; ++ ++ remainder_ielen = pnetwork_mlmeext->IELength - offset - tim_ielen; ++ ++ /* append TIM IE from offset */ ++ dst_ie = pie + offset; ++ ++ } ++ ++ ++ if (remainder_ielen>0) ++ { ++ pbackup_remainder_ie = rtw_malloc(remainder_ielen); ++ if (pbackup_remainder_ie && premainder_ie) ++ memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); ++ } ++ ++ *dst_ie++ = _TIM_IE_; ++ ++ if ((pstapriv->tim_bitmap&0xff00) && (pstapriv->tim_bitmap&0x00fe)) ++ tim_ielen = 5; ++ else ++ tim_ielen = 4; ++ ++ *dst_ie++ = tim_ielen; ++ ++ *dst_ie++ = 0;/* DTIM count */ ++ *dst_ie++ = 1;/* DTIM peroid */ ++ ++ if (pstapriv->tim_bitmap&BIT(0))/* for bc/mc frames */ ++ *dst_ie++ = BIT(0);/* bitmap ctrl */ ++ else ++ *dst_ie++ = 0; ++ ++ if (tim_ielen ==4) ++ { ++ __le16 pvb; ++ ++ if (pstapriv->tim_bitmap&0xff00) ++ pvb = cpu_to_le16(pstapriv->tim_bitmap >> 8); ++ else ++ pvb = tim_bitmap_le; ++ ++ *dst_ie++ = le16_to_cpu(pvb); ++ ++ } ++ else if (tim_ielen ==5) ++ { ++ memcpy(dst_ie, &tim_bitmap_le, 2); ++ dst_ie+=2; ++ } ++ ++ /* copy remainder IE */ ++ if (pbackup_remainder_ie) ++ { ++ memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen); ++ ++ kfree(pbackup_remainder_ie); ++ } ++ ++ offset = (uint)(dst_ie - pie); ++ pnetwork_mlmeext->IELength = offset + remainder_ielen; ++ ++ } ++} ++ ++u8 chk_sta_is_alive(struct sta_info *psta); ++u8 chk_sta_is_alive(struct sta_info *psta) ++{ ++ #ifdef DBG_EXPIRATION_CHK ++ DBG_871X("sta:"MAC_FMT", rssi:%d, rx:"STA_PKTS_FMT", expire_to:%u, %s%ssq_len:%u\n" ++ , MAC_ARG(psta->hwaddr) ++ , psta->rssi_stat.UndecoratedSmoothedPWDB ++ /* STA_RX_PKTS_ARG(psta) */ ++ , STA_RX_PKTS_DIFF_ARG(psta) ++ , psta->expire_to ++ , psta->state&WIFI_SLEEP_STATE?"PS, ":"" ++ , psta->state&WIFI_STA_ALIVE_CHK_STATE?"SAC, ":"" ++ , psta->sleepq_len ++ ); ++ #endif ++ ++ sta_update_last_rx_pkts(psta); ++ ++ return true; ++} ++ ++void expire_timeout_chk(struct adapter *padapter) ++{ ++ struct list_head *phead, *plist; ++ u8 updated = false; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 chk_alive_num = 0; ++ char chk_alive_list[NUM_STA]; ++ int i; ++ ++ ++ spin_lock_bh(&pstapriv->auth_list_lock); ++ ++ phead = &pstapriv->auth_list; ++ plist = get_next(phead); ++ ++ /* check auth_queue */ ++ #ifdef DBG_EXPIRATION_CHK ++ if (phead != plist) { ++ DBG_871X(FUNC_NDEV_FMT" auth_list, cnt:%u\n" ++ , FUNC_NDEV_ARG(padapter->pnetdev), pstapriv->auth_list_cnt); ++ } ++ #endif ++ while (phead != plist) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info, auth_list); ++ ++ plist = get_next(plist); ++ ++ if (psta->expire_to>0) ++ { ++ psta->expire_to--; ++ if (psta->expire_to == 0) ++ { ++ list_del_init(&psta->auth_list); ++ pstapriv->auth_list_cnt--; ++ ++ DBG_871X("auth expire %02X%02X%02X%02X%02X%02X\n", ++ psta->hwaddr[0], psta->hwaddr[1], psta->hwaddr[2], psta->hwaddr[3], psta->hwaddr[4], psta->hwaddr[5]); ++ ++ spin_unlock_bh(&pstapriv->auth_list_lock); ++ ++ rtw_free_stainfo(padapter, psta); ++ ++ spin_lock_bh(&pstapriv->auth_list_lock); ++ } ++ } ++ ++ } ++ ++ spin_unlock_bh(&pstapriv->auth_list_lock); ++ psta = NULL; ++ ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ ++ phead = &pstapriv->asoc_list; ++ plist = get_next(phead); ++ ++ /* check asoc_queue */ ++ #ifdef DBG_EXPIRATION_CHK ++ if (phead != plist) { ++ DBG_871X(FUNC_NDEV_FMT" asoc_list, cnt:%u\n" ++ , FUNC_NDEV_ARG(padapter->pnetdev), pstapriv->asoc_list_cnt); ++ } ++ #endif ++ while (phead != plist) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); ++ plist = get_next(plist); ++#ifdef CONFIG_AUTO_AP_MODE ++ if (psta->isrc) ++ continue; ++#endif ++ if (chk_sta_is_alive(psta) || !psta->expire_to) { ++ psta->expire_to = pstapriv->expire_to; ++ psta->keep_alive_trycnt = 0; ++ psta->under_exist_checking = 0; ++ } else { ++ if (psta->expire_to > 0) ++ psta->expire_to--; ++ } ++ ++ if (psta->expire_to == 0) ++ { ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ if (padapter->registrypriv.wifi_spec == 1) ++ { ++ psta->expire_to = pstapriv->expire_to; ++ continue; ++ } ++ ++ if (psta->state & WIFI_SLEEP_STATE) { ++ if (!(psta->state & WIFI_STA_ALIVE_CHK_STATE)) { ++ /* to check if alive by another methods if staion is at ps mode. */ ++ psta->expire_to = pstapriv->expire_to; ++ psta->state |= WIFI_STA_ALIVE_CHK_STATE; ++ ++ /* DBG_871X("alive chk, sta:" MAC_FMT " is at ps mode!\n", MAC_ARG(psta->hwaddr)); */ ++ ++ /* to update bcn with tim_bitmap for this station */ ++ pstapriv->tim_bitmap |= BIT(psta->aid); ++ update_beacon(padapter, _TIM_IE_, NULL, true); ++ ++ if (!pmlmeext->active_keep_alive_check) ++ continue; ++ } ++ } ++ if (pmlmeext->active_keep_alive_check) { ++ int stainfo_offset; ++ ++ stainfo_offset = rtw_stainfo_offset(pstapriv, psta); ++ if (stainfo_offset_valid(stainfo_offset)) { ++ chk_alive_list[chk_alive_num++] = stainfo_offset; ++ } ++ ++ continue; ++ } ++ list_del_init(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ DBG_871X("asoc expire "MAC_FMT", state = 0x%x\n", MAC_ARG(psta->hwaddr), psta->state); ++ updated = ap_free_sta(padapter, psta, false, WLAN_REASON_DEAUTH_LEAVING); ++ } ++ else ++ { ++ /* TODO: Aging mechanism to digest frames in sleep_q to avoid running out of xmitframe */ ++ if (psta->sleepq_len > (NR_XMITFRAME/pstapriv->asoc_list_cnt) ++ && padapter->xmitpriv.free_xmitframe_cnt < ((NR_XMITFRAME/pstapriv->asoc_list_cnt)/2) ++ ) { ++ DBG_871X("%s sta:"MAC_FMT", sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n", __func__ ++ , MAC_ARG(psta->hwaddr) ++ , psta->sleepq_len, padapter->xmitpriv.free_xmitframe_cnt, pstapriv->asoc_list_cnt); ++ wakeup_sta_to_xmit(padapter, psta); ++ } ++ } ++ } ++ ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++if (chk_alive_num) { ++ ++ u8 backup_oper_channel = 0; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ /* switch to correct channel of current network before issue keep-alive frames */ ++ if (rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) { ++ backup_oper_channel = rtw_get_oper_ch(padapter); ++ SelectChannel(padapter, pmlmeext->cur_channel); ++ } ++ ++ /* issue null data to check sta alive*/ ++ for (i = 0; i < chk_alive_num; i++) { ++ int ret = _FAIL; ++ ++ psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]); ++ if (!(psta->state &_FW_LINKED)) ++ continue; ++ ++ if (psta->state & WIFI_SLEEP_STATE) ++ ret = issue_nulldata(padapter, psta->hwaddr, 0, 1, 50); ++ else ++ ret = issue_nulldata(padapter, psta->hwaddr, 0, 3, 50); ++ ++ psta->keep_alive_trycnt++; ++ if (ret == _SUCCESS) ++ { ++ DBG_871X("asoc check, sta(" MAC_FMT ") is alive\n", MAC_ARG(psta->hwaddr)); ++ psta->expire_to = pstapriv->expire_to; ++ psta->keep_alive_trycnt = 0; ++ continue; ++ } ++ else if (psta->keep_alive_trycnt <= 3) ++ { ++ DBG_871X("ack check for asoc expire, keep_alive_trycnt =%d\n", psta->keep_alive_trycnt); ++ psta->expire_to = 1; ++ continue; ++ } ++ ++ psta->keep_alive_trycnt = 0; ++ DBG_871X("asoc expire "MAC_FMT", state = 0x%x\n", MAC_ARG(psta->hwaddr), psta->state); ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ if (list_empty(&psta->asoc_list) ==false) { ++ list_del_init(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ updated = ap_free_sta(padapter, psta, false, WLAN_REASON_DEAUTH_LEAVING); ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ } ++ ++ if (backup_oper_channel>0) /* back to the original operation channel */ ++ SelectChannel(padapter, backup_oper_channel); ++} ++ ++ associated_clients_update(padapter, updated); ++} ++ ++void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level) ++{ ++ unsigned char sta_band = 0, shortGIrate = false; ++ unsigned int tx_ra_bitmap = 0; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; ++ ++ if (!psta) ++ return; ++ ++ if (!(psta->state & _FW_LINKED)) ++ return; ++ ++ rtw_hal_update_sta_rate_mask(padapter, psta); ++ tx_ra_bitmap = psta->ra_mask; ++ ++ shortGIrate = query_ra_short_GI(psta); ++ ++ if (pcur_network->Configuration.DSConfig > 14) { ++ ++ if (tx_ra_bitmap & 0xffff000) ++ sta_band |= WIRELESS_11_5N ; ++ ++ if (tx_ra_bitmap & 0xff0) ++ sta_band |= WIRELESS_11A; ++ } else { ++ if (tx_ra_bitmap & 0xffff000) ++ sta_band |= WIRELESS_11_24N; ++ ++ if (tx_ra_bitmap & 0xff0) ++ sta_band |= WIRELESS_11G; ++ ++ if (tx_ra_bitmap & 0x0f) ++ sta_band |= WIRELESS_11B; ++ } ++ ++ psta->wireless_mode = sta_band; ++ psta->raid = rtw_hal_networktype_to_raid(padapter, psta); ++ ++ if (psta->aid < NUM_STA) ++ { ++ u8 arg[4] = {0}; ++ ++ arg[0] = psta->mac_id; ++ arg[1] = psta->raid; ++ arg[2] = shortGIrate; ++ arg[3] = psta->init_rate; ++ ++ DBG_871X("%s => mac_id:%d , raid:%d , shortGIrate =%d, bitmap = 0x%x\n", ++ __func__ , psta->mac_id, psta->raid , shortGIrate, tx_ra_bitmap); ++ ++ rtw_hal_add_ra_tid(padapter, tx_ra_bitmap, arg, rssi_level); ++ } ++ else ++ { ++ DBG_871X("station aid %d exceed the max number\n", psta->aid); ++ } ++ ++} ++ ++void update_bmc_sta(struct adapter *padapter) ++{ ++ unsigned char network_type; ++ int supportRateNum = 0; ++ unsigned int tx_ra_bitmap = 0; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; ++ struct sta_info *psta = rtw_get_bcmc_stainfo(padapter); ++ ++ if (psta) ++ { ++ psta->aid = 0;/* default set to 0 */ ++ /* psta->mac_id = psta->aid+4; */ ++ psta->mac_id = psta->aid + 1;/* mac_id = 1 for bc/mc stainfo */ ++ ++ pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta; ++ ++ psta->qos_option = 0; ++ psta->htpriv.ht_option = false; ++ ++ psta->ieee8021x_blocked = 0; ++ ++ memset((void*)&psta->sta_stats, 0, sizeof(struct stainfo_stats)); ++ ++ /* psta->dot118021XPrivacy = _NO_PRIVACY_;//!!! remove it, because it has been set before this. */ ++ ++ /* prepare for add_RATid */ ++ supportRateNum = rtw_get_rateset_len((u8 *)&pcur_network->SupportedRates); ++ network_type = rtw_check_network_type((u8 *)&pcur_network->SupportedRates, supportRateNum, pcur_network->Configuration.DSConfig); ++ if (IsSupportedTxCCK(network_type)) { ++ network_type = WIRELESS_11B; ++ } ++ else if (network_type == WIRELESS_INVALID) { /* error handling */ ++ if (pcur_network->Configuration.DSConfig > 14) ++ network_type = WIRELESS_11A; ++ else ++ network_type = WIRELESS_11B; ++ } ++ update_sta_basic_rate(psta, network_type); ++ psta->wireless_mode = network_type; ++ ++ rtw_hal_update_sta_rate_mask(padapter, psta); ++ tx_ra_bitmap = psta->ra_mask; ++ ++ psta->raid = rtw_hal_networktype_to_raid(padapter, psta); ++ ++ /* ap mode */ ++ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true); ++ ++ /* if (pHalData->fw_ractrl == true) */ ++ { ++ u8 arg[4] = {0}; ++ ++ arg[0] = psta->mac_id; ++ arg[1] = psta->raid; ++ arg[2] = 0; ++ arg[3] = psta->init_rate; ++ ++ DBG_871X("%s => mac_id:%d , raid:%d , bitmap = 0x%x\n", ++ __func__ , psta->mac_id, psta->raid , tx_ra_bitmap); ++ ++ rtw_hal_add_ra_tid(padapter, tx_ra_bitmap, arg, 0); ++ } ++ ++ rtw_sta_media_status_rpt(padapter, psta, 1); ++ ++ spin_lock_bh(&psta->lock); ++ psta->state = _FW_LINKED; ++ spin_unlock_bh(&psta->lock); ++ ++ } ++ else ++ { ++ DBG_871X("add_RATid_bmc_sta error!\n"); ++ } ++ ++} ++ ++/* notes: */ ++/* AID: 1~MAX for sta and 0 for bc/mc in ap/adhoc mode */ ++/* MAC_ID = AID+1 for sta in ap/adhoc mode */ ++/* MAC_ID = 1 for bc/mc for sta/ap/adhoc */ ++/* MAC_ID = 0 for bssid for sta/ap/adhoc */ ++/* CAM_ID = 0~3 for default key, cmd_id =macid + 3, macid =aid+1; */ ++ ++void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta) ++{ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv; ++ struct ht_priv *phtpriv_sta = &psta->htpriv; ++ u8 cur_ldpc_cap = 0, cur_stbc_cap = 0, cur_beamform_cap = 0; ++ /* set intf_tag to if1 */ ++ /* psta->intf_tag = 0; */ ++ ++ DBG_871X("%s\n", __func__); ++ ++ /* psta->mac_id = psta->aid+4; */ ++ /* psta->mac_id = psta->aid+1;//alloc macid when call rtw_alloc_stainfo(), */ ++ /* release macid when call rtw_free_stainfo() */ ++ ++ /* ap mode */ ++ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true); ++ ++ if (psecuritypriv->dot11AuthAlgrthm ==dot11AuthAlgrthm_8021X) ++ psta->ieee8021x_blocked = true; ++ else ++ psta->ieee8021x_blocked = false; ++ ++ ++ /* update sta's cap */ ++ ++ /* ERP */ ++ VCS_update(padapter, psta); ++ ++ /* HT related cap */ ++ if (phtpriv_sta->ht_option) ++ { ++ /* check if sta supports rx ampdu */ ++ phtpriv_sta->ampdu_enable = phtpriv_ap->ampdu_enable; ++ ++ phtpriv_sta->rx_ampdu_min_spacing = (phtpriv_sta->ht_cap.ampdu_params_info&IEEE80211_HT_CAP_AMPDU_DENSITY)>>2; ++ ++ /* bwmode */ ++ if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH)) ++ { ++ psta->bw_mode = CHANNEL_WIDTH_40; ++ } ++ else ++ { ++ psta->bw_mode = CHANNEL_WIDTH_20; ++ } ++ ++ if (pmlmeext->cur_bwmode < psta->bw_mode) ++ { ++ psta->bw_mode = pmlmeext->cur_bwmode; ++ } ++ ++ phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset; ++ ++ ++ /* check if sta support s Short GI 20M */ ++ if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_20)) ++ { ++ phtpriv_sta->sgi_20m = true; ++ } ++ ++ /* check if sta support s Short GI 40M */ ++ if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_40)) ++ { ++ if (psta->bw_mode == CHANNEL_WIDTH_40) /* according to psta->bw_mode */ ++ phtpriv_sta->sgi_40m = true; ++ else ++ phtpriv_sta->sgi_40m = false; ++ } ++ ++ psta->qos_option = true; ++ ++ /* B0 Config LDPC Coding Capability */ ++ if (TEST_FLAG(phtpriv_ap->ldpc_cap, LDPC_HT_ENABLE_TX) && ++ GET_HT_CAPABILITY_ELE_LDPC_CAP((u8 *)(&phtpriv_sta->ht_cap))) ++ { ++ SET_FLAG(cur_ldpc_cap, (LDPC_HT_ENABLE_TX | LDPC_HT_CAP_TX)); ++ DBG_871X("Enable HT Tx LDPC for STA(%d)\n", psta->aid); ++ } ++ ++ /* B7 B8 B9 Config STBC setting */ ++ if (TEST_FLAG(phtpriv_ap->stbc_cap, STBC_HT_ENABLE_TX) && ++ GET_HT_CAPABILITY_ELE_RX_STBC((u8 *)(&phtpriv_sta->ht_cap))) ++ { ++ SET_FLAG(cur_stbc_cap, (STBC_HT_ENABLE_TX | STBC_HT_CAP_TX)); ++ DBG_871X("Enable HT Tx STBC for STA(%d)\n", psta->aid); ++ } ++ } ++ else ++ { ++ phtpriv_sta->ampdu_enable = false; ++ ++ phtpriv_sta->sgi_20m = false; ++ phtpriv_sta->sgi_40m = false; ++ psta->bw_mode = CHANNEL_WIDTH_20; ++ phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ } ++ ++ phtpriv_sta->ldpc_cap = cur_ldpc_cap; ++ phtpriv_sta->stbc_cap = cur_stbc_cap; ++ phtpriv_sta->beamform_cap = cur_beamform_cap; ++ ++ /* Rx AMPDU */ ++ send_delba(padapter, 0, psta->hwaddr);/* recipient */ ++ ++ /* TX AMPDU */ ++ send_delba(padapter, 1, psta->hwaddr);/* originator */ ++ phtpriv_sta->agg_enable_bitmap = 0x0;/* reset */ ++ phtpriv_sta->candidate_tid_bitmap = 0x0;/* reset */ ++ ++ update_ldpc_stbc_cap(psta); ++ ++ /* todo: init other variables */ ++ ++ memset((void*)&psta->sta_stats, 0, sizeof(struct stainfo_stats)); ++ ++ ++ /* add ratid */ ++ /* add_RATid(padapter, psta);//move to ap_sta_info_defer_update() */ ++ ++ ++ spin_lock_bh(&psta->lock); ++ psta->state |= _FW_LINKED; ++ spin_unlock_bh(&psta->lock); ++ ++ ++} ++ ++static void update_ap_info(struct adapter *padapter, struct sta_info *psta) ++{ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv; ++ ++ psta->wireless_mode = pmlmeext->cur_wireless_mode; ++ ++ psta->bssratelen = rtw_get_rateset_len(pnetwork->SupportedRates); ++ memcpy(psta->bssrateset, pnetwork->SupportedRates, psta->bssratelen); ++ ++ /* HT related cap */ ++ if (phtpriv_ap->ht_option) ++ { ++ /* check if sta supports rx ampdu */ ++ /* phtpriv_ap->ampdu_enable = phtpriv_ap->ampdu_enable; */ ++ ++ /* check if sta support s Short GI 20M */ ++ if ((phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_20)) ++ { ++ phtpriv_ap->sgi_20m = true; ++ } ++ /* check if sta support s Short GI 40M */ ++ if ((phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_40)) ++ { ++ phtpriv_ap->sgi_40m = true; ++ } ++ ++ psta->qos_option = true; ++ } ++ else ++ { ++ phtpriv_ap->ampdu_enable = false; ++ ++ phtpriv_ap->sgi_20m = false; ++ phtpriv_ap->sgi_40m = false; ++ } ++ ++ psta->bw_mode = pmlmeext->cur_bwmode; ++ phtpriv_ap->ch_offset = pmlmeext->cur_ch_offset; ++ ++ phtpriv_ap->agg_enable_bitmap = 0x0;/* reset */ ++ phtpriv_ap->candidate_tid_bitmap = 0x0;/* reset */ ++ ++ memcpy(&psta->htpriv, &pmlmepriv->htpriv, sizeof(struct ht_priv)); ++} ++ ++static void update_hw_ht_param(struct adapter *padapter) ++{ ++ unsigned char max_AMPDU_len; ++ unsigned char min_MPDU_spacing; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ DBG_871X("%s\n", __func__); ++ ++ ++ /* handle A-MPDU parameter field */ ++ /* ++ AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k ++ AMPDU_para [4:2]:Min MPDU Start Spacing ++ */ ++ max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; ++ ++ min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing)); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len)); ++ ++ /* */ ++ /* Config SM Power Save setting */ ++ /* */ ++ pmlmeinfo->SM_PS = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & 0x0C) >> 2; ++ if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) ++ DBG_871X("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__); ++ ++ /* */ ++ /* Config current HT Protection mode. */ ++ /* */ ++ /* pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3; */ ++ ++} ++ ++void start_bss_network(struct adapter *padapter, u8 *pbuf) ++{ ++ u8 *p; ++ u8 val8, cur_channel, cur_bwmode, cur_ch_offset; ++ u16 bcn_interval; ++ u32 acparm; ++ int ie_len; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct security_priv* psecuritypriv =&(padapter->securitypriv); ++ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *pnetwork_mlmeext = &(pmlmeinfo->network); ++ struct HT_info_element *pht_info = NULL; ++ u8 cbw40_enable = 0; ++ ++ /* DBG_871X("%s\n", __func__); */ ++ ++ bcn_interval = (u16)pnetwork->Configuration.BeaconPeriod; ++ cur_channel = pnetwork->Configuration.DSConfig; ++ cur_bwmode = CHANNEL_WIDTH_20; ++ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ ++ /* check if there is wps ie, */ ++ /* if there is wpsie in beacon, the hostapd will update beacon twice when stating hostapd, */ ++ /* and at first time the security ie (RSN/WPA IE) will not include in beacon. */ ++ if (NULL == rtw_get_wps_ie(pnetwork->IEs+_FIXED_IE_LENGTH_, pnetwork->IELength-_FIXED_IE_LENGTH_, NULL, NULL)) ++ { ++ pmlmeext->bstart_bss = true; ++ } ++ ++ /* todo: update wmm, ht cap */ ++ /* pmlmeinfo->WMM_enable; */ ++ /* pmlmeinfo->HT_enable; */ ++ if (pmlmepriv->qospriv.qos_option) ++ pmlmeinfo->WMM_enable = true; ++ if (pmlmepriv->htpriv.ht_option) ++ { ++ pmlmeinfo->WMM_enable = true; ++ pmlmeinfo->HT_enable = true; ++ /* pmlmeinfo->HT_info_enable = true; */ ++ /* pmlmeinfo->HT_caps_enable = true; */ ++ ++ update_hw_ht_param(padapter); ++ } ++ ++ if (pmlmepriv->cur_network.join_res != true) /* setting only at first time */ ++ { ++ /* WEP Key will be set before this function, do not clear CAM. */ ++ if ((psecuritypriv->dot11PrivacyAlgrthm != _WEP40_) && (psecuritypriv->dot11PrivacyAlgrthm != _WEP104_)) ++ flush_all_cam_entry(padapter); /* clear CAM */ ++ } ++ ++ /* set MSR to AP_Mode */ ++ Set_MSR(padapter, _HW_STATE_AP_); ++ ++ /* Set BSSID REG */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pnetwork->MacAddress); ++ ++ /* Set EDCA param reg */ ++ acparm = 0x002F3217; /* VO */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acparm)); ++ acparm = 0x005E4317; /* VI */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acparm)); ++ /* acparm = 0x00105320; // BE */ ++ acparm = 0x005ea42b; ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm)); ++ acparm = 0x0000A444; /* BK */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acparm)); ++ ++ /* Set Security */ ++ val8 = (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)? 0xcc: 0xcf; ++ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); ++ ++ /* Beacon Control related register */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&bcn_interval)); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_DO_IQK, NULL); ++ ++ if (pmlmepriv->cur_network.join_res != true) /* setting only at first time */ ++ { ++ /* u32 initialgain; */ ++ ++ /* initialgain = 0x1e; */ ++ ++ ++ /* disable dynamic functions, such as high power, DIG */ ++ /* Save_DM_Func_Flag(padapter); */ ++ /* Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, false); */ ++ ++ /* turn on all dynamic functions */ ++ Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); ++ ++ /* rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); */ ++ ++ } ++ ++ /* set channel, bwmode */ ++ p = rtw_get_ie((pnetwork->IEs + sizeof(struct ndis_802_11_fix_ie)), _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - sizeof(struct ndis_802_11_fix_ie))); ++ if (p && ie_len) ++ { ++ pht_info = (struct HT_info_element *)(p+2); ++ ++ if (cur_channel > 14) { ++ if ((pregpriv->bw_mode & 0xf0) > 0) ++ cbw40_enable = 1; ++ } else { ++ if ((pregpriv->bw_mode & 0x0f) > 0) ++ cbw40_enable = 1; ++ } ++ ++ if ((cbw40_enable) && (pht_info->infos[0] & BIT(2))) ++ { ++ /* switch to the 40M Hz mode */ ++ /* pmlmeext->cur_bwmode = CHANNEL_WIDTH_40; */ ++ cur_bwmode = CHANNEL_WIDTH_40; ++ switch (pht_info->infos[0] & 0x3) ++ { ++ case 1: ++ /* pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; */ ++ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ break; ++ ++ case 3: ++ /* pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; */ ++ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ break; ++ ++ default: ++ /* pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; */ ++ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ break; ++ } ++ ++ } ++ ++ } ++ ++ set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode); ++ DBG_871X("CH =%d, BW =%d, offset =%d\n", cur_channel, cur_bwmode, cur_ch_offset); ++ pmlmeext->cur_channel = cur_channel; ++ pmlmeext->cur_bwmode = cur_bwmode; ++ pmlmeext->cur_ch_offset = cur_ch_offset; ++ pmlmeext->cur_wireless_mode = pmlmepriv->cur_network.network_type; ++ ++ /* let pnetwork_mlmeext == pnetwork_mlme. */ ++ memcpy(pnetwork_mlmeext, pnetwork, pnetwork->Length); ++ ++ /* update cur_wireless_mode */ ++ update_wireless_mode(padapter); ++ ++ /* update RRSR after set channel and bandwidth */ ++ UpdateBrateTbl(padapter, pnetwork->SupportedRates); ++ rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, pnetwork->SupportedRates); ++ ++ /* udpate capability after cur_wireless_mode updated */ ++ update_capinfo(padapter, rtw_get_capability((struct wlan_bssid_ex *)pnetwork)); ++ ++ ++ if (true == pmlmeext->bstart_bss) ++ { ++ update_beacon(padapter, _TIM_IE_, NULL, true); ++ ++#ifndef CONFIG_INTERRUPT_BASED_TXBCN /* other case will tx beacon when bcn interrupt coming in. */ ++ /* issue beacon frame */ ++ if (send_beacon(padapter) == _FAIL) ++ { ++ DBG_871X("issue_beacon, fail!\n"); ++ } ++#endif /* CONFIG_INTERRUPT_BASED_TXBCN */ ++ ++ } ++ ++ ++ /* update bc/mc sta_info */ ++ update_bmc_sta(padapter); ++ ++ /* pmlmeext->bstart_bss = true; */ ++ ++} ++ ++int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len) ++{ ++ int ret = _SUCCESS; ++ u8 *p; ++ u8 *pHT_caps_ie = NULL; ++ u8 *pHT_info_ie = NULL; ++ struct sta_info *psta = NULL; ++ u16 cap, ht_cap =false; ++ uint ie_len = 0; ++ int group_cipher, pairwise_cipher; ++ u8 channel, network_type, supportRate[NDIS_802_11_LENGTH_RATES_EX]; ++ int supportRateNum = 0; ++ u8 OUI1[] = {0x00, 0x50, 0xf2, 0x01}; ++ u8 WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct wlan_bssid_ex *pbss_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; ++ u8 *ie = pbss_network->IEs; ++ ++ /* SSID */ ++ /* Supported rates */ ++ /* DS Params */ ++ /* WLAN_EID_COUNTRY */ ++ /* ERP Information element */ ++ /* Extended supported rates */ ++ /* WPA/WPA2 */ ++ /* Wi-Fi Wireless Multimedia Extensions */ ++ /* ht_capab, ht_oper */ ++ /* WPS IE */ ++ ++ DBG_871X("%s, len =%d\n", __func__, len); ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) ++ return _FAIL; ++ ++ ++ if (len>MAX_IE_SZ) ++ return _FAIL; ++ ++ pbss_network->IELength = len; ++ ++ memset(ie, 0, MAX_IE_SZ); ++ ++ memcpy(ie, pbuf, pbss_network->IELength); ++ ++ ++ if (pbss_network->InfrastructureMode!=Ndis802_11APMode) ++ return _FAIL; ++ ++ pbss_network->Rssi = 0; ++ ++ memcpy(pbss_network->MacAddress, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ /* beacon interval */ ++ p = rtw_get_beacon_interval_from_ie(ie);/* ie + 8; 8: TimeStamp, 2: Beacon Interval 2:Capability */ ++ /* pbss_network->Configuration.BeaconPeriod = le16_to_cpu(*(unsigned short*)p); */ ++ pbss_network->Configuration.BeaconPeriod = RTW_GET_LE16(p); ++ ++ /* capability */ ++ /* cap = *(unsigned short *)rtw_get_capability_from_ie(ie); */ ++ /* cap = le16_to_cpu(cap); */ ++ cap = RTW_GET_LE16(ie); ++ ++ /* SSID */ ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SSID_IE_, &ie_len, (pbss_network->IELength -_BEACON_IE_OFFSET_)); ++ if (p && ie_len>0) ++ { ++ memset(&pbss_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); ++ memcpy(pbss_network->Ssid.Ssid, (p + 2), ie_len); ++ pbss_network->Ssid.SsidLength = ie_len; ++ } ++ ++ /* chnnel */ ++ channel = 0; ++ pbss_network->Configuration.Length = 0; ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _DSSET_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if (p && ie_len>0) ++ channel = *(p + 2); ++ ++ pbss_network->Configuration.DSConfig = channel; ++ ++ ++ memset(supportRate, 0, NDIS_802_11_LENGTH_RATES_EX); ++ /* get supported rates */ ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if (p != NULL) ++ { ++ memcpy(supportRate, p+2, ie_len); ++ supportRateNum = ie_len; ++ } ++ ++ /* get ext_supported rates */ ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ie_len, pbss_network->IELength - _BEACON_IE_OFFSET_); ++ if (p != NULL) ++ { ++ memcpy(supportRate+supportRateNum, p+2, ie_len); ++ supportRateNum += ie_len; ++ ++ } ++ ++ network_type = rtw_check_network_type(supportRate, supportRateNum, channel); ++ ++ rtw_set_supported_rate(pbss_network->SupportedRates, network_type); ++ ++ ++ /* parsing ERP_IE */ ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if (p && ie_len>0) ++ { ++ ERP_IE_handler(padapter, (struct ndis_80211_var_ie *)p); ++ } ++ ++ /* update privacy/security */ ++ if (cap & BIT(4)) ++ pbss_network->Privacy = 1; ++ else ++ pbss_network->Privacy = 0; ++ ++ psecuritypriv->wpa_psk = 0; ++ ++ /* wpa2 */ ++ group_cipher = 0; pairwise_cipher = 0; ++ psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_; ++ psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_; ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if (p && ie_len>0) ++ { ++ if (rtw_parse_wpa2_ie(p, ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) ++ { ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; ++ ++ psecuritypriv->dot8021xalg = 1;/* psk, todo:802.1x */ ++ psecuritypriv->wpa_psk |= BIT(1); ++ ++ psecuritypriv->wpa2_group_cipher = group_cipher; ++ psecuritypriv->wpa2_pairwise_cipher = pairwise_cipher; ++ } ++ ++ } ++ ++ /* wpa */ ++ ie_len = 0; ++ group_cipher = 0; pairwise_cipher = 0; ++ psecuritypriv->wpa_group_cipher = _NO_PRIVACY_; ++ psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_; ++ for (p = ie + _BEACON_IE_OFFSET_; ;p += (ie_len + 2)) ++ { ++ p = rtw_get_ie(p, _SSN_IE_1_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); ++ if ((p) && (!memcmp(p+2, OUI1, 4))) ++ { ++ if (rtw_parse_wpa_ie(p, ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) ++ { ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; ++ ++ psecuritypriv->dot8021xalg = 1;/* psk, todo:802.1x */ ++ ++ psecuritypriv->wpa_psk |= BIT(0); ++ ++ psecuritypriv->wpa_group_cipher = group_cipher; ++ psecuritypriv->wpa_pairwise_cipher = pairwise_cipher; ++ } ++ ++ break; ++ ++ } ++ ++ if ((p == NULL) || (ie_len == 0)) ++ { ++ break; ++ } ++ ++ } ++ ++ /* wmm */ ++ ie_len = 0; ++ pmlmepriv->qospriv.qos_option = 0; ++ if (pregistrypriv->wmm_enable) ++ { ++ for (p = ie + _BEACON_IE_OFFSET_; ;p += (ie_len + 2)) ++ { ++ p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); ++ if ((p) && !memcmp(p+2, WMM_PARA_IE, 6)) ++ { ++ pmlmepriv->qospriv.qos_option = 1; ++ ++ *(p+8) |= BIT(7);/* QoS Info, support U-APSD */ ++ ++ /* disable all ACM bits since the WMM admission control is not supported */ ++ *(p + 10) &= ~BIT(4); /* BE */ ++ *(p + 14) &= ~BIT(4); /* BK */ ++ *(p + 18) &= ~BIT(4); /* VI */ ++ *(p + 22) &= ~BIT(4); /* VO */ ++ ++ break; ++ } ++ ++ if ((p == NULL) || (ie_len == 0)) ++ { ++ break; ++ } ++ } ++ } ++ ++ /* parsing HT_CAP_IE */ ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if (p && ie_len>0) ++ { ++ u8 rf_type = 0; ++ u8 max_rx_ampdu_factor = 0; ++ struct rtw_ieee80211_ht_cap *pht_cap = (struct rtw_ieee80211_ht_cap *)(p+2); ++ ++ pHT_caps_ie =p; ++ ++ ht_cap = true; ++ network_type |= WIRELESS_11_24N; ++ ++ rtw_ht_use_default_setting(padapter); ++ ++ if (pmlmepriv->htpriv.sgi_20m == false) ++ pht_cap->cap_info &= cpu_to_le16(~(IEEE80211_HT_CAP_SGI_20)); ++ ++ if (pmlmepriv->htpriv.sgi_40m == false) ++ pht_cap->cap_info &= cpu_to_le16(~(IEEE80211_HT_CAP_SGI_40)); ++ ++ if (!TEST_FLAG(pmlmepriv->htpriv.ldpc_cap, LDPC_HT_ENABLE_RX)) ++ { ++ pht_cap->cap_info &= cpu_to_le16(~(IEEE80211_HT_CAP_LDPC_CODING)); ++ } ++ ++ if (!TEST_FLAG(pmlmepriv->htpriv.stbc_cap, STBC_HT_ENABLE_TX)) ++ { ++ pht_cap->cap_info &= cpu_to_le16(~(IEEE80211_HT_CAP_TX_STBC)); ++ } ++ ++ if (!TEST_FLAG(pmlmepriv->htpriv.stbc_cap, STBC_HT_ENABLE_RX)) ++ { ++ pht_cap->cap_info &= cpu_to_le16(~(IEEE80211_HT_CAP_RX_STBC_3R)); ++ } ++ ++ pht_cap->ampdu_params_info &= ~(IEEE80211_HT_CAP_AMPDU_FACTOR|IEEE80211_HT_CAP_AMPDU_DENSITY); ++ ++ if ((psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_CCMP) || ++ (psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP)) ++ { ++ pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&(0x07<<2)); ++ } ++ else ++ { ++ pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&0x00); ++ } ++ ++ rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor); ++ pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_FACTOR & max_rx_ampdu_factor); /* set Max Rx AMPDU size to 64K */ ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ if (rf_type == RF_1T1R) ++ { ++ pht_cap->supp_mcs_set[0] = 0xff; ++ pht_cap->supp_mcs_set[1] = 0x0; ++ } ++ ++ memcpy(&pmlmepriv->htpriv.ht_cap, p+2, ie_len); ++ ++ } ++ ++ /* parsing HT_INFO_IE */ ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if (p && ie_len>0) ++ { ++ pHT_info_ie =p; ++ } ++ ++ switch (network_type) ++ { ++ case WIRELESS_11B: ++ pbss_network->NetworkTypeInUse = Ndis802_11DS; ++ break; ++ case WIRELESS_11G: ++ case WIRELESS_11BG: ++ case WIRELESS_11G_24N: ++ case WIRELESS_11BG_24N: ++ pbss_network->NetworkTypeInUse = Ndis802_11OFDM24; ++ break; ++ case WIRELESS_11A: ++ pbss_network->NetworkTypeInUse = Ndis802_11OFDM5; ++ break; ++ default : ++ pbss_network->NetworkTypeInUse = Ndis802_11OFDM24; ++ break; ++ } ++ ++ pmlmepriv->cur_network.network_type = network_type; ++ ++ pmlmepriv->htpriv.ht_option = false; ++ ++ if ((psecuritypriv->wpa2_pairwise_cipher&WPA_CIPHER_TKIP) || ++ (psecuritypriv->wpa_pairwise_cipher&WPA_CIPHER_TKIP)) ++ { ++ /* todo: */ ++ /* ht_cap = false; */ ++ } ++ ++ /* ht_cap */ ++ if (pregistrypriv->ht_enable && ht_cap ==true) ++ { ++ pmlmepriv->htpriv.ht_option = true; ++ pmlmepriv->qospriv.qos_option = 1; ++ ++ if (pregistrypriv->ampdu_enable == 1) ++ { ++ pmlmepriv->htpriv.ampdu_enable = true; ++ } ++ ++ HT_caps_handler(padapter, (struct ndis_80211_var_ie *)pHT_caps_ie); ++ ++ HT_info_handler(padapter, (struct ndis_80211_var_ie *)pHT_info_ie); ++ } ++ ++ pbss_network->Length = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pbss_network); ++ ++ /* issue beacon to start bss network */ ++ /* start_bss_network(padapter, (u8 *)pbss_network); */ ++ rtw_startbss_cmd(padapter, RTW_CMDF_WAIT_ACK); ++ ++ ++ /* alloc sta_info for ap itself */ ++ psta = rtw_get_stainfo(&padapter->stapriv, pbss_network->MacAddress); ++ if (!psta) ++ { ++ psta = rtw_alloc_stainfo(&padapter->stapriv, pbss_network->MacAddress); ++ if (psta == NULL) ++ { ++ return _FAIL; ++ } ++ } ++ ++ /* update AP's sta info */ ++ update_ap_info(padapter, psta); ++ ++ psta->state |= WIFI_AP_STATE; /* Aries, add, fix bug of flush_cam_entry at STOP AP mode , 0724 */ ++ rtw_indicate_connect(padapter); ++ ++ pmlmepriv->cur_network.join_res = true;/* for check if already set beacon */ ++ ++ /* update bc/mc sta_info */ ++ /* update_bmc_sta(padapter); */ ++ ++ return ret; ++ ++} ++ ++void rtw_set_macaddr_acl(struct adapter *padapter, int mode) ++{ ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ ++ DBG_871X("%s, mode =%d\n", __func__, mode); ++ ++ pacl_list->mode = mode; ++} ++ ++int rtw_acl_add_sta(struct adapter *padapter, u8 *addr) ++{ ++ struct list_head *plist, *phead; ++ u8 added = false; ++ int i, ret = 0; ++ struct rtw_wlan_acl_node *paclnode; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ struct __queue *pacl_node_q =&pacl_list->acl_node_q; ++ ++ DBG_871X("%s(acl_num =%d) =" MAC_FMT "\n", __func__, pacl_list->num, MAC_ARG(addr)); ++ ++ if ((NUM_ACL-1) < pacl_list->num) ++ return (-1); ++ ++ ++ spin_lock_bh(&(pacl_node_q->lock)); ++ ++ phead = get_list_head(pacl_node_q); ++ plist = get_next(phead); ++ ++ while (phead != plist) ++ { ++ paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list); ++ plist = get_next(plist); ++ ++ if (!memcmp(paclnode->addr, addr, ETH_ALEN)) ++ { ++ if (paclnode->valid == true) ++ { ++ added = true; ++ DBG_871X("%s, sta has been added\n", __func__); ++ break; ++ } ++ } ++ } ++ ++ spin_unlock_bh(&(pacl_node_q->lock)); ++ ++ ++ if (added == true) ++ return ret; ++ ++ ++ spin_lock_bh(&(pacl_node_q->lock)); ++ ++ for (i = 0; i< NUM_ACL; i++) ++ { ++ paclnode = &pacl_list->aclnode[i]; ++ ++ if (paclnode->valid == false) ++ { ++ INIT_LIST_HEAD(&paclnode->list); ++ ++ memcpy(paclnode->addr, addr, ETH_ALEN); ++ ++ paclnode->valid = true; ++ ++ list_add_tail(&paclnode->list, get_list_head(pacl_node_q)); ++ ++ pacl_list->num++; ++ ++ break; ++ } ++ } ++ ++ DBG_871X("%s, acl_num =%d\n", __func__, pacl_list->num); ++ ++ spin_unlock_bh(&(pacl_node_q->lock)); ++ ++ return ret; ++} ++ ++int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr) ++{ ++ struct list_head *plist, *phead; ++ int ret = 0; ++ struct rtw_wlan_acl_node *paclnode; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ struct __queue *pacl_node_q =&pacl_list->acl_node_q; ++ u8 baddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; /* Baddr is used for clearing acl_list */ ++ ++ DBG_871X("%s(acl_num =%d) =" MAC_FMT "\n", __func__, pacl_list->num, MAC_ARG(addr)); ++ ++ spin_lock_bh(&(pacl_node_q->lock)); ++ ++ phead = get_list_head(pacl_node_q); ++ plist = get_next(phead); ++ ++ while (phead != plist) ++ { ++ paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list); ++ plist = get_next(plist); ++ ++ if (!memcmp(paclnode->addr, addr, ETH_ALEN) || !memcmp(baddr, addr, ETH_ALEN)) ++ { ++ if (paclnode->valid == true) ++ { ++ paclnode->valid = false; ++ ++ list_del_init(&paclnode->list); ++ ++ pacl_list->num--; ++ } ++ } ++ } ++ ++ spin_unlock_bh(&(pacl_node_q->lock)); ++ ++ DBG_871X("%s, acl_num =%d\n", __func__, pacl_list->num); ++ ++ return ret; ++ ++} ++ ++u8 rtw_ap_set_pairwise_key(struct adapter *padapter, struct sta_info *psta) ++{ ++ struct cmd_obj* ph2c; ++ struct set_stakey_parm *psetstakey_para; ++ struct cmd_priv *pcmdpriv =&padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ psetstakey_para = (struct set_stakey_parm*)rtw_zmalloc(sizeof(struct set_stakey_parm)); ++ if (psetstakey_para == NULL) { ++ kfree((u8 *) ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); ++ ++ ++ psetstakey_para->algorithm = (u8)psta->dot118021XPrivacy; ++ ++ memcpy(psetstakey_para->addr, psta->hwaddr, ETH_ALEN); ++ ++ memcpy(psetstakey_para->key, &psta->dot118021x_UncstKey, 16); ++ ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++ return res; ++ ++} ++ ++static int rtw_ap_set_key(struct adapter *padapter, u8 *key, u8 alg, int keyid, u8 set_tx) ++{ ++ u8 keylen; ++ struct cmd_obj* pcmd; ++ struct setkey_parm *psetkeyparm; ++ struct cmd_priv *pcmdpriv =&(padapter->cmdpriv); ++ int res = _SUCCESS; ++ ++ /* DBG_871X("%s\n", __func__); */ ++ ++ pcmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (pcmd == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ psetkeyparm =(struct setkey_parm*)rtw_zmalloc(sizeof(struct setkey_parm)); ++ if (psetkeyparm == NULL) { ++ kfree((unsigned char *)pcmd); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ memset(psetkeyparm, 0, sizeof(struct setkey_parm)); ++ ++ psetkeyparm->keyid =(u8)keyid; ++ if (is_wep_enc(alg)) ++ padapter->securitypriv.key_mask |= BIT(psetkeyparm->keyid); ++ ++ psetkeyparm->algorithm = alg; ++ ++ psetkeyparm->set_tx = set_tx; ++ ++ switch (alg) ++ { ++ case _WEP40_: ++ keylen = 5; ++ break; ++ case _WEP104_: ++ keylen = 13; ++ break; ++ case _TKIP_: ++ case _TKIP_WTMIC_: ++ case _AES_: ++ default: ++ keylen = 16; ++ } ++ ++ memcpy(&(psetkeyparm->key[0]), key, keylen); ++ ++ pcmd->cmdcode = _SetKey_CMD_; ++ pcmd->parmbuf = (u8 *)psetkeyparm; ++ pcmd->cmdsz = (sizeof(struct setkey_parm)); ++ pcmd->rsp = NULL; ++ pcmd->rspsz = 0; ++ ++ ++ INIT_LIST_HEAD(&pcmd->list); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, pcmd); ++ ++exit: ++ ++ return res; ++} ++ ++int rtw_ap_set_group_key(struct adapter *padapter, u8 *key, u8 alg, int keyid) ++{ ++ DBG_871X("%s\n", __func__); ++ ++ return rtw_ap_set_key(padapter, key, alg, keyid, 1); ++} ++ ++int rtw_ap_set_wep_key(struct adapter *padapter, u8 *key, u8 keylen, int keyid, u8 set_tx) ++{ ++ u8 alg; ++ ++ switch (keylen) ++ { ++ case 5: ++ alg = _WEP40_; ++ break; ++ case 13: ++ alg = _WEP104_; ++ break; ++ default: ++ alg = _NO_PRIVACY_; ++ } ++ ++ DBG_871X("%s\n", __func__); ++ ++ return rtw_ap_set_key(padapter, key, alg, keyid, set_tx); ++} ++ ++static void update_bcn_fixed_ie(struct adapter *padapter) ++{ ++ DBG_871X("%s\n", __func__); ++ ++} ++ ++static void update_bcn_erpinfo_ie(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); ++ unsigned char *p, *ie = pnetwork->IEs; ++ u32 len = 0; ++ ++ DBG_871X("%s, ERP_enable =%d\n", __func__, pmlmeinfo->ERP_enable); ++ ++ if (!pmlmeinfo->ERP_enable) ++ return; ++ ++ /* parsing ERP_IE */ ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); ++ if (p && len>0) ++ { ++ struct ndis_80211_var_ie * pIE = (struct ndis_80211_var_ie *)p; ++ ++ if (pmlmepriv->num_sta_non_erp == 1) ++ pIE->data[0] |= RTW_ERP_INFO_NON_ERP_PRESENT|RTW_ERP_INFO_USE_PROTECTION; ++ else ++ pIE->data[0] &= ~(RTW_ERP_INFO_NON_ERP_PRESENT|RTW_ERP_INFO_USE_PROTECTION); ++ ++ if (pmlmepriv->num_sta_no_short_preamble > 0) ++ pIE->data[0] |= RTW_ERP_INFO_BARKER_PREAMBLE_MODE; ++ else ++ pIE->data[0] &= ~(RTW_ERP_INFO_BARKER_PREAMBLE_MODE); ++ ++ ERP_IE_handler(padapter, pIE); ++ } ++ ++} ++ ++static void update_bcn_htcap_ie(struct adapter *padapter) ++{ ++ DBG_871X("%s\n", __func__); ++ ++} ++ ++static void update_bcn_htinfo_ie(struct adapter *padapter) ++{ ++ DBG_871X("%s\n", __func__); ++ ++} ++ ++static void update_bcn_rsn_ie(struct adapter *padapter) ++{ ++ DBG_871X("%s\n", __func__); ++ ++} ++ ++static void update_bcn_wpa_ie(struct adapter *padapter) ++{ ++ DBG_871X("%s\n", __func__); ++ ++} ++ ++static void update_bcn_wmm_ie(struct adapter *padapter) ++{ ++ DBG_871X("%s\n", __func__); ++ ++} ++ ++static void update_bcn_wps_ie(struct adapter *padapter) ++{ ++ u8 *pwps_ie = NULL, *pwps_ie_src, *premainder_ie, *pbackup_remainder_ie = NULL; ++ uint wps_ielen = 0, wps_offset, remainder_ielen; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); ++ unsigned char *ie = pnetwork->IEs; ++ u32 ielen = pnetwork->IELength; ++ ++ ++ DBG_871X("%s\n", __func__); ++ ++ pwps_ie = rtw_get_wps_ie(ie+_FIXED_IE_LENGTH_, ielen-_FIXED_IE_LENGTH_, NULL, &wps_ielen); ++ ++ if (pwps_ie == NULL || wps_ielen == 0) ++ return; ++ ++ pwps_ie_src = pmlmepriv->wps_beacon_ie; ++ if (pwps_ie_src == NULL) ++ return; ++ ++ wps_offset = (uint)(pwps_ie-ie); ++ ++ premainder_ie = pwps_ie + wps_ielen; ++ ++ remainder_ielen = ielen - wps_offset - wps_ielen; ++ ++ if (remainder_ielen>0) ++ { ++ pbackup_remainder_ie = rtw_malloc(remainder_ielen); ++ if (pbackup_remainder_ie) ++ memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); ++ } ++ ++ wps_ielen = (uint)pwps_ie_src[1];/* to get ie data len */ ++ if ((wps_offset+wps_ielen+2+remainder_ielen)<=MAX_IE_SZ) ++ { ++ memcpy(pwps_ie, pwps_ie_src, wps_ielen+2); ++ pwps_ie += (wps_ielen+2); ++ ++ if (pbackup_remainder_ie) ++ memcpy(pwps_ie, pbackup_remainder_ie, remainder_ielen); ++ ++ /* update IELength */ ++ pnetwork->IELength = wps_offset + (wps_ielen+2) + remainder_ielen; ++ } ++ ++ if (pbackup_remainder_ie) ++ kfree(pbackup_remainder_ie); ++ ++ /* deal with the case without set_tx_beacon_cmd() in update_beacon() */ ++#if defined(CONFIG_INTERRUPT_BASED_TXBCN) ++ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) ++ { ++ u8 sr = 0; ++ rtw_get_wps_attr_content(pwps_ie_src, wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, (u8 *)(&sr), NULL); ++ ++ if (sr) { ++ set_fwstate(pmlmepriv, WIFI_UNDER_WPS); ++ DBG_871X("%s, set WIFI_UNDER_WPS\n", __func__); ++ } ++ } ++#endif ++} ++ ++static void update_bcn_p2p_ie(struct adapter *padapter) ++{ ++ ++} ++ ++static void update_bcn_vendor_spec_ie(struct adapter *padapter, u8*oui) ++{ ++ DBG_871X("%s\n", __func__); ++ ++ if (!memcmp(RTW_WPA_OUI, oui, 4)) ++ { ++ update_bcn_wpa_ie(padapter); ++ } ++ else if (!memcmp(WMM_OUI, oui, 4)) ++ { ++ update_bcn_wmm_ie(padapter); ++ } ++ else if (!memcmp(WPS_OUI, oui, 4)) ++ { ++ update_bcn_wps_ie(padapter); ++ } ++ else if (!memcmp(P2P_OUI, oui, 4)) ++ { ++ update_bcn_p2p_ie(padapter); ++ } ++ else ++ { ++ DBG_871X("unknown OUI type!\n"); ++ } ++ ++ ++} ++ ++void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx) ++{ ++ struct mlme_priv *pmlmepriv; ++ struct mlme_ext_priv *pmlmeext; ++ /* struct mlme_ext_info *pmlmeinfo; */ ++ ++ /* DBG_871X("%s\n", __func__); */ ++ ++ if (!padapter) ++ return; ++ ++ pmlmepriv = &(padapter->mlmepriv); ++ pmlmeext = &(padapter->mlmeextpriv); ++ /* pmlmeinfo = &(pmlmeext->mlmext_info); */ ++ ++ if (false == pmlmeext->bstart_bss) ++ return; ++ ++ spin_lock_bh(&pmlmepriv->bcn_update_lock); ++ ++ switch (ie_id) ++ { ++ case 0xFF: ++ ++ update_bcn_fixed_ie(padapter);/* 8: TimeStamp, 2: Beacon Interval 2:Capability */ ++ ++ break; ++ ++ case _TIM_IE_: ++ ++ update_BCNTIM(padapter); ++ ++ break; ++ ++ case _ERPINFO_IE_: ++ ++ update_bcn_erpinfo_ie(padapter); ++ ++ break; ++ ++ case _HT_CAPABILITY_IE_: ++ ++ update_bcn_htcap_ie(padapter); ++ ++ break; ++ ++ case _RSN_IE_2_: ++ ++ update_bcn_rsn_ie(padapter); ++ ++ break; ++ ++ case _HT_ADD_INFO_IE_: ++ ++ update_bcn_htinfo_ie(padapter); ++ ++ break; ++ ++ case _VENDOR_SPECIFIC_IE_: ++ ++ update_bcn_vendor_spec_ie(padapter, oui); ++ ++ break; ++ ++ default: ++ break; ++ } ++ ++ pmlmepriv->update_bcn = true; ++ ++ spin_unlock_bh(&pmlmepriv->bcn_update_lock); ++ ++#ifndef CONFIG_INTERRUPT_BASED_TXBCN ++ if (tx) ++ { ++ /* send_beacon(padapter);//send_beacon must execute on TSR level */ ++ set_tx_beacon_cmd(padapter); ++ } ++#endif /* CONFIG_INTERRUPT_BASED_TXBCN */ ++ ++} ++ ++/* ++op_mode ++Set to 0 (HT pure) under the followign conditions ++ - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or ++ - all STAs in the BSS are 20 MHz HT in 20 MHz BSS ++Set to 1 (HT non-member protection) if there may be non-HT STAs ++ in both the primary and the secondary channel ++Set to 2 if only HT STAs are associated in BSS, ++ however and at least one 20 MHz HT STA is associated ++Set to 3 (HT mixed mode) when one or more non-HT STAs are associated ++ (currently non-GF HT station is considered as non-HT STA also) ++*/ ++static int rtw_ht_operation_update(struct adapter *padapter) ++{ ++ u16 cur_op_mode, new_op_mode; ++ int op_mode_changes = 0; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv; ++ ++ if (pmlmepriv->htpriv.ht_option == true) ++ return 0; ++ ++ /* if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed) */ ++ /* return 0; */ ++ ++ DBG_871X("%s current operation mode = 0x%X\n", ++ __func__, pmlmepriv->ht_op_mode); ++ ++ if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) ++ && pmlmepriv->num_sta_ht_no_gf) { ++ pmlmepriv->ht_op_mode |= ++ HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT; ++ op_mode_changes++; ++ } else if ((pmlmepriv->ht_op_mode & ++ HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) && ++ pmlmepriv->num_sta_ht_no_gf == 0) { ++ pmlmepriv->ht_op_mode &= ++ ~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT; ++ op_mode_changes++; ++ } ++ ++ if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) && ++ (pmlmepriv->num_sta_no_ht || pmlmepriv->olbc_ht)) { ++ pmlmepriv->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT; ++ op_mode_changes++; ++ } else if ((pmlmepriv->ht_op_mode & ++ HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) && ++ (pmlmepriv->num_sta_no_ht == 0 && !pmlmepriv->olbc_ht)) { ++ pmlmepriv->ht_op_mode &= ++ ~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT; ++ op_mode_changes++; ++ } ++ ++ /* Note: currently we switch to the MIXED op mode if HT non-greenfield ++ * station is associated. Probably it's a theoretical case, since ++ * it looks like all known HT STAs support greenfield. ++ */ ++ new_op_mode = 0; ++ if (pmlmepriv->num_sta_no_ht || ++ (pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)) ++ new_op_mode = OP_MODE_MIXED; ++ else if ((le16_to_cpu(phtpriv_ap->ht_cap.cap_info) & IEEE80211_HT_CAP_SUP_WIDTH) ++ && pmlmepriv->num_sta_ht_20mhz) ++ new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED; ++ else if (pmlmepriv->olbc_ht) ++ new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS; ++ else ++ new_op_mode = OP_MODE_PURE; ++ ++ cur_op_mode = pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK; ++ if (cur_op_mode != new_op_mode) { ++ pmlmepriv->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK; ++ pmlmepriv->ht_op_mode |= new_op_mode; ++ op_mode_changes++; ++ } ++ ++ DBG_871X("%s new operation mode = 0x%X changes =%d\n", ++ __func__, pmlmepriv->ht_op_mode, op_mode_changes); ++ ++ return op_mode_changes; ++ ++} ++ ++void associated_clients_update(struct adapter *padapter, u8 updated) ++{ ++ /* update associcated stations cap. */ ++ if (updated == true) ++ { ++ struct list_head *phead, *plist; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ ++ phead = &pstapriv->asoc_list; ++ plist = get_next(phead); ++ ++ /* check asoc_queue */ ++ while (phead != plist) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); ++ ++ plist = get_next(plist); ++ ++ VCS_update(padapter, psta); ++ } ++ ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ } ++ ++} ++ ++/* called > TSR LEVEL for USB or SDIO Interface*/ ++void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta) ++{ ++ u8 beacon_updated = false; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ ++ if (!(psta->flags & WLAN_STA_SHORT_PREAMBLE)) ++ { ++ if (!psta->no_short_preamble_set) ++ { ++ psta->no_short_preamble_set = 1; ++ ++ pmlmepriv->num_sta_no_short_preamble++; ++ ++ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && ++ (pmlmepriv->num_sta_no_short_preamble == 1)) ++ { ++ beacon_updated = true; ++ update_beacon(padapter, 0xFF, NULL, true); ++ } ++ ++ } ++ } ++ else ++ { ++ if (psta->no_short_preamble_set) ++ { ++ psta->no_short_preamble_set = 0; ++ ++ pmlmepriv->num_sta_no_short_preamble--; ++ ++ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && ++ (pmlmepriv->num_sta_no_short_preamble == 0)) ++ { ++ beacon_updated = true; ++ update_beacon(padapter, 0xFF, NULL, true); ++ } ++ ++ } ++ } ++ ++ if (psta->flags & WLAN_STA_NONERP) ++ { ++ if (!psta->nonerp_set) ++ { ++ psta->nonerp_set = 1; ++ ++ pmlmepriv->num_sta_non_erp++; ++ ++ if (pmlmepriv->num_sta_non_erp == 1) ++ { ++ beacon_updated = true; ++ update_beacon(padapter, _ERPINFO_IE_, NULL, true); ++ } ++ } ++ ++ } ++ else ++ { ++ if (psta->nonerp_set) ++ { ++ psta->nonerp_set = 0; ++ ++ pmlmepriv->num_sta_non_erp--; ++ ++ if (pmlmepriv->num_sta_non_erp == 0) ++ { ++ beacon_updated = true; ++ update_beacon(padapter, _ERPINFO_IE_, NULL, true); ++ } ++ } ++ ++ } ++ ++ ++ if (!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT)) ++ { ++ if (!psta->no_short_slot_time_set) ++ { ++ psta->no_short_slot_time_set = 1; ++ ++ pmlmepriv->num_sta_no_short_slot_time++; ++ ++ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && ++ (pmlmepriv->num_sta_no_short_slot_time == 1)) ++ { ++ beacon_updated = true; ++ update_beacon(padapter, 0xFF, NULL, true); ++ } ++ ++ } ++ } ++ else ++ { ++ if (psta->no_short_slot_time_set) ++ { ++ psta->no_short_slot_time_set = 0; ++ ++ pmlmepriv->num_sta_no_short_slot_time--; ++ ++ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && ++ (pmlmepriv->num_sta_no_short_slot_time == 0)) ++ { ++ beacon_updated = true; ++ update_beacon(padapter, 0xFF, NULL, true); ++ } ++ } ++ } ++ ++ if (psta->flags & WLAN_STA_HT) ++ { ++ u16 ht_capab = le16_to_cpu(psta->htpriv.ht_cap.cap_info); ++ ++ DBG_871X("HT: STA " MAC_FMT " HT Capabilities " ++ "Info: 0x%04x\n", MAC_ARG(psta->hwaddr), ht_capab); ++ ++ if (psta->no_ht_set) { ++ psta->no_ht_set = 0; ++ pmlmepriv->num_sta_no_ht--; ++ } ++ ++ if ((ht_capab & IEEE80211_HT_CAP_GRN_FLD) == 0) { ++ if (!psta->no_ht_gf_set) { ++ psta->no_ht_gf_set = 1; ++ pmlmepriv->num_sta_ht_no_gf++; ++ } ++ DBG_871X("%s STA " MAC_FMT " - no " ++ "greenfield, num of non-gf stations %d\n", ++ __func__, MAC_ARG(psta->hwaddr), ++ pmlmepriv->num_sta_ht_no_gf); ++ } ++ ++ if ((ht_capab & IEEE80211_HT_CAP_SUP_WIDTH) == 0) { ++ if (!psta->ht_20mhz_set) { ++ psta->ht_20mhz_set = 1; ++ pmlmepriv->num_sta_ht_20mhz++; ++ } ++ DBG_871X("%s STA " MAC_FMT " - 20 MHz HT, " ++ "num of 20MHz HT STAs %d\n", ++ __func__, MAC_ARG(psta->hwaddr), ++ pmlmepriv->num_sta_ht_20mhz); ++ } ++ ++ } ++ else ++ { ++ if (!psta->no_ht_set) { ++ psta->no_ht_set = 1; ++ pmlmepriv->num_sta_no_ht++; ++ } ++ if (pmlmepriv->htpriv.ht_option == true) { ++ DBG_871X("%s STA " MAC_FMT ++ " - no HT, num of non-HT stations %d\n", ++ __func__, MAC_ARG(psta->hwaddr), ++ pmlmepriv->num_sta_no_ht); ++ } ++ } ++ ++ if (rtw_ht_operation_update(padapter) > 0) ++ { ++ update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, false); ++ update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true); ++ } ++ ++ /* update associcated stations cap. */ ++ associated_clients_update(padapter, beacon_updated); ++ ++ DBG_871X("%s, updated =%d\n", __func__, beacon_updated); ++ ++} ++ ++u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta) ++{ ++ u8 beacon_updated = false; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ ++ if (!psta) ++ return beacon_updated; ++ ++ if (psta->no_short_preamble_set) { ++ psta->no_short_preamble_set = 0; ++ pmlmepriv->num_sta_no_short_preamble--; ++ if (pmlmeext->cur_wireless_mode > WIRELESS_11B ++ && pmlmepriv->num_sta_no_short_preamble == 0) ++ { ++ beacon_updated = true; ++ update_beacon(padapter, 0xFF, NULL, true); ++ } ++ } ++ ++ if (psta->nonerp_set) { ++ psta->nonerp_set = 0; ++ pmlmepriv->num_sta_non_erp--; ++ if (pmlmepriv->num_sta_non_erp == 0) ++ { ++ beacon_updated = true; ++ update_beacon(padapter, _ERPINFO_IE_, NULL, true); ++ } ++ } ++ ++ if (psta->no_short_slot_time_set) { ++ psta->no_short_slot_time_set = 0; ++ pmlmepriv->num_sta_no_short_slot_time--; ++ if (pmlmeext->cur_wireless_mode > WIRELESS_11B ++ && pmlmepriv->num_sta_no_short_slot_time == 0) ++ { ++ beacon_updated = true; ++ update_beacon(padapter, 0xFF, NULL, true); ++ } ++ } ++ ++ if (psta->no_ht_gf_set) { ++ psta->no_ht_gf_set = 0; ++ pmlmepriv->num_sta_ht_no_gf--; ++ } ++ ++ if (psta->no_ht_set) { ++ psta->no_ht_set = 0; ++ pmlmepriv->num_sta_no_ht--; ++ } ++ ++ if (psta->ht_20mhz_set) { ++ psta->ht_20mhz_set = 0; ++ pmlmepriv->num_sta_ht_20mhz--; ++ } ++ ++ if (rtw_ht_operation_update(padapter) > 0) ++ { ++ update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, false); ++ update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true); ++ } ++ ++ /* update associcated stations cap. */ ++ /* associated_clients_update(padapter, beacon_updated); //move it to avoid deadlock */ ++ ++ DBG_871X("%s, updated =%d\n", __func__, beacon_updated); ++ ++ return beacon_updated; ++ ++} ++ ++u8 ap_free_sta(struct adapter *padapter, struct sta_info *psta, bool active, u16 reason) ++{ ++ u8 beacon_updated = false; ++ ++ if (!psta) ++ return beacon_updated; ++ ++ if (active == true) ++ { ++ /* tear down Rx AMPDU */ ++ send_delba(padapter, 0, psta->hwaddr);/* recipient */ ++ ++ /* tear down TX AMPDU */ ++ send_delba(padapter, 1, psta->hwaddr);/* // originator */ ++ ++ issue_deauth(padapter, psta->hwaddr, reason); ++ } ++ ++ psta->htpriv.agg_enable_bitmap = 0x0;/* reset */ ++ psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */ ++ ++ ++ /* report_del_sta_event(padapter, psta->hwaddr, reason); */ ++ ++ /* clear cam entry / key */ ++ rtw_clearstakey_cmd(padapter, psta, true); ++ ++ ++ spin_lock_bh(&psta->lock); ++ psta->state &= ~_FW_LINKED; ++ spin_unlock_bh(&psta->lock); ++ ++ rtw_cfg80211_indicate_sta_disassoc(padapter, psta->hwaddr, reason); ++ ++ report_del_sta_event(padapter, psta->hwaddr, reason); ++ ++ beacon_updated = bss_cap_update_on_sta_leave(padapter, psta); ++ ++ rtw_free_stainfo(padapter, psta); ++ ++ ++ return beacon_updated; ++ ++} ++ ++int rtw_sta_flush(struct adapter *padapter) ++{ ++ struct list_head *phead, *plist; ++ int ret = 0; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev)); ++ ++ if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) ++ return ret; ++ ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ phead = &pstapriv->asoc_list; ++ plist = get_next(phead); ++ ++ /* free sta asoc_queue */ ++ while (phead != plist) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); ++ ++ plist = get_next(plist); ++ ++ list_del_init(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ ++ /* spin_unlock_bh(&pstapriv->asoc_list_lock); */ ++ ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING); ++ /* spin_lock_bh(&pstapriv->asoc_list_lock); */ ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ ++ issue_deauth(padapter, bc_addr, WLAN_REASON_DEAUTH_LEAVING); ++ ++ associated_clients_update(padapter, true); ++ ++ return ret; ++ ++} ++ ++/* called > TSR LEVEL for USB or SDIO Interface*/ ++void sta_info_update(struct adapter *padapter, struct sta_info *psta) ++{ ++ int flags = psta->flags; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ ++ /* update wmm cap. */ ++ if (WLAN_STA_WME&flags) ++ psta->qos_option = 1; ++ else ++ psta->qos_option = 0; ++ ++ if (pmlmepriv->qospriv.qos_option == 0) ++ psta->qos_option = 0; ++ ++ /* update 802.11n ht cap. */ ++ if (WLAN_STA_HT&flags) ++ { ++ psta->htpriv.ht_option = true; ++ psta->qos_option = 1; ++ } ++ else ++ { ++ psta->htpriv.ht_option = false; ++ } ++ ++ if (pmlmepriv->htpriv.ht_option == false) ++ psta->htpriv.ht_option = false; ++ ++ update_sta_info_apmode(padapter, psta); ++ ++ ++} ++ ++/* called >= TSR LEVEL for USB or SDIO Interface*/ ++void ap_sta_info_defer_update(struct adapter *padapter, struct sta_info *psta) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if (psta->state & _FW_LINKED) ++ { ++ pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta; ++ ++ /* add ratid */ ++ add_RATid(padapter, psta, 0);/* DM_RATR_STA_INIT */ ++ } ++} ++/* restore hw setting from sw data structures */ ++void rtw_ap_restore_network(struct adapter *padapter) ++{ ++ struct mlme_priv *mlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct sta_priv * pstapriv = &padapter->stapriv; ++ struct sta_info *psta; ++ struct security_priv* psecuritypriv =&(padapter->securitypriv); ++ struct list_head *phead, *plist; ++ u8 chk_alive_num = 0; ++ char chk_alive_list[NUM_STA]; ++ int i; ++ ++ rtw_setopmode_cmd(padapter, Ndis802_11APMode, false); ++ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ ++ start_bss_network(padapter, (u8 *)&mlmepriv->cur_network.network); ++ ++ if ((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) || ++ (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) ++ { ++ /* restore group key, WEP keys is restored in ips_leave() */ ++ rtw_set_key(padapter, psecuritypriv, psecuritypriv->dot118021XGrpKeyid, 0, false); ++ } ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ ++ phead = &pstapriv->asoc_list; ++ plist = get_next(phead); ++ ++ while (phead != plist) { ++ int stainfo_offset; ++ ++ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); ++ plist = get_next(plist); ++ ++ stainfo_offset = rtw_stainfo_offset(pstapriv, psta); ++ if (stainfo_offset_valid(stainfo_offset)) { ++ chk_alive_list[chk_alive_num++] = stainfo_offset; ++ } ++ } ++ ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ for (i = 0; i < chk_alive_num; i++) { ++ psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]); ++ ++ if (psta == NULL) { ++ DBG_871X(FUNC_ADPT_FMT" sta_info is null\n", FUNC_ADPT_ARG(padapter)); ++ } else if (psta->state &_FW_LINKED) { ++ rtw_sta_media_status_rpt(padapter, psta, 1); ++ Update_RA_Entry(padapter, psta); ++ /* pairwise key */ ++ /* per sta pairwise key and settings */ ++ if ((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) || ++ (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) ++ { ++ rtw_setstakey_cmd(padapter, psta, true, false); ++ } ++ } ++ } ++ ++} ++ ++void start_ap_mode(struct adapter *padapter) ++{ ++ int i; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ ++ pmlmepriv->update_bcn = false; ++ ++ /* init_mlme_ap_info(padapter); */ ++ pmlmeext->bstart_bss = false; ++ ++ pmlmepriv->num_sta_non_erp = 0; ++ ++ pmlmepriv->num_sta_no_short_slot_time = 0; ++ ++ pmlmepriv->num_sta_no_short_preamble = 0; ++ ++ pmlmepriv->num_sta_ht_no_gf = 0; ++ pmlmepriv->num_sta_no_ht = 0; ++ pmlmepriv->num_sta_ht_20mhz = 0; ++ ++ pmlmepriv->olbc = false; ++ ++ pmlmepriv->olbc_ht = false; ++ ++ pmlmepriv->ht_op_mode = 0; ++ ++ for (i = 0; ista_aid[i] = NULL; ++ ++ pmlmepriv->wps_beacon_ie = NULL; ++ pmlmepriv->wps_probe_resp_ie = NULL; ++ pmlmepriv->wps_assoc_resp_ie = NULL; ++ ++ pmlmepriv->p2p_beacon_ie = NULL; ++ pmlmepriv->p2p_probe_resp_ie = NULL; ++ ++ ++ /* for ACL */ ++ INIT_LIST_HEAD(&(pacl_list->acl_node_q.queue)); ++ pacl_list->num = 0; ++ pacl_list->mode = 0; ++ for (i = 0; i < NUM_ACL; i++) { ++ INIT_LIST_HEAD(&pacl_list->aclnode[i].list); ++ pacl_list->aclnode[i].valid = false; ++ } ++ ++} ++ ++void stop_ap_mode(struct adapter *padapter) ++{ ++ struct list_head *phead, *plist; ++ struct rtw_wlan_acl_node *paclnode; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ struct __queue *pacl_node_q =&pacl_list->acl_node_q; ++ ++ pmlmepriv->update_bcn = false; ++ pmlmeext->bstart_bss = false; ++ ++ /* reset and init security priv , this can refine with rtw_reset_securitypriv */ ++ memset((unsigned char *)&padapter->securitypriv, 0, sizeof (struct security_priv)); ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled; ++ ++ /* for ACL */ ++ spin_lock_bh(&(pacl_node_q->lock)); ++ phead = get_list_head(pacl_node_q); ++ plist = get_next(phead); ++ while (phead != plist) ++ { ++ paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list); ++ plist = get_next(plist); ++ ++ if (paclnode->valid == true) ++ { ++ paclnode->valid = false; ++ ++ list_del_init(&paclnode->list); ++ ++ pacl_list->num--; ++ } ++ } ++ spin_unlock_bh(&(pacl_node_q->lock)); ++ ++ DBG_871X("%s, free acl_node_queue, num =%d\n", __func__, pacl_list->num); ++ ++ rtw_sta_flush(padapter); ++ ++ /* free_assoc_sta_resources */ ++ rtw_free_all_stainfo(padapter); ++ ++ psta = rtw_get_bcmc_stainfo(padapter); ++ rtw_free_stainfo(padapter, psta); ++ ++ rtw_init_bcmc_stainfo(padapter); ++ ++ rtw_free_mlme_priv_ie_data(pmlmepriv); ++ ++ rtw_btcoex_MediaStatusNotify(padapter, 0); /* disconnect */ ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_btcoex.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_btcoex.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_btcoex.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_btcoex.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,253 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2013 Realtek 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. ++ * ++ ******************************************************************************/ ++#include ++#include ++#include ++#include ++ ++ ++void rtw_btcoex_Initialize(struct adapter *padapter) ++{ ++ hal_btcoex_Initialize(padapter); ++} ++ ++void rtw_btcoex_PowerOnSetting(struct adapter *padapter) ++{ ++ hal_btcoex_PowerOnSetting(padapter); ++} ++ ++void rtw_btcoex_HAL_Initialize(struct adapter *padapter, u8 bWifiOnly) ++{ ++ hal_btcoex_InitHwConfig(padapter, bWifiOnly); ++} ++ ++void rtw_btcoex_IpsNotify(struct adapter *padapter, u8 type) ++{ ++ hal_btcoex_IpsNotify(padapter, type); ++} ++ ++void rtw_btcoex_LpsNotify(struct adapter *padapter, u8 type) ++{ ++ hal_btcoex_LpsNotify(padapter, type); ++} ++ ++void rtw_btcoex_ScanNotify(struct adapter *padapter, u8 type) ++{ ++ hal_btcoex_ScanNotify(padapter, type); ++} ++ ++void rtw_btcoex_ConnectNotify(struct adapter *padapter, u8 action) ++{ ++ hal_btcoex_ConnectNotify(padapter, action); ++} ++ ++void rtw_btcoex_MediaStatusNotify(struct adapter *padapter, u8 mediaStatus) ++{ ++ if ((RT_MEDIA_CONNECT == mediaStatus) ++ && (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true)) ++ { ++ rtw_hal_set_hwreg(padapter, HW_VAR_DL_RSVD_PAGE, NULL); ++ } ++ ++ hal_btcoex_MediaStatusNotify(padapter, mediaStatus); ++} ++ ++void rtw_btcoex_SpecialPacketNotify(struct adapter *padapter, u8 pktType) ++{ ++ hal_btcoex_SpecialPacketNotify(padapter, pktType); ++} ++ ++void rtw_btcoex_IQKNotify(struct adapter *padapter, u8 state) ++{ ++ hal_btcoex_IQKNotify(padapter, state); ++} ++ ++void rtw_btcoex_BtInfoNotify(struct adapter *padapter, u8 length, u8 *tmpBuf) ++{ ++ hal_btcoex_BtInfoNotify(padapter, length, tmpBuf); ++} ++ ++void rtw_btcoex_SuspendNotify(struct adapter *padapter, u8 state) ++{ ++ hal_btcoex_SuspendNotify(padapter, state); ++} ++ ++void rtw_btcoex_HaltNotify(struct adapter *padapter) ++{ ++ if (false == padapter->bup) ++ { ++ DBG_871X(FUNC_ADPT_FMT ": bup =%d Skip!\n", ++ FUNC_ADPT_ARG(padapter), padapter->bup); ++ ++ return; ++ } ++ ++ if (true == padapter->bSurpriseRemoved) ++ { ++ DBG_871X(FUNC_ADPT_FMT ": bSurpriseRemoved =%d Skip!\n", ++ FUNC_ADPT_ARG(padapter), padapter->bSurpriseRemoved); ++ ++ return; ++ } ++ ++ hal_btcoex_HaltNotify(padapter); ++} ++ ++u8 rtw_btcoex_IsBtDisabled(struct adapter *padapter) ++{ ++ return hal_btcoex_IsBtDisabled(padapter); ++} ++ ++void rtw_btcoex_Handler(struct adapter *padapter) ++{ ++ hal_btcoex_Hanlder(padapter); ++} ++ ++s32 rtw_btcoex_IsBTCoexCtrlAMPDUSize(struct adapter *padapter) ++{ ++ s32 coexctrl; ++ ++ coexctrl = hal_btcoex_IsBTCoexCtrlAMPDUSize(padapter); ++ ++ return coexctrl; ++} ++ ++void rtw_btcoex_SetManualControl(struct adapter *padapter, u8 manual) ++{ ++ if (true == manual) ++ { ++ hal_btcoex_SetManualControl(padapter, true); ++ } ++ else ++ { ++ hal_btcoex_SetManualControl(padapter, false); ++ } ++} ++ ++u8 rtw_btcoex_IsBtControlLps(struct adapter *padapter) ++{ ++ return hal_btcoex_IsBtControlLps(padapter); ++} ++ ++u8 rtw_btcoex_IsLpsOn(struct adapter *padapter) ++{ ++ return hal_btcoex_IsLpsOn(padapter); ++} ++ ++u8 rtw_btcoex_RpwmVal(struct adapter *padapter) ++{ ++ return hal_btcoex_RpwmVal(padapter); ++} ++ ++u8 rtw_btcoex_LpsVal(struct adapter *padapter) ++{ ++ return hal_btcoex_LpsVal(padapter); ++} ++ ++void rtw_btcoex_SetBTCoexist(struct adapter *padapter, u8 bBtExist) ++{ ++ hal_btcoex_SetBTCoexist(padapter, bBtExist); ++} ++ ++void rtw_btcoex_SetChipType(struct adapter *padapter, u8 chipType) ++{ ++ hal_btcoex_SetChipType(padapter, chipType); ++} ++ ++void rtw_btcoex_SetPGAntNum(struct adapter *padapter, u8 antNum) ++{ ++ hal_btcoex_SetPgAntNum(padapter, antNum); ++} ++ ++void rtw_btcoex_SetSingleAntPath(struct adapter *padapter, u8 singleAntPath) ++{ ++ hal_btcoex_SetSingleAntPath(padapter, singleAntPath); ++} ++ ++u32 rtw_btcoex_GetRaMask(struct adapter *padapter) ++{ ++ return hal_btcoex_GetRaMask(padapter); ++} ++ ++void rtw_btcoex_RecordPwrMode(struct adapter *padapter, u8 *pCmdBuf, u8 cmdLen) ++{ ++ hal_btcoex_RecordPwrMode(padapter, pCmdBuf, cmdLen); ++} ++ ++void rtw_btcoex_DisplayBtCoexInfo(struct adapter *padapter, u8 *pbuf, u32 bufsize) ++{ ++ hal_btcoex_DisplayBtCoexInfo(padapter, pbuf, bufsize); ++} ++ ++void rtw_btcoex_SetDBG(struct adapter *padapter, u32 *pDbgModule) ++{ ++ hal_btcoex_SetDBG(padapter, pDbgModule); ++} ++ ++u32 rtw_btcoex_GetDBG(struct adapter *padapter, u8 *pStrBuf, u32 bufSize) ++{ ++ return hal_btcoex_GetDBG(padapter, pStrBuf, bufSize); ++} ++ ++/* ================================================== */ ++/* Below Functions are called by BT-Coex */ ++/* ================================================== */ ++void rtw_btcoex_RejectApAggregatedPacket(struct adapter *padapter, u8 enable) ++{ ++ struct mlme_ext_info *pmlmeinfo; ++ struct sta_info *psta; ++ ++ pmlmeinfo = &padapter->mlmeextpriv.mlmext_info; ++ psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(&padapter->mlmepriv)); ++ ++ if (true == enable) ++ { ++ pmlmeinfo->bAcceptAddbaReq = false; ++ if (psta) ++ send_delba(padapter, 0, psta->hwaddr); ++ } ++ else ++ { ++ pmlmeinfo->bAcceptAddbaReq = true; ++ } ++} ++ ++void rtw_btcoex_LPS_Enter(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv; ++ u8 lpsVal; ++ ++ ++ pwrpriv = adapter_to_pwrctl(padapter); ++ ++ pwrpriv->bpower_saving = true; ++ lpsVal = rtw_btcoex_LpsVal(padapter); ++ rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, lpsVal, "BTCOEX"); ++} ++ ++void rtw_btcoex_LPS_Leave(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv; ++ ++ ++ pwrpriv = adapter_to_pwrctl(padapter); ++ ++ if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) ++ { ++ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, "BTCOEX"); ++ LPS_RF_ON_check(padapter, 100); ++ pwrpriv->bpower_saving = false; ++ } ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_cmd.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_cmd.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_cmd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_cmd.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,2322 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTW_CMD_C_ ++ ++#include ++#include ++#include ++ ++static struct _cmd_callback rtw_cmd_callback[] = ++{ ++ {GEN_CMD_CODE(_Read_MACREG), NULL}, /*0*/ ++ {GEN_CMD_CODE(_Write_MACREG), NULL}, ++ {GEN_CMD_CODE(_Read_BBREG), &rtw_getbbrfreg_cmdrsp_callback}, ++ {GEN_CMD_CODE(_Write_BBREG), NULL}, ++ {GEN_CMD_CODE(_Read_RFREG), &rtw_getbbrfreg_cmdrsp_callback}, ++ {GEN_CMD_CODE(_Write_RFREG), NULL}, /*5*/ ++ {GEN_CMD_CODE(_Read_EEPROM), NULL}, ++ {GEN_CMD_CODE(_Write_EEPROM), NULL}, ++ {GEN_CMD_CODE(_Read_EFUSE), NULL}, ++ {GEN_CMD_CODE(_Write_EFUSE), NULL}, ++ ++ {GEN_CMD_CODE(_Read_CAM), NULL}, /*10*/ ++ {GEN_CMD_CODE(_Write_CAM), NULL}, ++ {GEN_CMD_CODE(_setBCNITV), NULL}, ++ {GEN_CMD_CODE(_setMBIDCFG), NULL}, ++ {GEN_CMD_CODE(_JoinBss), &rtw_joinbss_cmd_callback}, /*14*/ ++ {GEN_CMD_CODE(_DisConnect), &rtw_disassoc_cmd_callback}, /*15*/ ++ {GEN_CMD_CODE(_CreateBss), &rtw_createbss_cmd_callback}, ++ {GEN_CMD_CODE(_SetOpMode), NULL}, ++ {GEN_CMD_CODE(_SiteSurvey), &rtw_survey_cmd_callback}, /*18*/ ++ {GEN_CMD_CODE(_SetAuth), NULL}, ++ ++ {GEN_CMD_CODE(_SetKey), NULL}, /*20*/ ++ {GEN_CMD_CODE(_SetStaKey), &rtw_setstaKey_cmdrsp_callback}, ++ {GEN_CMD_CODE(_SetAssocSta), &rtw_setassocsta_cmdrsp_callback}, ++ {GEN_CMD_CODE(_DelAssocSta), NULL}, ++ {GEN_CMD_CODE(_SetStaPwrState), NULL}, ++ {GEN_CMD_CODE(_SetBasicRate), NULL}, /*25*/ ++ {GEN_CMD_CODE(_GetBasicRate), NULL}, ++ {GEN_CMD_CODE(_SetDataRate), NULL}, ++ {GEN_CMD_CODE(_GetDataRate), NULL}, ++ {GEN_CMD_CODE(_SetPhyInfo), NULL}, ++ ++ {GEN_CMD_CODE(_GetPhyInfo), NULL}, /*30*/ ++ {GEN_CMD_CODE(_SetPhy), NULL}, ++ {GEN_CMD_CODE(_GetPhy), NULL}, ++ {GEN_CMD_CODE(_readRssi), NULL}, ++ {GEN_CMD_CODE(_readGain), NULL}, ++ {GEN_CMD_CODE(_SetAtim), NULL}, /*35*/ ++ {GEN_CMD_CODE(_SetPwrMode), NULL}, ++ {GEN_CMD_CODE(_JoinbssRpt), NULL}, ++ {GEN_CMD_CODE(_SetRaTable), NULL}, ++ {GEN_CMD_CODE(_GetRaTable) , NULL}, ++ ++ {GEN_CMD_CODE(_GetCCXReport), NULL}, /*40*/ ++ {GEN_CMD_CODE(_GetDTMReport), NULL}, ++ {GEN_CMD_CODE(_GetTXRateStatistics), NULL}, ++ {GEN_CMD_CODE(_SetUsbSuspend), NULL}, ++ {GEN_CMD_CODE(_SetH2cLbk), NULL}, ++ {GEN_CMD_CODE(_AddBAReq), NULL}, /*45*/ ++ {GEN_CMD_CODE(_SetChannel), NULL}, /*46*/ ++ {GEN_CMD_CODE(_SetTxPower), NULL}, ++ {GEN_CMD_CODE(_SwitchAntenna), NULL}, ++ {GEN_CMD_CODE(_SetCrystalCap), NULL}, ++ {GEN_CMD_CODE(_SetSingleCarrierTx), NULL}, /*50*/ ++ ++ {GEN_CMD_CODE(_SetSingleToneTx), NULL}, /*51*/ ++ {GEN_CMD_CODE(_SetCarrierSuppressionTx), NULL}, ++ {GEN_CMD_CODE(_SetContinuousTx), NULL}, ++ {GEN_CMD_CODE(_SwitchBandwidth), NULL}, /*54*/ ++ {GEN_CMD_CODE(_TX_Beacon), NULL},/*55*/ ++ ++ {GEN_CMD_CODE(_Set_MLME_EVT), NULL},/*56*/ ++ {GEN_CMD_CODE(_Set_Drv_Extra), NULL},/*57*/ ++ {GEN_CMD_CODE(_Set_H2C_MSG), NULL},/*58*/ ++ {GEN_CMD_CODE(_SetChannelPlan), NULL},/*59*/ ++ {GEN_CMD_CODE(_LedBlink), NULL},/*60*/ ++ ++ {GEN_CMD_CODE(_SetChannelSwitch), NULL},/*61*/ ++ {GEN_CMD_CODE(_TDLS), NULL},/*62*/ ++ {GEN_CMD_CODE(_ChkBMCSleepq), NULL}, /*63*/ ++ ++ {GEN_CMD_CODE(_RunInThreadCMD), NULL},/*64*/ ++}; ++ ++static struct cmd_hdl wlancmds[] = { ++ GEN_DRV_CMD_HANDLER(0, NULL) /*0*/ ++ GEN_DRV_CMD_HANDLER(0, NULL) ++ GEN_DRV_CMD_HANDLER(0, NULL) ++ GEN_DRV_CMD_HANDLER(0, NULL) ++ GEN_DRV_CMD_HANDLER(0, NULL) ++ GEN_DRV_CMD_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) /*10*/ ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct joinbss_parm), join_cmd_hdl) /*14*/ ++ GEN_MLME_EXT_HANDLER(sizeof (struct disconnect_parm), disconnect_hdl) ++ GEN_MLME_EXT_HANDLER(sizeof (struct createbss_parm), createbss_hdl) ++ GEN_MLME_EXT_HANDLER(sizeof (struct setopmode_parm), setopmode_hdl) ++ GEN_MLME_EXT_HANDLER(sizeof (struct sitesurvey_parm), sitesurvey_cmd_hdl) /*18*/ ++ GEN_MLME_EXT_HANDLER(sizeof (struct setauth_parm), setauth_hdl) ++ GEN_MLME_EXT_HANDLER(sizeof (struct setkey_parm), setkey_hdl) /*20*/ ++ GEN_MLME_EXT_HANDLER(sizeof (struct set_stakey_parm), set_stakey_hdl) ++ GEN_MLME_EXT_HANDLER(sizeof (struct set_assocsta_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct del_assocsta_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct setstapwrstate_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct setbasicrate_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct getbasicrate_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct setdatarate_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct getdatarate_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct setphyinfo_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct getphyinfo_parm), NULL) /*30*/ ++ GEN_MLME_EXT_HANDLER(sizeof (struct setphy_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct getphy_parm), NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) /*40*/ ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(sizeof(struct addBaReq_parm), add_ba_hdl) ++ GEN_MLME_EXT_HANDLER(sizeof(struct set_ch_parm), set_ch_hdl) /* 46 */ ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) /*50*/ ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(0, NULL) ++ GEN_MLME_EXT_HANDLER(sizeof(struct Tx_Beacon_param), tx_beacon_hdl) /*55*/ ++ ++ GEN_MLME_EXT_HANDLER(0, mlme_evt_hdl) /*56*/ ++ GEN_MLME_EXT_HANDLER(0, rtw_drvextra_cmd_hdl) /*57*/ ++ ++ GEN_MLME_EXT_HANDLER(0, h2c_msg_hdl) /*58*/ ++ GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelPlan_param), set_chplan_hdl) /*59*/ ++ GEN_MLME_EXT_HANDLER(sizeof(struct LedBlink_param), led_blink_hdl) /*60*/ ++ ++ GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelSwitch_param), set_csa_hdl) /*61*/ ++ GEN_MLME_EXT_HANDLER(sizeof(struct TDLSoption_param), tdls_hdl) /*62*/ ++ GEN_MLME_EXT_HANDLER(0, chk_bmc_sleepq_hdl) /*63*/ ++ GEN_MLME_EXT_HANDLER(sizeof(struct RunInThread_param), run_in_thread_hdl) /*63*/ ++}; ++ ++/* ++Caller and the rtw_cmd_thread can protect cmd_q by spin_lock. ++No irqsave is necessary. ++*/ ++ ++sint _rtw_init_cmd_priv (struct cmd_priv *pcmdpriv) ++{ ++ sint res = _SUCCESS; ++ ++ sema_init(&(pcmdpriv->cmd_queue_sema), 0); ++ /* sema_init(&(pcmdpriv->cmd_done_sema), 0); */ ++ sema_init(&(pcmdpriv->terminate_cmdthread_sema), 0); ++ ++ ++ _rtw_init_queue(&(pcmdpriv->cmd_queue)); ++ ++ /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ ++ ++ pcmdpriv->cmd_seq = 1; ++ ++ pcmdpriv->cmd_allocated_buf = rtw_zmalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ); ++ ++ if (pcmdpriv->cmd_allocated_buf == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf + CMDBUFF_ALIGN_SZ - ((SIZE_PTR)(pcmdpriv->cmd_allocated_buf) & (CMDBUFF_ALIGN_SZ-1)); ++ ++ pcmdpriv->rsp_allocated_buf = rtw_zmalloc(MAX_RSPSZ + 4); ++ ++ if (pcmdpriv->rsp_allocated_buf == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf + 4 - ((SIZE_PTR)(pcmdpriv->rsp_allocated_buf) & 3); ++ ++ pcmdpriv->cmd_issued_cnt = pcmdpriv->cmd_done_cnt = pcmdpriv->rsp_cnt = 0; ++ ++ mutex_init(&pcmdpriv->sctx_mutex); ++exit: ++ return res; ++} ++ ++static void c2h_wk_callback(_workitem *work); ++sint _rtw_init_evt_priv(struct evt_priv *pevtpriv) ++{ ++ sint res = _SUCCESS; ++ ++ /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ ++ atomic_set(&pevtpriv->event_seq, 0); ++ pevtpriv->evt_done_cnt = 0; ++ ++ _init_workitem(&pevtpriv->c2h_wk, c2h_wk_callback, NULL); ++ pevtpriv->c2h_wk_alive = false; ++ pevtpriv->c2h_queue = rtw_cbuf_alloc(C2H_QUEUE_MAX_LEN+1); ++ ++ return res; ++} ++ ++void _rtw_free_evt_priv (struct evt_priv *pevtpriv) ++{ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+_rtw_free_evt_priv\n")); ++ ++ _cancel_workitem_sync(&pevtpriv->c2h_wk); ++ while (pevtpriv->c2h_wk_alive) ++ msleep(10); ++ ++ while (!rtw_cbuf_empty(pevtpriv->c2h_queue)) { ++ void *c2h; ++ if ((c2h = rtw_cbuf_pop(pevtpriv->c2h_queue)) != NULL ++ && c2h != (void *)pevtpriv) { ++ kfree(c2h); ++ } ++ } ++ kfree(pevtpriv->c2h_queue); ++ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("-_rtw_free_evt_priv\n")); ++} ++ ++void _rtw_free_cmd_priv (struct cmd_priv *pcmdpriv) ++{ ++ if (pcmdpriv) { ++ if (pcmdpriv->cmd_allocated_buf) ++ kfree(pcmdpriv->cmd_allocated_buf); ++ ++ if (pcmdpriv->rsp_allocated_buf) ++ kfree(pcmdpriv->rsp_allocated_buf); ++ ++ mutex_destroy(&pcmdpriv->sctx_mutex); ++ } ++} ++ ++/* ++Calling Context: ++ ++rtw_enqueue_cmd can only be called between kernel thread, ++since only spin_lock is used. ++ ++ISR/Call-Back functions can't call this sub-function. ++ ++*/ ++ ++sint _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj) ++{ ++ _irqL irqL; ++ ++ if (obj == NULL) ++ goto exit; ++ ++ /* spin_lock_bh(&queue->lock); */ ++ spin_lock_irqsave(&queue->lock, irqL); ++ ++ list_add_tail(&obj->list, &queue->queue); ++ ++ /* spin_unlock_bh(&queue->lock); */ ++ spin_unlock_irqrestore(&queue->lock, irqL); ++ ++exit: ++ return _SUCCESS; ++} ++ ++struct cmd_obj *_rtw_dequeue_cmd(struct __queue *queue) ++{ ++ _irqL irqL; ++ struct cmd_obj *obj; ++ ++ /* spin_lock_bh(&(queue->lock)); */ ++ spin_lock_irqsave(&queue->lock, irqL); ++ if (list_empty(&(queue->queue))) ++ obj = NULL; ++ else ++ { ++ obj = LIST_CONTAINOR(get_next(&(queue->queue)), struct cmd_obj, list); ++ list_del_init(&obj->list); ++ } ++ ++ /* spin_unlock_bh(&(queue->lock)); */ ++ spin_unlock_irqrestore(&queue->lock, irqL); ++ ++ return obj; ++} ++ ++u32 rtw_init_cmd_priv(struct cmd_priv *pcmdpriv) ++{ ++ u32 res; ++ ++ res = _rtw_init_cmd_priv (pcmdpriv); ++ return res; ++} ++ ++u32 rtw_init_evt_priv (struct evt_priv *pevtpriv) ++{ ++ int res; ++ ++ res = _rtw_init_evt_priv(pevtpriv); ++ return res; ++} ++ ++void rtw_free_evt_priv (struct evt_priv *pevtpriv) ++{ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("rtw_free_evt_priv\n")); ++ _rtw_free_evt_priv(pevtpriv); ++} ++ ++void rtw_free_cmd_priv (struct cmd_priv *pcmdpriv) ++{ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("rtw_free_cmd_priv\n")); ++ _rtw_free_cmd_priv(pcmdpriv); ++} ++ ++int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj); ++int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) ++{ ++ u8 bAllow = false; /* set to true to allow enqueuing cmd when hw_init_completed is false */ ++ ++ if (cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan)) ++ bAllow = true; ++ ++ if ((pcmdpriv->padapter->hw_init_completed ==false && bAllow == false) ++ || atomic_read(&(pcmdpriv->cmdthd_running)) == false /* com_thread not running */ ++ ) ++ { ++ /* DBG_871X("%s:%s: drop cmdcode:%u, hw_init_completed:%u, cmdthd_running:%u\n", caller_func, __func__, */ ++ /* cmd_obj->cmdcode, */ ++ /* pcmdpriv->padapter->hw_init_completed, */ ++ /* pcmdpriv->cmdthd_running */ ++ /* */ ++ ++ return _FAIL; ++ } ++ return _SUCCESS; ++} ++ ++ ++ ++u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) ++{ ++ int res = _FAIL; ++ struct adapter *padapter = pcmdpriv->padapter; ++ ++ if (cmd_obj == NULL) { ++ goto exit; ++ } ++ ++ cmd_obj->padapter = padapter; ++ ++ if (_FAIL == (res =rtw_cmd_filter(pcmdpriv, cmd_obj))) { ++ rtw_free_cmd_obj(cmd_obj); ++ goto exit; ++ } ++ ++ res = _rtw_enqueue_cmd(&pcmdpriv->cmd_queue, cmd_obj); ++ ++ if (res == _SUCCESS) ++ up(&pcmdpriv->cmd_queue_sema); ++ ++exit: ++ return res; ++} ++ ++struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv) ++{ ++ struct cmd_obj *cmd_obj; ++ ++ cmd_obj = _rtw_dequeue_cmd(&pcmdpriv->cmd_queue); ++ ++ return cmd_obj; ++} ++ ++void rtw_free_cmd_obj(struct cmd_obj *pcmd) ++{ ++ if ((pcmd->cmdcode!= _JoinBss_CMD_) && ++ (pcmd->cmdcode!= _CreateBss_CMD_)) { ++ /* free parmbuf in cmd_obj */ ++ kfree((unsigned char*)pcmd->parmbuf); ++ } ++ ++ if (pcmd->rsp!= NULL) { ++ if (pcmd->rspsz!= 0) { ++ /* free rsp in cmd_obj */ ++ kfree((unsigned char*)pcmd->rsp); ++ } ++ } ++ ++ /* free cmd_obj */ ++ kfree((unsigned char*)pcmd); ++} ++ ++ ++void rtw_stop_cmd_thread(struct adapter *adapter) ++{ ++ if (adapter->cmdThread && ++ atomic_read(&(adapter->cmdpriv.cmdthd_running)) == true && ++ adapter->cmdpriv.stop_req == 0) ++ { ++ adapter->cmdpriv.stop_req = 1; ++ up(&adapter->cmdpriv.cmd_queue_sema); ++ down(&adapter->cmdpriv.terminate_cmdthread_sema); ++ } ++} ++ ++int rtw_cmd_thread(void *context) ++{ ++ u8 ret; ++ struct cmd_obj *pcmd; ++ u8 *pcmdbuf, *prspbuf; ++ unsigned long cmd_start_time; ++ unsigned long cmd_process_time; ++ u8 (*cmd_hdl)(struct adapter *padapter, u8 *pbuf); ++ void (*pcmd_callback)(struct adapter *dev, struct cmd_obj *pcmd); ++ struct adapter *padapter = (struct adapter *)context; ++ struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); ++ struct drvextra_cmd_parm *extra_parm = NULL; ++ ++ thread_enter("RTW_CMD_THREAD"); ++ ++ pcmdbuf = pcmdpriv->cmd_buf; ++ prspbuf = pcmdpriv->rsp_buf; ++ ++ pcmdpriv->stop_req = 0; ++ atomic_set(&(pcmdpriv->cmdthd_running), true); ++ up(&pcmdpriv->terminate_cmdthread_sema); ++ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("start r871x rtw_cmd_thread !!!!\n")); ++ ++ while (1) ++ { ++ if (down_interruptible(&pcmdpriv->cmd_queue_sema)) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" down_interruptible(&pcmdpriv->cmd_queue_sema) return != 0, break\n", FUNC_ADPT_ARG(padapter)); ++ break; ++ } ++ ++ if ((padapter->bDriverStopped == true)||(padapter->bSurpriseRemoved == true)) ++ { ++ DBG_871X_LEVEL(_drv_always_, "%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n", ++ __func__, padapter->bDriverStopped, padapter->bSurpriseRemoved, __LINE__); ++ break; ++ } ++ ++ if (pcmdpriv->stop_req) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" stop_req:%u, break\n", FUNC_ADPT_ARG(padapter), pcmdpriv->stop_req); ++ break; ++ } ++ ++ if (list_empty(&(pcmdpriv->cmd_queue.queue))) ++ { ++ /* DBG_871X("%s: cmd queue is empty!\n", __func__); */ ++ continue; ++ } ++ ++ if (rtw_register_cmd_alive(padapter) != _SUCCESS) ++ { ++ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ++ ("%s: wait to leave LPS_LCLK\n", __func__)); ++ continue; ++ } ++ ++_next: ++ if ((padapter->bDriverStopped == true)||(padapter->bSurpriseRemoved == true)) ++ { ++ DBG_871X_LEVEL(_drv_always_, "%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n", ++ __func__, padapter->bDriverStopped, padapter->bSurpriseRemoved, __LINE__); ++ break; ++ } ++ ++ if (!(pcmd = rtw_dequeue_cmd(pcmdpriv))) { ++ rtw_unregister_cmd_alive(padapter); ++ continue; ++ } ++ ++ cmd_start_time = jiffies; ++ ++ if (_FAIL == rtw_cmd_filter(pcmdpriv, pcmd)) ++ { ++ pcmd->res = H2C_DROPPED; ++ goto post_process; ++ } ++ ++ pcmdpriv->cmd_issued_cnt++; ++ ++ pcmd->cmdsz = _RND4((pcmd->cmdsz));/* _RND4 */ ++ ++ memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz); ++ ++ if (pcmd->cmdcode < ARRAY_SIZE(wlancmds)) ++ { ++ cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns; ++ ++ if (cmd_hdl) ++ { ++ ret = cmd_hdl(pcmd->padapter, pcmdbuf); ++ pcmd->res = ret; ++ } ++ ++ pcmdpriv->cmd_seq++; ++ } ++ else ++ { ++ pcmd->res = H2C_PARAMETERS_ERROR; ++ } ++ ++ cmd_hdl = NULL; ++ ++post_process: ++ ++ if (mutex_lock_interruptible(&(pcmd->padapter->cmdpriv.sctx_mutex)) == 0) { ++ if (pcmd->sctx) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" pcmd->sctx\n", ++ FUNC_ADPT_ARG(pcmd->padapter)); ++ ++ if (pcmd->res == H2C_SUCCESS) ++ rtw_sctx_done(&pcmd->sctx); ++ else ++ rtw_sctx_done_err(&pcmd->sctx, RTW_SCTX_DONE_CMD_ERROR); ++ } ++ mutex_unlock(&(pcmd->padapter->cmdpriv.sctx_mutex)); ++ } ++ ++ if ((cmd_process_time = jiffies_to_msecs(jiffies - cmd_start_time)) > 1000) ++ { ++ if (pcmd->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) { ++ DBG_871X(ADPT_FMT" cmd =%d process_time =%lu > 1 sec\n", ++ ADPT_ARG(pcmd->padapter), pcmd->cmdcode, cmd_process_time); ++ /* rtw_warn_on(1); */ ++ } else if (pcmd->cmdcode == GEN_CMD_CODE(_Set_MLME_EVT)) { ++ DBG_871X(ADPT_FMT" cmd =%d, process_time =%lu > 1 sec\n", ++ ADPT_ARG(pcmd->padapter), pcmd->cmdcode, cmd_process_time); ++ /* rtw_warn_on(1); */ ++ } else { ++ DBG_871X(ADPT_FMT" cmd =%d, process_time =%lu > 1 sec\n", ++ ADPT_ARG(pcmd->padapter), pcmd->cmdcode, cmd_process_time); ++ /* rtw_warn_on(1); */ ++ } ++ } ++ ++ /* call callback function for post-processed */ ++ if (pcmd->cmdcode < ARRAY_SIZE(rtw_cmd_callback)) ++ { ++ pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback; ++ if (pcmd_callback == NULL) ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("mlme_cmd_hdl(): pcmd_callback = 0x%p, cmdcode = 0x%x\n", pcmd_callback, pcmd->cmdcode)); ++ rtw_free_cmd_obj(pcmd); ++ } ++ else ++ { ++ /* todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!= NULL) */ ++ pcmd_callback(pcmd->padapter, pcmd);/* need conider that free cmd_obj in rtw_cmd_callback */ ++ } ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("%s: cmdcode = 0x%x callback not defined!\n", __func__, pcmd->cmdcode)); ++ rtw_free_cmd_obj(pcmd); ++ } ++ ++ flush_signals_thread(); ++ ++ goto _next; ++ ++ } ++ ++ /* free all cmd_obj resources */ ++ do{ ++ pcmd = rtw_dequeue_cmd(pcmdpriv); ++ if (pcmd == NULL) { ++ rtw_unregister_cmd_alive(padapter); ++ break; ++ } ++ ++ /* DBG_871X("%s: leaving... drop cmdcode:%u size:%d\n", __func__, pcmd->cmdcode, pcmd->cmdsz); */ ++ ++ if (pcmd->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) { ++ extra_parm = (struct drvextra_cmd_parm *)pcmd->parmbuf; ++ if (extra_parm->pbuf && extra_parm->size > 0) { ++ kfree(extra_parm->pbuf); ++ } ++ } ++ ++ rtw_free_cmd_obj(pcmd); ++ }while (1); ++ ++ up(&pcmdpriv->terminate_cmdthread_sema); ++ atomic_set(&(pcmdpriv->cmdthd_running), false); ++ ++ thread_exit(); ++} ++ ++/* ++rtw_sitesurvey_cmd(~) ++ ### NOTE:#### (!!!!) ++ MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock ++*/ ++u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid, int ssid_num, ++ struct rtw_ieee80211_channel *ch, int ch_num) ++{ ++ u8 res = _FAIL; ++ struct cmd_obj *ph2c; ++ struct sitesurvey_parm *psurveyPara; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1); ++ } ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) ++ return _FAIL; ++ ++ psurveyPara = (struct sitesurvey_parm*)rtw_zmalloc(sizeof(struct sitesurvey_parm)); ++ if (psurveyPara == NULL) { ++ kfree((unsigned char*) ph2c); ++ return _FAIL; ++ } ++ ++ rtw_free_network_queue(padapter, false); ++ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("%s: flush network queue\n", __func__)); ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey)); ++ ++ /* psurveyPara->bsslimit = 48; */ ++ psurveyPara->scan_mode = pmlmepriv->scan_mode; ++ ++ /* prepare ssid list */ ++ if (ssid) { ++ int i; ++ for (i = 0; issid[i], &ssid[i], sizeof(struct ndis_802_11_ssid)); ++ psurveyPara->ssid_num++; ++ ++ DBG_871X(FUNC_ADPT_FMT" ssid:(%s, %d)\n", FUNC_ADPT_ARG(padapter), ++ psurveyPara->ssid[i].Ssid, psurveyPara->ssid[i].SsidLength); ++ } ++ } ++ } ++ ++ /* prepare channel list */ ++ if (ch) { ++ int i; ++ for (i = 0; ich[i], &ch[i], sizeof(struct rtw_ieee80211_channel)); ++ psurveyPara->ch_num++; ++ ++ DBG_871X(FUNC_ADPT_FMT" ch:%u\n", FUNC_ADPT_ARG(padapter), ++ psurveyPara->ch[i].hw_value); ++ } ++ } ++ } ++ ++ set_fwstate(pmlmepriv, _FW_UNDER_SURVEY); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++ if (res == _SUCCESS) { ++ ++ pmlmepriv->scan_start_time = jiffies; ++ _set_timer(&pmlmepriv->scan_to_timer, SCANNING_TIMEOUT); ++ } else { ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); ++ } ++ return res; ++} ++ ++u8 rtw_setdatarate_cmd(struct adapter *padapter, u8 *rateset) ++{ ++ struct cmd_obj* ph2c; ++ struct setdatarate_parm*pbsetdataratepara; ++ struct cmd_priv* pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pbsetdataratepara = (struct setdatarate_parm*)rtw_zmalloc(sizeof(struct setdatarate_parm)); ++ if (pbsetdataratepara == NULL) { ++ kfree((u8 *) ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara, GEN_CMD_CODE(_SetDataRate)); ++ pbsetdataratepara->mac_id = 5; ++ memcpy(pbsetdataratepara->datarates, rateset, NumRates); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++ return res; ++} ++ ++void rtw_getbbrfreg_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd) ++{ ++ /* rtw_free_cmd_obj(pcmd); */ ++ kfree((unsigned char*) pcmd->parmbuf); ++ kfree((unsigned char*) pcmd); ++} ++ ++u8 rtw_createbss_cmd(struct adapter *padapter) ++{ ++ struct cmd_obj* pcmd; ++ struct cmd_priv *pcmdpriv =&padapter->cmdpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_bssid_ex *pdev_network = &padapter->registrypriv.dev_network; ++ u8 res = _SUCCESS; ++ ++ if (pmlmepriv->assoc_ssid.SsidLength == 0) { ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, (" createbss for Any SSid:%s\n", pmlmepriv->assoc_ssid.Ssid)); ++ } else { ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, (" createbss for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid)); ++ } ++ ++ pcmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (pcmd == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ INIT_LIST_HEAD(&pcmd->list); ++ pcmd->cmdcode = _CreateBss_CMD_; ++ pcmd->parmbuf = (unsigned char *)pdev_network; ++ pcmd->cmdsz = get_wlan_bssid_ex_sz((struct wlan_bssid_ex*)pdev_network); ++ pcmd->rsp = NULL; ++ pcmd->rspsz = 0; ++ ++ pdev_network->Length = pcmd->cmdsz; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, pcmd); ++ ++exit: ++ return res; ++} ++ ++u8 rtw_startbss_cmd(struct adapter *padapter, int flags) ++{ ++ struct cmd_obj* pcmd; ++ struct cmd_priv *pcmdpriv =&padapter->cmdpriv; ++ struct submit_ctx sctx; ++ u8 res = _SUCCESS; ++ ++ if (flags & RTW_CMDF_DIRECTLY) { ++ /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ ++ start_bss_network(padapter, (u8 *)&(padapter->mlmepriv.cur_network.network)); ++ } else { ++ /* need enqueue, prepare cmd_obj and enqueue */ ++ pcmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (pcmd == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ INIT_LIST_HEAD(&pcmd->list); ++ pcmd->cmdcode = GEN_CMD_CODE(_CreateBss); ++ pcmd->parmbuf = NULL; ++ pcmd->cmdsz = 0; ++ pcmd->rsp = NULL; ++ pcmd->rspsz = 0; ++ ++ if (flags & RTW_CMDF_WAIT_ACK) { ++ pcmd->sctx = &sctx; ++ rtw_sctx_init(&sctx, 2000); ++ } ++ ++ res = rtw_enqueue_cmd(pcmdpriv, pcmd); ++ ++ if (res == _SUCCESS && (flags & RTW_CMDF_WAIT_ACK)) { ++ rtw_sctx_wait(&sctx, __func__); ++ if (mutex_lock_interruptible(&pcmdpriv->sctx_mutex) == 0) { ++ if (sctx.status == RTW_SCTX_SUBMITTED) ++ pcmd->sctx = NULL; ++ mutex_unlock(&pcmdpriv->sctx_mutex); ++ } ++ } ++ } ++ ++exit: ++ return res; ++} ++ ++u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network* pnetwork) ++{ ++ u8 *auth, res = _SUCCESS; ++ uint t_len = 0; ++ struct wlan_bssid_ex *psecnetwork; ++ struct cmd_obj *pcmd; ++ struct cmd_priv *pcmdpriv =&padapter->cmdpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct qos_priv *pqospriv = &pmlmepriv->qospriv; ++ struct security_priv *psecuritypriv =&padapter->securitypriv; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ enum NDIS_802_11_NETWORK_INFRASTRUCTURE ndis_network_mode = pnetwork->network.InfrastructureMode; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u32 tmp_len; ++ u8 *ptmp = NULL; ++ ++ if (pmlmepriv->assoc_ssid.SsidLength == 0) { ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+Join cmd: Any SSid\n")); ++ } else { ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+Join cmd: SSid =[%s]\n", pmlmepriv->assoc_ssid.Ssid)); ++ } ++ ++ pcmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (pcmd == NULL) { ++ res = _FAIL; ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd: memory allocate for cmd_obj fail!!!\n")); ++ goto exit; ++ } ++ /* for IEs is fix buf size */ ++ t_len = sizeof(struct wlan_bssid_ex); ++ ++ ++ /* for hidden ap to set fw_state here */ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) != true) ++ { ++ switch (ndis_network_mode) ++ { ++ case Ndis802_11IBSS: ++ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); ++ break; ++ ++ case Ndis802_11Infrastructure: ++ set_fwstate(pmlmepriv, WIFI_STATION_STATE); ++ break; ++ ++ case Ndis802_11APMode: ++ case Ndis802_11AutoUnknown: ++ case Ndis802_11InfrastructureMax: ++ break; ++ ++ } ++ } ++ ++ psecnetwork =(struct wlan_bssid_ex *)&psecuritypriv->sec_bss; ++ if (psecnetwork == NULL) ++ { ++ if (pcmd != NULL) ++ kfree((unsigned char *)pcmd); ++ ++ res = _FAIL; ++ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd :psecnetwork == NULL!!!\n")); ++ ++ goto exit; ++ } ++ ++ memset(psecnetwork, 0, t_len); ++ ++ memcpy(psecnetwork, &pnetwork->network, get_wlan_bssid_ex_sz(&pnetwork->network)); ++ ++ auth =&psecuritypriv->authenticator_ie[0]; ++ psecuritypriv->authenticator_ie[0]=(unsigned char)psecnetwork->IELength; ++ ++ if ((psecnetwork->IELength-12) < (256-1)) { ++ memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], psecnetwork->IELength-12); ++ } else { ++ memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], (256-1)); ++ } ++ ++ psecnetwork->IELength = 0; ++ /* Added by Albert 2009/02/18 */ ++ /* If the the driver wants to use the bssid to create the connection. */ ++ /* If not, we have to copy the connecting AP's MAC address to it so that */ ++ /* the driver just has the bssid information for PMKIDList searching. */ ++ ++ if (pmlmepriv->assoc_by_bssid == false) ++ { ++ memcpy(&pmlmepriv->assoc_bssid[ 0 ], &pnetwork->network.MacAddress[ 0 ], ETH_ALEN); ++ } ++ ++ psecnetwork->IELength = rtw_restruct_sec_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength); ++ ++ ++ pqospriv->qos_option = 0; ++ ++ if (pregistrypriv->wmm_enable) ++ { ++ tmp_len = rtw_restruct_wmm_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength, psecnetwork->IELength); ++ ++ if (psecnetwork->IELength != tmp_len) ++ { ++ psecnetwork->IELength = tmp_len; ++ pqospriv->qos_option = 1; /* There is WMM IE in this corresp. beacon */ ++ } ++ else ++ { ++ pqospriv->qos_option = 0;/* There is no WMM IE in this corresp. beacon */ ++ } ++ } ++ ++ phtpriv->ht_option = false; ++ ptmp = rtw_get_ie(&pnetwork->network.IEs[12], _HT_CAPABILITY_IE_, &tmp_len, pnetwork->network.IELength-12); ++ if (pregistrypriv->ht_enable && ptmp && tmp_len>0) ++ { ++ /* Added by Albert 2010/06/23 */ ++ /* For the WEP mode, we will use the bg mode to do the connection to avoid some IOT issue. */ ++ /* Especially for Realtek 8192u SoftAP. */ ++ if ((padapter->securitypriv.dot11PrivacyAlgrthm != _WEP40_) && ++ (padapter->securitypriv.dot11PrivacyAlgrthm != _WEP104_) && ++ (padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_)) ++ { ++ rtw_ht_use_default_setting(padapter); ++ ++ rtw_build_wmm_ie_ht(padapter, &psecnetwork->IEs[12], &psecnetwork->IELength); ++ ++ /* rtw_restructure_ht_ie */ ++ rtw_restructure_ht_ie(padapter, &pnetwork->network.IEs[12], &psecnetwork->IEs[0], ++ pnetwork->network.IELength-12, &psecnetwork->IELength, ++ pnetwork->network.Configuration.DSConfig); ++ } ++ } ++ ++ rtw_append_exented_cap(padapter, &psecnetwork->IEs[0], &psecnetwork->IELength); ++ ++ pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->network.IEs, pnetwork->network.IELength); ++ ++ pcmd->cmdsz = get_wlan_bssid_ex_sz(psecnetwork);/* get cmdsz before endian conversion */ ++ ++ INIT_LIST_HEAD(&pcmd->list); ++ pcmd->cmdcode = _JoinBss_CMD_;/* GEN_CMD_CODE(_JoinBss) */ ++ pcmd->parmbuf = (unsigned char *)psecnetwork; ++ pcmd->rsp = NULL; ++ pcmd->rspsz = 0; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, pcmd); ++ ++exit: ++ return res; ++} ++ ++u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueue) /* for sta_mode */ ++{ ++ struct cmd_obj *cmdobj = NULL; ++ struct disconnect_parm *param = NULL; ++ struct cmd_priv *cmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_disassoc_cmd\n")); ++ ++ /* prepare cmd parameter */ ++ param = (struct disconnect_parm *)rtw_zmalloc(sizeof(*param)); ++ if (param == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ param->deauth_timeout_ms = deauth_timeout_ms; ++ ++ if (enqueue) { ++ /* need enqueue, prepare cmd_obj and enqueue */ ++ cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(*cmdobj)); ++ if (cmdobj == NULL) { ++ res = _FAIL; ++ kfree((u8 *)param); ++ goto exit; ++ } ++ init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_); ++ res = rtw_enqueue_cmd(cmdpriv, cmdobj); ++ } else { ++ /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ ++ if (H2C_SUCCESS != disconnect_hdl(padapter, (u8 *)param)) ++ res = _FAIL; ++ kfree((u8 *)param); ++ } ++ ++exit: ++ return res; ++} ++ ++u8 rtw_setopmode_cmd(struct adapter *padapter, enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype, bool enqueue) ++{ ++ struct cmd_obj*ph2c; ++ struct setopmode_parm* psetop; ++ ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ psetop = (struct setopmode_parm*)rtw_zmalloc(sizeof(struct setopmode_parm)); ++ ++ if (psetop == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ psetop->mode = (u8)networktype; ++ ++ if (enqueue) { ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ kfree((u8 *)psetop); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_); ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ } ++ else { ++ setopmode_hdl(padapter, (u8 *)psetop); ++ kfree((u8 *)psetop); ++ } ++exit: ++ return res; ++} ++ ++u8 rtw_setstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 unicast_key, bool enqueue) ++{ ++ struct cmd_obj* ph2c; ++ struct set_stakey_parm *psetstakey_para; ++ struct cmd_priv *pcmdpriv =&padapter->cmdpriv; ++ struct set_stakey_rsp *psetstakey_rsp = NULL; ++ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ u8 res = _SUCCESS; ++ ++ psetstakey_para = (struct set_stakey_parm*)rtw_zmalloc(sizeof(struct set_stakey_parm)); ++ if (psetstakey_para == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN); ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { ++ psetstakey_para->algorithm =(unsigned char) psecuritypriv->dot11PrivacyAlgrthm; ++ } else { ++ GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, false); ++ } ++ ++ if (unicast_key == true) { ++ memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16); ++ } ++ else { ++ memcpy(&psetstakey_para->key, &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16); ++ } ++ ++ /* jeff: set this becasue at least sw key is ready */ ++ padapter->securitypriv.busetkipkey =true; ++ ++ if (enqueue) ++ { ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ kfree((u8 *) psetstakey_para); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ psetstakey_rsp = (struct set_stakey_rsp*)rtw_zmalloc(sizeof(struct set_stakey_rsp)); ++ if (psetstakey_rsp == NULL) { ++ kfree((u8 *) ph2c); ++ kfree((u8 *) psetstakey_para); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); ++ ph2c->rsp = (u8 *) psetstakey_rsp; ++ ph2c->rspsz = sizeof(struct set_stakey_rsp); ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ } ++ else { ++ set_stakey_hdl(padapter, (u8 *)psetstakey_para); ++ kfree((u8 *) psetstakey_para); ++ } ++exit: ++ return res; ++} ++ ++u8 rtw_clearstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 enqueue) ++{ ++ struct cmd_obj* ph2c; ++ struct set_stakey_parm *psetstakey_para; ++ struct cmd_priv *pcmdpriv =&padapter->cmdpriv; ++ struct set_stakey_rsp *psetstakey_rsp = NULL; ++ s16 cam_id = 0; ++ u8 res = _SUCCESS; ++ ++ if (!enqueue) ++ { ++ while ((cam_id = rtw_camid_search(padapter, sta->hwaddr, -1)) >= 0) { ++ DBG_871X_LEVEL(_drv_always_, "clear key for addr:"MAC_FMT", camid:%d\n", MAC_ARG(sta->hwaddr), cam_id); ++ clear_cam_entry(padapter, cam_id); ++ rtw_camid_free(padapter, cam_id); ++ } ++ } ++ else ++ { ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ psetstakey_para = (struct set_stakey_parm*)rtw_zmalloc(sizeof(struct set_stakey_parm)); ++ if (psetstakey_para == NULL) { ++ kfree((u8 *) ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ psetstakey_rsp = (struct set_stakey_rsp*)rtw_zmalloc(sizeof(struct set_stakey_rsp)); ++ if (psetstakey_rsp == NULL) { ++ kfree((u8 *) ph2c); ++ kfree((u8 *) psetstakey_para); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); ++ ph2c->rsp = (u8 *) psetstakey_rsp; ++ ph2c->rspsz = sizeof(struct set_stakey_rsp); ++ ++ memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN); ++ ++ psetstakey_para->algorithm = _NO_PRIVACY_; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++ } ++ ++exit: ++ return res; ++} ++ ++u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr) ++{ ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ struct cmd_obj* ph2c; ++ struct addBaReq_parm *paddbareq_parm; ++ ++ u8 res = _SUCCESS; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ paddbareq_parm = (struct addBaReq_parm*)rtw_zmalloc(sizeof(struct addBaReq_parm)); ++ if (paddbareq_parm == NULL) { ++ kfree((unsigned char *)ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ paddbareq_parm->tid = tid; ++ memcpy(paddbareq_parm->addr, addr, ETH_ALEN); ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq)); ++ ++ /* DBG_871X("rtw_addbareq_cmd, tid =%d\n", tid); */ ++ ++ /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ return res; ++} ++/* add for CONFIG_IEEE80211W, none 11w can use it */ ++u8 rtw_reset_securitypriv_cmd(struct adapter *padapter) ++{ ++ struct cmd_obj* ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv =&padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if (pdrvextra_cmd_parm == NULL) { ++ kfree((unsigned char *)ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = RESET_SECURITYPRIV; ++ pdrvextra_cmd_parm->type = 0; ++ pdrvextra_cmd_parm->size = 0; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ ++ /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ return res; ++} ++ ++u8 rtw_free_assoc_resources_cmd(struct adapter *padapter) ++{ ++ struct cmd_obj* ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv =&padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if (pdrvextra_cmd_parm == NULL) { ++ kfree((unsigned char *)ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = FREE_ASSOC_RESOURCES; ++ pdrvextra_cmd_parm->type = 0; ++ pdrvextra_cmd_parm->size = 0; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ ++ /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ return res; ++} ++ ++u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter) ++{ ++ struct cmd_obj* ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv =&padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ /* only primary padapter does this cmd */ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if (pdrvextra_cmd_parm == NULL) { ++ kfree((unsigned char *)ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = DYNAMIC_CHK_WK_CID; ++ pdrvextra_cmd_parm->type = 0; ++ pdrvextra_cmd_parm->size = 0; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ ++ /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ return res; ++} ++ ++u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan, u8 enqueue, u8 swconfig) ++{ ++ struct cmd_obj*pcmdobj; ++ struct SetChannelPlan_param *setChannelPlan_param; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ u8 res = _SUCCESS; ++ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_chplan_cmd\n")); ++ ++ /* check if allow software config */ ++ if (swconfig && rtw_hal_is_disable_sw_channel_plan(padapter) == true) ++ { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ /* check input parameter */ ++ if (!rtw_is_channel_plan_valid(chplan)) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ /* prepare cmd parameter */ ++ setChannelPlan_param = (struct SetChannelPlan_param *)rtw_zmalloc(sizeof(struct SetChannelPlan_param)); ++ if (setChannelPlan_param == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ setChannelPlan_param->channel_plan =chplan; ++ ++ if (enqueue) ++ { ++ /* need enqueue, prepare cmd_obj and enqueue */ ++ pcmdobj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (pcmdobj == NULL) { ++ kfree((u8 *)setChannelPlan_param); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelPlan_param, GEN_CMD_CODE(_SetChannelPlan)); ++ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); ++ } ++ else ++ { ++ /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ ++ if (H2C_SUCCESS !=set_chplan_hdl(padapter, (unsigned char *)setChannelPlan_param)) ++ res = _FAIL; ++ ++ kfree((u8 *)setChannelPlan_param); ++ } ++ ++ /* do something based on res... */ ++ if (res == _SUCCESS) ++ padapter->mlmepriv.ChannelPlan = chplan; ++ ++exit: ++ return res; ++} ++ ++static void collect_traffic_statistics(struct adapter *padapter) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ ++ /* Tx */ ++ pdvobjpriv->traffic_stat.tx_bytes = padapter->xmitpriv.tx_bytes; ++ pdvobjpriv->traffic_stat.tx_pkts = padapter->xmitpriv.tx_pkts; ++ pdvobjpriv->traffic_stat.tx_drop = padapter->xmitpriv.tx_drop; ++ ++ /* Rx */ ++ pdvobjpriv->traffic_stat.rx_bytes = padapter->recvpriv.rx_bytes; ++ pdvobjpriv->traffic_stat.rx_pkts = padapter->recvpriv.rx_pkts; ++ pdvobjpriv->traffic_stat.rx_drop = padapter->recvpriv.rx_drop; ++ ++ /* Calculate throughput in last interval */ ++ pdvobjpriv->traffic_stat.cur_tx_bytes = pdvobjpriv->traffic_stat.tx_bytes - pdvobjpriv->traffic_stat.last_tx_bytes; ++ pdvobjpriv->traffic_stat.cur_rx_bytes = pdvobjpriv->traffic_stat.rx_bytes - pdvobjpriv->traffic_stat.last_rx_bytes; ++ pdvobjpriv->traffic_stat.last_tx_bytes = pdvobjpriv->traffic_stat.tx_bytes; ++ pdvobjpriv->traffic_stat.last_rx_bytes = pdvobjpriv->traffic_stat.rx_bytes; ++ ++ pdvobjpriv->traffic_stat.cur_tx_tp = (u32)(pdvobjpriv->traffic_stat.cur_tx_bytes *8/2/1024/1024); ++ pdvobjpriv->traffic_stat.cur_rx_tp = (u32)(pdvobjpriv->traffic_stat.cur_rx_bytes *8/2/1024/1024); ++} ++ ++u8 traffic_status_watchdog(struct adapter *padapter, u8 from_timer) ++{ ++ u8 bEnterPS = false; ++ u16 BusyThresholdHigh = 25; ++ u16 BusyThresholdLow = 10; ++ u16 BusyThreshold = BusyThresholdHigh; ++ u8 bBusyTraffic = false, bTxBusyTraffic = false, bRxBusyTraffic = false; ++ u8 bHigherBusyTraffic = false, bHigherBusyRxTraffic = false, bHigherBusyTxTraffic = false; ++ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ RT_LINK_DETECT_T * link_detect = &pmlmepriv->LinkDetectInfo; ++ ++ collect_traffic_statistics(padapter); ++ ++ /* */ ++ /* Determine if our traffic is busy now */ ++ /* */ ++ if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) ++ /*&& !MgntInitAdapterInProgress(pMgntInfo)*/) ++ { ++ /* if we raise bBusyTraffic in last watchdog, using lower threshold. */ ++ if (pmlmepriv->LinkDetectInfo.bBusyTraffic) ++ BusyThreshold = BusyThresholdLow; ++ ++ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > BusyThreshold || ++ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > BusyThreshold) ++ { ++ bBusyTraffic = true; ++ ++ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) ++ bRxBusyTraffic = true; ++ else ++ bTxBusyTraffic = true; ++ } ++ ++ /* Higher Tx/Rx data. */ ++ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 4000 || ++ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 4000) ++ { ++ bHigherBusyTraffic = true; ++ ++ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) ++ bHigherBusyRxTraffic = true; ++ else ++ bHigherBusyTxTraffic = true; ++ } ++ ++#ifdef CONFIG_TRAFFIC_PROTECT ++#define TX_ACTIVE_TH 10 ++#define RX_ACTIVE_TH 20 ++#define TRAFFIC_PROTECT_PERIOD_MS 4500 ++ ++ if (link_detect->NumTxOkInPeriod > TX_ACTIVE_TH ++ || link_detect->NumRxUnicastOkInPeriod > RX_ACTIVE_TH) { ++ ++ DBG_871X_LEVEL(_drv_info_, FUNC_ADPT_FMT" acqiure wake_lock for %u ms(tx:%d, rx_unicast:%d)\n", ++ FUNC_ADPT_ARG(padapter), ++ TRAFFIC_PROTECT_PERIOD_MS, ++ link_detect->NumTxOkInPeriod, ++ link_detect->NumRxUnicastOkInPeriod); ++ } ++#endif ++ ++ /* check traffic for powersaving. */ ++ if (((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8) || ++ (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 2)) ++ { ++ /* DBG_871X("(-)Tx = %d, Rx = %d\n", pmlmepriv->LinkDetectInfo.NumTxOkInPeriod, pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod); */ ++ bEnterPS = false; ++ ++ if (bBusyTraffic == true) ++ { ++ if (pmlmepriv->LinkDetectInfo.TrafficTransitionCount <= 4) ++ pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 4; ++ ++ pmlmepriv->LinkDetectInfo.TrafficTransitionCount++; ++ ++ /* DBG_871X("Set TrafficTransitionCount to %d\n", pmlmepriv->LinkDetectInfo.TrafficTransitionCount); */ ++ ++ if (pmlmepriv->LinkDetectInfo.TrafficTransitionCount > 30/*TrafficTransitionLevel*/) ++ { ++ pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 30; ++ } ++ } ++ } ++ else ++ { ++ /* DBG_871X("(+)Tx = %d, Rx = %d\n", pmlmepriv->LinkDetectInfo.NumTxOkInPeriod, pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod); */ ++ ++ if (pmlmepriv->LinkDetectInfo.TrafficTransitionCount>=2) ++ pmlmepriv->LinkDetectInfo.TrafficTransitionCount -=2; ++ else ++ pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 0; ++ ++ if (pmlmepriv->LinkDetectInfo.TrafficTransitionCount == 0) ++ bEnterPS = true; ++ } ++ ++ /* LeisurePS only work in infra mode. */ ++ if (bEnterPS) { ++ if (!from_timer) ++ LPS_Enter(padapter, "TRAFFIC_IDLE"); ++ } else { ++ if (!from_timer) ++ LPS_Leave(padapter, "TRAFFIC_BUSY"); ++ else ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_TRAFFIC_BUSY, 1); ++ } ++ } else { ++ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); ++ int n_assoc_iface = 0; ++ ++ if (check_fwstate(&(dvobj->padapters->mlmepriv), WIFI_ASOC_STATE)) ++ n_assoc_iface++; ++ ++ if (!from_timer && n_assoc_iface == 0) ++ LPS_Leave(padapter, "NON_LINKED"); ++ } ++ ++ pmlmepriv->LinkDetectInfo.NumRxOkInPeriod = 0; ++ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod = 0; ++ pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod = 0; ++ pmlmepriv->LinkDetectInfo.bBusyTraffic = bBusyTraffic; ++ pmlmepriv->LinkDetectInfo.bTxBusyTraffic = bTxBusyTraffic; ++ pmlmepriv->LinkDetectInfo.bRxBusyTraffic = bRxBusyTraffic; ++ pmlmepriv->LinkDetectInfo.bHigherBusyTraffic = bHigherBusyTraffic; ++ pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic = bHigherBusyRxTraffic; ++ pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic; ++ ++ return bEnterPS; ++ ++} ++ ++static void dynamic_chk_wk_hdl(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv; ++ pmlmepriv = &(padapter->mlmepriv); ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ++ { ++ expire_timeout_chk(padapter); ++ } ++ ++ /* for debug purpose */ ++ _linked_info_dump(padapter); ++ ++ ++ /* if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING|_FW_UNDER_SURVEY) ==false) */ ++ { ++ linked_status_chk(padapter); ++ traffic_status_watchdog(padapter, 0); ++ } ++ ++ rtw_hal_dm_watchdog(padapter); ++ ++ /* check_hw_pbc(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type); */ ++ ++ /* */ ++ /* BT-Coexist */ ++ /* */ ++ rtw_btcoex_Handler(padapter); ++ ++ ++ /* always call rtw_ps_processor() at last one. */ ++ if (is_primary_adapter(padapter)) ++ rtw_ps_processor(padapter); ++} ++ ++void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type); ++void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ u8 mstatus; ++ ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) ++ || (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) ++ { ++ return; ++ } ++ ++ switch (lps_ctrl_type) ++ { ++ case LPS_CTRL_SCAN: ++ /* DBG_871X("LPS_CTRL_SCAN\n"); */ ++ rtw_btcoex_ScanNotify(padapter, true); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) ++ { ++ /* connect */ ++ LPS_Leave(padapter, "LPS_CTRL_SCAN"); ++ } ++ break; ++ case LPS_CTRL_JOINBSS: ++ /* DBG_871X("LPS_CTRL_JOINBSS\n"); */ ++ LPS_Leave(padapter, "LPS_CTRL_JOINBSS"); ++ break; ++ case LPS_CTRL_CONNECT: ++ /* DBG_871X("LPS_CTRL_CONNECT\n"); */ ++ mstatus = 1;/* connect */ ++ /* Reset LPS Setting */ ++ pwrpriv->LpsIdleCount = 0; ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus)); ++ rtw_btcoex_MediaStatusNotify(padapter, mstatus); ++ break; ++ case LPS_CTRL_DISCONNECT: ++ /* DBG_871X("LPS_CTRL_DISCONNECT\n"); */ ++ mstatus = 0;/* disconnect */ ++ rtw_btcoex_MediaStatusNotify(padapter, mstatus); ++ LPS_Leave(padapter, "LPS_CTRL_DISCONNECT"); ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus)); ++ break; ++ case LPS_CTRL_SPECIAL_PACKET: ++ /* DBG_871X("LPS_CTRL_SPECIAL_PACKET\n"); */ ++ pwrpriv->DelayLPSLastTimeStamp = jiffies; ++ rtw_btcoex_SpecialPacketNotify(padapter, PACKET_DHCP); ++ LPS_Leave(padapter, "LPS_CTRL_SPECIAL_PACKET"); ++ break; ++ case LPS_CTRL_LEAVE: ++ /* DBG_871X("LPS_CTRL_LEAVE\n"); */ ++ LPS_Leave(padapter, "LPS_CTRL_LEAVE"); ++ break; ++ case LPS_CTRL_TRAFFIC_BUSY: ++ LPS_Leave(padapter, "LPS_CTRL_TRAFFIC_BUSY"); ++ default: ++ break; ++ } ++} ++ ++u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ /* struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); */ ++ u8 res = _SUCCESS; ++ ++ /* if (!pwrctrlpriv->bLeisurePs) */ ++ /* return res; */ ++ ++ if (enqueue) ++ { ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if (pdrvextra_cmd_parm == NULL) { ++ kfree((unsigned char *)ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID; ++ pdrvextra_cmd_parm->type = lps_ctrl_type; ++ pdrvextra_cmd_parm->size = 0; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ } ++ else ++ { ++ lps_ctrl_wk_hdl(padapter, lps_ctrl_type); ++ } ++ ++exit: ++ return res; ++} ++ ++static void rtw_dm_in_lps_hdl(struct adapter *padapter) ++{ ++ rtw_hal_set_hwreg(padapter, HW_VAR_DM_IN_LPS, NULL); ++} ++ ++u8 rtw_dm_in_lps_wk_cmd(struct adapter *padapter) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if (pdrvextra_cmd_parm == NULL) { ++ kfree((unsigned char *)ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = DM_IN_LPS_WK_CID; ++ pdrvextra_cmd_parm->type = 0; ++ pdrvextra_cmd_parm->size = 0; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++ return res; ++ ++} ++ ++static void rtw_lps_change_dtim_hdl(struct adapter *padapter, u8 dtim) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ ++ if (dtim <= 0 || dtim > 16) ++ return; ++ ++ if (rtw_btcoex_IsBtControlLps(padapter) == true) ++ return; ++ ++ down(&pwrpriv->lock); ++ ++ if (pwrpriv->dtim!=dtim) ++ { ++ DBG_871X("change DTIM from %d to %d, bFwCurrentInPSMode =%d, ps_mode =%d\n", pwrpriv->dtim, dtim, ++ pwrpriv->bFwCurrentInPSMode, pwrpriv->pwr_mode); ++ ++ pwrpriv->dtim = dtim; ++ } ++ ++ if ((pwrpriv->bFwCurrentInPSMode ==true) && (pwrpriv->pwr_mode > PS_MODE_ACTIVE)) ++ { ++ u8 ps_mode = pwrpriv->pwr_mode; ++ ++ /* DBG_871X("change DTIM from %d to %d, ps_mode =%d\n", pwrpriv->dtim, dtim, ps_mode); */ ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); ++ } ++ ++ up(&pwrpriv->lock); ++} ++ ++static void rtw_dm_ra_mask_hdl(struct adapter *padapter, struct sta_info *psta) ++{ ++ if (psta) { ++ set_sta_rate(padapter, psta); ++ } ++} ++ ++u8 rtw_dm_ra_mask_wk_cmd(struct adapter *padapter, u8 *psta) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if (pdrvextra_cmd_parm == NULL) { ++ kfree((unsigned char *)ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = DM_RA_MSK_WK_CID; ++ pdrvextra_cmd_parm->type = 0; ++ pdrvextra_cmd_parm->size = 0; ++ pdrvextra_cmd_parm->pbuf = psta; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++ return res; ++ ++} ++ ++static void power_saving_wk_hdl(struct adapter *padapter) ++{ ++ rtw_ps_processor(padapter); ++} ++ ++/* add for CONFIG_IEEE80211W, none 11w can use it */ ++static void reset_securitypriv_hdl(struct adapter *padapter) ++{ ++ rtw_reset_securitypriv(padapter); ++} ++ ++static void free_assoc_resources_hdl(struct adapter *padapter) ++{ ++ rtw_free_assoc_resources(padapter, 1); ++} ++ ++u8 rtw_ps_cmd(struct adapter *padapter) ++{ ++ struct cmd_obj *ppscmd; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ppscmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ppscmd == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if (pdrvextra_cmd_parm == NULL) { ++ kfree((unsigned char *)ppscmd); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID; ++ pdrvextra_cmd_parm->type = 0; ++ pdrvextra_cmd_parm->size = 0; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ppscmd); ++ ++exit: ++ return res; ++} ++ ++static void rtw_chk_hi_queue_hdl(struct adapter *padapter) ++{ ++ struct sta_info *psta_bmc; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ unsigned long start = jiffies; ++ u8 empty = false; ++ ++ psta_bmc = rtw_get_bcmc_stainfo(padapter); ++ if (!psta_bmc) ++ return; ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &empty); ++ ++ while (false == empty && jiffies_to_msecs(jiffies - start) < g_wait_hiq_empty) ++ { ++ msleep(100); ++ rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &empty); ++ } ++ ++ if (psta_bmc->sleepq_len == 0) ++ { ++ if (empty == _SUCCESS) ++ { ++ bool update_tim = false; ++ ++ if (pstapriv->tim_bitmap & BIT(0)) ++ update_tim = true; ++ ++ pstapriv->tim_bitmap &= ~BIT(0); ++ pstapriv->sta_dz_bitmap &= ~BIT(0); ++ ++ if (update_tim == true) ++ update_beacon(padapter, _TIM_IE_, NULL, true); ++ } ++ else /* re check again */ ++ { ++ rtw_chk_hi_queue_cmd(padapter); ++ } ++ ++ } ++ ++} ++ ++u8 rtw_chk_hi_queue_cmd(struct adapter *padapter) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if (pdrvextra_cmd_parm == NULL) { ++ kfree((unsigned char *)ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID; ++ pdrvextra_cmd_parm->type = 0; ++ pdrvextra_cmd_parm->size = 0; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++ return res; ++ ++} ++ ++struct btinfo { ++ u8 cid; ++ u8 len; ++ ++ u8 bConnection:1; ++ u8 bSCOeSCO:1; ++ u8 bInQPage:1; ++ u8 bACLBusy:1; ++ u8 bSCOBusy:1; ++ u8 bHID:1; ++ u8 bA2DP:1; ++ u8 bFTP:1; ++ ++ u8 retry_cnt:4; ++ u8 rsvd_34:1; ++ u8 rsvd_35:1; ++ u8 rsvd_36:1; ++ u8 rsvd_37:1; ++ ++ u8 rssi; ++ ++ u8 rsvd_50:1; ++ u8 rsvd_51:1; ++ u8 rsvd_52:1; ++ u8 rsvd_53:1; ++ u8 rsvd_54:1; ++ u8 rsvd_55:1; ++ u8 eSCO_SCO:1; ++ u8 Master_Slave:1; ++ ++ u8 rsvd_6; ++ u8 rsvd_7; ++}; ++ ++static void rtw_btinfo_hdl(struct adapter *adapter, u8 *buf, u16 buf_len) ++{ ++ #define BTINFO_WIFI_FETCH 0x23 ++ #define BTINFO_BT_AUTO_RPT 0x27 ++ struct btinfo *info = (struct btinfo *)buf; ++ u8 cmd_idx; ++ u8 len; ++ ++ cmd_idx = info->cid; ++ ++ if (info->len > buf_len-2) { ++ rtw_warn_on(1); ++ len = buf_len-2; ++ } else { ++ len = info->len; ++ } ++ ++/* define DBG_PROC_SET_BTINFO_EVT */ ++#ifdef DBG_PROC_SET_BTINFO_EVT ++ btinfo_evt_dump(RTW_DBGDUMP, info); ++#endif ++ ++ /* transform BT-FW btinfo to WiFI-FW C2H format and notify */ ++ if (cmd_idx == BTINFO_WIFI_FETCH) ++ buf[1] = 0; ++ else if (cmd_idx == BTINFO_BT_AUTO_RPT) ++ buf[1] = 2; ++ rtw_btcoex_BtInfoNotify(adapter , len+1, &buf[1]); ++} ++ ++u8 rtw_c2h_packet_wk_cmd(struct adapter *padapter, u8 *pbuf, u16 length) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if (pdrvextra_cmd_parm == NULL) { ++ kfree((u8 *)ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = C2H_WK_CID; ++ pdrvextra_cmd_parm->type = 0; ++ pdrvextra_cmd_parm->size = length; ++ pdrvextra_cmd_parm->pbuf = pbuf; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ return res; ++} ++ ++/* dont call R/W in this function, beucase SDIO interrupt have claim host */ ++/* or deadlock will happen and cause special-systemserver-died in android */ ++u8 rtw_c2h_wk_cmd(struct adapter *padapter, u8 *c2h_evt) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (ph2c == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); ++ if (pdrvextra_cmd_parm == NULL) { ++ kfree((u8 *)ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = C2H_WK_CID; ++ pdrvextra_cmd_parm->type = 0; ++ pdrvextra_cmd_parm->size = c2h_evt?16:0; ++ pdrvextra_cmd_parm->pbuf = c2h_evt; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++ return res; ++} ++ ++static void c2h_wk_callback(_workitem *work) ++{ ++ struct evt_priv *evtpriv = container_of(work, struct evt_priv, c2h_wk); ++ struct adapter *adapter = container_of(evtpriv, struct adapter, evtpriv); ++ u8 *c2h_evt; ++ c2h_id_filter ccx_id_filter = rtw_hal_c2h_id_filter_ccx(adapter); ++ ++ evtpriv->c2h_wk_alive = true; ++ ++ while (!rtw_cbuf_empty(evtpriv->c2h_queue)) { ++ if ((c2h_evt = (u8 *)rtw_cbuf_pop(evtpriv->c2h_queue)) != NULL) { ++ /* This C2H event is read, clear it */ ++ c2h_evt_clear(adapter); ++ } else if ((c2h_evt = (u8 *)rtw_malloc(16)) != NULL) { ++ /* This C2H event is not read, read & clear now */ ++ if (rtw_hal_c2h_evt_read(adapter, c2h_evt) != _SUCCESS) { ++ kfree(c2h_evt); ++ continue; ++ } ++ } ++ ++ /* Special pointer to trigger c2h_evt_clear only */ ++ if ((void *)c2h_evt == (void *)evtpriv) ++ continue; ++ ++ if (!rtw_hal_c2h_valid(adapter, c2h_evt)) { ++ kfree(c2h_evt); ++ continue; ++ } ++ ++ if (ccx_id_filter(c2h_evt) == true) { ++ /* Handle CCX report here */ ++ rtw_hal_c2h_handler(adapter, c2h_evt); ++ kfree(c2h_evt); ++ } else { ++ /* Enqueue into cmd_thread for others */ ++ rtw_c2h_wk_cmd(adapter, c2h_evt); ++ } ++ } ++ ++ evtpriv->c2h_wk_alive = false; ++} ++ ++u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ struct drvextra_cmd_parm *pdrvextra_cmd; ++ ++ if (!pbuf) ++ return H2C_PARAMETERS_ERROR; ++ ++ pdrvextra_cmd = (struct drvextra_cmd_parm*)pbuf; ++ ++ switch (pdrvextra_cmd->ec_id) ++ { ++ case DYNAMIC_CHK_WK_CID:/* only primary padapter go to this cmd, but execute dynamic_chk_wk_hdl() for two interfaces */ ++ dynamic_chk_wk_hdl(padapter); ++ break; ++ case POWER_SAVING_CTRL_WK_CID: ++ power_saving_wk_hdl(padapter); ++ break; ++ case LPS_CTRL_WK_CID: ++ lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type); ++ break; ++ case DM_IN_LPS_WK_CID: ++ rtw_dm_in_lps_hdl(padapter); ++ break; ++ case LPS_CHANGE_DTIM_CID: ++ rtw_lps_change_dtim_hdl(padapter, (u8)pdrvextra_cmd->type); ++ break; ++ case CHECK_HIQ_WK_CID: ++ rtw_chk_hi_queue_hdl(padapter); ++ break; ++#ifdef CONFIG_INTEL_WIDI ++ case INTEl_WIDI_WK_CID: ++ intel_widi_wk_hdl(padapter, pdrvextra_cmd->type, pdrvextra_cmd->pbuf); ++ break; ++#endif /* CONFIG_INTEL_WIDI */ ++ /* add for CONFIG_IEEE80211W, none 11w can use it */ ++ case RESET_SECURITYPRIV: ++ reset_securitypriv_hdl(padapter); ++ break; ++ case FREE_ASSOC_RESOURCES: ++ free_assoc_resources_hdl(padapter); ++ break; ++ case C2H_WK_CID: ++ rtw_hal_set_hwreg_with_buf(padapter, HW_VAR_C2H_HANDLE, pdrvextra_cmd->pbuf, pdrvextra_cmd->size); ++ break; ++ case DM_RA_MSK_WK_CID: ++ rtw_dm_ra_mask_hdl(padapter, (struct sta_info *)pdrvextra_cmd->pbuf); ++ break; ++ case BTINFO_WK_CID: ++ rtw_btinfo_hdl(padapter , pdrvextra_cmd->pbuf, pdrvextra_cmd->size); ++ break; ++ default: ++ break; ++ } ++ ++ if (pdrvextra_cmd->pbuf && pdrvextra_cmd->size>0) ++ { ++ kfree(pdrvextra_cmd->pbuf); ++ } ++ ++ return H2C_SUCCESS; ++} ++ ++void rtw_survey_cmd_callback(struct adapter *padapter , struct cmd_obj *pcmd) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ if (pcmd->res == H2C_DROPPED) ++ { ++ /* TODO: cancel timer and do timeout handler directly... */ ++ /* need to make timeout handlerOS independent */ ++ _set_timer(&pmlmepriv->scan_to_timer, 1); ++ } ++ else if (pcmd->res != H2C_SUCCESS) { ++ _set_timer(&pmlmepriv->scan_to_timer, 1); ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ********Error: MgntActrtw_set_802_11_bssid_LIST_SCAN Fail ************\n\n.")); ++ } ++ ++ /* free cmd */ ++ rtw_free_cmd_obj(pcmd); ++} ++ ++void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ if (pcmd->res != H2C_SUCCESS) ++ { ++ spin_lock_bh(&pmlmepriv->lock); ++ set_fwstate(pmlmepriv, _FW_LINKED); ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ***Error: disconnect_cmd_callback Fail ***\n.")); ++ return; ++ } ++ /* free cmd */ ++ rtw_free_cmd_obj(pcmd); ++} ++ ++void rtw_joinbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ if (pcmd->res == H2C_DROPPED) ++ { ++ /* TODO: cancel timer and do timeout handler directly... */ ++ /* need to make timeout handlerOS independent */ ++ _set_timer(&pmlmepriv->assoc_timer, 1); ++ } ++ else if (pcmd->res != H2C_SUCCESS) ++ { ++ _set_timer(&pmlmepriv->assoc_timer, 1); ++ } ++ ++ rtw_free_cmd_obj(pcmd); ++} ++ ++void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) ++{ ++ u8 timer_cancelled; ++ struct sta_info *psta = NULL; ++ struct wlan_network *pwlan = NULL; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf; ++ struct wlan_network *tgt_network = &(pmlmepriv->cur_network); ++ ++ if (pcmd->parmbuf == NULL) ++ goto exit; ++ ++ if ((pcmd->res != H2C_SUCCESS)) ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ********Error: rtw_createbss_cmd_callback Fail ************\n\n.")); ++ _set_timer(&pmlmepriv->assoc_timer, 1); ++ } ++ ++ _cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled); ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ { ++ psta = rtw_get_stainfo(&padapter->stapriv, pnetwork->MacAddress); ++ if (!psta) ++ { ++ psta = rtw_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress); ++ if (psta == NULL) ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nCan't alloc sta_info when createbss_cmd_callback\n")); ++ goto createbss_cmd_fail ; ++ } ++ } ++ ++ rtw_indicate_connect(padapter); ++ } ++ else ++ { ++ pwlan = _rtw_alloc_network(pmlmepriv); ++ spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); ++ if (pwlan == NULL) ++ { ++ pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue); ++ if (pwlan == NULL) ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n Error: can't get pwlan in rtw_joinbss_event_callback\n")); ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ goto createbss_cmd_fail; ++ } ++ pwlan->last_scanned = jiffies; ++ } ++ else ++ { ++ list_add_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue); ++ } ++ ++ pnetwork->Length = get_wlan_bssid_ex_sz(pnetwork); ++ memcpy(&(pwlan->network), pnetwork, pnetwork->Length); ++ /* pwlan->fixed = true; */ ++ ++ /* list_add_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue); */ ++ ++ /* copy pdev_network information to pmlmepriv->cur_network */ ++ memcpy(&tgt_network->network, pnetwork, (get_wlan_bssid_ex_sz(pnetwork))); ++ ++ /* reset DSConfig */ ++ /* tgt_network->network.Configuration.DSConfig = (u32)rtw_ch2freq(pnetwork->Configuration.DSConfig); */ ++ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ /* we will set _FW_LINKED when there is one more sat to join us (rtw_stassoc_event_callback) */ ++ ++ } ++ ++createbss_cmd_fail: ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++exit: ++ rtw_free_cmd_obj(pcmd); ++} ++ ++ ++ ++void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter , struct cmd_obj *pcmd) ++{ ++ ++ struct sta_priv * pstapriv = &padapter->stapriv; ++ struct set_stakey_rsp* psetstakey_rsp = (struct set_stakey_rsp*) (pcmd->rsp); ++ struct sta_info*psta = rtw_get_stainfo(pstapriv, psetstakey_rsp->addr); ++ ++ if (psta == NULL) ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nERROR: rtw_setstaKey_cmdrsp_callback => can't get sta_info\n\n")); ++ goto exit; ++ } ++exit: ++ rtw_free_cmd_obj(pcmd); ++} ++ ++void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd) ++{ ++ struct sta_priv * pstapriv = &padapter->stapriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct set_assocsta_parm* passocsta_parm = (struct set_assocsta_parm*)(pcmd->parmbuf); ++ struct set_assocsta_rsp* passocsta_rsp = (struct set_assocsta_rsp*) (pcmd->rsp); ++ struct sta_info*psta = rtw_get_stainfo(pstapriv, passocsta_parm->addr); ++ ++ if (psta == NULL) ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nERROR: setassocsta_cmdrsp_callbac => can't get sta_info\n\n")); ++ goto exit; ++ } ++ ++ psta->aid = psta->mac_id = passocsta_rsp->cam_id; ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) && (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true)) ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ ++ set_fwstate(pmlmepriv, _FW_LINKED); ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++exit: ++ rtw_free_cmd_obj(pcmd); ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_debug.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_debug.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_debug.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_debug.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,1477 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTW_DEBUG_C_ ++ ++#include ++#include ++ ++u32 GlobalDebugLevel = _drv_err_; ++ ++#ifdef CONFIG_DEBUG_RTL871X ++ ++ u64 GlobalDebugComponents = \ ++ _module_rtl871x_xmit_c_ | ++ _module_xmit_osdep_c_ | ++ _module_rtl871x_recv_c_ | ++ _module_recv_osdep_c_ | ++ _module_rtl871x_mlme_c_ | ++ _module_mlme_osdep_c_ | ++ _module_rtl871x_sta_mgt_c_ | ++ _module_rtl871x_cmd_c_ | ++ _module_cmd_osdep_c_ | ++ _module_rtl871x_io_c_ | ++ _module_io_osdep_c_ | ++ _module_os_intfs_c_| ++ _module_rtl871x_security_c_| ++ _module_rtl871x_eeprom_c_| ++ _module_hal_init_c_| ++ _module_hci_hal_init_c_| ++ _module_rtl871x_ioctl_c_| ++ _module_rtl871x_ioctl_set_c_| ++ _module_rtl871x_ioctl_query_c_| ++ _module_rtl871x_pwrctrl_c_| ++ _module_hci_intfs_c_| ++ _module_hci_ops_c_| ++ _module_hci_ops_os_c_| ++ _module_rtl871x_ioctl_os_c| ++ _module_rtl8712_cmd_c_| ++ _module_hal_xmit_c_| ++ _module_rtl8712_recv_c_ | ++ _module_mp_ | ++ _module_efuse_; ++ ++#endif /* CONFIG_DEBUG_RTL871X */ ++ ++#include ++ ++void dump_drv_version(void *sel) ++{ ++ DBG_871X_SEL_NL(sel, "%s %s\n", "rtl8723bs", DRIVERVERSION); ++} ++ ++void dump_log_level(void *sel) ++{ ++ DBG_871X_SEL_NL(sel, "log_level:%d\n", GlobalDebugLevel); ++} ++ ++void sd_f0_reg_dump(void *sel, struct adapter *adapter) ++{ ++ int i; ++ ++ for (i = 0x0;i<= 0xff;i++) ++ { ++ if (i%16 == 0) ++ DBG_871X_SEL_NL(sel, "0x%02x ", i); ++ ++ DBG_871X_SEL(sel, "%02x ", rtw_sd_f0_read8(adapter, i)); ++ ++ if (i%16 == 15) ++ DBG_871X_SEL(sel, "\n"); ++ else if (i%8 ==7) ++ DBG_871X_SEL(sel, "\t"); ++ } ++} ++ ++void mac_reg_dump(void *sel, struct adapter *adapter) ++{ ++ int i, j = 1; ++ ++ DBG_871X_SEL_NL(sel, "======= MAC REG =======\n"); ++ ++ for (i = 0x0;i<0x800;i+=4) ++ { ++ if (j%4 == 1) ++ DBG_871X_SEL_NL(sel, "0x%03x", i); ++ DBG_871X_SEL(sel, " 0x%08x ", rtw_read32(adapter, i)); ++ if ((j++)%4 == 0) ++ DBG_871X_SEL(sel, "\n"); ++ } ++} ++ ++void bb_reg_dump(void *sel, struct adapter *adapter) ++{ ++ int i, j = 1; ++ ++ DBG_871X_SEL_NL(sel, "======= BB REG =======\n"); ++ for (i = 0x800;i<0x1000;i+=4) ++ { ++ if (j%4 == 1) ++ DBG_871X_SEL_NL(sel, "0x%03x", i); ++ DBG_871X_SEL(sel, " 0x%08x ", rtw_read32(adapter, i)); ++ if ((j++)%4 == 0) ++ DBG_871X_SEL(sel, "\n"); ++ } ++} ++ ++void rf_reg_dump(void *sel, struct adapter *adapter) ++{ ++ int i, j = 1, path; ++ u32 value; ++ u8 rf_type = 0; ++ u8 path_nums = 0; ++ ++ rtw_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ if ((RF_1T2R == rf_type) ||(RF_1T1R ==rf_type)) ++ path_nums = 1; ++ else ++ path_nums = 2; ++ ++ DBG_871X_SEL_NL(sel, "======= RF REG =======\n"); ++ ++ for (path = 0;pathprivate; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ if (proc_get_read_addr == 0xeeeeeeee) { ++ DBG_871X_SEL_NL(m, "address not initialized\n"); ++ return 0; ++ } ++ ++ switch (proc_get_read_len) ++ { ++ case 1: ++ DBG_871X_SEL_NL(m, "rtw_read8(0x%x) = 0x%x\n", proc_get_read_addr, rtw_read8(padapter, proc_get_read_addr)); ++ break; ++ case 2: ++ DBG_871X_SEL_NL(m, "rtw_read16(0x%x) = 0x%x\n", proc_get_read_addr, rtw_read16(padapter, proc_get_read_addr)); ++ break; ++ case 4: ++ DBG_871X_SEL_NL(m, "rtw_read32(0x%x) = 0x%x\n", proc_get_read_addr, rtw_read32(padapter, proc_get_read_addr)); ++ break; ++ default: ++ DBG_871X_SEL_NL(m, "error read length =%d\n", proc_get_read_len); ++ break; ++ } ++ ++ return 0; ++} ++ ++ssize_t proc_set_read_reg(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ char tmp[16]; ++ u32 addr, len; ++ ++ if (count < 2) ++ { ++ DBG_871X("argument size is less than 2\n"); ++ return -EFAULT; ++ } ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%x %x", &addr, &len); ++ ++ if (num != 2) { ++ DBG_871X("invalid read_reg parameter!\n"); ++ return count; ++ } ++ ++ proc_get_read_addr = addr; ++ ++ proc_get_read_len = len; ++ } ++ ++ return count; ++ ++} ++ ++int proc_get_fwstate(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ DBG_871X_SEL_NL(m, "fwstate = 0x%x\n", get_fwstate(pmlmepriv)); ++ ++ return 0; ++} ++ ++int proc_get_sec_info(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct security_priv *sec = &padapter->securitypriv; ++ ++ DBG_871X_SEL_NL(m, "auth_alg = 0x%x, enc_alg = 0x%x, auth_type = 0x%x, enc_type = 0x%x\n", ++ sec->dot11AuthAlgrthm, sec->dot11PrivacyAlgrthm, ++ sec->ndisauthtype, sec->ndisencryptstatus); ++ ++ DBG_871X_SEL_NL(m, "hw_decrypted =%d\n", sec->hw_decrypted); ++ ++#ifdef DBG_SW_SEC_CNT ++ DBG_871X_SEL_NL(m, "wep_sw_enc_cnt =%llu, %llu, %llu\n" ++ , sec->wep_sw_enc_cnt_bc , sec->wep_sw_enc_cnt_mc, sec->wep_sw_enc_cnt_uc); ++ DBG_871X_SEL_NL(m, "wep_sw_dec_cnt =%llu, %llu, %llu\n" ++ , sec->wep_sw_dec_cnt_bc , sec->wep_sw_dec_cnt_mc, sec->wep_sw_dec_cnt_uc); ++ ++ DBG_871X_SEL_NL(m, "tkip_sw_enc_cnt =%llu, %llu, %llu\n" ++ , sec->tkip_sw_enc_cnt_bc , sec->tkip_sw_enc_cnt_mc, sec->tkip_sw_enc_cnt_uc); ++ DBG_871X_SEL_NL(m, "tkip_sw_dec_cnt =%llu, %llu, %llu\n" ++ , sec->tkip_sw_dec_cnt_bc , sec->tkip_sw_dec_cnt_mc, sec->tkip_sw_dec_cnt_uc); ++ ++ DBG_871X_SEL_NL(m, "aes_sw_enc_cnt =%llu, %llu, %llu\n" ++ , sec->aes_sw_enc_cnt_bc , sec->aes_sw_enc_cnt_mc, sec->aes_sw_enc_cnt_uc); ++ DBG_871X_SEL_NL(m, "aes_sw_dec_cnt =%llu, %llu, %llu\n" ++ , sec->aes_sw_dec_cnt_bc , sec->aes_sw_dec_cnt_mc, sec->aes_sw_dec_cnt_uc); ++#endif /* DBG_SW_SEC_CNT */ ++ ++ return 0; ++} ++ ++int proc_get_mlmext_state(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ DBG_871X_SEL_NL(m, "pmlmeinfo->state = 0x%x\n", pmlmeinfo->state); ++ ++ return 0; ++} ++ ++int proc_get_roam_flags(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ DBG_871X_SEL_NL(m, "0x%02x\n", rtw_roam_flags(adapter)); ++ ++ return 0; ++} ++ ++ssize_t proc_set_roam_flags(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ char tmp[32]; ++ u8 flags; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%hhx", &flags); ++ ++ if (num == 1) ++ rtw_assign_roam_flags(adapter, flags); ++ } ++ ++ return count; ++ ++} ++ ++int proc_get_roam_param(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *mlme = &adapter->mlmepriv; ++ ++ DBG_871X_SEL_NL(m, "%12s %12s %11s\n", "rssi_diff_th", "scanr_exp_ms", "scan_int_ms"); ++ DBG_871X_SEL_NL(m, "%-12u %-12u %-11u\n" ++ , mlme->roam_rssi_diff_th ++ , mlme->roam_scanr_exp_ms ++ , mlme->roam_scan_int_ms ++ ); ++ ++ return 0; ++} ++ ++ssize_t proc_set_roam_param(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *mlme = &adapter->mlmepriv; ++ ++ char tmp[32]; ++ u8 rssi_diff_th; ++ u32 scanr_exp_ms; ++ u32 scan_int_ms; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%hhu %u %u", &rssi_diff_th, &scanr_exp_ms, &scan_int_ms); ++ ++ if (num >= 1) ++ mlme->roam_rssi_diff_th = rssi_diff_th; ++ if (num >= 2) ++ mlme->roam_scanr_exp_ms = scanr_exp_ms; ++ if (num >= 3) ++ mlme->roam_scan_int_ms = scan_int_ms; ++ } ++ ++ return count; ++ ++} ++ ++ssize_t proc_set_roam_tgt_addr(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ char tmp[32]; ++ u8 addr[ETH_ALEN]; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", addr, addr+1, addr+2, addr+3, addr+4, addr+5); ++ if (num == 6) ++ memcpy(adapter->mlmepriv.roam_tgt_addr, addr, ETH_ALEN); ++ ++ DBG_871X("set roam_tgt_addr to "MAC_FMT"\n", MAC_ARG(adapter->mlmepriv.roam_tgt_addr)); ++ } ++ ++ return count; ++} ++ ++int proc_get_qos_option(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ DBG_871X_SEL_NL(m, "qos_option =%d\n", pmlmepriv->qospriv.qos_option); ++ ++ return 0; ++} ++ ++int proc_get_ht_option(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ DBG_871X_SEL_NL(m, "ht_option =%d\n", pmlmepriv->htpriv.ht_option); ++ ++ return 0; ++} ++ ++int proc_get_rf_info(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ DBG_871X_SEL_NL(m, "cur_ch =%d, cur_bw =%d, cur_ch_offet =%d\n", ++ pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset); ++ ++ DBG_871X_SEL_NL(m, "oper_ch =%d, oper_bw =%d, oper_ch_offet =%d\n", ++ rtw_get_oper_ch(padapter), rtw_get_oper_bw(padapter), rtw_get_oper_choffset(padapter)); ++ ++ return 0; ++} ++ ++int proc_get_survey_info(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct __queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ struct list_head *plist, *phead; ++ s32 notify_signal; ++ s16 notify_noise = 0; ++ u16 index = 0; ++ ++ spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); ++ phead = get_list_head(queue); ++ plist = phead ? get_next(phead) : NULL; ++ plist = get_next(phead); ++ if ((!phead) || (!plist)) { ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ return 0; ++ } ++ ++ DBG_871X_SEL_NL(m, "%5s %-17s %3s %-3s %-4s %-4s %5s %s\n","index", "bssid", "ch", "RSSI", "SdBm", "Noise", "age", "ssid"); ++ while (1) ++ { ++ if (phead == plist) ++ break; ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ if (!pnetwork) ++ break; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == true && ++ is_same_network(&pmlmepriv->cur_network.network, &pnetwork->network, 0)) { ++ notify_signal = translate_percentage_to_dbm(padapter->recvpriv.signal_strength);//dbm ++ } else { ++ notify_signal = translate_percentage_to_dbm(pnetwork->network.PhyInfo.SignalStrength);//dbm ++ } ++ ++ #if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) ++ rtw_hal_get_odm_var(padapter, HAL_ODM_NOISE_MONITOR,&(pnetwork->network.Configuration.DSConfig), &(notify_noise)); ++ #endif ++ ++ DBG_871X_SEL_NL(m, "%5d "MAC_FMT" %3d %3d %4d %4d %5d %s\n", ++ ++index, ++ MAC_ARG(pnetwork->network.MacAddress), ++ pnetwork->network.Configuration.DSConfig, ++ (int)pnetwork->network.Rssi, ++ notify_signal, ++ notify_noise, ++ jiffies_to_msecs(jiffies - pnetwork->last_scanned), ++ //translate_percentage_to_dbm(pnetwork->network.PhyInfo.SignalStrength), ++ pnetwork->network.Ssid.Ssid); ++ plist = get_next(plist); ++ } ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ ++ return 0; ++} ++ ++int proc_get_ap_info(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct sta_info *psta; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct wlan_network *cur_network = &(pmlmepriv->cur_network); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress); ++ if (psta) ++ { ++ int i; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ ++ DBG_871X_SEL_NL(m, "SSID =%s\n", cur_network->network.Ssid.Ssid); ++ DBG_871X_SEL_NL(m, "sta's macaddr:" MAC_FMT "\n", MAC_ARG(psta->hwaddr)); ++ DBG_871X_SEL_NL(m, "cur_channel =%d, cur_bwmode =%d, cur_ch_offset =%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset); ++ DBG_871X_SEL_NL(m, "wireless_mode = 0x%x, rtsen =%d, cts2slef =%d\n", psta->wireless_mode, psta->rtsen, psta->cts2self); ++ DBG_871X_SEL_NL(m, "state = 0x%x, aid =%d, macid =%d, raid =%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); ++ DBG_871X_SEL_NL(m, "qos_en =%d, ht_en =%d, init_rate =%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate); ++ DBG_871X_SEL_NL(m, "bwmode =%d, ch_offset =%d, sgi_20m =%d, sgi_40m =%d\n", psta->bw_mode, psta->htpriv.ch_offset, psta->htpriv.sgi_20m, psta->htpriv.sgi_40m); ++ DBG_871X_SEL_NL(m, "ampdu_enable = %d\n", psta->htpriv.ampdu_enable); ++ DBG_871X_SEL_NL(m, "agg_enable_bitmap =%x, candidate_tid_bitmap =%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap); ++ DBG_871X_SEL_NL(m, "ldpc_cap = 0x%x, stbc_cap = 0x%x, beamform_cap = 0x%x\n", psta->htpriv.ldpc_cap, psta->htpriv.stbc_cap, psta->htpriv.beamform_cap); ++ ++ for (i = 0;i<16;i++) ++ { ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ if (preorder_ctrl->enable) ++ { ++ DBG_871X_SEL_NL(m, "tid =%d, indicate_seq =%d\n", i, preorder_ctrl->indicate_seq); ++ } ++ } ++ ++ } ++ else ++ { ++ DBG_871X_SEL_NL(m, "can't get sta's macaddr, cur_network's macaddr:" MAC_FMT "\n", MAC_ARG(cur_network->network.MacAddress)); ++ } ++ ++ return 0; ++} ++ ++int proc_get_adapter_state(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ DBG_871X_SEL_NL(m, "name =%s, bSurpriseRemoved =%d, bDriverStopped =%d\n", ++ dev->name, padapter->bSurpriseRemoved, padapter->bDriverStopped); ++ ++ return 0; ++} ++ ++int proc_get_trx_info(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ int i; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ struct hw_xmit *phwxmit; ++ ++ DBG_871X_SEL_NL(m, "free_xmitbuf_cnt =%d, free_xmitframe_cnt =%d\n" ++ , pxmitpriv->free_xmitbuf_cnt, pxmitpriv->free_xmitframe_cnt); ++ DBG_871X_SEL_NL(m, "free_ext_xmitbuf_cnt =%d, free_xframe_ext_cnt =%d\n" ++ , pxmitpriv->free_xmit_extbuf_cnt, pxmitpriv->free_xframe_ext_cnt); ++ DBG_871X_SEL_NL(m, "free_recvframe_cnt =%d\n" ++ , precvpriv->free_recvframe_cnt); ++ ++ for (i = 0; i < 4; i++) ++ { ++ phwxmit = pxmitpriv->hwxmits + i; ++ DBG_871X_SEL_NL(m, "%d, hwq.accnt =%d\n", i, phwxmit->accnt); ++ } ++ ++ return 0; ++} ++ ++int proc_get_rate_ctl(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ if (adapter->fix_rate != 0xff) { ++ DBG_871X_SEL_NL(m, "FIX\n"); ++ DBG_871X_SEL_NL(m, "0x%02x\n", adapter->fix_rate); ++ } else { ++ DBG_871X_SEL_NL(m, "RA\n"); ++ } ++ ++ return 0; ++} ++ ++ssize_t proc_set_rate_ctl(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ char tmp[32]; ++ u8 fix_rate; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%hhx", &fix_rate); ++ ++ if (num >= 1) ++ adapter->fix_rate = fix_rate; ++ } ++ ++ return count; ++} ++ ++u8 g_fwdl_chksum_fail = 0; ++u8 g_fwdl_wintint_rdy_fail = 0; ++ ++ssize_t proc_set_fwdl_test_case(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ char tmp[32]; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ sscanf(tmp, "%hhu %hhu", &g_fwdl_chksum_fail, &g_fwdl_wintint_rdy_fail); ++ } ++ ++ return count; ++} ++ ++u32 g_wait_hiq_empty = 0; ++ ++ssize_t proc_set_wait_hiq_empty(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ char tmp[32]; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ sscanf(tmp, "%u", &g_wait_hiq_empty); ++ } ++ ++ return count; ++} ++ ++int proc_get_suspend_resume_info(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct dvobj_priv *dvobj = padapter->dvobj; ++ struct debug_priv *pdbgpriv = &dvobj->drv_dbg; ++ ++ DBG_871X_SEL_NL(m, "dbg_sdio_alloc_irq_cnt =%d\n", pdbgpriv->dbg_sdio_alloc_irq_cnt); ++ DBG_871X_SEL_NL(m, "dbg_sdio_free_irq_cnt =%d\n", pdbgpriv->dbg_sdio_free_irq_cnt); ++ DBG_871X_SEL_NL(m, "dbg_sdio_alloc_irq_error_cnt =%d\n", pdbgpriv->dbg_sdio_alloc_irq_error_cnt); ++ DBG_871X_SEL_NL(m, "dbg_sdio_free_irq_error_cnt =%d\n", pdbgpriv->dbg_sdio_free_irq_error_cnt); ++ DBG_871X_SEL_NL(m, "dbg_sdio_init_error_cnt =%d\n", pdbgpriv->dbg_sdio_init_error_cnt); ++ DBG_871X_SEL_NL(m, "dbg_sdio_deinit_error_cnt =%d\n", pdbgpriv->dbg_sdio_deinit_error_cnt); ++ DBG_871X_SEL_NL(m, "dbg_suspend_error_cnt =%d\n", pdbgpriv->dbg_suspend_error_cnt); ++ DBG_871X_SEL_NL(m, "dbg_suspend_cnt =%d\n", pdbgpriv->dbg_suspend_cnt); ++ DBG_871X_SEL_NL(m, "dbg_resume_cnt =%d\n", pdbgpriv->dbg_resume_cnt); ++ DBG_871X_SEL_NL(m, "dbg_resume_error_cnt =%d\n", pdbgpriv->dbg_resume_error_cnt); ++ DBG_871X_SEL_NL(m, "dbg_deinit_fail_cnt =%d\n", pdbgpriv->dbg_deinit_fail_cnt); ++ DBG_871X_SEL_NL(m, "dbg_carddisable_cnt =%d\n", pdbgpriv->dbg_carddisable_cnt); ++ DBG_871X_SEL_NL(m, "dbg_ps_insuspend_cnt =%d\n", pdbgpriv->dbg_ps_insuspend_cnt); ++ DBG_871X_SEL_NL(m, "dbg_dev_unload_inIPS_cnt =%d\n", pdbgpriv->dbg_dev_unload_inIPS_cnt); ++ DBG_871X_SEL_NL(m, "dbg_scan_pwr_state_cnt =%d\n", pdbgpriv->dbg_scan_pwr_state_cnt); ++ DBG_871X_SEL_NL(m, "dbg_downloadfw_pwr_state_cnt =%d\n", pdbgpriv->dbg_downloadfw_pwr_state_cnt); ++ DBG_871X_SEL_NL(m, "dbg_carddisable_error_cnt =%d\n", pdbgpriv->dbg_carddisable_error_cnt); ++ DBG_871X_SEL_NL(m, "dbg_fw_read_ps_state_fail_cnt =%d\n", pdbgpriv->dbg_fw_read_ps_state_fail_cnt); ++ DBG_871X_SEL_NL(m, "dbg_leave_ips_fail_cnt =%d\n", pdbgpriv->dbg_leave_ips_fail_cnt); ++ DBG_871X_SEL_NL(m, "dbg_leave_lps_fail_cnt =%d\n", pdbgpriv->dbg_leave_lps_fail_cnt); ++ DBG_871X_SEL_NL(m, "dbg_h2c_leave32k_fail_cnt =%d\n", pdbgpriv->dbg_h2c_leave32k_fail_cnt); ++ DBG_871X_SEL_NL(m, "dbg_diswow_dload_fw_fail_cnt =%d\n", pdbgpriv->dbg_diswow_dload_fw_fail_cnt); ++ DBG_871X_SEL_NL(m, "dbg_enwow_dload_fw_fail_cnt =%d\n", pdbgpriv->dbg_enwow_dload_fw_fail_cnt); ++ DBG_871X_SEL_NL(m, "dbg_ips_drvopen_fail_cnt =%d\n", pdbgpriv->dbg_ips_drvopen_fail_cnt); ++ DBG_871X_SEL_NL(m, "dbg_poll_fail_cnt =%d\n", pdbgpriv->dbg_poll_fail_cnt); ++ DBG_871X_SEL_NL(m, "dbg_rpwm_toogle_cnt =%d\n", pdbgpriv->dbg_rpwm_toogle_cnt); ++ DBG_871X_SEL_NL(m, "dbg_rpwm_timeout_fail_cnt =%d\n", pdbgpriv->dbg_rpwm_timeout_fail_cnt); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_DBG_COUNTER ++ ++int proc_get_rx_logs(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct rx_logs *rx_logs = &padapter->rx_logs; ++ ++ DBG_871X_SEL_NL(m, ++ "intf_rx =%d\n" ++ "intf_rx_err_recvframe =%d\n" ++ "intf_rx_err_skb =%d\n" ++ "intf_rx_report =%d\n" ++ "core_rx =%d\n" ++ "core_rx_pre =%d\n" ++ "core_rx_pre_ver_err =%d\n" ++ "core_rx_pre_mgmt =%d\n" ++ "core_rx_pre_mgmt_err_80211w =%d\n" ++ "core_rx_pre_mgmt_err =%d\n" ++ "core_rx_pre_ctrl =%d\n" ++ "core_rx_pre_ctrl_err =%d\n" ++ "core_rx_pre_data =%d\n" ++ "core_rx_pre_data_wapi_seq_err =%d\n" ++ "core_rx_pre_data_wapi_key_err =%d\n" ++ "core_rx_pre_data_handled =%d\n" ++ "core_rx_pre_data_err =%d\n" ++ "core_rx_pre_data_unknown =%d\n" ++ "core_rx_pre_unknown =%d\n" ++ "core_rx_enqueue =%d\n" ++ "core_rx_dequeue =%d\n" ++ "core_rx_post =%d\n" ++ "core_rx_post_decrypt =%d\n" ++ "core_rx_post_decrypt_wep =%d\n" ++ "core_rx_post_decrypt_tkip =%d\n" ++ "core_rx_post_decrypt_aes =%d\n" ++ "core_rx_post_decrypt_wapi =%d\n" ++ "core_rx_post_decrypt_hw =%d\n" ++ "core_rx_post_decrypt_unknown =%d\n" ++ "core_rx_post_decrypt_err =%d\n" ++ "core_rx_post_defrag_err =%d\n" ++ "core_rx_post_portctrl_err =%d\n" ++ "core_rx_post_indicate =%d\n" ++ "core_rx_post_indicate_in_oder =%d\n" ++ "core_rx_post_indicate_reoder =%d\n" ++ "core_rx_post_indicate_err =%d\n" ++ "os_indicate =%d\n" ++ "os_indicate_ap_mcast =%d\n" ++ "os_indicate_ap_forward =%d\n" ++ "os_indicate_ap_self =%d\n" ++ "os_indicate_err =%d\n" ++ "os_netif_ok =%d\n" ++ "os_netif_err =%d\n", ++ rx_logs->intf_rx, ++ rx_logs->intf_rx_err_recvframe, ++ rx_logs->intf_rx_err_skb, ++ rx_logs->intf_rx_report, ++ rx_logs->core_rx, ++ rx_logs->core_rx_pre, ++ rx_logs->core_rx_pre_ver_err, ++ rx_logs->core_rx_pre_mgmt, ++ rx_logs->core_rx_pre_mgmt_err_80211w, ++ rx_logs->core_rx_pre_mgmt_err, ++ rx_logs->core_rx_pre_ctrl, ++ rx_logs->core_rx_pre_ctrl_err, ++ rx_logs->core_rx_pre_data, ++ rx_logs->core_rx_pre_data_wapi_seq_err, ++ rx_logs->core_rx_pre_data_wapi_key_err, ++ rx_logs->core_rx_pre_data_handled, ++ rx_logs->core_rx_pre_data_err, ++ rx_logs->core_rx_pre_data_unknown, ++ rx_logs->core_rx_pre_unknown, ++ rx_logs->core_rx_enqueue, ++ rx_logs->core_rx_dequeue, ++ rx_logs->core_rx_post, ++ rx_logs->core_rx_post_decrypt, ++ rx_logs->core_rx_post_decrypt_wep, ++ rx_logs->core_rx_post_decrypt_tkip, ++ rx_logs->core_rx_post_decrypt_aes, ++ rx_logs->core_rx_post_decrypt_wapi, ++ rx_logs->core_rx_post_decrypt_hw, ++ rx_logs->core_rx_post_decrypt_unknown, ++ rx_logs->core_rx_post_decrypt_err, ++ rx_logs->core_rx_post_defrag_err, ++ rx_logs->core_rx_post_portctrl_err, ++ rx_logs->core_rx_post_indicate, ++ rx_logs->core_rx_post_indicate_in_oder, ++ rx_logs->core_rx_post_indicate_reoder, ++ rx_logs->core_rx_post_indicate_err, ++ rx_logs->os_indicate, ++ rx_logs->os_indicate_ap_mcast, ++ rx_logs->os_indicate_ap_forward, ++ rx_logs->os_indicate_ap_self, ++ rx_logs->os_indicate_err, ++ rx_logs->os_netif_ok, ++ rx_logs->os_netif_err ++ ); ++ ++ return 0; ++} ++ ++int proc_get_tx_logs(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct tx_logs *tx_logs = &padapter->tx_logs; ++ ++ DBG_871X_SEL_NL(m, ++ "os_tx =%d\n" ++ "os_tx_err_up =%d\n" ++ "os_tx_err_xmit =%d\n" ++ "os_tx_m2u =%d\n" ++ "os_tx_m2u_ignore_fw_linked =%d\n" ++ "os_tx_m2u_ignore_self =%d\n" ++ "os_tx_m2u_entry =%d\n" ++ "os_tx_m2u_entry_err_xmit =%d\n" ++ "os_tx_m2u_entry_err_skb =%d\n" ++ "os_tx_m2u_stop =%d\n" ++ "core_tx =%d\n" ++ "core_tx_err_pxmitframe =%d\n" ++ "core_tx_err_brtx =%d\n" ++ "core_tx_upd_attrib =%d\n" ++ "core_tx_upd_attrib_adhoc =%d\n" ++ "core_tx_upd_attrib_sta =%d\n" ++ "core_tx_upd_attrib_ap =%d\n" ++ "core_tx_upd_attrib_unknown =%d\n" ++ "core_tx_upd_attrib_dhcp =%d\n" ++ "core_tx_upd_attrib_icmp =%d\n" ++ "core_tx_upd_attrib_active =%d\n" ++ "core_tx_upd_attrib_err_ucast_sta =%d\n" ++ "core_tx_upd_attrib_err_ucast_ap_link =%d\n" ++ "core_tx_upd_attrib_err_sta =%d\n" ++ "core_tx_upd_attrib_err_link =%d\n" ++ "core_tx_upd_attrib_err_sec =%d\n" ++ "core_tx_ap_enqueue_warn_fwstate =%d\n" ++ "core_tx_ap_enqueue_warn_sta =%d\n" ++ "core_tx_ap_enqueue_warn_nosta =%d\n" ++ "core_tx_ap_enqueue_warn_link =%d\n" ++ "core_tx_ap_enqueue_warn_trigger =%d\n" ++ "core_tx_ap_enqueue_mcast =%d\n" ++ "core_tx_ap_enqueue_ucast =%d\n" ++ "core_tx_ap_enqueue =%d\n" ++ "intf_tx =%d\n" ++ "intf_tx_pending_ac =%d\n" ++ "intf_tx_pending_fw_under_survey =%d\n" ++ "intf_tx_pending_fw_under_linking =%d\n" ++ "intf_tx_pending_xmitbuf =%d\n" ++ "intf_tx_enqueue =%d\n" ++ "core_tx_enqueue =%d\n" ++ "core_tx_enqueue_class =%d\n" ++ "core_tx_enqueue_class_err_sta =%d\n" ++ "core_tx_enqueue_class_err_nosta =%d\n" ++ "core_tx_enqueue_class_err_fwlink =%d\n" ++ "intf_tx_direct =%d\n" ++ "intf_tx_direct_err_coalesce =%d\n" ++ "intf_tx_dequeue =%d\n" ++ "intf_tx_dequeue_err_coalesce =%d\n" ++ "intf_tx_dump_xframe =%d\n" ++ "intf_tx_dump_xframe_err_txdesc =%d\n" ++ "intf_tx_dump_xframe_err_port =%d\n", ++ tx_logs->os_tx, ++ tx_logs->os_tx_err_up, ++ tx_logs->os_tx_err_xmit, ++ tx_logs->os_tx_m2u, ++ tx_logs->os_tx_m2u_ignore_fw_linked, ++ tx_logs->os_tx_m2u_ignore_self, ++ tx_logs->os_tx_m2u_entry, ++ tx_logs->os_tx_m2u_entry_err_xmit, ++ tx_logs->os_tx_m2u_entry_err_skb, ++ tx_logs->os_tx_m2u_stop, ++ tx_logs->core_tx, ++ tx_logs->core_tx_err_pxmitframe, ++ tx_logs->core_tx_err_brtx, ++ tx_logs->core_tx_upd_attrib, ++ tx_logs->core_tx_upd_attrib_adhoc, ++ tx_logs->core_tx_upd_attrib_sta, ++ tx_logs->core_tx_upd_attrib_ap, ++ tx_logs->core_tx_upd_attrib_unknown, ++ tx_logs->core_tx_upd_attrib_dhcp, ++ tx_logs->core_tx_upd_attrib_icmp, ++ tx_logs->core_tx_upd_attrib_active, ++ tx_logs->core_tx_upd_attrib_err_ucast_sta, ++ tx_logs->core_tx_upd_attrib_err_ucast_ap_link, ++ tx_logs->core_tx_upd_attrib_err_sta, ++ tx_logs->core_tx_upd_attrib_err_link, ++ tx_logs->core_tx_upd_attrib_err_sec, ++ tx_logs->core_tx_ap_enqueue_warn_fwstate, ++ tx_logs->core_tx_ap_enqueue_warn_sta, ++ tx_logs->core_tx_ap_enqueue_warn_nosta, ++ tx_logs->core_tx_ap_enqueue_warn_link, ++ tx_logs->core_tx_ap_enqueue_warn_trigger, ++ tx_logs->core_tx_ap_enqueue_mcast, ++ tx_logs->core_tx_ap_enqueue_ucast, ++ tx_logs->core_tx_ap_enqueue, ++ tx_logs->intf_tx, ++ tx_logs->intf_tx_pending_ac, ++ tx_logs->intf_tx_pending_fw_under_survey, ++ tx_logs->intf_tx_pending_fw_under_linking, ++ tx_logs->intf_tx_pending_xmitbuf, ++ tx_logs->intf_tx_enqueue, ++ tx_logs->core_tx_enqueue, ++ tx_logs->core_tx_enqueue_class, ++ tx_logs->core_tx_enqueue_class_err_sta, ++ tx_logs->core_tx_enqueue_class_err_nosta, ++ tx_logs->core_tx_enqueue_class_err_fwlink, ++ tx_logs->intf_tx_direct, ++ tx_logs->intf_tx_direct_err_coalesce, ++ tx_logs->intf_tx_dequeue, ++ tx_logs->intf_tx_dequeue_err_coalesce, ++ tx_logs->intf_tx_dump_xframe, ++ tx_logs->intf_tx_dump_xframe_err_txdesc, ++ tx_logs->intf_tx_dump_xframe_err_port ++ ); ++ ++ return 0; ++} ++ ++int proc_get_int_logs(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ DBG_871X_SEL_NL(m, ++ "all =%d\n" ++ "err =%d\n" ++ "tbdok =%d\n" ++ "tbder =%d\n" ++ "bcnderr =%d\n" ++ "bcndma =%d\n" ++ "bcndma_e =%d\n" ++ "rx =%d\n" ++ "rx_rdu =%d\n" ++ "rx_fovw =%d\n" ++ "txfovw =%d\n" ++ "mgntok =%d\n" ++ "highdok =%d\n" ++ "bkdok =%d\n" ++ "bedok =%d\n" ++ "vidok =%d\n" ++ "vodok =%d\n", ++ padapter->int_logs.all, ++ padapter->int_logs.err, ++ padapter->int_logs.tbdok, ++ padapter->int_logs.tbder, ++ padapter->int_logs.bcnderr, ++ padapter->int_logs.bcndma, ++ padapter->int_logs.bcndma_e, ++ padapter->int_logs.rx, ++ padapter->int_logs.rx_rdu, ++ padapter->int_logs.rx_fovw, ++ padapter->int_logs.txfovw, ++ padapter->int_logs.mgntok, ++ padapter->int_logs.highdok, ++ padapter->int_logs.bkdok, ++ padapter->int_logs.bedok, ++ padapter->int_logs.vidok, ++ padapter->int_logs.vodok ++ ); ++ ++ return 0; ++} ++ ++#endif // CONFIG_DBG_COUNTER ++ ++int proc_get_rx_signal(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ DBG_871X_SEL_NL(m, "rssi:%d\n", padapter->recvpriv.rssi); ++ //DBG_871X_SEL_NL(m, "rxpwdb:%d\n", padapter->recvpriv.rxpwdb); ++ DBG_871X_SEL_NL(m, "signal_strength:%u\n", padapter->recvpriv.signal_strength); ++ DBG_871X_SEL_NL(m, "signal_qual:%u\n", padapter->recvpriv.signal_qual); ++ DBG_871X_SEL_NL(m, "noise:%d\n", padapter->recvpriv.noise); ++ rtw_odm_get_perpkt_rssi(m, padapter); ++ #ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA ++ rtw_get_raw_rssi_info(m, padapter); ++ #endif ++ return 0; ++} ++ ++ ++int proc_get_hw_status(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct dvobj_priv *dvobj = padapter->dvobj; ++ struct debug_priv *pdbgpriv = &dvobj->drv_dbg; ++ ++ DBG_871X_SEL_NL(m, "RX FIFO full count: last_time =%lld, current_time =%lld, differential =%lld\n" ++ , pdbgpriv->dbg_rx_fifo_last_overflow, pdbgpriv->dbg_rx_fifo_curr_overflow, pdbgpriv->dbg_rx_fifo_diff_overflow); ++ ++ return 0; ++} ++ ++ssize_t proc_set_rx_signal(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ char tmp[32]; ++ u32 is_signal_dbg, signal_strength; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%u %u", &is_signal_dbg, &signal_strength); ++ ++ is_signal_dbg = is_signal_dbg == 0?0:1; ++ ++ if (is_signal_dbg && num!=2) ++ return count; ++ ++ signal_strength = signal_strength>100?100:signal_strength; ++ ++ padapter->recvpriv.is_signal_dbg = is_signal_dbg; ++ padapter->recvpriv.signal_strength_dbg =signal_strength; ++ ++ if (is_signal_dbg) ++ DBG_871X("set %s %u\n", "DBG_SIGNAL_STRENGTH", signal_strength); ++ else ++ DBG_871X("set %s\n", "HW_SIGNAL_STRENGTH"); ++ ++ } ++ ++ return count; ++ ++} ++ ++int proc_get_ht_enable(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ ++ if (pregpriv) ++ DBG_871X_SEL_NL(m, "%d\n", pregpriv->ht_enable); ++ ++ return 0; ++} ++ ++ssize_t proc_set_ht_enable(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ char tmp[32]; ++ u32 mode; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ sscanf(tmp, "%d ", &mode); ++ ++ if (pregpriv && mode >= 0 && mode < 2) ++ { ++ pregpriv->ht_enable = mode; ++ printk("ht_enable =%d\n", pregpriv->ht_enable); ++ } ++ } ++ ++ return count; ++ ++} ++ ++int proc_get_bw_mode(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ ++ if (pregpriv) ++ DBG_871X_SEL_NL(m, "0x%02x\n", pregpriv->bw_mode); ++ ++ return 0; ++} ++ ++ssize_t proc_set_bw_mode(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ char tmp[32]; ++ u32 mode; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ sscanf(tmp, "%d ", &mode); ++ ++ if (pregpriv && mode < 2) ++ { ++ ++ pregpriv->bw_mode = mode; ++ printk("bw_mode =%d\n", mode); ++ ++ } ++ } ++ ++ return count; ++ ++} ++ ++int proc_get_ampdu_enable(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ ++ if (pregpriv) ++ DBG_871X_SEL_NL(m, "%d\n", pregpriv->ampdu_enable); ++ ++ return 0; ++} ++ ++ssize_t proc_set_ampdu_enable(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ char tmp[32]; ++ u32 mode; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ sscanf(tmp, "%d ", &mode); ++ ++ if (pregpriv && mode < 3) ++ { ++ pregpriv->ampdu_enable = mode; ++ printk("ampdu_enable =%d\n", mode); ++ } ++ ++ } ++ ++ return count; ++ ++} ++ ++int proc_get_rx_ampdu(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if (pregpriv) ++ DBG_871X_SEL_NL(m, ++ "bAcceptAddbaReq = %d , 0:Reject AP's Add BA req, 1:Accept AP's Add BA req.\n", pmlmeinfo->bAcceptAddbaReq ++ ); ++ ++ return 0; ++} ++ ++ssize_t proc_set_rx_ampdu(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ char tmp[32]; ++ u32 mode; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ sscanf(tmp, "%d ", &mode); ++ ++ if (pregpriv && mode >= 0 && mode < 2) ++ { ++ pmlmeinfo->bAcceptAddbaReq = mode; ++ DBG_871X("pmlmeinfo->bAcceptAddbaReq =%d\n", pmlmeinfo->bAcceptAddbaReq); ++ if (mode == 0) ++ { ++ //tear down Rx AMPDU ++ send_delba(padapter, 0, get_my_bssid(&(pmlmeinfo->network)));// recipient ++ } ++ } ++ ++ } ++ ++ return count; ++} ++ ++int proc_get_en_fwps(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ ++ if (pregpriv) ++ DBG_871X_SEL_NL(m, "check_fw_ps = %d , 1:enable get FW PS state , 0: disable get FW PS state\n" ++ , pregpriv->check_fw_ps); ++ ++ return 0; ++} ++ ++ssize_t proc_set_en_fwps(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ char tmp[32]; ++ u32 mode; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ sscanf(tmp, "%d ", &mode); ++ ++ if (pregpriv && mode >= 0 && mode < 2) { ++ pregpriv->check_fw_ps = mode; ++ DBG_871X("pregpriv->check_fw_ps =%d\n", pregpriv->check_fw_ps); ++ } ++ } ++ return count; ++} ++ ++int proc_get_rx_stbc(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ ++ if (pregpriv) ++ DBG_871X_SEL_NL(m, "%d\n", pregpriv->rx_stbc); ++ ++ return 0; ++} ++ ++ssize_t proc_set_rx_stbc(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ char tmp[32]; ++ u32 mode; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ sscanf(tmp, "%d ", &mode); ++ ++ if (pregpriv && (mode == 0 || mode == 1 || ++ mode == 2 || mode == 3)) { ++ pregpriv->rx_stbc = mode; ++ printk("rx_stbc =%d\n", mode); ++ } ++ } ++ ++ return count; ++ ++} ++ ++int proc_get_rssi_disp(struct seq_file *m, void *v) ++{ ++ return 0; ++} ++ ++ssize_t proc_set_rssi_disp(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ char tmp[32]; ++ u32 enable = 0; ++ ++ if (count < 1) { ++ DBG_8192C("argument size is less than 1\n"); ++ return -EFAULT; ++ } ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ int num = sscanf(tmp, "%x", &enable); ++ ++ if (num != 1) { ++ DBG_8192C("invalid set_rssi_disp parameter!\n"); ++ return count; ++ } ++ ++ if (enable) { ++ DBG_8192C("Linked info Function Enable\n"); ++ padapter->bLinkInfoDump = enable ; ++ } else { ++ DBG_8192C("Linked info Function Disable\n"); ++ padapter->bLinkInfoDump = 0 ; ++ } ++ } ++ return count; ++} ++ ++int proc_get_all_sta_info(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct sta_info *psta; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ int i, j; ++ struct list_head *plist, *phead; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ ++ DBG_871X_SEL_NL(m, "sta_dz_bitmap = 0x%x, tim_bitmap = 0x%x\n", pstapriv->sta_dz_bitmap, pstapriv->tim_bitmap); ++ ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ ++ for (i = 0; i < NUM_STA; i++) { ++ phead = &(pstapriv->sta_hash[i]); ++ plist = get_next(phead); ++ ++ while (phead != plist) { ++ psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); ++ ++ plist = get_next(plist); ++ ++ DBG_871X_SEL_NL(m, "==============================\n"); ++ DBG_871X_SEL_NL(m, "sta's macaddr:" MAC_FMT "\n", ++ MAC_ARG(psta->hwaddr)); ++ DBG_871X_SEL_NL(m, "rtsen =%d, cts2slef =%d\n", ++ psta->rtsen, psta->cts2self); ++ DBG_871X_SEL_NL(m, "state = 0x%x, aid =%d, macid =%d, raid =%d\n", ++ psta->state, psta->aid, psta->mac_id, ++ psta->raid); ++ DBG_871X_SEL_NL(m, "qos_en =%d, ht_en =%d, init_rate =%d\n", ++ psta->qos_option, ++ psta->htpriv.ht_option, ++ psta->init_rate); ++ DBG_871X_SEL_NL(m, "bwmode =%d, ch_offset =%d, sgi_20m =%d, sgi_40m =%d\n", ++ psta->bw_mode, psta->htpriv.ch_offset, ++ psta->htpriv.sgi_20m, ++ psta->htpriv.sgi_40m); ++ DBG_871X_SEL_NL(m, "ampdu_enable = %d\n", ++ psta->htpriv.ampdu_enable); ++ DBG_871X_SEL_NL(m, "agg_enable_bitmap =%x, candidate_tid_bitmap =%x\n", ++ psta->htpriv.agg_enable_bitmap, ++ psta->htpriv.candidate_tid_bitmap); ++ DBG_871X_SEL_NL(m, "sleepq_len =%d\n", ++ psta->sleepq_len); ++ DBG_871X_SEL_NL(m, "sta_xmitpriv.vo_q_qcnt =%d\n", ++ psta->sta_xmitpriv.vo_q.qcnt); ++ DBG_871X_SEL_NL(m, "sta_xmitpriv.vi_q_qcnt =%d\n", ++ psta->sta_xmitpriv.vi_q.qcnt); ++ DBG_871X_SEL_NL(m, "sta_xmitpriv.be_q_qcnt =%d\n", ++ psta->sta_xmitpriv.be_q.qcnt); ++ DBG_871X_SEL_NL(m, "sta_xmitpriv.bk_q_qcnt =%d\n", ++ psta->sta_xmitpriv.bk_q.qcnt); ++ ++ DBG_871X_SEL_NL(m, "capability = 0x%x\n", ++ psta->capability); ++ DBG_871X_SEL_NL(m, "flags = 0x%x\n", psta->flags); ++ DBG_871X_SEL_NL(m, "wpa_psk = 0x%x\n", psta->wpa_psk); ++ DBG_871X_SEL_NL(m, "wpa2_group_cipher = 0x%x\n", ++ psta->wpa2_group_cipher); ++ DBG_871X_SEL_NL(m, "wpa2_pairwise_cipher = 0x%x\n", ++ psta->wpa2_pairwise_cipher); ++ DBG_871X_SEL_NL(m, "qos_info = 0x%x\n", psta->qos_info); ++ DBG_871X_SEL_NL(m, "dot118021XPrivacy = 0x%x\n", ++ psta->dot118021XPrivacy); ++ ++ for (j = 0; j < 16; j++) { ++ preorder_ctrl = &psta->recvreorder_ctrl[j]; ++ if (preorder_ctrl->enable) ++ DBG_871X_SEL_NL(m, "tid =%d, indicate_seq =%d\n", ++ j, preorder_ctrl->indicate_seq); ++ } ++ DBG_871X_SEL_NL(m, "==============================\n"); ++ } ++ } ++ ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++ ++ return 0; ++} ++ ++int proc_get_btcoex_dbg(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter; ++ char buf[512] = {0}; ++ padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ rtw_btcoex_GetDBG(padapter, buf, 512); ++ ++ DBG_871X_SEL(m, "%s", buf); ++ ++ return 0; ++} ++ ++ssize_t proc_set_btcoex_dbg(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter; ++ u8 tmp[80] = {0}; ++ u32 module[2] = {0}; ++ u32 num; ++ ++ padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++// DBG_871X("+" FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(padapter)); ++ ++ if (NULL == buffer) ++ { ++ DBG_871X(FUNC_ADPT_FMT ": input buffer is NULL!\n", ++ FUNC_ADPT_ARG(padapter)); ++ ++ return -EFAULT; ++ } ++ ++ if (count < 1) ++ { ++ DBG_871X(FUNC_ADPT_FMT ": input length is 0!\n", ++ FUNC_ADPT_ARG(padapter)); ++ ++ return -EFAULT; ++ } ++ ++ num = count; ++ if (num > (sizeof(tmp) - 1)) ++ num = (sizeof(tmp) - 1); ++ ++ if (copy_from_user(tmp, buffer, num)) ++ { ++ DBG_871X(FUNC_ADPT_FMT ": copy buffer from user space FAIL!\n", ++ FUNC_ADPT_ARG(padapter)); ++ ++ return -EFAULT; ++ } ++ ++ num = sscanf(tmp, "%x %x", module, module+1); ++ if (1 == num) ++ { ++ if (0 == module[0]) ++ memset(module, 0, sizeof(module)); ++ else ++ memset(module, 0xFF, sizeof(module)); ++ } ++ else if (2 != num) ++ { ++ DBG_871X(FUNC_ADPT_FMT ": input(\"%s\") format incorrect!\n", ++ FUNC_ADPT_ARG(padapter), tmp); ++ ++ if (0 == num) ++ return -EFAULT; ++ } ++ ++ DBG_871X(FUNC_ADPT_FMT ": input 0x%08X 0x%08X\n", ++ FUNC_ADPT_ARG(padapter), module[0], module[1]); ++ rtw_btcoex_SetDBG(padapter, module); ++ ++ return count; ++} ++ ++int proc_get_btcoex_info(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter; ++ const u32 bufsize = 30*100; ++ u8 *pbuf = NULL; ++ ++ padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ pbuf = rtw_zmalloc(bufsize); ++ if (NULL == pbuf) { ++ return -ENOMEM; ++ } ++ ++ rtw_btcoex_DisplayBtCoexInfo(padapter, pbuf, bufsize); ++ ++ DBG_871X_SEL(m, "%s\n", pbuf); ++ ++ kfree(pbuf); ++ ++ return 0; ++} ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_eeprom.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_eeprom.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_eeprom.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_eeprom.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,375 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTW_EEPROM_C_ ++ ++#include ++#include ++#include ++ ++void up_clk(_adapter*padapter, u16 *x) ++{ ++_func_enter_; ++ *x = *x | _EESK; ++ rtw_write8(padapter, EE_9346CR, (u8)*x); ++ udelay(CLOCK_RATE); ++ ++_func_exit_; ++ ++} ++ ++void down_clk(_adapter *padapter, u16 *x ) ++{ ++_func_enter_; ++ *x = *x & ~_EESK; ++ rtw_write8(padapter, EE_9346CR, (u8)*x); ++ udelay(CLOCK_RATE); ++_func_exit_; ++} ++ ++void shift_out_bits(_adapter *padapter, u16 data, u16 count) ++{ ++ u16 x,mask; ++_func_enter_; ++ ++ if(padapter->bSurpriseRemoved==true) { ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); ++ goto out; ++ } ++ mask = 0x01 << (count - 1); ++ x = rtw_read8(padapter, EE_9346CR); ++ ++ x &= ~(_EEDO | _EEDI); ++ ++ do ++ { ++ x &= ~_EEDI; ++ if(data & mask) ++ x |= _EEDI; ++ if(padapter->bSurpriseRemoved==true) { ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); ++ goto out; ++ } ++ rtw_write8(padapter, EE_9346CR, (u8)x); ++ udelay(CLOCK_RATE); ++ up_clk(padapter, &x); ++ down_clk(padapter, &x); ++ mask = mask >> 1; ++ } while(mask); ++ if(padapter->bSurpriseRemoved==true) { ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); ++ goto out; ++ } ++ x &= ~_EEDI; ++ rtw_write8(padapter, EE_9346CR, (u8)x); ++out: ++_func_exit_; ++} ++ ++u16 shift_in_bits (_adapter *padapter) ++{ ++ u16 x,d=0,i; ++_func_enter_; ++ if(padapter->bSurpriseRemoved==true) { ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); ++ goto out; ++ } ++ x = rtw_read8(padapter, EE_9346CR); ++ ++ x &= ~(_EEDO | _EEDI); ++ d = 0; ++ ++ for(i=0; i<16; i++) ++ { ++ d = d << 1; ++ up_clk(padapter, &x); ++ if(padapter->bSurpriseRemoved==true) { ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); ++ goto out; ++ } ++ x = rtw_read8(padapter, EE_9346CR); ++ ++ x &= ~(_EEDI); ++ if(x & _EEDO) ++ d |= 1; ++ ++ down_clk(padapter, &x); ++ } ++out: ++_func_exit_; ++ ++ return d; ++} ++ ++void standby(_adapter *padapter ) ++{ ++ u8 x; ++_func_enter_; ++ x = rtw_read8(padapter, EE_9346CR); ++ ++ x &= ~(_EECS | _EESK); ++ rtw_write8(padapter, EE_9346CR,x); ++ ++ udelay(CLOCK_RATE); ++ x |= _EECS; ++ rtw_write8(padapter, EE_9346CR, x); ++ udelay(CLOCK_RATE); ++_func_exit_; ++} ++ ++u16 wait_eeprom_cmd_done(_adapter* padapter) ++{ ++ u8 x; ++ u16 i,res=false; ++_func_enter_; ++ standby(padapter ); ++ for (i=0; i<200; i++) ++ { ++ x = rtw_read8(padapter, EE_9346CR); ++ if (x & _EEDO) { ++ res=true; ++ goto exit; ++ } ++ udelay(CLOCK_RATE); ++ } ++exit: ++_func_exit_; ++ return res; ++} ++ ++void eeprom_clean(_adapter *padapter) ++{ ++ u16 x; ++_func_enter_; ++ if(padapter->bSurpriseRemoved==true) { ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); ++ goto out; ++ } ++ x = rtw_read8(padapter, EE_9346CR); ++ if(padapter->bSurpriseRemoved==true) { ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); ++ goto out; ++ } ++ x &= ~(_EECS | _EEDI); ++ rtw_write8(padapter, EE_9346CR, (u8)x); ++ if(padapter->bSurpriseRemoved==true) { ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); ++ goto out; ++ } ++ up_clk(padapter, &x); ++ if(padapter->bSurpriseRemoved==true) { ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); ++ goto out; ++ } ++ down_clk(padapter, &x); ++out: ++_func_exit_; ++} ++ ++void eeprom_write16(_adapter *padapter, u16 reg, u16 data) ++{ ++ u8 x; ++ ++_func_enter_; ++ ++ x = rtw_read8(padapter, EE_9346CR); ++ ++ x &= ~(_EEDI | _EEDO | _EESK | _EEM0); ++ x |= _EEM1 | _EECS; ++ rtw_write8(padapter, EE_9346CR, x); ++ ++ shift_out_bits(padapter, EEPROM_EWEN_OPCODE, 5); ++ ++ if(padapter->EepromAddressSize==8) //CF+ and SDIO ++ shift_out_bits(padapter, 0, 6); ++ else //USB ++ shift_out_bits(padapter, 0, 4); ++ ++ standby(padapter); ++ ++// Commented out by rcnjko, 2004.0 ++// // Erase this particular word. Write the erase opcode and register ++// // number in that order. The opcode is 3bits in length; reg is 6 bits long. ++// shift_out_bits(Adapter, EEPROM_ERASE_OPCODE, 3); ++// shift_out_bits(Adapter, reg, Adapter->EepromAddressSize); ++// ++// if (wait_eeprom_cmd_done(Adapter ) == false) ++// { ++// return; ++// } ++ ++ ++ standby(padapter ); ++ ++ // write the new word to the EEPROM ++ ++ // send the write opcode the EEPORM ++ shift_out_bits(padapter, EEPROM_WRITE_OPCODE, 3); ++ ++ // select which word in the EEPROM that we are writing to. ++ shift_out_bits(padapter, reg, padapter->EepromAddressSize); ++ ++ // write the data to the selected EEPROM word. ++ shift_out_bits(padapter, data, 16); ++ ++ if (wait_eeprom_cmd_done(padapter ) == false) ++ { ++ ++ goto exit; ++ } ++ ++ standby(padapter ); ++ ++ shift_out_bits(padapter, EEPROM_EWDS_OPCODE, 5); ++ shift_out_bits(padapter, reg, 4); ++ ++ eeprom_clean(padapter ); ++exit: ++_func_exit_; ++ return; ++} ++ ++u16 eeprom_read16(_adapter *padapter, u16 reg) //ReadEEprom ++{ ++ ++ u16 x; ++ u16 data=0; ++ ++_func_enter_; ++ ++ if(padapter->bSurpriseRemoved==true) { ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); ++ goto out; ++ } ++ // select EEPROM, reset bits, set _EECS ++ x = rtw_read8(padapter, EE_9346CR); ++ ++ if(padapter->bSurpriseRemoved==true) { ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); ++ goto out; ++ } ++ ++ x &= ~(_EEDI | _EEDO | _EESK | _EEM0); ++ x |= _EEM1 | _EECS; ++ rtw_write8(padapter, EE_9346CR, (unsigned char)x); ++ ++ // write the read opcode and register number in that order ++ // The opcode is 3bits in length, reg is 6 bits long ++ shift_out_bits(padapter, EEPROM_READ_OPCODE, 3); ++ shift_out_bits(padapter, reg, padapter->EepromAddressSize); ++ ++ // Now read the data (16 bits) in from the selected EEPROM word ++ data = shift_in_bits(padapter); ++ ++ eeprom_clean(padapter); ++out: ++_func_exit_; ++ return data; ++ ++ ++} ++ ++ ++ ++ ++//From even offset ++void eeprom_read_sz(_adapter *padapter, u16 reg, u8 *data, u32 sz) ++{ ++ ++ u16 x, data16; ++ u32 i; ++_func_enter_; ++ if(padapter->bSurpriseRemoved==true) { ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); ++ goto out; ++ } ++ // select EEPROM, reset bits, set _EECS ++ x = rtw_read8(padapter, EE_9346CR); ++ ++ if(padapter->bSurpriseRemoved==true) { ++ RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); ++ goto out; ++ } ++ ++ x &= ~(_EEDI | _EEDO | _EESK | _EEM0); ++ x |= _EEM1 | _EECS; ++ rtw_write8(padapter, EE_9346CR, (unsigned char)x); ++ ++ // write the read opcode and register number in that order ++ // The opcode is 3bits in length, reg is 6 bits long ++ shift_out_bits(padapter, EEPROM_READ_OPCODE, 3); ++ shift_out_bits(padapter, reg, padapter->EepromAddressSize); ++ ++ ++ for(i=0; i>8; ++ } ++ ++ eeprom_clean(padapter); ++out: ++_func_exit_; ++ ++ ++ ++} ++ ++ ++//addr_off : address offset of the entry in eeprom (not the tuple number of eeprom (reg); that is addr_off !=reg) ++u8 eeprom_read(_adapter *padapter, u32 addr_off, u8 sz, u8 *rbuf) ++{ ++ u8 quotient, remainder, addr_2align_odd; ++ u16 reg, stmp , i=0, idx = 0; ++_func_enter_; ++ reg = (u16)(addr_off >> 1); ++ addr_2align_odd = (u8)(addr_off & 0x1); ++ ++ if(addr_2align_odd) //read that start at high part: e.g 1,3,5,7,9,... ++ { ++ stmp = eeprom_read16(padapter, reg); ++ rbuf[idx++] = (u8) ((stmp>>8)&0xff); //return hogh-part of the short ++ reg++; sz--; ++ } ++ ++ quotient = sz >> 1; ++ remainder = sz & 0x1; ++ ++ for(i=0 ; i < quotient; i++) ++ { ++ stmp = eeprom_read16(padapter, reg+i); ++ rbuf[idx++] = (u8) (stmp&0xff); ++ rbuf[idx++] = (u8) ((stmp>>8)&0xff); ++ } ++ ++ reg = reg+i; ++ if(remainder) { //end of read at lower part of short : 0,2,4,6,... ++ stmp = eeprom_read16(padapter, reg); ++ rbuf[idx] = (u8)(stmp & 0xff); ++ } ++_func_exit_; ++ return true; ++} ++ ++ ++ ++void read_eeprom_content(_adapter *padapter) ++{ ++ ++_func_enter_; ++ ++ ++_func_exit_; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_efuse.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_efuse.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_efuse.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_efuse.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,654 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTW_EFUSE_C_ ++ ++#include ++#include ++#include ++#include ++ ++ ++/*------------------------Define local variable------------------------------*/ ++u8 fakeEfuseBank = 0; ++u32 fakeEfuseUsedBytes = 0; ++u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE]={0}; ++u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN]={0}; ++u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN]={0}; ++ ++u32 BTEfuseUsedBytes = 0; ++u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; ++u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN]={0}; ++u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN]={0}; ++ ++u32 fakeBTEfuseUsedBytes = 0; ++u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; ++u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN]={0}; ++u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN]={0}; ++/*------------------------Define local variable------------------------------*/ ++ ++/* */ ++#define REG_EFUSE_CTRL 0x0030 ++#define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */ ++/* */ ++ ++bool ++Efuse_Read1ByteFromFakeContent( ++ struct adapter *padapter, ++ u16 Offset, ++ u8 *Value ); ++bool ++Efuse_Read1ByteFromFakeContent( ++ struct adapter *padapter, ++ u16 Offset, ++ u8 *Value ) ++{ ++ if (Offset >= EFUSE_MAX_HW_SIZE) ++ { ++ return false; ++ } ++ /* DbgPrint("Read fake content, offset = %d\n", Offset); */ ++ if (fakeEfuseBank == 0) ++ *Value = fakeEfuseContent[Offset]; ++ else ++ *Value = fakeBTEfuseContent[fakeEfuseBank-1][Offset]; ++ return true; ++} ++ ++bool ++Efuse_Write1ByteToFakeContent( ++ struct adapter *padapter, ++ u16 Offset, ++ u8 Value ); ++bool ++Efuse_Write1ByteToFakeContent( ++ struct adapter *padapter, ++ u16 Offset, ++ u8 Value ) ++{ ++ if (Offset >= EFUSE_MAX_HW_SIZE) ++ { ++ return false; ++ } ++ if (fakeEfuseBank == 0) ++ fakeEfuseContent[Offset] = Value; ++ else ++ { ++ fakeBTEfuseContent[fakeEfuseBank-1][Offset] = Value; ++ } ++ return true; ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: Efuse_PowerSwitch ++ * ++ * Overview: When we want to enable write operation, we should change to ++ * pwr on state. When we stop write, we should switch to 500k mode ++ * and disable LDO 2.5V. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/17/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++void ++Efuse_PowerSwitch( ++struct adapter *padapter, ++u8 bWrite, ++u8 PwrState) ++{ ++ padapter->HalFunc.EfusePowerSwitch(padapter, bWrite, PwrState); ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: Efuse_GetCurrentSize ++ * ++ * Overview: Get current efuse size!!! ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/16/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++u16 ++Efuse_GetCurrentSize( ++ struct adapter * padapter, ++ u8 efuseType, ++ bool bPseudoTest) ++{ ++ u16 ret = 0; ++ ++ ret = padapter->HalFunc.EfuseGetCurrentSize(padapter, efuseType, bPseudoTest); ++ ++ return ret; ++} ++ ++/* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */ ++u8 ++Efuse_CalculateWordCnts(u8 word_en) ++{ ++ u8 word_cnts = 0; ++ if (!(word_en & BIT(0))) word_cnts++; /* 0 : write enable */ ++ if (!(word_en & BIT(1))) word_cnts++; ++ if (!(word_en & BIT(2))) word_cnts++; ++ if (!(word_en & BIT(3))) word_cnts++; ++ return word_cnts; ++} ++ ++/* */ ++/* Description: */ ++/* 1. Execute E-Fuse read byte operation according as map offset and */ ++/* save to E-Fuse table. */ ++/* 2. Refered from SD1 Richard. */ ++/* */ ++/* Assumption: */ ++/* 1. Boot from E-Fuse and successfully auto-load. */ ++/* 2. PASSIVE_LEVEL (USB interface) */ ++/* */ ++/* Created by Roger, 2008.10.21. */ ++/* */ ++/* 2008/12/12 MH 1. Reorganize code flow and reserve bytes. and add description. */ ++/* 2. Add efuse utilization collect. */ ++/* 2008/12/22 MH Read Efuse must check if we write section 1 data again!!! Sec1 */ ++/* write addr must be after sec5. */ ++/* */ ++ ++void ++efuse_ReadEFuse( ++ struct adapter *Adapter, ++ u8 efuseType, ++ u16 _offset, ++ u16 _size_byte, ++ u8 *pbuf, ++bool bPseudoTest ++ ); ++void ++efuse_ReadEFuse( ++ struct adapter *Adapter, ++ u8 efuseType, ++ u16 _offset, ++ u16 _size_byte, ++ u8 *pbuf, ++bool bPseudoTest ++ ) ++{ ++ Adapter->HalFunc.ReadEFuse(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest); ++} ++ ++void ++EFUSE_GetEfuseDefinition( ++ struct adapter *padapter, ++ u8 efuseType, ++ u8 type, ++ void *pOut, ++ bool bPseudoTest ++ ) ++{ ++ padapter->HalFunc.EFUSEGetEfuseDefinition(padapter, efuseType, type, pOut, bPseudoTest); ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: EFUSE_Read1Byte ++ * ++ * Overview: Copy from WMAC fot EFUSE read 1 byte. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 09/23/2008 MHC Copy from WMAC. ++ * ++ *---------------------------------------------------------------------------*/ ++u8 ++EFUSE_Read1Byte( ++struct adapter *Adapter, ++u16 Address) ++{ ++ u8 data; ++ u8 Bytetemp = {0x00}; ++ u8 temp = {0x00}; ++ u32 k = 0; ++ u16 contentLen = 0; ++ ++ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI , TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&contentLen, false); ++ ++ if (Address < contentLen) /* E-fuse 512Byte */ ++ { ++ /* Write E-fuse Register address bit0~7 */ ++ temp = Address & 0xFF; ++ rtw_write8(Adapter, EFUSE_CTRL+1, temp); ++ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+2); ++ /* Write E-fuse Register address bit8~9 */ ++ temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC); ++ rtw_write8(Adapter, EFUSE_CTRL+2, temp); ++ ++ /* Write 0x30[31]= 0 */ ++ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); ++ temp = Bytetemp & 0x7F; ++ rtw_write8(Adapter, EFUSE_CTRL+3, temp); ++ ++ /* Wait Write-ready (0x30[31]= 1) */ ++ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); ++ while (!(Bytetemp & 0x80)) ++ { ++ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); ++ k++; ++ if (k == 1000) ++ { ++ k = 0; ++ break; ++ } ++ } ++ data =rtw_read8(Adapter, EFUSE_CTRL); ++ return data; ++ } ++ else ++ return 0xFF; ++ ++}/* EFUSE_Read1Byte */ ++ ++/* 11/16/2008 MH Read one byte from real Efuse. */ ++u8 ++efuse_OneByteRead( ++struct adapter *padapter, ++u16 addr, ++u8 *data, ++bool bPseudoTest) ++{ ++ u32 tmpidx = 0; ++ u8 bResult; ++ u8 readbyte; ++ ++ /* DBG_871X("===> EFUSE_OneByteRead(), addr = %x\n", addr); */ ++ /* DBG_871X("===> EFUSE_OneByteRead() start, 0x34 = 0x%X\n", rtw_read32(padapter, EFUSE_TEST)); */ ++ ++ if (bPseudoTest) ++ { ++ bResult = Efuse_Read1ByteFromFakeContent(padapter, addr, data); ++ return bResult; ++ } ++ ++ /* <20130121, Kordan> For SMIC EFUSE specificatoin. */ ++ /* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */ ++ /* PHY_SetMacReg(padapter, 0x34, BIT11, 0); */ ++ rtw_write16(padapter, 0x34, rtw_read16(padapter, 0x34)& (~BIT11)); ++ ++ /* -----------------e-fuse reg ctrl --------------------------------- */ ++ /* address */ ++ rtw_write8(padapter, EFUSE_CTRL+1, (u8)(addr&0xff)); ++ rtw_write8(padapter, EFUSE_CTRL+2, ((u8)((addr>>8) &0x03)) | ++ (rtw_read8(padapter, EFUSE_CTRL+2)&0xFC)); ++ ++ /* rtw_write8(padapter, EFUSE_CTRL+3, 0x72); read cmd */ ++ /* Write bit 32 0 */ ++ readbyte = rtw_read8(padapter, EFUSE_CTRL+3); ++ rtw_write8(padapter, EFUSE_CTRL+3, (readbyte & 0x7f)); ++ ++ while (!(0x80 &rtw_read8(padapter, EFUSE_CTRL+3)) && (tmpidx<1000)) ++ { ++ mdelay(1); ++ tmpidx++; ++ } ++ if (tmpidx<100) ++ { ++ *data =rtw_read8(padapter, EFUSE_CTRL); ++ bResult = true; ++ } ++ else ++ { ++ *data = 0xff; ++ bResult = false; ++ DBG_871X("%s: [ERROR] addr = 0x%x bResult =%d time out 1s !!!\n", __func__, addr, bResult); ++ DBG_871X("%s: [ERROR] EFUSE_CTRL = 0x%08x !!!\n", __func__, rtw_read32(padapter, EFUSE_CTRL)); ++ } ++ ++ return bResult; ++} ++ ++/* 11/16/2008 MH Write one byte to reald Efuse. */ ++u8 ++efuse_OneByteWrite( ++struct adapter *padapter, ++u16 addr, ++u8 data, ++bool bPseudoTest) ++{ ++ u8 tmpidx = 0; ++ u8 bResult =false; ++ u32 efuseValue = 0; ++ ++ /* DBG_871X("===> EFUSE_OneByteWrite(), addr = %x data =%x\n", addr, data); */ ++ /* DBG_871X("===> EFUSE_OneByteWrite() start, 0x34 = 0x%X\n", rtw_read32(padapter, EFUSE_TEST)); */ ++ ++ if (bPseudoTest) ++ { ++ bResult = Efuse_Write1ByteToFakeContent(padapter, addr, data); ++ return bResult; ++ } ++ ++ ++ /* -----------------e-fuse reg ctrl --------------------------------- */ ++ /* address */ ++ ++ ++ efuseValue = rtw_read32(padapter, EFUSE_CTRL); ++ efuseValue |= (BIT21|BIT31); ++ efuseValue &= ~(0x3FFFF); ++ efuseValue |= ((addr<<8 | data) & 0x3FFFF); ++ ++ ++ /* <20130227, Kordan> 8192E MP chip A-cut had better not set 0x34[11] until B-Cut. */ ++ ++ /* <20130121, Kordan> For SMIC EFUSE specificatoin. */ ++ /* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */ ++ /* PHY_SetMacReg(padapter, 0x34, BIT11, 1); */ ++ rtw_write16(padapter, 0x34, rtw_read16(padapter, 0x34)| (BIT11)); ++ rtw_write32(padapter, EFUSE_CTRL, 0x90600000|((addr<<8 | data))); ++ ++ while ((0x80 & rtw_read8(padapter, EFUSE_CTRL+3)) && (tmpidx<100)) { ++ mdelay(1); ++ tmpidx++; ++ } ++ ++ if (tmpidx<100) ++ { ++ bResult = true; ++ } ++ else ++ { ++ bResult = false; ++ DBG_871X("%s: [ERROR] addr = 0x%x , efuseValue = 0x%x , bResult =%d time out 1s !!!\n", ++ __func__, addr, efuseValue, bResult); ++ DBG_871X("%s: [ERROR] EFUSE_CTRL = 0x%08x !!!\n", __func__, rtw_read32(padapter, EFUSE_CTRL)); ++ } ++ ++ /* disable Efuse program enable */ ++ PHY_SetMacReg(padapter, EFUSE_TEST, BIT(11), 0); ++ ++ return bResult; ++} ++ ++int ++Efuse_PgPacketRead(struct adapter *padapter, ++ u8 offset, ++ u8 *data, ++ bool bPseudoTest) ++{ ++ int ret = 0; ++ ++ ret = padapter->HalFunc.Efuse_PgPacketRead(padapter, offset, data, bPseudoTest); ++ ++ return ret; ++} ++ ++int ++Efuse_PgPacketWrite(struct adapter *padapter, ++ u8 offset, ++ u8 word_en, ++ u8 *data, ++ bool bPseudoTest) ++{ ++ int ret; ++ ++ ret = padapter->HalFunc.Efuse_PgPacketWrite(padapter, offset, word_en, data, bPseudoTest); ++ ++ return ret; ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: efuse_WordEnableDataRead ++ * ++ * Overview: Read allowed word in current efuse section data. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/16/2008 MHC Create Version 0. ++ * 11/21/2008 MHC Fix Write bug when we only enable late word. ++ * ++ *---------------------------------------------------------------------------*/ ++void ++efuse_WordEnableDataRead(u8 word_en, ++ u8 *sourdata, ++ u8 *targetdata) ++{ ++ if (!(word_en&BIT(0))) ++ { ++ targetdata[0] = sourdata[0]; ++ targetdata[1] = sourdata[1]; ++ } ++ if (!(word_en&BIT(1))) ++ { ++ targetdata[2] = sourdata[2]; ++ targetdata[3] = sourdata[3]; ++ } ++ if (!(word_en&BIT(2))) ++ { ++ targetdata[4] = sourdata[4]; ++ targetdata[5] = sourdata[5]; ++ } ++ if (!(word_en&BIT(3))) ++ { ++ targetdata[6] = sourdata[6]; ++ targetdata[7] = sourdata[7]; ++ } ++} ++ ++ ++u8 ++Efuse_WordEnableDataWrite(struct adapter *padapter, ++ u16 efuse_addr, ++ u8 word_en, ++ u8 *data, ++ bool bPseudoTest) ++{ ++ u8 ret = 0; ++ ++ ret = padapter->HalFunc.Efuse_WordEnableDataWrite(padapter, efuse_addr, word_en, data, bPseudoTest); ++ ++ return ret; ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: Efuse_ReadAllMap ++ * ++ * Overview: Read All Efuse content ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/11/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++void ++Efuse_ReadAllMap( ++ struct adapter *padapter, ++ u8 efuseType, ++ u8 *Efuse, ++ bool bPseudoTest); ++void ++Efuse_ReadAllMap( ++ struct adapter *padapter, ++ u8 efuseType, ++ u8 *Efuse, ++ bool bPseudoTest) ++{ ++ u16 mapLen = 0; ++ ++ Efuse_PowerSwitch(padapter, false, true); ++ ++ EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, bPseudoTest); ++ ++ efuse_ReadEFuse(padapter, efuseType, 0, mapLen, Efuse, bPseudoTest); ++ ++ Efuse_PowerSwitch(padapter, false, false); ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: efuse_ShadowRead1Byte ++ * efuse_ShadowRead2Byte ++ * efuse_ShadowRead4Byte ++ * ++ * Overview: Read from efuse init map by one/two/four bytes !!!!! ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/12/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++static void ++efuse_ShadowRead1Byte( ++struct adapter *padapter, ++u16 Offset, ++ u8 *Value) ++{ ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ ++ *Value = pEEPROM->efuse_eeprom_data[Offset]; ++ ++} /* EFUSE_ShadowRead1Byte */ ++ ++/* Read Two Bytes */ ++static void ++efuse_ShadowRead2Byte( ++struct adapter *padapter, ++u16 Offset, ++ u16 *Value) ++{ ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ ++ *Value = pEEPROM->efuse_eeprom_data[Offset]; ++ *Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8; ++ ++} /* EFUSE_ShadowRead2Byte */ ++ ++/* Read Four Bytes */ ++static void ++efuse_ShadowRead4Byte( ++struct adapter *padapter, ++u16 Offset, ++ u32 *Value) ++{ ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ ++ *Value = pEEPROM->efuse_eeprom_data[Offset]; ++ *Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8; ++ *Value |= pEEPROM->efuse_eeprom_data[Offset+2]<<16; ++ *Value |= pEEPROM->efuse_eeprom_data[Offset+3]<<24; ++ ++} /* efuse_ShadowRead4Byte */ ++ ++/*----------------------------------------------------------------------------- ++ * Function: EFUSE_ShadowMapUpdate ++ * ++ * Overview: Transfer current EFUSE content to shadow init and modify map. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/13/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++void EFUSE_ShadowMapUpdate( ++ struct adapter *padapter, ++ u8 efuseType, ++ bool bPseudoTest) ++{ ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ u16 mapLen = 0; ++ ++ EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, bPseudoTest); ++ ++ if (pEEPROM->bautoload_fail_flag == true) ++ { ++ memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen); ++ } ++ else ++ { ++ Efuse_ReadAllMap(padapter, efuseType, pEEPROM->efuse_eeprom_data, bPseudoTest); ++ } ++ ++ /* PlatformMoveMemory((void *)&pHalData->EfuseMap[EFUSE_MODIFY_MAP][0], */ ++ /* void *)&pHalData->EfuseMap[EFUSE_INIT_MAP][0], mapLen); */ ++}/* EFUSE_ShadowMapUpdate */ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: EFUSE_ShadowRead ++ * ++ * Overview: Read from efuse init map !!!!! ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/12/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++void ++EFUSE_ShadowRead( ++ struct adapter *padapter, ++ u8 Type, ++ u16 Offset, ++ u32 *Value ) ++{ ++ if (Type == 1) ++ efuse_ShadowRead1Byte(padapter, Offset, (u8 *)Value); ++ else if (Type == 2) ++ efuse_ShadowRead2Byte(padapter, Offset, (u16 *)Value); ++ else if (Type == 4) ++ efuse_ShadowRead4Byte(padapter, Offset, (u32 *)Value); ++ ++} // EFUSE_ShadowRead +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_ieee80211.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_ieee80211.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_ieee80211.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_ieee80211.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,1488 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _IEEE80211_C ++ ++#include ++#include ++ ++ ++u8 RTW_WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 }; ++u16 RTW_WPA_VERSION = 1; ++u8 WPA_AUTH_KEY_MGMT_NONE[] = { 0x00, 0x50, 0xf2, 0 }; ++u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x50, 0xf2, 1 }; ++u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x50, 0xf2, 2 }; ++u8 WPA_CIPHER_SUITE_NONE[] = { 0x00, 0x50, 0xf2, 0 }; ++u8 WPA_CIPHER_SUITE_WEP40[] = { 0x00, 0x50, 0xf2, 1 }; ++u8 WPA_CIPHER_SUITE_TKIP[] = { 0x00, 0x50, 0xf2, 2 }; ++u8 WPA_CIPHER_SUITE_WRAP[] = { 0x00, 0x50, 0xf2, 3 }; ++u8 WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 }; ++u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 }; ++ ++u16 RSN_VERSION_BSD = 1; ++u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x0f, 0xac, 1 }; ++u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x0f, 0xac, 2 }; ++u8 RSN_CIPHER_SUITE_NONE[] = { 0x00, 0x0f, 0xac, 0 }; ++u8 RSN_CIPHER_SUITE_WEP40[] = { 0x00, 0x0f, 0xac, 1 }; ++u8 RSN_CIPHER_SUITE_TKIP[] = { 0x00, 0x0f, 0xac, 2 }; ++u8 RSN_CIPHER_SUITE_WRAP[] = { 0x00, 0x0f, 0xac, 3 }; ++u8 RSN_CIPHER_SUITE_CCMP[] = { 0x00, 0x0f, 0xac, 4 }; ++u8 RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 }; ++/* */ ++/* for adhoc-master to generate ie and provide supported-rate to fw */ ++/* */ ++ ++static u8 WIFI_CCKRATES[] = ++{(IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK), ++ (IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK), ++ (IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK), ++ (IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK)}; ++ ++static u8 WIFI_OFDMRATES[] = ++{(IEEE80211_OFDM_RATE_6MB), ++ (IEEE80211_OFDM_RATE_9MB), ++ (IEEE80211_OFDM_RATE_12MB), ++ (IEEE80211_OFDM_RATE_18MB), ++ (IEEE80211_OFDM_RATE_24MB), ++ IEEE80211_OFDM_RATE_36MB, ++ IEEE80211_OFDM_RATE_48MB, ++ IEEE80211_OFDM_RATE_54MB}; ++ ++ ++int rtw_get_bit_value_from_ieee_value(u8 val) ++{ ++ unsigned char dot11_rate_table[]={2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 0}; /* last element must be zero!! */ ++ ++ int i = 0; ++ while (dot11_rate_table[i] != 0) { ++ if (dot11_rate_table[i] == val) ++ return BIT(i); ++ i++; ++ } ++ return 0; ++} ++ ++uint rtw_is_cckrates_included(u8 *rate) ++{ ++ u32 i = 0; ++ ++ while (rate[i]!= 0) ++ { ++ if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) || ++ (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22)) ++ return true; ++ i++; ++ } ++ ++ return false; ++} ++ ++uint rtw_is_cckratesonly_included(u8 *rate) ++{ ++ u32 i = 0; ++ ++ ++ while (rate[i]!= 0) ++ { ++ if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && ++ (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22)) ++ ++ return false; ++ ++ i++; ++ } ++ ++ return true; ++ ++} ++ ++int rtw_check_network_type(unsigned char *rate, int ratelen, int channel) ++{ ++ if (channel > 14) ++ { ++ if ((rtw_is_cckrates_included(rate)) == true) ++ return WIRELESS_INVALID; ++ else ++ return WIRELESS_11A; ++ } ++ else /* could be pure B, pure G, or B/G */ ++ { ++ if ((rtw_is_cckratesonly_included(rate)) == true) ++ return WIRELESS_11B; ++ else if ((rtw_is_cckrates_included(rate)) == true) ++ return WIRELESS_11BG; ++ else ++ return WIRELESS_11G; ++ } ++ ++} ++ ++u8 *rtw_set_fixed_ie(unsigned char *pbuf, unsigned int len, unsigned char *source, ++ unsigned int *frlen) ++{ ++ memcpy((void *)pbuf, (void *)source, len); ++ *frlen = *frlen + len; ++ return (pbuf + len); ++} ++ ++/* rtw_set_ie will update frame length */ ++u8 *rtw_set_ie ++( ++ u8 *pbuf, ++ sint index, ++ uint len, ++ u8 *source, ++ uint *frlen /* frame length */ ++) ++{ ++ *pbuf = (u8)index; ++ ++ *(pbuf + 1) = (u8)len; ++ ++ if (len > 0) ++ memcpy((void *)(pbuf + 2), (void *)source, len); ++ ++ *frlen = *frlen + (len + 2); ++ ++ return (pbuf + len + 2); ++} ++ ++/*---------------------------------------------------------------------------- ++index: the information element id index, limit is the limit for search ++-----------------------------------------------------------------------------*/ ++u8 *rtw_get_ie(u8 *pbuf, sint index, sint *len, sint limit) ++{ ++ sint tmp, i; ++ u8 *p; ++ ++ if (limit < 1) { ++ return NULL; ++ } ++ ++ p = pbuf; ++ i = 0; ++ *len = 0; ++ while (1) ++ { ++ if (*p == index) ++ { ++ *len = *(p + 1); ++ return (p); ++ } ++ else ++ { ++ tmp = *(p + 1); ++ p += (tmp + 2); ++ i += (tmp + 2); ++ } ++ if (i >= limit) ++ break; ++ } ++ return NULL; ++} ++ ++/** ++ * rtw_get_ie_ex - Search specific IE from a series of IEs ++ * @in_ie: Address of IEs to search ++ * @in_len: Length limit from in_ie ++ * @eid: Element ID to match ++ * @oui: OUI to match ++ * @oui_len: OUI length ++ * @ie: If not NULL and the specific IE is found, the IE will be copied to the buf starting from the specific IE ++ * @ielen: If not NULL and the specific IE is found, will set to the length of the entire IE ++ * ++ * Returns: The address of the specific IE found, or NULL ++ */ ++u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, uint *ielen) ++{ ++ uint cnt; ++ u8 *target_ie = NULL; ++ ++ ++ if (ielen) ++ *ielen = 0; ++ ++ if (!in_ie || in_len<= 0) ++ return target_ie; ++ ++ cnt = 0; ++ ++ while (cnt 12) ++ break; ++ ++ i++; ++ } ++ return i; ++} ++ ++int rtw_generate_ie(struct registry_priv *pregistrypriv) ++{ ++ u8 wireless_mode; ++ int sz = 0, rateLen; ++ struct wlan_bssid_ex*pdev_network = &pregistrypriv->dev_network; ++ u8*ie = pdev_network->IEs; ++ ++ /* timestamp will be inserted by hardware */ ++ sz += 8; ++ ie += sz; ++ ++ /* beacon interval : 2bytes */ ++ *(__le16*)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod);/* BCN_INTERVAL; */ ++ sz += 2; ++ ie += 2; ++ ++ /* capability info */ ++ *(u16*)ie = 0; ++ ++ *(__le16*)ie |= cpu_to_le16(cap_IBSS); ++ ++ if (pregistrypriv->preamble == PREAMBLE_SHORT) ++ *(__le16*)ie |= cpu_to_le16(cap_ShortPremble); ++ ++ if (pdev_network->Privacy) ++ *(__le16*)ie |= cpu_to_le16(cap_Privacy); ++ ++ sz += 2; ++ ie += 2; ++ ++ /* SSID */ ++ ie = rtw_set_ie(ie, _SSID_IE_, pdev_network->Ssid.SsidLength, pdev_network->Ssid.Ssid, &sz); ++ ++ /* supported rates */ ++ if (pregistrypriv->wireless_mode == WIRELESS_11ABGN) ++ { ++ if (pdev_network->Configuration.DSConfig > 14) ++ wireless_mode = WIRELESS_11A_5N; ++ else ++ wireless_mode = WIRELESS_11BG_24N; ++ } ++ else ++ { ++ wireless_mode = pregistrypriv->wireless_mode; ++ } ++ ++ rtw_set_supported_rate(pdev_network->SupportedRates, wireless_mode) ; ++ ++ rateLen = rtw_get_rateset_len(pdev_network->SupportedRates); ++ ++ if (rateLen > 8) ++ { ++ ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, 8, pdev_network->SupportedRates, &sz); ++ /* ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); */ ++ } ++ else ++ { ++ ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, rateLen, pdev_network->SupportedRates, &sz); ++ } ++ ++ /* DS parameter set */ ++ ie = rtw_set_ie(ie, _DSSET_IE_, 1, (u8 *)&(pdev_network->Configuration.DSConfig), &sz); ++ ++ ++ /* IBSS Parameter Set */ ++ ++ ie = rtw_set_ie(ie, _IBSS_PARA_IE_, 2, (u8 *)&(pdev_network->Configuration.ATIMWindow), &sz); ++ ++ if (rateLen > 8) ++ { ++ ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); ++ } ++ ++ /* HT Cap. */ ++ if (((pregistrypriv->wireless_mode&WIRELESS_11_5N)||(pregistrypriv->wireless_mode&WIRELESS_11_24N)) ++ && (pregistrypriv->ht_enable ==true)) ++ { ++ /* todo: */ ++ } ++ ++ /* pdev_network->IELength = sz; update IELength */ ++ ++ /* return _SUCCESS; */ ++ ++ return sz; ++} ++ ++unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit) ++{ ++ int len; ++ u16 val16; ++ unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01}; ++ u8 *pbuf = pie; ++ int limit_new = limit; ++ __le16 le_tmp; ++ ++ while (1) ++ { ++ pbuf = rtw_get_ie(pbuf, _WPA_IE_ID_, &len, limit_new); ++ ++ if (pbuf) { ++ ++ /* check if oui matches... */ ++ if (memcmp((pbuf + 2), wpa_oui_type, sizeof (wpa_oui_type))) { ++ ++ goto check_next_ie; ++ } ++ ++ /* check version... */ ++ memcpy((u8 *)&le_tmp, (pbuf + 6), sizeof(val16)); ++ ++ val16 = le16_to_cpu(le_tmp); ++ if (val16 != 0x0001) ++ goto check_next_ie; ++ ++ *wpa_ie_len = *(pbuf + 1); ++ ++ return pbuf; ++ ++ } ++ else { ++ ++ *wpa_ie_len = 0; ++ return NULL; ++ } ++ ++check_next_ie: ++ ++ limit_new = limit - (pbuf - pie) - 2 - len; ++ ++ if (limit_new <= 0) ++ break; ++ ++ pbuf += (2 + len); ++ ++ } ++ ++ *wpa_ie_len = 0; ++ ++ return NULL; ++ ++} ++ ++unsigned char *rtw_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit) ++{ ++ ++ return rtw_get_ie(pie, _WPA2_IE_ID_, rsn_ie_len, limit); ++ ++} ++ ++int rtw_get_wpa_cipher_suite(u8 *s) ++{ ++ if (!memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN)) ++ return WPA_CIPHER_NONE; ++ if (!memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN)) ++ return WPA_CIPHER_WEP40; ++ if (!memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN)) ++ return WPA_CIPHER_TKIP; ++ if (!memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN)) ++ return WPA_CIPHER_CCMP; ++ if (!memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN)) ++ return WPA_CIPHER_WEP104; ++ ++ return 0; ++} ++ ++int rtw_get_wpa2_cipher_suite(u8 *s) ++{ ++ if (!memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN)) ++ return WPA_CIPHER_NONE; ++ if (!memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN)) ++ return WPA_CIPHER_WEP40; ++ if (!memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN)) ++ return WPA_CIPHER_TKIP; ++ if (!memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN)) ++ return WPA_CIPHER_CCMP; ++ if (!memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN)) ++ return WPA_CIPHER_WEP104; ++ ++ return 0; ++} ++ ++ ++int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x) ++{ ++ int i, ret = _SUCCESS; ++ int left, count; ++ u8 *pos; ++ u8 SUITE_1X[4] = {0x00, 0x50, 0xf2, 1}; ++ ++ if (wpa_ie_len <= 0) { ++ /* No WPA IE - fail silently */ ++ return _FAIL; ++ } ++ ++ ++ if ((*wpa_ie != _WPA_IE_ID_) || (*(wpa_ie+1) != (u8)(wpa_ie_len - 2)) || ++ (memcmp(wpa_ie+2, RTW_WPA_OUI_TYPE, WPA_SELECTOR_LEN))) ++ { ++ return _FAIL; ++ } ++ ++ pos = wpa_ie; ++ ++ pos += 8; ++ left = wpa_ie_len - 8; ++ ++ ++ /* group_cipher */ ++ if (left >= WPA_SELECTOR_LEN) { ++ ++ *group_cipher = rtw_get_wpa_cipher_suite(pos); ++ ++ pos += WPA_SELECTOR_LEN; ++ left -= WPA_SELECTOR_LEN; ++ ++ } ++ else if (left > 0) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie length mismatch, %u too much", __func__, left)); ++ ++ return _FAIL; ++ } ++ ++ ++ /* pairwise_cipher */ ++ if (left >= 2) ++ { ++ /* count = le16_to_cpu(*(u16*)pos); */ ++ count = RTW_GET_LE16(pos); ++ pos += 2; ++ left -= 2; ++ ++ if (count == 0 || left < count * WPA_SELECTOR_LEN) { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie count botch (pairwise), " ++ "count %u left %u", __func__, count, left)); ++ return _FAIL; ++ } ++ ++ for (i = 0; i < count; i++) ++ { ++ *pairwise_cipher |= rtw_get_wpa_cipher_suite(pos); ++ ++ pos += WPA_SELECTOR_LEN; ++ left -= WPA_SELECTOR_LEN; ++ } ++ ++ } ++ else if (left == 1) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie too short (for key mgmt)", __func__)); ++ return _FAIL; ++ } ++ ++ if (is_8021x) { ++ if (left >= 6) { ++ pos += 2; ++ if (!memcmp(pos, SUITE_1X, 4)) { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s : there has 802.1x auth\n", __func__)); ++ *is_8021x = 1; ++ } ++ } ++ } ++ ++ return ret; ++ ++} ++ ++int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x) ++{ ++ int i, ret = _SUCCESS; ++ int left, count; ++ u8 *pos; ++ u8 SUITE_1X[4] = {0x00, 0x0f, 0xac, 0x01}; ++ ++ if (rsn_ie_len <= 0) { ++ /* No RSN IE - fail silently */ ++ return _FAIL; ++ } ++ ++ ++ if ((*rsn_ie!= _WPA2_IE_ID_) || (*(rsn_ie+1) != (u8)(rsn_ie_len - 2))) ++ { ++ return _FAIL; ++ } ++ ++ pos = rsn_ie; ++ pos += 4; ++ left = rsn_ie_len - 4; ++ ++ /* group_cipher */ ++ if (left >= RSN_SELECTOR_LEN) { ++ ++ *group_cipher = rtw_get_wpa2_cipher_suite(pos); ++ ++ pos += RSN_SELECTOR_LEN; ++ left -= RSN_SELECTOR_LEN; ++ ++ } else if (left > 0) { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie length mismatch, %u too much", __func__, left)); ++ return _FAIL; ++ } ++ ++ /* pairwise_cipher */ ++ if (left >= 2) ++ { ++ /* count = le16_to_cpu(*(u16*)pos); */ ++ count = RTW_GET_LE16(pos); ++ pos += 2; ++ left -= 2; ++ ++ if (count == 0 || left < count * RSN_SELECTOR_LEN) { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie count botch (pairwise), " ++ "count %u left %u", __func__, count, left)); ++ return _FAIL; ++ } ++ ++ for (i = 0; i < count; i++) ++ { ++ *pairwise_cipher |= rtw_get_wpa2_cipher_suite(pos); ++ ++ pos += RSN_SELECTOR_LEN; ++ left -= RSN_SELECTOR_LEN; ++ } ++ ++ } ++ else if (left == 1) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie too short (for key mgmt)", __func__)); ++ ++ return _FAIL; ++ } ++ ++ if (is_8021x) { ++ if (left >= 6) { ++ pos += 2; ++ if (!memcmp(pos, SUITE_1X, 4)) { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s (): there has 802.1x auth\n", __func__)); ++ *is_8021x = 1; ++ } ++ } ++ } ++ ++ return ret; ++ ++} ++ ++/* ifdef CONFIG_WAPI_SUPPORT */ ++int rtw_get_wapi_ie(u8 *in_ie, uint in_len, u8 *wapi_ie, u16 *wapi_len) ++{ ++ int len = 0; ++ u8 authmode, i; ++ uint cnt; ++ u8 wapi_oui1[4]={0x0, 0x14, 0x72, 0x01}; ++ u8 wapi_oui2[4]={0x0, 0x14, 0x72, 0x02}; ++ ++ if (wapi_len) ++ *wapi_len = 0; ++ ++ if (!in_ie || in_len<= 0) ++ return len; ++ ++ cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_); ++ ++ while (cnt found WPS_IE.....\n"); */ ++ *wps_ielen = ie_ptr[1]+2; ++ match =true; ++ } ++ return match; ++} ++ ++/** ++ * rtw_get_wps_ie - Search WPS IE from a series of IEs ++ * @in_ie: Address of IEs to search ++ * @in_len: Length limit from in_ie ++ * @wps_ie: If not NULL and WPS IE is found, WPS IE will be copied to the buf starting from wps_ie ++ * @wps_ielen: If not NULL and WPS IE is found, will set to the length of the entire WPS IE ++ * ++ * Returns: The address of the WPS IE found, or NULL ++ */ ++u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen) ++{ ++ uint cnt; ++ u8 *wpsie_ptr = NULL; ++ u8 eid, wps_oui[4]={0x0, 0x50, 0xf2, 0x04}; ++ ++ if (wps_ielen) ++ *wps_ielen = 0; ++ ++ if (!in_ie || in_len<= 0) ++ return wpsie_ptr; ++ ++ cnt = 0; ++ ++ while (cntwpa_ie = pos; ++ elems->wpa_ie_len = elen; ++ break; ++ case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */ ++ if (elen < 5) { ++ DBG_871X("short WME " ++ "information element ignored " ++ "(len =%lu)\n", ++ (unsigned long) elen); ++ return -1; ++ } ++ switch (pos[4]) { ++ case WME_OUI_SUBTYPE_INFORMATION_ELEMENT: ++ case WME_OUI_SUBTYPE_PARAMETER_ELEMENT: ++ elems->wme = pos; ++ elems->wme_len = elen; ++ break; ++ case WME_OUI_SUBTYPE_TSPEC_ELEMENT: ++ elems->wme_tspec = pos; ++ elems->wme_tspec_len = elen; ++ break; ++ default: ++ DBG_871X("unknown WME " ++ "information element ignored " ++ "(subtype =%d len =%lu)\n", ++ pos[4], (unsigned long) elen); ++ return -1; ++ } ++ break; ++ case 4: ++ /* Wi-Fi Protected Setup (WPS) IE */ ++ elems->wps_ie = pos; ++ elems->wps_ie_len = elen; ++ break; ++ default: ++ DBG_871X("Unknown Microsoft " ++ "information element ignored " ++ "(type =%d len =%lu)\n", ++ pos[3], (unsigned long) elen); ++ return -1; ++ } ++ break; ++ ++ case OUI_BROADCOM: ++ switch (pos[3]) { ++ case VENDOR_HT_CAPAB_OUI_TYPE: ++ elems->vendor_ht_cap = pos; ++ elems->vendor_ht_cap_len = elen; ++ break; ++ default: ++ DBG_871X("Unknown Broadcom " ++ "information element ignored " ++ "(type =%d len =%lu)\n", ++ pos[3], (unsigned long) elen); ++ return -1; ++ } ++ break; ++ ++ default: ++ DBG_871X("unknown vendor specific information " ++ "element ignored (vendor OUI %02x:%02x:%02x " ++ "len =%lu)\n", ++ pos[0], pos[1], pos[2], (unsigned long) elen); ++ return -1; ++ } ++ ++ return 0; ++ ++} ++ ++/** ++ * ieee802_11_parse_elems - Parse information elements in management frames ++ * @start: Pointer to the start of IEs ++ * @len: Length of IE buffer in octets ++ * @elems: Data structure for parsed elements ++ * @show_errors: Whether to show parsing errors in debug log ++ * Returns: Parsing result ++ */ ++ParseRes rtw_ieee802_11_parse_elems(u8 *start, uint len, ++ struct rtw_ieee802_11_elems *elems, ++ int show_errors) ++{ ++ uint left = len; ++ u8 *pos = start; ++ int unknown = 0; ++ ++ memset(elems, 0, sizeof(*elems)); ++ ++ while (left >= 2) { ++ u8 id, elen; ++ ++ id = *pos++; ++ elen = *pos++; ++ left -= 2; ++ ++ if (elen > left) { ++ if (show_errors) { ++ DBG_871X("IEEE 802.11 element " ++ "parse failed (id =%d elen =%d " ++ "left =%lu)\n", ++ id, elen, (unsigned long) left); ++ } ++ return ParseFailed; ++ } ++ ++ switch (id) { ++ case WLAN_EID_SSID: ++ elems->ssid = pos; ++ elems->ssid_len = elen; ++ break; ++ case WLAN_EID_SUPP_RATES: ++ elems->supp_rates = pos; ++ elems->supp_rates_len = elen; ++ break; ++ case WLAN_EID_FH_PARAMS: ++ elems->fh_params = pos; ++ elems->fh_params_len = elen; ++ break; ++ case WLAN_EID_DS_PARAMS: ++ elems->ds_params = pos; ++ elems->ds_params_len = elen; ++ break; ++ case WLAN_EID_CF_PARAMS: ++ elems->cf_params = pos; ++ elems->cf_params_len = elen; ++ break; ++ case WLAN_EID_TIM: ++ elems->tim = pos; ++ elems->tim_len = elen; ++ break; ++ case WLAN_EID_IBSS_PARAMS: ++ elems->ibss_params = pos; ++ elems->ibss_params_len = elen; ++ break; ++ case WLAN_EID_CHALLENGE: ++ elems->challenge = pos; ++ elems->challenge_len = elen; ++ break; ++ case WLAN_EID_ERP_INFO: ++ elems->erp_info = pos; ++ elems->erp_info_len = elen; ++ break; ++ case WLAN_EID_EXT_SUPP_RATES: ++ elems->ext_supp_rates = pos; ++ elems->ext_supp_rates_len = elen; ++ break; ++ case WLAN_EID_VENDOR_SPECIFIC: ++ if (rtw_ieee802_11_parse_vendor_specific(pos, elen, ++ elems, ++ show_errors)) ++ unknown++; ++ break; ++ case WLAN_EID_RSN: ++ elems->rsn_ie = pos; ++ elems->rsn_ie_len = elen; ++ break; ++ case WLAN_EID_PWR_CAPABILITY: ++ elems->power_cap = pos; ++ elems->power_cap_len = elen; ++ break; ++ case WLAN_EID_SUPPORTED_CHANNELS: ++ elems->supp_channels = pos; ++ elems->supp_channels_len = elen; ++ break; ++ case WLAN_EID_MOBILITY_DOMAIN: ++ elems->mdie = pos; ++ elems->mdie_len = elen; ++ break; ++ case WLAN_EID_FAST_BSS_TRANSITION: ++ elems->ftie = pos; ++ elems->ftie_len = elen; ++ break; ++ case WLAN_EID_TIMEOUT_INTERVAL: ++ elems->timeout_int = pos; ++ elems->timeout_int_len = elen; ++ break; ++ case WLAN_EID_HT_CAP: ++ elems->ht_capabilities = pos; ++ elems->ht_capabilities_len = elen; ++ break; ++ case WLAN_EID_HT_OPERATION: ++ elems->ht_operation = pos; ++ elems->ht_operation_len = elen; ++ break; ++ case WLAN_EID_VHT_CAPABILITY: ++ elems->vht_capabilities = pos; ++ elems->vht_capabilities_len = elen; ++ break; ++ case WLAN_EID_VHT_OPERATION: ++ elems->vht_operation = pos; ++ elems->vht_operation_len = elen; ++ break; ++ case WLAN_EID_VHT_OP_MODE_NOTIFY: ++ elems->vht_op_mode_notify = pos; ++ elems->vht_op_mode_notify_len = elen; ++ break; ++ default: ++ unknown++; ++ if (!show_errors) ++ break; ++ DBG_871X("IEEE 802.11 element parse " ++ "ignored unknown element (id =%d elen =%d)\n", ++ id, elen); ++ break; ++ } ++ ++ left -= elen; ++ pos += elen; ++ } ++ ++ if (left) ++ return ParseFailed; ++ ++ return unknown ? ParseUnknown : ParseOK; ++ ++} ++ ++static u8 key_char2num(u8 ch); ++static u8 key_char2num(u8 ch) ++{ ++ if ((ch>='0') && (ch<='9')) ++ return ch - '0'; ++ else if ((ch>='a') && (ch<='f')) ++ return ch - 'a' + 10; ++ else if ((ch>='A') && (ch<='F')) ++ return ch - 'A' + 10; ++ else ++ return 0xff; ++} ++ ++u8 key_2char2num(u8 hch, u8 lch); ++u8 key_2char2num(u8 hch, u8 lch) ++{ ++ return ((key_char2num(hch) << 4) | key_char2num(lch)); ++} ++ ++void rtw_macaddr_cfg(u8 *mac_addr) ++{ ++ u8 mac[ETH_ALEN]; ++ if (mac_addr == NULL) return; ++ ++ if (rtw_initmac) ++ { /* Users specify the mac address */ ++ int jj, kk; ++ ++ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3) ++ { ++ mac[jj] = key_2char2num(rtw_initmac[kk], rtw_initmac[kk+ 1]); ++ } ++ memcpy(mac_addr, mac, ETH_ALEN); ++ } ++ else ++ { /* Use the mac address stored in the Efuse */ ++ memcpy(mac, mac_addr, ETH_ALEN); ++ } ++ ++ if (((mac[0]== 0xff) && (mac[1]== 0xff) && (mac[2]== 0xff) && ++ (mac[3]== 0xff) && (mac[4]== 0xff) && (mac[5]== 0xff)) || ++ ((mac[0]== 0x0) && (mac[1]== 0x0) && (mac[2]== 0x0) && ++ (mac[3]== 0x0) && (mac[4]== 0x0) && (mac[5]== 0x0))) ++ { ++ mac[0] = 0x00; ++ mac[1] = 0xe0; ++ mac[2] = 0x4c; ++ mac[3] = 0x87; ++ mac[4] = 0x00; ++ mac[5] = 0x00; ++ /* use default mac addresss */ ++ memcpy(mac_addr, mac, ETH_ALEN); ++ DBG_871X("MAC Address from efuse error, assign default one !!!\n"); ++ } ++ ++ DBG_871X("rtw_macaddr_cfg MAC Address = "MAC_FMT"\n", MAC_ARG(mac_addr)); ++} ++ ++static int rtw_get_cipher_info(struct wlan_network *pnetwork) ++{ ++ u32 wpa_ielen; ++ unsigned char *pbuf; ++ int group_cipher = 0, pairwise_cipher = 0, is8021x = 0; ++ int ret = _FAIL; ++ pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12); ++ ++ if (pbuf && (wpa_ielen>0)) { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_cipher_info: wpa_ielen: %d", wpa_ielen)); ++ if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is8021x)) { ++ ++ pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher; ++ pnetwork->BcnInfo.group_cipher = group_cipher; ++ pnetwork->BcnInfo.is_8021x = is8021x; ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: pnetwork->pairwise_cipher: %d, is_8021x is %d", ++ __func__, pnetwork->BcnInfo.pairwise_cipher, pnetwork->BcnInfo.is_8021x)); ++ ret = _SUCCESS; ++ } ++ } else { ++ ++ pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12); ++ ++ if (pbuf && (wpa_ielen>0)) { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("get RSN IE\n")); ++ if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is8021x)) { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("get RSN IE OK!!!\n")); ++ pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher; ++ pnetwork->BcnInfo.group_cipher = group_cipher; ++ pnetwork->BcnInfo.is_8021x = is8021x; ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: pnetwork->pairwise_cipher: %d," ++ "pnetwork->group_cipher is %d, is_8021x is %d", __func__, pnetwork->BcnInfo.pairwise_cipher, ++ pnetwork->BcnInfo.group_cipher, pnetwork->BcnInfo.is_8021x)); ++ ret = _SUCCESS; ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++void rtw_get_bcn_info(struct wlan_network *pnetwork) ++{ ++ unsigned short cap = 0; ++ u8 bencrypt = 0; ++ /* u8 wpa_ie[255], rsn_ie[255]; */ ++ u16 wpa_len = 0, rsn_len = 0; ++ struct HT_info_element *pht_info = NULL; ++ struct ieee80211_ht_cap *pht_cap = NULL; ++ unsigned int len; ++ unsigned char *p; ++ __le16 le_cap; ++ ++ memcpy((u8 *)&le_cap, rtw_get_capability_from_ie(pnetwork->network.IEs), 2); ++ cap = le16_to_cpu(le_cap); ++ if (cap & WLAN_CAPABILITY_PRIVACY) { ++ bencrypt = 1; ++ pnetwork->network.Privacy = 1; ++ } else { ++ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_OPENSYS; ++ } ++ rtw_get_sec_ie(pnetwork->network.IEs , pnetwork->network.IELength, NULL,&rsn_len, NULL,&wpa_len); ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: ssid =%s\n", pnetwork->network.Ssid.Ssid)); ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len)); ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: ssid =%s\n", pnetwork->network.Ssid.Ssid)); ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len)); ++ ++ if (rsn_len > 0) { ++ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA2; ++ } else if (wpa_len > 0) { ++ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA; ++ } else { ++ if (bencrypt) ++ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WEP; ++ } ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: pnetwork->encryp_protocol is %x\n", ++ pnetwork->BcnInfo.encryp_protocol)); ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: pnetwork->encryp_protocol is %x\n", ++ pnetwork->BcnInfo.encryp_protocol)); ++ rtw_get_cipher_info(pnetwork); ++ ++ /* get bwmode and ch_offset */ ++ /* parsing HT_CAP_IE */ ++ p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_); ++ if (p && len>0) { ++ pht_cap = (struct ieee80211_ht_cap *)(p + 2); ++ pnetwork->BcnInfo.ht_cap_info = le16_to_cpu(pht_cap->cap_info); ++ } else { ++ pnetwork->BcnInfo.ht_cap_info = 0; ++ } ++ /* parsing HT_INFO_IE */ ++ p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_); ++ if (p && len>0) { ++ pht_info = (struct HT_info_element *)(p + 2); ++ pnetwork->BcnInfo.ht_info_infos_0 = pht_info->infos[0]; ++ } else { ++ pnetwork->BcnInfo.ht_info_infos_0 = 0; ++ } ++} ++ ++/* show MCS rate, unit: 100Kbps */ ++u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI, unsigned char * MCS_rate) ++{ ++ u16 max_rate = 0; ++ ++ if (rf_type == RF_1T1R) ++ { ++ if (MCS_rate[0] & BIT(7)) ++ max_rate = (bw_40MHz) ? ((short_GI)?1500:1350):((short_GI)?722:650); ++ else if (MCS_rate[0] & BIT(6)) ++ max_rate = (bw_40MHz) ? ((short_GI)?1350:1215):((short_GI)?650:585); ++ else if (MCS_rate[0] & BIT(5)) ++ max_rate = (bw_40MHz) ? ((short_GI)?1200:1080):((short_GI)?578:520); ++ else if (MCS_rate[0] & BIT(4)) ++ max_rate = (bw_40MHz) ? ((short_GI)?900:810):((short_GI)?433:390); ++ else if (MCS_rate[0] & BIT(3)) ++ max_rate = (bw_40MHz) ? ((short_GI)?600:540):((short_GI)?289:260); ++ else if (MCS_rate[0] & BIT(2)) ++ max_rate = (bw_40MHz) ? ((short_GI)?450:405):((short_GI)?217:195); ++ else if (MCS_rate[0] & BIT(1)) ++ max_rate = (bw_40MHz) ? ((short_GI)?300:270):((short_GI)?144:130); ++ else if (MCS_rate[0] & BIT(0)) ++ max_rate = (bw_40MHz) ? ((short_GI)?150:135):((short_GI)?72:65); ++ } ++ else ++ { ++ if (MCS_rate[1]) ++ { ++ if (MCS_rate[1] & BIT(7)) ++ max_rate = (bw_40MHz) ? ((short_GI)?3000:2700):((short_GI)?1444:1300); ++ else if (MCS_rate[1] & BIT(6)) ++ max_rate = (bw_40MHz) ? ((short_GI)?2700:2430):((short_GI)?1300:1170); ++ else if (MCS_rate[1] & BIT(5)) ++ max_rate = (bw_40MHz) ? ((short_GI)?2400:2160):((short_GI)?1156:1040); ++ else if (MCS_rate[1] & BIT(4)) ++ max_rate = (bw_40MHz) ? ((short_GI)?1800:1620):((short_GI)?867:780); ++ else if (MCS_rate[1] & BIT(3)) ++ max_rate = (bw_40MHz) ? ((short_GI)?1200:1080):((short_GI)?578:520); ++ else if (MCS_rate[1] & BIT(2)) ++ max_rate = (bw_40MHz) ? ((short_GI)?900:810):((short_GI)?433:390); ++ else if (MCS_rate[1] & BIT(1)) ++ max_rate = (bw_40MHz) ? ((short_GI)?600:540):((short_GI)?289:260); ++ else if (MCS_rate[1] & BIT(0)) ++ max_rate = (bw_40MHz) ? ((short_GI)?300:270):((short_GI)?144:130); ++ } ++ else ++ { ++ if (MCS_rate[0] & BIT(7)) ++ max_rate = (bw_40MHz) ? ((short_GI)?1500:1350):((short_GI)?722:650); ++ else if (MCS_rate[0] & BIT(6)) ++ max_rate = (bw_40MHz) ? ((short_GI)?1350:1215):((short_GI)?650:585); ++ else if (MCS_rate[0] & BIT(5)) ++ max_rate = (bw_40MHz) ? ((short_GI)?1200:1080):((short_GI)?578:520); ++ else if (MCS_rate[0] & BIT(4)) ++ max_rate = (bw_40MHz) ? ((short_GI)?900:810):((short_GI)?433:390); ++ else if (MCS_rate[0] & BIT(3)) ++ max_rate = (bw_40MHz) ? ((short_GI)?600:540):((short_GI)?289:260); ++ else if (MCS_rate[0] & BIT(2)) ++ max_rate = (bw_40MHz) ? ((short_GI)?450:405):((short_GI)?217:195); ++ else if (MCS_rate[0] & BIT(1)) ++ max_rate = (bw_40MHz) ? ((short_GI)?300:270):((short_GI)?144:130); ++ else if (MCS_rate[0] & BIT(0)) ++ max_rate = (bw_40MHz) ? ((short_GI)?150:135):((short_GI)?72:65); ++ } ++ } ++ return max_rate; ++} ++ ++int rtw_action_frame_parse(const u8 *frame, u32 frame_len, u8 *category, u8 *action) ++{ ++ const u8 *frame_body = frame + sizeof(struct ieee80211_hdr_3addr); ++ u16 fc; ++ u8 c; ++ u8 a = ACT_PUBLIC_MAX; ++ ++ fc = le16_to_cpu(((struct ieee80211_hdr_3addr *)frame)->frame_control); ++ ++ if ((fc & (RTW_IEEE80211_FCTL_FTYPE|RTW_IEEE80211_FCTL_STYPE)) ++ != (RTW_IEEE80211_FTYPE_MGMT|RTW_IEEE80211_STYPE_ACTION) ++ ) ++ { ++ return false; ++ } ++ ++ c = frame_body[0]; ++ ++ switch (c) { ++ case RTW_WLAN_CATEGORY_P2P: /* vendor-specific */ ++ break; ++ default: ++ a = frame_body[1]; ++ } ++ ++ if (category) ++ *category = c; ++ if (action) ++ *action = a; ++ ++ return true; ++} ++ ++static const char *_action_public_str[] = { ++ "ACT_PUB_BSSCOEXIST", ++ "ACT_PUB_DSE_ENABLE", ++ "ACT_PUB_DSE_DEENABLE", ++ "ACT_PUB_DSE_REG_LOCATION", ++ "ACT_PUB_EXT_CHL_SWITCH", ++ "ACT_PUB_DSE_MSR_REQ", ++ "ACT_PUB_DSE_MSR_RPRT", ++ "ACT_PUB_MP", ++ "ACT_PUB_DSE_PWR_CONSTRAINT", ++ "ACT_PUB_VENDOR", ++ "ACT_PUB_GAS_INITIAL_REQ", ++ "ACT_PUB_GAS_INITIAL_RSP", ++ "ACT_PUB_GAS_COMEBACK_REQ", ++ "ACT_PUB_GAS_COMEBACK_RSP", ++ "ACT_PUB_TDLS_DISCOVERY_RSP", ++ "ACT_PUB_LOCATION_TRACK", ++ "ACT_PUB_RSVD", ++}; ++ ++const char *action_public_str(u8 action) ++{ ++ action = (action >= ACT_PUBLIC_MAX) ? ACT_PUBLIC_MAX : action; ++ return _action_public_str[action]; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_io.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_io.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_io.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_io.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,203 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++/* ++ ++The purpose of rtw_io.c ++ ++a. provides the API ++ ++b. provides the protocol engine ++ ++c. provides the software interface between caller and the hardware interface ++ ++ ++Compiler Flag Option: ++ ++1. CONFIG_SDIO_HCI: ++ a. USE_SYNC_IRP: Only sync operations are provided. ++ b. USE_ASYNC_IRP:Both sync/async operations are provided. ++ ++jackson@realtek.com.tw ++ ++*/ ++ ++#define _RTW_IO_C_ ++ ++#include ++#include ++ ++#define rtw_le16_to_cpu(val) val ++#define rtw_le32_to_cpu(val) val ++#define rtw_cpu_to_le16(val) val ++#define rtw_cpu_to_le32(val) val ++ ++u8 _rtw_read8(struct adapter *adapter, u32 addr) ++{ ++ u8 r_val; ++ /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr); ++ ++ _read8 = pintfhdl->io_ops._read8; ++ ++ r_val = _read8(pintfhdl, addr); ++ return r_val; ++} ++ ++u16 _rtw_read16(struct adapter *adapter, u32 addr) ++{ ++ u16 r_val; ++ /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ u16 (*_read16)(struct intf_hdl *pintfhdl, u32 addr); ++ ++ _read16 = pintfhdl->io_ops._read16; ++ ++ r_val = _read16(pintfhdl, addr); ++ return rtw_le16_to_cpu(r_val); ++} ++ ++u32 _rtw_read32(struct adapter *adapter, u32 addr) ++{ ++ u32 r_val; ++ /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ u32 (*_read32)(struct intf_hdl *pintfhdl, u32 addr); ++ ++ _read32 = pintfhdl->io_ops._read32; ++ ++ r_val = _read32(pintfhdl, addr); ++ return rtw_le32_to_cpu(r_val); ++ ++} ++ ++int _rtw_write8(struct adapter *adapter, u32 addr, u8 val) ++{ ++ /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ int (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val); ++ int ret; ++ ++ _write8 = pintfhdl->io_ops._write8; ++ ++ ret = _write8(pintfhdl, addr, val); ++ ++ return RTW_STATUS_CODE(ret); ++} ++int _rtw_write16(struct adapter *adapter, u32 addr, u16 val) ++{ ++ /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ int (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val); ++ int ret; ++ ++ _write16 = pintfhdl->io_ops._write16; ++ ++ ret = _write16(pintfhdl, addr, val); ++ return RTW_STATUS_CODE(ret); ++} ++int _rtw_write32(struct adapter *adapter, u32 addr, u32 val) ++{ ++ /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ int (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val); ++ int ret; ++ ++ _write32 = pintfhdl->io_ops._write32; ++ ++ ret = _write32(pintfhdl, addr, val); ++ ++ return RTW_STATUS_CODE(ret); ++} ++ ++u8 _rtw_sd_f0_read8(struct adapter *adapter, u32 addr) ++{ ++ u8 r_val = 0x00; ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ u8 (*_sd_f0_read8)(struct intf_hdl *pintfhdl, u32 addr); ++ ++ _sd_f0_read8 = pintfhdl->io_ops._sd_f0_read8; ++ ++ if (_sd_f0_read8) ++ r_val = _sd_f0_read8(pintfhdl, addr); ++ else ++ DBG_871X_LEVEL(_drv_warning_, FUNC_ADPT_FMT" _sd_f0_read8 callback is NULL\n", FUNC_ADPT_ARG(adapter)); ++ ++ return r_val; ++} ++ ++u32 _rtw_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem) ++{ ++ u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &(pio_priv->intf); ++ u32 ret = _SUCCESS; ++ ++ _write_port = pintfhdl->io_ops._write_port; ++ ++ ret = _write_port(pintfhdl, addr, cnt, pmem); ++ ++ return ret; ++} ++ ++int rtw_init_io_priv(struct adapter *padapter, void (*set_intf_ops)(struct adapter *padapter, struct _io_ops *pops)) ++{ ++ struct io_priv *piopriv = &padapter->iopriv; ++ struct intf_hdl *pintf = &piopriv->intf; ++ ++ if (set_intf_ops == NULL) ++ return _FAIL; ++ ++ piopriv->padapter = padapter; ++ pintf->padapter = padapter; ++ pintf->pintf_dev = adapter_to_dvobj(padapter); ++ ++ set_intf_ops(padapter,&pintf->io_ops); ++ ++ return _SUCCESS; ++} ++ ++/* ++* Increase and check if the continual_io_error of this @param dvobjprive is larger than MAX_CONTINUAL_IO_ERR ++* @return true: ++* @return false: ++*/ ++int rtw_inc_and_chk_continual_io_error(struct dvobj_priv *dvobj) ++{ ++ int ret = false; ++ int value; ++ if ((value =atomic_inc_return(&dvobj->continual_io_error)) > MAX_CONTINUAL_IO_ERR) { ++ DBG_871X("[dvobj:%p][ERROR] continual_io_error:%d > %d\n", dvobj, value, MAX_CONTINUAL_IO_ERR); ++ ret = true; ++ } else { ++ /* DBG_871X("[dvobj:%p] continual_io_error:%d\n", dvobj, value); */ ++ } ++ return ret; ++} ++ ++/* ++* Set the continual_io_error of this @param dvobjprive to 0 ++*/ ++void rtw_reset_continual_io_error(struct dvobj_priv *dvobj) ++{ ++ atomic_set(&dvobj->continual_io_error, 0); ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_ioctl_set.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_ioctl_set.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_ioctl_set.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_ioctl_set.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,736 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTW_IOCTL_SET_C_ ++ ++#include ++#include ++ ++#define IS_MAC_ADDRESS_BROADCAST(addr) \ ++(\ ++ ((addr[0] == 0xff) && (addr[1] == 0xff) && \ ++ (addr[2] == 0xff) && (addr[3] == 0xff) && \ ++ (addr[4] == 0xff) && (addr[5] == 0xff)) ? true : false \ ++) ++ ++u8 rtw_validate_bssid(u8 *bssid) ++{ ++ u8 ret = true; ++ ++ if (is_zero_mac_addr(bssid) ++ || is_broadcast_mac_addr(bssid) ++ || is_multicast_mac_addr(bssid) ++ ) { ++ ret = false; ++ } ++ ++ return ret; ++} ++ ++u8 rtw_validate_ssid(struct ndis_802_11_ssid *ssid) ++{ ++ u8 ret =true; ++ ++ if (ssid->SsidLength > 32) { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("ssid length >32\n")); ++ ret = false; ++ goto exit; ++ } ++ ++#ifdef CONFIG_VALIDATE_SSID ++ for (i = 0; i < ssid->SsidLength; i++) ++ { ++ /* wifi, printable ascii code must be supported */ ++ if (!((ssid->Ssid[i] >= 0x20) && (ssid->Ssid[i] <= 0x7e))) { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("ssid has nonprintabl ascii\n")); ++ ret = false; ++ break; ++ } ++ } ++#endif /* CONFIG_VALIDATE_SSID */ ++ ++exit: ++ return ret; ++} ++ ++u8 rtw_do_join(struct adapter *padapter); ++u8 rtw_do_join(struct adapter *padapter) ++{ ++ struct list_head *plist, *phead; ++ u8 *pibss = NULL; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct __queue *queue = &(pmlmepriv->scanned_queue); ++ u8 ret = _SUCCESS; ++ ++ spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("\n rtw_do_join: phead = %p; plist = %p\n\n\n", phead, plist)); ++ ++ pmlmepriv->cur_network.join_res = -2; ++ ++ set_fwstate(pmlmepriv, _FW_UNDER_LINKING); ++ ++ pmlmepriv->pscanned = plist; ++ ++ pmlmepriv->to_join = true; ++ ++ if (list_empty(&queue->queue)) ++ { ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ ++ /* when set_ssid/set_bssid for rtw_do_join(), but scanning queue is empty */ ++ /* we try to issue sitesurvey firstly */ ++ ++ if (pmlmepriv->LinkDetectInfo.bBusyTraffic ==false ++ || rtw_to_roam(padapter) > 0 ++ ) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("rtw_do_join(): site survey if scanned_queue is empty\n.")); ++ /* submit site_survey_cmd */ ++ if (_SUCCESS!=(ret =rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0))) { ++ pmlmepriv->to_join = false; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("rtw_do_join(): site survey return error\n.")); ++ } ++ } ++ else ++ { ++ pmlmepriv->to_join = false; ++ ret = _FAIL; ++ } ++ ++ goto exit; ++ } ++ else ++ { ++ int select_ret; ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ if ((select_ret =rtw_select_and_join_from_scanned_queue(pmlmepriv)) == _SUCCESS) ++ { ++ pmlmepriv->to_join = false; ++ _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); ++ } ++ else ++ { ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ==true) ++ { ++ /* submit createbss_cmd to change to a ADHOC_MASTER */ ++ ++ /* pmlmepriv->lock has been acquired by caller... */ ++ struct wlan_bssid_ex *pdev_network = &(padapter->registrypriv.dev_network); ++ ++ pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE; ++ ++ pibss = padapter->registrypriv.dev_network.MacAddress; ++ ++ memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); ++ memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); ++ ++ rtw_update_registrypriv_dev_network(padapter); ++ ++ rtw_generate_random_ibss(pibss); ++ ++ if (rtw_createbss_cmd(padapter)!= _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("***Error =>do_goin: rtw_createbss_cmd status FAIL***\n ")); ++ ret = false; ++ goto exit; ++ } ++ ++ pmlmepriv->to_join = false; ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("***Error => rtw_select_and_join_from_scanned_queue FAIL under STA_Mode***\n ")); ++ ++ } ++ else ++ { ++ /* can't associate ; reset under-linking */ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ ++ /* when set_ssid/set_bssid for rtw_do_join(), but there are no desired bss in scanning queue */ ++ /* we try to issue sitesurvey firstly */ ++ if (pmlmepriv->LinkDetectInfo.bBusyTraffic ==false ++ || rtw_to_roam(padapter) > 0 ++ ) ++ { ++ /* DBG_871X("rtw_do_join() when no desired bss in scanning queue\n"); */ ++ if (_SUCCESS!=(ret =rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0))) { ++ pmlmepriv->to_join = false; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("do_join(): site survey return error\n.")); ++ } ++ } ++ else ++ { ++ ret = _FAIL; ++ pmlmepriv->to_join = false; ++ } ++ } ++ ++ } ++ ++ } ++ ++exit: ++ return ret; ++} ++ ++u8 rtw_set_802_11_bssid(struct adapter *padapter, u8 *bssid) ++{ ++ u8 status = _SUCCESS; ++ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ DBG_871X_LEVEL(_drv_always_, "set bssid:%pM\n", bssid); ++ ++ if ((bssid[0]== 0x00 && bssid[1]== 0x00 && bssid[2]== 0x00 && bssid[3]== 0x00 && bssid[4]== 0x00 &&bssid[5]== 0x00) || ++ (bssid[0]== 0xFF && bssid[1]== 0xFF && bssid[2]== 0xFF && bssid[3]== 0xFF && bssid[4]== 0xFF &&bssid[5]== 0xFF)) ++ { ++ status = _FAIL; ++ goto exit; ++ } ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ ++ DBG_871X("Set BSSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv)); ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) { ++ goto handle_tkip_countermeasure; ++ } else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) { ++ goto release_mlme_lock; ++ } ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_bssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n")); ++ ++ if (!memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid, ETH_ALEN)) ++ { ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == false) ++ goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */ ++ } else { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("Set BSSID not the same bssid\n")); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_bssid ="MAC_FMT"\n", MAC_ARG(bssid))); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("cur_bssid ="MAC_FMT"\n", MAC_ARG(pmlmepriv->cur_network.network.MacAddress))); ++ ++ rtw_disassoc_cmd(padapter, 0, true); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) ++ rtw_indicate_disconnect(padapter); ++ ++ rtw_free_assoc_resources(padapter, 1); ++ ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { ++ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); ++ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); ++ } ++ } ++ } ++ ++handle_tkip_countermeasure: ++ if (rtw_handle_tkip_countermeasure(padapter, __func__) == _FAIL) { ++ status = _FAIL; ++ goto release_mlme_lock; ++ } ++ ++ memset(&pmlmepriv->assoc_ssid, 0, sizeof(struct ndis_802_11_ssid)); ++ memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN); ++ pmlmepriv->assoc_by_bssid =true; ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) { ++ pmlmepriv->to_join = true; ++ } ++ else { ++ status = rtw_do_join(padapter); ++ } ++ ++release_mlme_lock: ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++exit: ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ++ ("rtw_set_802_11_bssid: status =%d\n", status)); ++ ++ return status; ++} ++ ++u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid) ++{ ++ u8 status = _SUCCESS; ++ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *pnetwork = &pmlmepriv->cur_network; ++ ++ DBG_871X_LEVEL(_drv_always_, "set ssid [%s] fw_state = 0x%08x\n", ++ ssid->Ssid, get_fwstate(pmlmepriv)); ++ ++ if (padapter->hw_init_completed ==false) { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ++ ("set_ssid: hw_init_completed ==false =>exit!!!\n")); ++ status = _FAIL; ++ goto exit; ++ } ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ DBG_871X("Set SSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv)); ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) { ++ goto handle_tkip_countermeasure; ++ } else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) { ++ goto release_mlme_lock; ++ } ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ++ ("set_ssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n")); ++ ++ if ((pmlmepriv->assoc_ssid.SsidLength == ssid->SsidLength) && ++ (!memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, ssid->SsidLength))) ++ { ++ if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == false)) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ++ ("Set SSID is the same ssid, fw_state = 0x%08x\n", ++ get_fwstate(pmlmepriv))); ++ ++ if (rtw_is_same_ibss(padapter, pnetwork) == false) ++ { ++ /* if in WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE, create bss or rejoin again */ ++ rtw_disassoc_cmd(padapter, 0, true); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) ++ rtw_indicate_disconnect(padapter); ++ ++ rtw_free_assoc_resources(padapter, 1); ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) { ++ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); ++ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); ++ } ++ } ++ else ++ { ++ goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */ ++ } ++ } ++ else { ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_JOINBSS, 1); ++ } ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("Set SSID not the same ssid\n")); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_ssid =[%s] len = 0x%x\n", ssid->Ssid, (unsigned int)ssid->SsidLength)); ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("assoc_ssid =[%s] len = 0x%x\n", pmlmepriv->assoc_ssid.Ssid, (unsigned int)pmlmepriv->assoc_ssid.SsidLength)); ++ ++ rtw_disassoc_cmd(padapter, 0, true); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) ++ rtw_indicate_disconnect(padapter); ++ ++ rtw_free_assoc_resources(padapter, 1); ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) { ++ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); ++ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); ++ } ++ } ++ } ++ ++handle_tkip_countermeasure: ++ if (rtw_handle_tkip_countermeasure(padapter, __func__) == _FAIL) { ++ status = _FAIL; ++ goto release_mlme_lock; ++ } ++ ++ if (rtw_validate_ssid(ssid) == false) { ++ status = _FAIL; ++ goto release_mlme_lock; ++ } ++ ++ memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct ndis_802_11_ssid)); ++ pmlmepriv->assoc_by_bssid =false; ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) { ++ pmlmepriv->to_join = true; ++ } ++ else { ++ status = rtw_do_join(padapter); ++ } ++ ++release_mlme_lock: ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++exit: ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ++ ("-rtw_set_802_11_ssid: status =%d\n", status)); ++ ++ return status; ++} ++ ++u8 rtw_set_802_11_connect(struct adapter *padapter, u8 *bssid, struct ndis_802_11_ssid *ssid) ++{ ++ u8 status = _SUCCESS; ++ bool bssid_valid = true; ++ bool ssid_valid = true; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ if (!ssid || rtw_validate_ssid(ssid) == false) ++ ssid_valid = false; ++ ++ if (!bssid || rtw_validate_bssid(bssid) == false) ++ bssid_valid = false; ++ ++ if (ssid_valid == false && bssid_valid == false) { ++ DBG_871X(FUNC_ADPT_FMT" ssid:%p, ssid_valid:%d, bssid:%p, bssid_valid:%d\n", ++ FUNC_ADPT_ARG(padapter), ssid, ssid_valid, bssid, bssid_valid); ++ status = _FAIL; ++ goto exit; ++ } ++ ++ if (padapter->hw_init_completed ==false) { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ++ ("set_ssid: hw_init_completed ==false =>exit!!!\n")); ++ status = _FAIL; ++ goto exit; ++ } ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" fw_state = 0x%08x\n", ++ FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv)); ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) { ++ goto handle_tkip_countermeasure; ++ } else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) { ++ goto release_mlme_lock; ++ } ++ ++handle_tkip_countermeasure: ++ if (rtw_handle_tkip_countermeasure(padapter, __func__) == _FAIL) { ++ status = _FAIL; ++ goto release_mlme_lock; ++ } ++ ++ if (ssid && ssid_valid) ++ memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct ndis_802_11_ssid)); ++ else ++ memset(&pmlmepriv->assoc_ssid, 0, sizeof(struct ndis_802_11_ssid)); ++ ++ if (bssid && bssid_valid) { ++ memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN); ++ pmlmepriv->assoc_by_bssid = true; ++ } else { ++ pmlmepriv->assoc_by_bssid = false; ++ } ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) { ++ pmlmepriv->to_join = true; ++ } ++ else { ++ status = rtw_do_join(padapter); ++ } ++ ++release_mlme_lock: ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++exit: ++ return status; ++} ++ ++u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter, ++ enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *cur_network = &pmlmepriv->cur_network; ++ enum NDIS_802_11_NETWORK_INFRASTRUCTURE *pold_state = &(cur_network->network.InfrastructureMode); ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_notice_, ++ ("+rtw_set_802_11_infrastructure_mode: old =%d new =%d fw_state = 0x%08x\n", ++ *pold_state, networktype, get_fwstate(pmlmepriv))); ++ ++ if (*pold_state != networktype) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, (" change mode!")); ++ /* DBG_871X("change mode, old_mode =%d, new_mode =%d, fw_state = 0x%x\n", *pold_state, networktype, get_fwstate(pmlmepriv)); */ ++ ++ if (*pold_state ==Ndis802_11APMode) ++ { ++ /* change to other mode from Ndis802_11APMode */ ++ cur_network->join_res = -1; ++ ++ stop_ap_mode(padapter); ++ } ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) ||(*pold_state ==Ndis802_11IBSS)) ++ rtw_disassoc_cmd(padapter, 0, true); ++ ++ if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) ++ rtw_free_assoc_resources(padapter, 1); ++ ++ if ((*pold_state == Ndis802_11Infrastructure) ||(*pold_state == Ndis802_11IBSS)) ++ { ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) ++ { ++ rtw_indicate_disconnect(padapter); /* will clr Linked_state; before this function, we must have chked whether issue dis-assoc_cmd or not */ ++ } ++ } ++ ++ *pold_state = networktype; ++ ++ _clr_fwstate_(pmlmepriv, ~WIFI_NULL_STATE); ++ ++ switch (networktype) ++ { ++ case Ndis802_11IBSS: ++ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); ++ break; ++ ++ case Ndis802_11Infrastructure: ++ set_fwstate(pmlmepriv, WIFI_STATION_STATE); ++ break; ++ ++ case Ndis802_11APMode: ++ set_fwstate(pmlmepriv, WIFI_AP_STATE); ++ start_ap_mode(padapter); ++ /* rtw_indicate_connect(padapter); */ ++ ++ break; ++ ++ case Ndis802_11AutoUnknown: ++ case Ndis802_11InfrastructureMax: ++ break; ++ } ++ ++ /* SecClearAllKeys(adapter); */ ++ ++ /* RT_TRACE(COMP_OID_SET, DBG_LOUD, ("set_infrastructure: fw_state:%x after changing mode\n", */ ++ /* get_fwstate(pmlmepriv))); */ ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++ } ++ return true; ++} ++ ++ ++u8 rtw_set_802_11_disassociate(struct adapter *padapter) ++{ ++ struct mlme_priv * pmlmepriv = &padapter->mlmepriv; ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_disassociate: rtw_indicate_disconnect\n")); ++ ++ rtw_disassoc_cmd(padapter, 0, true); ++ rtw_indicate_disconnect(padapter); ++ /* modify for CONFIG_IEEE80211W, none 11w can use it */ ++ rtw_free_assoc_resources_cmd(padapter); ++ if (_FAIL == rtw_pwr_wakeup(padapter)) ++ DBG_871X("%s(): rtw_pwr_wakeup fail !!!\n", __func__); ++ } ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++ return true; ++} ++ ++u8 rtw_set_802_11_bssid_list_scan(struct adapter *padapter, struct ndis_802_11_ssid *pssid, int ssid_max_num) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u8 res =true; ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("+rtw_set_802_11_bssid_list_scan(), fw_state =%x\n", get_fwstate(pmlmepriv))); ++ ++ if (padapter == NULL) { ++ res =false; ++ goto exit; ++ } ++ if (padapter->hw_init_completed ==false) { ++ res = false; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n ===rtw_set_802_11_bssid_list_scan:hw_init_completed ==false ===\n")); ++ goto exit; ++ } ++ ++ if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true) || ++ (pmlmepriv->LinkDetectInfo.bBusyTraffic == true)) ++ { ++ /* Scan or linking is in progress, do nothing. */ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("rtw_set_802_11_bssid_list_scan fail since fw_state = %x\n", get_fwstate(pmlmepriv))); ++ res = true; ++ ++ if (check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING)) == true) { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n###_FW_UNDER_SURVEY|_FW_UNDER_LINKING\n\n")); ++ } else { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n###pmlmepriv->sitesurveyctrl.traffic_busy ==true\n\n")); ++ } ++ } else { ++ if (rtw_is_scan_deny(padapter)) { ++ DBG_871X(FUNC_ADPT_FMT": scan deny\n", FUNC_ADPT_ARG(padapter)); ++ indicate_wx_scan_complete_event(padapter); ++ return _SUCCESS; ++ } ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ res = rtw_sitesurvey_cmd(padapter, pssid, ssid_max_num, NULL, 0); ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++ } ++exit: ++ ++ return res; ++} ++ ++u8 rtw_set_802_11_authentication_mode(struct adapter *padapter, enum NDIS_802_11_AUTHENTICATION_MODE authmode) ++{ ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ int res; ++ u8 ret; ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_802_11_auth.mode(): mode =%x\n", authmode)); ++ ++ psecuritypriv->ndisauthtype =authmode; ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("rtw_set_802_11_authentication_mode:psecuritypriv->ndisauthtype =%d", psecuritypriv->ndisauthtype)); ++ ++ if (psecuritypriv->ndisauthtype>3) ++ psecuritypriv->dot11AuthAlgrthm =dot11AuthAlgrthm_8021X; ++ ++ res =rtw_set_auth(padapter, psecuritypriv); ++ ++ if (res == _SUCCESS) ++ ret =true; ++ else ++ ret =false; ++ ++ return ret; ++} ++ ++u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep *wep) { ++ ++ u8 bdefaultkey; ++ u8 btransmitkey; ++ sint keyid, res; ++ struct security_priv* psecuritypriv =&(padapter->securitypriv); ++ u8 ret = _SUCCESS; ++ ++ bdefaultkey =(wep->KeyIndex & 0x40000000) > 0 ? false : true; /* for ??? */ ++ btransmitkey = (wep->KeyIndex & 0x80000000) > 0 ? true : false; /* for ??? */ ++ keyid =wep->KeyIndex & 0x3fffffff; ++ ++ if (keyid>=4) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("MgntActrtw_set_802_11_add_wep:keyid>4 =>fail\n")); ++ ret =false; ++ goto exit; ++ } ++ ++ switch (wep->KeyLength) ++ { ++ case 5: ++ psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_add_wep:wep->KeyLength =5\n")); ++ break; ++ case 13: ++ psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_add_wep:wep->KeyLength = 13\n")); ++ break; ++ default: ++ psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_add_wep:wep->KeyLength!=5 or 13\n")); ++ break; ++ } ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("rtw_set_802_11_add_wep:befor memcpy, wep->KeyLength = 0x%x wep->KeyIndex = 0x%x keyid =%x\n", wep->KeyLength, wep->KeyIndex, keyid)); ++ ++ memcpy(&(psecuritypriv->dot11DefKey[keyid].skey[0]),&(wep->KeyMaterial), wep->KeyLength); ++ ++ psecuritypriv->dot11DefKeylen[keyid]=wep->KeyLength; ++ ++ psecuritypriv->dot11PrivacyKeyIndex =keyid; ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("rtw_set_802_11_add_wep:security key material : %x %x %x %x %x %x %x %x %x %x %x %x %x\n", ++ psecuritypriv->dot11DefKey[keyid].skey[0], psecuritypriv->dot11DefKey[keyid].skey[1], psecuritypriv->dot11DefKey[keyid].skey[2], ++ psecuritypriv->dot11DefKey[keyid].skey[3], psecuritypriv->dot11DefKey[keyid].skey[4], psecuritypriv->dot11DefKey[keyid].skey[5], ++ psecuritypriv->dot11DefKey[keyid].skey[6], psecuritypriv->dot11DefKey[keyid].skey[7], psecuritypriv->dot11DefKey[keyid].skey[8], ++ psecuritypriv->dot11DefKey[keyid].skey[9], psecuritypriv->dot11DefKey[keyid].skey[10], psecuritypriv->dot11DefKey[keyid].skey[11], ++ psecuritypriv->dot11DefKey[keyid].skey[12])); ++ ++ res =rtw_set_key(padapter, psecuritypriv, keyid, 1, true); ++ ++ if (res == _FAIL) ++ ret = false; ++exit: ++ ++ return ret; ++} ++ ++/* ++* rtw_get_cur_max_rate - ++* @adapter: pointer to struct adapter structure ++* ++* Return 0 or 100Kbps ++*/ ++u16 rtw_get_cur_max_rate(struct adapter *adapter) ++{ ++ int i = 0; ++ u16 rate = 0, max_rate = 0; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; ++ struct sta_info *psta = NULL; ++ u8 short_GI = 0; ++ u8 rf_type = 0; ++ ++ if ((check_fwstate(pmlmepriv, _FW_LINKED) != true) ++ && (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) != true)) ++ return 0; ++ ++ psta = rtw_get_stainfo(&adapter->stapriv, get_bssid(pmlmepriv)); ++ if (psta == NULL) ++ return 0; ++ ++ short_GI = query_ra_short_GI(psta); ++ ++ if (IsSupportedHT(psta->wireless_mode)) { ++ rtw_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ ++ max_rate = rtw_mcs_rate( ++ rf_type, ++ ((psta->bw_mode == CHANNEL_WIDTH_40)?1:0), ++ short_GI, ++ psta->htpriv.ht_cap.supp_mcs_set ++ ); ++ } ++ else ++ { ++ while ((pcur_bss->SupportedRates[i]!= 0) && (pcur_bss->SupportedRates[i]!= 0xFF)) ++ { ++ rate = pcur_bss->SupportedRates[i]&0x7F; ++ if (rate>max_rate) ++ max_rate = rate; ++ i++; ++ } ++ ++ max_rate = max_rate*10/2; ++ } ++ ++ return max_rate; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_mlme.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_mlme.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_mlme.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_mlme.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,3331 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTW_MLME_C_ ++ ++#include ++#include ++#include ++ ++extern u8 rtw_do_join(struct adapter *padapter); ++ ++sint _rtw_init_mlme_priv (struct adapter *padapter) ++{ ++ sint i; ++ u8 *pbuf; ++ struct wlan_network *pnetwork; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ sint res = _SUCCESS; ++ ++ /* We don't need to memset padapter->XXX to zero, because adapter is allocated by vzalloc(). */ ++ /* memset((u8 *)pmlmepriv, 0, sizeof(struct mlme_priv)); */ ++ ++ pmlmepriv->nic_hdl = (u8 *)padapter; ++ ++ pmlmepriv->pscanned = NULL; ++ pmlmepriv->fw_state = WIFI_STATION_STATE; /* Must sync with rtw_wdev_alloc() */ ++ /* wdev->iftype = NL80211_IFTYPE_STATION */ ++ pmlmepriv->cur_network.network.InfrastructureMode = Ndis802_11AutoUnknown; ++ pmlmepriv->scan_mode =SCAN_ACTIVE;/* 1: active, 0: pasive. Maybe someday we should rename this varable to "active_mode" (Jeff) */ ++ ++ spin_lock_init(&(pmlmepriv->lock)); ++ _rtw_init_queue(&(pmlmepriv->free_bss_pool)); ++ _rtw_init_queue(&(pmlmepriv->scanned_queue)); ++ ++ set_scanned_network_val(pmlmepriv, 0); ++ ++ memset(&pmlmepriv->assoc_ssid, 0, sizeof(struct ndis_802_11_ssid)); ++ ++ pbuf = vzalloc(MAX_BSS_CNT * (sizeof(struct wlan_network))); ++ ++ if (pbuf == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ pmlmepriv->free_bss_buf = pbuf; ++ ++ pnetwork = (struct wlan_network *)pbuf; ++ ++ for (i = 0; i < MAX_BSS_CNT; i++) ++ { ++ INIT_LIST_HEAD(&(pnetwork->list)); ++ ++ list_add_tail(&(pnetwork->list), &(pmlmepriv->free_bss_pool.queue)); ++ ++ pnetwork++; ++ } ++ ++ /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ ++ ++ rtw_clear_scan_deny(padapter); ++ ++ #define RTW_ROAM_SCAN_RESULT_EXP_MS 5*1000 ++ #define RTW_ROAM_RSSI_DIFF_TH 10 ++ #define RTW_ROAM_SCAN_INTERVAL_MS 10*1000 ++ ++ pmlmepriv->roam_flags = 0 ++ | RTW_ROAM_ON_EXPIRED ++ | RTW_ROAM_ON_RESUME ++ #ifdef CONFIG_LAYER2_ROAMING_ACTIVE /* FIXME */ ++ | RTW_ROAM_ACTIVE ++ #endif ++ ; ++ ++ pmlmepriv->roam_scanr_exp_ms = RTW_ROAM_SCAN_RESULT_EXP_MS; ++ pmlmepriv->roam_rssi_diff_th = RTW_ROAM_RSSI_DIFF_TH; ++ pmlmepriv->roam_scan_int_ms = RTW_ROAM_SCAN_INTERVAL_MS; ++ ++ rtw_init_mlme_timer(padapter); ++ ++exit: ++ ++ return res; ++} ++ ++static void rtw_free_mlme_ie_data(u8 **ppie, u32 *plen) ++{ ++ if (*ppie) ++ { ++ kfree(*ppie); ++ *plen = 0; ++ *ppie = NULL; ++ } ++} ++ ++void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv) ++{ ++ rtw_buf_free(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len); ++ rtw_buf_free(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->wps_beacon_ie, &pmlmepriv->wps_beacon_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_req_ie, &pmlmepriv->wps_probe_req_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_resp_ie, &pmlmepriv->wps_probe_resp_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->wps_assoc_resp_ie, &pmlmepriv->wps_assoc_resp_ie_len); ++ ++ rtw_free_mlme_ie_data(&pmlmepriv->p2p_beacon_ie, &pmlmepriv->p2p_beacon_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_req_ie, &pmlmepriv->p2p_probe_req_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_resp_ie, &pmlmepriv->p2p_probe_resp_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->p2p_go_probe_resp_ie, &pmlmepriv->p2p_go_probe_resp_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->p2p_assoc_req_ie, &pmlmepriv->p2p_assoc_req_ie_len); ++} ++ ++void _rtw_free_mlme_priv (struct mlme_priv *pmlmepriv) ++{ ++ rtw_free_mlme_priv_ie_data(pmlmepriv); ++ ++ if (pmlmepriv) { ++ if (pmlmepriv->free_bss_buf) { ++ vfree(pmlmepriv->free_bss_buf); ++ } ++ } ++} ++ ++/* ++struct wlan_network *_rtw_dequeue_network(struct __queue *queue) ++{ ++ _irqL irqL; ++ ++ struct wlan_network *pnetwork; ++ ++ spin_lock_bh(&queue->lock); ++ ++ if (list_empty(&queue->queue)) ++ ++ pnetwork = NULL; ++ ++ else ++ { ++ pnetwork = LIST_CONTAINOR(get_next(&queue->queue), struct wlan_network, list); ++ ++ list_del_init(&(pnetwork->list)); ++ } ++ ++ spin_unlock_bh(&queue->lock); ++ ++ return pnetwork; ++} ++*/ ++ ++struct wlan_network *_rtw_alloc_network(struct mlme_priv *pmlmepriv)/* _queue *free_queue) */ ++{ ++ struct wlan_network *pnetwork; ++ struct __queue *free_queue = &pmlmepriv->free_bss_pool; ++ struct list_head* plist = NULL; ++ ++ spin_lock_bh(&free_queue->lock); ++ ++ if (list_empty(&free_queue->queue)) { ++ pnetwork = NULL; ++ goto exit; ++ } ++ plist = get_next(&(free_queue->queue)); ++ ++ pnetwork = LIST_CONTAINOR(plist , struct wlan_network, list); ++ ++ list_del_init(&pnetwork->list); ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("_rtw_alloc_network: ptr =%p\n", plist)); ++ pnetwork->network_type = 0; ++ pnetwork->fixed = false; ++ pnetwork->last_scanned = jiffies; ++ pnetwork->aid = 0; ++ pnetwork->join_res = 0; ++ ++ pmlmepriv->num_of_scanned ++; ++ ++exit: ++ spin_unlock_bh(&free_queue->lock); ++ ++ return pnetwork; ++} ++ ++void _rtw_free_network(struct mlme_priv *pmlmepriv , struct wlan_network *pnetwork, u8 isfreeall) ++{ ++ unsigned int delta_time; ++ u32 lifetime = SCANQUEUE_LIFETIME; ++/* _irqL irqL; */ ++ struct __queue *free_queue = &(pmlmepriv->free_bss_pool); ++ ++ if (pnetwork == NULL) ++ return; ++ ++ if (pnetwork->fixed == true) ++ return; ++ ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ==true) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ==true)) ++ lifetime = 1; ++ ++ if (!isfreeall) ++ { ++ delta_time = jiffies_to_msecs(jiffies - pnetwork->last_scanned); ++ if (delta_time < lifetime)/* unit:msec */ ++ return; ++ } ++ ++ spin_lock_bh(&free_queue->lock); ++ ++ list_del_init(&(pnetwork->list)); ++ ++ list_add_tail(&(pnetwork->list),&(free_queue->queue)); ++ ++ pmlmepriv->num_of_scanned --; ++ ++ ++ /* DBG_871X("_rtw_free_network:SSID =%s\n", pnetwork->network.Ssid.Ssid); */ ++ ++ spin_unlock_bh(&free_queue->lock); ++} ++ ++void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork) ++{ ++ ++ struct __queue *free_queue = &(pmlmepriv->free_bss_pool); ++ ++ if (pnetwork == NULL) ++ return; ++ ++ if (pnetwork->fixed == true) ++ return; ++ ++ /* spin_lock_irqsave(&free_queue->lock, irqL); */ ++ ++ list_del_init(&(pnetwork->list)); ++ ++ list_add_tail(&(pnetwork->list), get_list_head(free_queue)); ++ ++ pmlmepriv->num_of_scanned --; ++ ++ /* spin_unlock_irqrestore(&free_queue->lock, irqL); */ ++} ++ ++/* ++ return the wlan_network with the matching addr ++ ++ Shall be calle under atomic context... to avoid possible racing condition... ++*/ ++struct wlan_network *_rtw_find_network(struct __queue *scanned_queue, u8 *addr) ++{ ++ struct list_head *phead, *plist; ++ struct wlan_network *pnetwork = NULL; ++ u8 zero_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; ++ ++ if (!memcmp(zero_addr, addr, ETH_ALEN)) { ++ pnetwork = NULL; ++ goto exit; ++ } ++ ++ /* spin_lock_bh(&scanned_queue->lock); */ ++ ++ phead = get_list_head(scanned_queue); ++ plist = get_next(phead); ++ ++ while (plist != phead) ++ { ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network , list); ++ ++ if (!memcmp(addr, pnetwork->network.MacAddress, ETH_ALEN)) ++ break; ++ ++ plist = get_next(plist); ++ } ++ ++ if (plist == phead) ++ pnetwork = NULL; ++ ++ /* spin_unlock_bh(&scanned_queue->lock); */ ++ ++exit: ++ return pnetwork; ++} ++ ++void _rtw_free_network_queue(struct adapter *padapter, u8 isfreeall) ++{ ++ struct list_head *phead, *plist; ++ struct wlan_network *pnetwork; ++ struct mlme_priv* pmlmepriv = &padapter->mlmepriv; ++ struct __queue *scanned_queue = &pmlmepriv->scanned_queue; ++ ++ spin_lock_bh(&scanned_queue->lock); ++ ++ phead = get_list_head(scanned_queue); ++ plist = get_next(phead); ++ ++ while (phead != plist) ++ { ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ ++ plist = get_next(plist); ++ ++ _rtw_free_network(pmlmepriv, pnetwork, isfreeall); ++ ++ } ++ ++ spin_unlock_bh(&scanned_queue->lock); ++} ++ ++ ++ ++ ++sint rtw_if_up(struct adapter *padapter) { ++ ++ sint res; ++ ++ if (padapter->bDriverStopped || padapter->bSurpriseRemoved || ++ (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == false)) { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_if_up:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved)); ++ res =false; ++ } ++ else ++ res = true; ++ return res; ++} ++ ++ ++void rtw_generate_random_ibss(u8 *pibss) ++{ ++ unsigned long curtime = jiffies; ++ ++ pibss[0] = 0x02; /* in ad-hoc mode bit1 must set to 1 */ ++ pibss[1] = 0x11; ++ pibss[2] = 0x87; ++ pibss[3] = (u8)(curtime & 0xff) ;/* p[0]; */ ++ pibss[4] = (u8)((curtime>>8) & 0xff) ;/* p[1]; */ ++ pibss[5] = (u8)((curtime>>16) & 0xff) ;/* p[2]; */ ++ return; ++} ++ ++u8 *rtw_get_capability_from_ie(u8 *ie) ++{ ++ return (ie + 8 + 2); ++} ++ ++ ++u16 rtw_get_capability(struct wlan_bssid_ex *bss) ++{ ++ __le16 val; ++ ++ memcpy((u8 *)&val, rtw_get_capability_from_ie(bss->IEs), 2); ++ ++ return le16_to_cpu(val); ++} ++ ++u8 *rtw_get_beacon_interval_from_ie(u8 *ie) ++{ ++ return (ie + 8); ++} ++ ++ ++int rtw_init_mlme_priv (struct adapter *padapter)/* struct mlme_priv *pmlmepriv) */ ++{ ++ int res; ++ ++ res = _rtw_init_mlme_priv(padapter);/* (pmlmepriv); */ ++ return res; ++} ++ ++void rtw_free_mlme_priv (struct mlme_priv *pmlmepriv) ++{ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_mlme_priv\n")); ++ _rtw_free_mlme_priv (pmlmepriv); ++} ++ ++/* ++static struct wlan_network *rtw_dequeue_network(struct __queue *queue) ++{ ++ struct wlan_network *pnetwork; ++ ++ pnetwork = _rtw_dequeue_network(queue); ++ return pnetwork; ++} ++*/ ++ ++struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv); ++struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv)/* _queue *free_queue) */ ++{ ++ struct wlan_network *pnetwork; ++ ++ pnetwork = _rtw_alloc_network(pmlmepriv); ++ return pnetwork; ++} ++ ++void rtw_free_network_nolock(struct adapter *padapter, struct wlan_network *pnetwork); ++void rtw_free_network_nolock(struct adapter *padapter, struct wlan_network *pnetwork) ++{ ++ /* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_network ==> ssid = %s\n\n" , pnetwork->network.Ssid.Ssid)); */ ++ _rtw_free_network_nolock(&(padapter->mlmepriv), pnetwork); ++ rtw_cfg80211_unlink_bss(padapter, pnetwork); ++} ++ ++ ++void rtw_free_network_queue(struct adapter * dev, u8 isfreeall) ++{ ++ _rtw_free_network_queue(dev, isfreeall); ++} ++ ++/* ++ return the wlan_network with the matching addr ++ ++ Shall be calle under atomic context... to avoid possible racing condition... ++*/ ++struct wlan_network *rtw_find_network(struct __queue *scanned_queue, u8 *addr) ++{ ++ struct wlan_network *pnetwork = _rtw_find_network(scanned_queue, addr); ++ ++ return pnetwork; ++} ++ ++int rtw_is_same_ibss(struct adapter *adapter, struct wlan_network *pnetwork) ++{ ++ int ret =true; ++ struct security_priv *psecuritypriv = &adapter->securitypriv; ++ ++ if ((psecuritypriv->dot11PrivacyAlgrthm != _NO_PRIVACY_) && ++ (pnetwork->network.Privacy == 0)) ++ { ++ ret =false; ++ } ++ else if ((psecuritypriv->dot11PrivacyAlgrthm == _NO_PRIVACY_) && ++ (pnetwork->network.Privacy == 1)) ++ { ++ ret =false; ++ } ++ else ++ { ++ ret =true; ++ } ++ ++ return ret; ++ ++} ++ ++inline int is_same_ess(struct wlan_bssid_ex *a, struct wlan_bssid_ex *b) ++{ ++ /* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("(%s,%d)(%s,%d)\n", */ ++ /* a->Ssid.Ssid, a->Ssid.SsidLength, b->Ssid.Ssid, b->Ssid.SsidLength)); */ ++ return (a->Ssid.SsidLength == b->Ssid.SsidLength) ++ && !memcmp(a->Ssid.Ssid, b->Ssid.Ssid, a->Ssid.SsidLength); ++} ++ ++int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst, u8 feature) ++{ ++ u16 s_cap, d_cap; ++ __le16 tmps, tmpd; ++ ++ if (rtw_bug_check(dst, src, &s_cap, &d_cap) ==false) ++ return false; ++ ++ memcpy((u8 *)&tmps, rtw_get_capability_from_ie(src->IEs), 2); ++ memcpy((u8 *)&tmpd, rtw_get_capability_from_ie(dst->IEs), 2); ++ ++ ++ s_cap = le16_to_cpu(tmps); ++ d_cap = le16_to_cpu(tmpd); ++ ++ return ((src->Ssid.SsidLength == dst->Ssid.SsidLength) && ++ /* (src->Configuration.DSConfig == dst->Configuration.DSConfig) && */ ++ ((!memcmp(src->MacAddress, dst->MacAddress, ETH_ALEN))) && ++ ((!memcmp(src->Ssid.Ssid, dst->Ssid.Ssid, src->Ssid.SsidLength))) && ++ ((s_cap & WLAN_CAPABILITY_IBSS) == ++ (d_cap & WLAN_CAPABILITY_IBSS)) && ++ ((s_cap & WLAN_CAPABILITY_BSS) == ++ (d_cap & WLAN_CAPABILITY_BSS))); ++ ++} ++ ++struct wlan_network *_rtw_find_same_network(struct __queue *scanned_queue, struct wlan_network *network) ++{ ++ struct list_head *phead, *plist; ++ struct wlan_network *found = NULL; ++ ++ phead = get_list_head(scanned_queue); ++ plist = get_next(phead); ++ ++ while (plist != phead) { ++ found = LIST_CONTAINOR(plist, struct wlan_network , list); ++ ++ if (is_same_network(&network->network, &found->network, 0)) ++ break; ++ ++ plist = get_next(plist); ++ } ++ ++ if (plist == phead) ++ found = NULL; ++ ++ return found; ++} ++ ++struct wlan_network * rtw_get_oldest_wlan_network(struct __queue *scanned_queue) ++{ ++ struct list_head *plist, *phead; ++ ++ ++ struct wlan_network *pwlan = NULL; ++ struct wlan_network *oldest = NULL; ++ ++ phead = get_list_head(scanned_queue); ++ ++ plist = get_next(phead); ++ ++ while (1) ++ { ++ ++ if (phead == plist) ++ break; ++ ++ pwlan = LIST_CONTAINOR(plist, struct wlan_network, list); ++ ++ if (pwlan->fixed!=true) ++ { ++ if (oldest == NULL ||time_after(oldest->last_scanned, pwlan->last_scanned)) ++ oldest = pwlan; ++ } ++ ++ plist = get_next(plist); ++ } ++ return oldest; ++ ++} ++ ++void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src, ++ struct adapter *padapter, bool update_ie) ++{ ++ long rssi_ori = dst->Rssi; ++ ++ u8 sq_smp = src->PhyInfo.SignalQuality; ++ ++ u8 ss_final; ++ u8 sq_final; ++ long rssi_final; ++ ++ #if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) && 1 ++ if (strcmp(dst->Ssid.Ssid, DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) == 0) { ++ DBG_871X(FUNC_ADPT_FMT" %s("MAC_FMT", ch%u) ss_ori:%3u, sq_ori:%3u, rssi_ori:%3ld, ss_smp:%3u, sq_smp:%3u, rssi_smp:%3ld\n" ++ , FUNC_ADPT_ARG(padapter) ++ , src->Ssid.Ssid, MAC_ARG(src->MacAddress), src->Configuration.DSConfig ++ , ss_ori, sq_ori, rssi_ori ++ , ss_smp, sq_smp, rssi_smp ++ ); ++ } ++ #endif ++ ++ /* The rule below is 1/5 for sample value, 4/5 for history value */ ++ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && is_same_network(&(padapter->mlmepriv.cur_network.network), src, 0)) { ++ /* Take the recvpriv's value for the connected AP*/ ++ ss_final = padapter->recvpriv.signal_strength; ++ sq_final = padapter->recvpriv.signal_qual; ++ /* the rssi value here is undecorated, and will be used for antenna diversity */ ++ if (sq_smp != 101) /* from the right channel */ ++ rssi_final = (src->Rssi+dst->Rssi*4)/5; ++ else ++ rssi_final = rssi_ori; ++ } ++ else { ++ if (sq_smp != 101) { /* from the right channel */ ++ ss_final = ((u32)(src->PhyInfo.SignalStrength)+(u32)(dst->PhyInfo.SignalStrength)*4)/5; ++ sq_final = ((u32)(src->PhyInfo.SignalQuality)+(u32)(dst->PhyInfo.SignalQuality)*4)/5; ++ rssi_final = (src->Rssi+dst->Rssi*4)/5; ++ } else { ++ /* bss info not receving from the right channel, use the original RX signal infos */ ++ ss_final = dst->PhyInfo.SignalStrength; ++ sq_final = dst->PhyInfo.SignalQuality; ++ rssi_final = dst->Rssi; ++ } ++ ++ } ++ ++ if (update_ie) { ++ dst->Reserved[0] = src->Reserved[0]; ++ dst->Reserved[1] = src->Reserved[1]; ++ memcpy((u8 *)dst, (u8 *)src, get_wlan_bssid_ex_sz(src)); ++ } ++ ++ dst->PhyInfo.SignalStrength = ss_final; ++ dst->PhyInfo.SignalQuality = sq_final; ++ dst->Rssi = rssi_final; ++ ++ #if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) && 1 ++ if (strcmp(dst->Ssid.Ssid, DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) == 0) { ++ DBG_871X(FUNC_ADPT_FMT" %s("MAC_FMT"), SignalStrength:%u, SignalQuality:%u, RawRSSI:%ld\n" ++ , FUNC_ADPT_ARG(padapter) ++ , dst->Ssid.Ssid, MAC_ARG(dst->MacAddress), dst->PhyInfo.SignalStrength, dst->PhyInfo.SignalQuality, dst->Rssi); ++ } ++ #endif ++} ++ ++static void update_current_network(struct adapter *adapter, struct wlan_bssid_ex *pnetwork) ++{ ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ ++ rtw_bug_check(&(pmlmepriv->cur_network.network), ++ &(pmlmepriv->cur_network.network), ++ &(pmlmepriv->cur_network.network), ++ &(pmlmepriv->cur_network.network)); ++ ++ if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) && (is_same_network(&(pmlmepriv->cur_network.network), pnetwork, 0))) ++ { ++ /* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,"Same Network\n"); */ ++ ++ /* if (pmlmepriv->cur_network.network.IELength<= pnetwork->IELength) */ ++ { ++ update_network(&(pmlmepriv->cur_network.network), pnetwork, adapter, true); ++ rtw_update_protection(adapter, (pmlmepriv->cur_network.network.IEs) + sizeof (struct ndis_802_11_fix_ie), ++ pmlmepriv->cur_network.network.IELength); ++ } ++ } ++} ++ ++ ++/* ++ ++Caller must hold pmlmepriv->lock first. ++ ++ ++*/ ++void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *target) ++{ ++ struct list_head *plist, *phead; ++ u32 bssid_ex_sz; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ struct __queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ struct wlan_network *oldest = NULL; ++ int target_find = 0; ++ u8 feature = 0; ++ ++ spin_lock_bh(&queue->lock); ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ while (1) ++ { ++ if (phead == plist) ++ break; ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ ++ rtw_bug_check(pnetwork, pnetwork, pnetwork, pnetwork); ++ ++ if (is_same_network(&(pnetwork->network), target, feature)) ++ { ++ target_find = 1; ++ break; ++ } ++ ++ if (rtw_roam_flags(adapter)) { ++ /* TODO: don't select netowrk in the same ess as oldest if it's new enough*/ ++ } ++ ++ if (oldest == NULL || time_after(oldest->last_scanned, pnetwork->last_scanned)) ++ oldest = pnetwork; ++ ++ plist = get_next(plist); ++ ++ } ++ ++ ++ /* If we didn't find a match, then get a new network slot to initialize ++ * with this beacon's information */ ++ /* if (phead == plist) { */ ++ if (!target_find) { ++ if (list_empty(&pmlmepriv->free_bss_pool.queue)) { ++ /* If there are no more slots, expire the oldest */ ++ /* list_del_init(&oldest->list); */ ++ pnetwork = oldest; ++ if (pnetwork == NULL) { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n\n\nsomething wrong here\n\n\n")); ++ goto exit; ++ } ++ memcpy(&(pnetwork->network), target, get_wlan_bssid_ex_sz(target)); ++ /* variable initialize */ ++ pnetwork->fixed = false; ++ pnetwork->last_scanned = jiffies; ++ ++ pnetwork->network_type = 0; ++ pnetwork->aid = 0; ++ pnetwork->join_res = 0; ++ ++ /* bss info not receving from the right channel */ ++ if (pnetwork->network.PhyInfo.SignalQuality == 101) ++ pnetwork->network.PhyInfo.SignalQuality = 0; ++ } ++ else { ++ /* Otherwise just pull from the free list */ ++ ++ pnetwork = rtw_alloc_network(pmlmepriv); /* will update scan_time */ ++ ++ if (pnetwork == NULL) { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n\n\nsomething wrong here\n\n\n")); ++ goto exit; ++ } ++ ++ bssid_ex_sz = get_wlan_bssid_ex_sz(target); ++ target->Length = bssid_ex_sz; ++ memcpy(&(pnetwork->network), target, bssid_ex_sz); ++ ++ pnetwork->last_scanned = jiffies; ++ ++ /* bss info not receving from the right channel */ ++ if (pnetwork->network.PhyInfo.SignalQuality == 101) ++ pnetwork->network.PhyInfo.SignalQuality = 0; ++ ++ list_add_tail(&(pnetwork->list),&(queue->queue)); ++ ++ } ++ } ++ else { ++ /* 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 ++ */ ++ bool update_ie = true; ++ ++ pnetwork->last_scanned = jiffies; ++ ++ /* target.Reserved[0]== 1, means that scaned network is a bcn frame. */ ++ if ((pnetwork->network.IELength>target->IELength) && (target->Reserved[0]== 1)) ++ update_ie = false; ++ ++ /* probe resp(3) > beacon(1) > probe req(2) */ ++ if ((target->Reserved[0] != 2) && ++ (target->Reserved[0] >= pnetwork->network.Reserved[0]) ++ ) { ++ update_ie = true; ++ } ++ else { ++ update_ie = false; ++ } ++ ++ update_network(&(pnetwork->network), target, adapter, update_ie); ++ } ++ ++exit: ++ spin_unlock_bh(&queue->lock); ++} ++ ++void rtw_add_network(struct adapter *adapter, struct wlan_bssid_ex *pnetwork); ++void rtw_add_network(struct adapter *adapter, struct wlan_bssid_ex *pnetwork) ++{ ++ /* struct __queue *queue = &(pmlmepriv->scanned_queue); */ ++ ++ /* spin_lock_bh(&queue->lock); */ ++ ++ update_current_network(adapter, pnetwork); ++ ++ rtw_update_scanned_network(adapter, pnetwork); ++ ++ /* spin_unlock_bh(&queue->lock); */ ++} ++ ++/* select the desired network based on the capability of the (i)bss. */ ++/* check items: (1) security */ ++/* (2) network_type */ ++/* (3) WMM */ ++/* (4) HT */ ++/* (5) others */ ++int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwork); ++int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwork) ++{ ++ struct security_priv *psecuritypriv = &adapter->securitypriv; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ u32 desired_encmode; ++ u32 privacy; ++ ++ /* u8 wps_ie[512]; */ ++ uint wps_ielen; ++ ++ int bselected = true; ++ ++ desired_encmode = psecuritypriv->ndisencryptstatus; ++ privacy = pnetwork->network.Privacy; ++ ++ if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) ++ { ++ if (rtw_get_wps_ie(pnetwork->network.IEs+_FIXED_IE_LENGTH_, pnetwork->network.IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen)!= NULL) ++ { ++ return true; ++ } ++ else ++ { ++ return false; ++ } ++ } ++ if (adapter->registrypriv.wifi_spec == 1) /* for correct flow of 8021X to do.... */ ++ { ++ u8 *p = NULL; ++ uint ie_len = 0; ++ ++ if ((desired_encmode == Ndis802_11EncryptionDisabled) && (privacy != 0)) ++ bselected = false; ++ ++ if (psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPA2PSK) { ++ p = rtw_get_ie(pnetwork->network.IEs + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, (pnetwork->network.IELength - _BEACON_IE_OFFSET_)); ++ if (p && ie_len>0) { ++ bselected = true; ++ } else { ++ bselected = false; ++ } ++ } ++ } ++ ++ ++ if ((desired_encmode != Ndis802_11EncryptionDisabled) && (privacy == 0)) { ++ DBG_871X("desired_encmode: %d, privacy: %d\n", desired_encmode, privacy); ++ bselected = false; ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) ++ { ++ if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode) ++ bselected = false; ++ } ++ ++ ++ return bselected; ++} ++ ++/* TODO: Perry : For Power Management */ ++void rtw_atimdone_event_callback(struct adapter *adapter , u8 *pbuf) ++{ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("receive atimdone_evet\n")); ++} ++ ++ ++void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf) ++{ ++ u32 len; ++ struct wlan_bssid_ex *pnetwork; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ ++ pnetwork = (struct wlan_bssid_ex *)pbuf; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_survey_event_callback, ssid =%s\n", pnetwork->Ssid.Ssid)); ++ ++ len = get_wlan_bssid_ex_sz(pnetwork); ++ if (len > (sizeof(struct wlan_bssid_ex))) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n ****rtw_survey_event_callback: return a wrong bss ***\n")); ++ return; ++ } ++ ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ /* update IBSS_network 's timestamp */ ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == true) ++ { ++ /* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,"rtw_survey_event_callback : WIFI_ADHOC_MASTER_STATE\n\n"); */ ++ if (!memcmp(&(pmlmepriv->cur_network.network.MacAddress), pnetwork->MacAddress, ETH_ALEN)) ++ { ++ struct wlan_network* ibss_wlan = NULL; ++ ++ memcpy(pmlmepriv->cur_network.network.IEs, pnetwork->IEs, 8); ++ spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); ++ ibss_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->MacAddress); ++ if (ibss_wlan) ++ { ++ memcpy(ibss_wlan->network.IEs , pnetwork->IEs, 8); ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ goto exit; ++ } ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ } ++ } ++ ++ /* lock pmlmepriv->lock when you accessing network_q */ ++ if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == false) ++ { ++ if (pnetwork->Ssid.Ssid[0] == 0) ++ { ++ pnetwork->Ssid.SsidLength = 0; ++ } ++ rtw_add_network(adapter, pnetwork); ++ } ++ ++exit: ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++ return; ++} ++ ++ ++ ++void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf) ++{ ++ u8 timer_cancelled = false; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ if (pmlmepriv->wps_probe_req_ie) ++ { ++ pmlmepriv->wps_probe_req_ie_len = 0; ++ kfree(pmlmepriv->wps_probe_req_ie); ++ pmlmepriv->wps_probe_req_ie = NULL; ++ } ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_surveydone_event_callback: fw_state:%x\n\n", get_fwstate(pmlmepriv))); ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) ++ { ++ /* u8 timer_cancelled; */ ++ ++ timer_cancelled = true; ++ /* _cancel_timer(&pmlmepriv->scan_to_timer, &timer_cancelled); */ ++ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); ++ } ++ else { ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("nic status =%x, survey done event comes too late!\n", get_fwstate(pmlmepriv))); ++ } ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++ if (timer_cancelled) ++ _cancel_timer(&pmlmepriv->scan_to_timer, &timer_cancelled); ++ ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ rtw_set_signal_stat_timer(&adapter->recvpriv); ++ ++ if (pmlmepriv->to_join == true) ++ { ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ==true)) ++ { ++ if (check_fwstate(pmlmepriv, _FW_LINKED) ==false) ++ { ++ set_fwstate(pmlmepriv, _FW_UNDER_LINKING); ++ ++ if (rtw_select_and_join_from_scanned_queue(pmlmepriv) == _SUCCESS) ++ { ++ _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); ++ } ++ else ++ { ++ struct wlan_bssid_ex *pdev_network = &(adapter->registrypriv.dev_network); ++ u8 *pibss = adapter->registrypriv.dev_network.MacAddress; ++ ++ /* pmlmepriv->fw_state ^= _FW_UNDER_SURVEY;because don't set assoc_timer */ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("switching to adhoc master\n")); ++ ++ memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); ++ memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); ++ ++ rtw_update_registrypriv_dev_network(adapter); ++ rtw_generate_random_ibss(pibss); ++ ++ pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE; ++ ++ if (rtw_createbss_cmd(adapter)!= _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Error =>rtw_createbss_cmd status FAIL\n")); ++ } ++ ++ pmlmepriv->to_join = false; ++ } ++ } ++ } ++ else ++ { ++ int s_ret; ++ set_fwstate(pmlmepriv, _FW_UNDER_LINKING); ++ pmlmepriv->to_join = false; ++ if (_SUCCESS == (s_ret =rtw_select_and_join_from_scanned_queue(pmlmepriv))) ++ { ++ _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); ++ } ++ else if (s_ret == 2)/* there is no need to wait for join */ ++ { ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ rtw_indicate_connect(adapter); ++ } ++ else ++ { ++ DBG_871X("try_to_join, but select scanning queue fail, to_roam:%d\n", rtw_to_roam(adapter)); ++ ++ if (rtw_to_roam(adapter) != 0) { ++ if (rtw_dec_to_roam(adapter) == 0 ++ || _SUCCESS != rtw_sitesurvey_cmd(adapter, &pmlmepriv->assoc_ssid, 1, NULL, 0) ++ ) { ++ rtw_set_to_roam(adapter, 0); ++#ifdef CONFIG_INTEL_WIDI ++ if (adapter->mlmepriv.widi_state == INTEL_WIDI_STATE_ROAMING) ++ { ++ memset(pmlmepriv->sa_ext, 0x00, L2SDTA_SERVICE_VE_LEN); ++ intel_widi_wk_cmd(adapter, INTEL_WIDI_LISTEN_WK, NULL, 0); ++ DBG_871X("change to widi listen\n"); ++ } ++#endif /* CONFIG_INTEL_WIDI */ ++ rtw_free_assoc_resources(adapter, 1); ++ rtw_indicate_disconnect(adapter); ++ } else { ++ pmlmepriv->to_join = true; ++ } ++ } ++ else ++ { ++ rtw_indicate_disconnect(adapter); ++ } ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ } ++ } ++ } else { ++ if (rtw_chk_roam_flags(adapter, RTW_ROAM_ACTIVE)) { ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) ++ && check_fwstate(pmlmepriv, _FW_LINKED)) ++ { ++ if (rtw_select_roaming_candidate(pmlmepriv) == _SUCCESS) { ++ receive_disconnect(adapter, pmlmepriv->cur_network.network.MacAddress ++ , WLAN_REASON_ACTIVE_ROAM); ++ } ++ } ++ } ++ } ++ ++ /* DBG_871X("scan complete in %dms\n", jiffies_to_msecs(jiffies - pmlmepriv->scan_start_time)); */ ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++ rtw_os_xmit_schedule(adapter); ++ ++ rtw_cfg80211_surveydone_event_callback(adapter); ++ ++ rtw_indicate_scan_done(adapter, false); ++} ++ ++void rtw_dummy_event_callback(struct adapter *adapter , u8 *pbuf) ++{ ++} ++ ++void rtw_fwdbg_event_callback(struct adapter *adapter , u8 *pbuf) ++{ ++} ++ ++static void free_scanqueue(struct mlme_priv *pmlmepriv) ++{ ++ struct __queue *free_queue = &pmlmepriv->free_bss_pool; ++ struct __queue *scan_queue = &pmlmepriv->scanned_queue; ++ struct list_head *plist, *phead, *ptemp; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+free_scanqueue\n")); ++ spin_lock_bh(&scan_queue->lock); ++ spin_lock_bh(&free_queue->lock); ++ ++ phead = get_list_head(scan_queue); ++ plist = get_next(phead); ++ ++ while (plist != phead) ++ { ++ ptemp = get_next(plist); ++ list_del_init(plist); ++ list_add_tail(plist, &free_queue->queue); ++ plist =ptemp; ++ pmlmepriv->num_of_scanned --; ++ } ++ ++ spin_unlock_bh(&free_queue->lock); ++ spin_unlock_bh(&scan_queue->lock); ++} ++ ++static void rtw_reset_rx_info(struct debug_priv *pdbgpriv) ++{ ++ pdbgpriv->dbg_rx_ampdu_drop_count = 0; ++ pdbgpriv->dbg_rx_ampdu_forced_indicate_count = 0; ++ pdbgpriv->dbg_rx_ampdu_loss_count = 0; ++ pdbgpriv->dbg_rx_dup_mgt_frame_drop_count = 0; ++ pdbgpriv->dbg_rx_ampdu_window_shift_cnt = 0; ++} ++ ++static void find_network(struct adapter *adapter) ++{ ++ struct wlan_network* pwlan = NULL; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ struct wlan_network *tgt_network = &pmlmepriv->cur_network; ++ ++ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); ++ if (pwlan) ++ pwlan->fixed = false; ++ else ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_assoc_resources : pwlan == NULL\n\n")); ++ ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) && ++ (adapter->stapriv.asoc_sta_count == 1)) ++ rtw_free_network_nolock(adapter, pwlan); ++} ++ ++/* ++*rtw_free_assoc_resources: the caller has to lock pmlmepriv->lock ++*/ ++void rtw_free_assoc_resources(struct adapter *adapter, int lock_scanned_queue) ++{ ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ struct wlan_network *tgt_network = &pmlmepriv->cur_network; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct dvobj_priv *psdpriv = adapter->dvobj; ++ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_free_assoc_resources\n")); ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("tgt_network->network.MacAddress ="MAC_FMT" ssid =%s\n", ++ MAC_ARG(tgt_network->network.MacAddress), tgt_network->network.Ssid.Ssid)); ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_AP_STATE)) ++ { ++ struct sta_info* psta; ++ ++ psta = rtw_get_stainfo(&adapter->stapriv, tgt_network->network.MacAddress); ++ spin_lock_bh(&(pstapriv->sta_hash_lock)); ++ rtw_free_stainfo(adapter, psta); ++ ++ spin_unlock_bh(&(pstapriv->sta_hash_lock)); ++ ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE)) ++ { ++ struct sta_info* psta; ++ ++ rtw_free_all_stainfo(adapter); ++ ++ psta = rtw_get_bcmc_stainfo(adapter); ++ rtw_free_stainfo(adapter, psta); ++ ++ rtw_init_bcmc_stainfo(adapter); ++ } ++ ++ if (lock_scanned_queue) { ++ find_network(adapter); ++ } else { ++ find_network(adapter); ++ } ++ ++ if (lock_scanned_queue) ++ ++ adapter->securitypriv.key_mask = 0; ++ ++ rtw_reset_rx_info(pdbgpriv); ++} ++ ++/* ++*rtw_indicate_connect: the caller has to lock pmlmepriv->lock ++*/ ++void rtw_indicate_connect(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_connect\n")); ++ ++ pmlmepriv->to_join = false; ++ ++ if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) ++ { ++ ++ set_fwstate(pmlmepriv, _FW_LINKED); ++ ++ rtw_os_indicate_connect(padapter); ++ } ++ ++ rtw_set_to_roam(padapter, 0); ++#ifdef CONFIG_INTEL_WIDI ++ if (padapter->mlmepriv.widi_state == INTEL_WIDI_STATE_ROAMING) ++ { ++ memset(pmlmepriv->sa_ext, 0x00, L2SDTA_SERVICE_VE_LEN); ++ intel_widi_wk_cmd(padapter, INTEL_WIDI_LISTEN_WK, NULL, 0); ++ DBG_871X("change to widi listen\n"); ++ } ++#endif /* CONFIG_INTEL_WIDI */ ++ ++ rtw_set_scan_deny(padapter, 3000); ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("-rtw_indicate_connect: fw_state = 0x%08x\n", get_fwstate(pmlmepriv))); ++} ++ ++/* ++*rtw_indicate_disconnect: the caller has to lock pmlmepriv->lock ++*/ ++void rtw_indicate_disconnect(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_disconnect\n")); ++ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING|WIFI_UNDER_WPS); ++ ++ /* DBG_871X("clear wps when %s\n", __func__); */ ++ ++ if (rtw_to_roam(padapter) > 0) ++ _clr_fwstate_(pmlmepriv, _FW_LINKED); ++ ++ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) ++ || (rtw_to_roam(padapter) <= 0) ++ ) ++ { ++ rtw_os_indicate_disconnect(padapter); ++ ++ /* set ips_deny_time to avoid enter IPS before LPS leave */ ++ rtw_set_ips_deny(padapter, 3000); ++ ++ _clr_fwstate_(pmlmepriv, _FW_LINKED); ++ ++ rtw_clear_scan_deny(padapter); ++ } ++ ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_DISCONNECT, 1); ++} ++ ++inline void rtw_indicate_scan_done(struct adapter *padapter, bool aborted) ++{ ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); ++ ++ rtw_os_indicate_scan_done(padapter, aborted); ++ ++ if (is_primary_adapter(padapter) && ++ (!adapter_to_pwrctl(padapter)->bInSuspend) && ++ (!check_fwstate(&padapter->mlmepriv, ++ WIFI_ASOC_STATE|WIFI_UNDER_LINKING))) { ++ struct pwrctrl_priv *pwrpriv; ++ ++ pwrpriv = adapter_to_pwrctl(padapter); ++ rtw_set_ips_deny(padapter, 0); ++ _set_timer(&padapter->mlmepriv.dynamic_chk_timer, 1); ++ } ++} ++ ++void rtw_scan_abort(struct adapter *adapter) ++{ ++ unsigned long start; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv); ++ ++ start = jiffies; ++ pmlmeext->scan_abort = true; ++ while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) ++ && jiffies_to_msecs(start) <= 200) { ++ ++ if (adapter->bDriverStopped || adapter->bSurpriseRemoved) ++ break; ++ ++ DBG_871X(FUNC_NDEV_FMT"fw_state = _FW_UNDER_SURVEY!\n", FUNC_NDEV_ARG(adapter->pnetdev)); ++ msleep(20); ++ } ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { ++ if (!adapter->bDriverStopped && !adapter->bSurpriseRemoved) ++ DBG_871X(FUNC_NDEV_FMT"waiting for scan_abort time out!\n", FUNC_NDEV_ARG(adapter->pnetdev)); ++ rtw_indicate_scan_done(adapter, true); ++ } ++ pmlmeext->scan_abort = false; ++} ++ ++static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, struct wlan_network *pnetwork) ++{ ++ int i; ++ struct sta_info *bmc_sta, *psta = NULL; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ psta = rtw_get_stainfo(pstapriv, pnetwork->network.MacAddress); ++ if (psta == NULL) { ++ psta = rtw_alloc_stainfo(pstapriv, pnetwork->network.MacAddress); ++ } ++ ++ if (psta) /* update ptarget_sta */ ++ { ++ DBG_871X("%s\n", __func__); ++ ++ psta->aid = pnetwork->join_res; ++ ++ update_sta_info(padapter, psta); ++ ++ /* update station supportRate */ ++ psta->bssratelen = rtw_get_rateset_len(pnetwork->network.SupportedRates); ++ memcpy(psta->bssrateset, pnetwork->network.SupportedRates, psta->bssratelen); ++ rtw_hal_update_sta_rate_mask(padapter, psta); ++ ++ psta->wireless_mode = pmlmeext->cur_wireless_mode; ++ psta->raid = rtw_hal_networktype_to_raid(padapter, psta); ++ ++ ++ /* sta mode */ ++ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true); ++ ++ /* security related */ ++ if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) ++ { ++ padapter->securitypriv.binstallGrpkey =false; ++ padapter->securitypriv.busetkipkey =false; ++ padapter->securitypriv.bgrpkey_handshake =false; ++ ++ psta->ieee8021x_blocked =true; ++ psta->dot118021XPrivacy =padapter->securitypriv.dot11PrivacyAlgrthm; ++ ++ memset((u8 *)&psta->dot118021x_UncstKey, 0, sizeof (union Keytype)); ++ ++ memset((u8 *)&psta->dot11tkiprxmickey, 0, sizeof (union Keytype)); ++ memset((u8 *)&psta->dot11tkiptxmickey, 0, sizeof (union Keytype)); ++ ++ memset((u8 *)&psta->dot11txpn, 0, sizeof (union pn48)); ++ psta->dot11txpn.val = psta->dot11txpn.val + 1; ++ memset((u8 *)&psta->dot11wtxpn, 0, sizeof (union pn48)); ++ memset((u8 *)&psta->dot11rxpn, 0, sizeof (union pn48)); ++ } ++ ++ /* Commented by Albert 2012/07/21 */ ++ /* When doing the WPS, the wps_ie_len won't equal to 0 */ ++ /* And the Wi-Fi driver shouldn't allow the data packet to be tramsmitted. */ ++ if (padapter->securitypriv.wps_ie_len != 0) ++ { ++ psta->ieee8021x_blocked =true; ++ padapter->securitypriv.wps_ie_len = 0; ++ } ++ ++ ++ /* for A-MPDU Rx reordering buffer control for bmc_sta & sta_info */ ++ /* if A-MPDU Rx is enabled, reseting rx_ordering_ctrl wstart_b(indicate_seq) to default value = 0xffff */ ++ /* todo: check if AP can send A-MPDU packets */ ++ for (i = 0; i < 16 ; i++) ++ { ++ /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */ ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ preorder_ctrl->enable = false; ++ preorder_ctrl->indicate_seq = 0xffff; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d indicate_seq:%u\n", __func__, __LINE__, ++ preorder_ctrl->indicate_seq); ++ #endif ++ preorder_ctrl->wend_b = 0xffff; ++ preorder_ctrl->wsize_b = 64;/* max_ampdu_sz;ex. 32(kbytes) -> wsize_b =32 */ ++ } ++ ++ ++ bmc_sta = rtw_get_bcmc_stainfo(padapter); ++ if (bmc_sta) ++ { ++ for (i = 0; i < 16 ; i++) ++ { ++ /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */ ++ preorder_ctrl = &bmc_sta->recvreorder_ctrl[i]; ++ preorder_ctrl->enable = false; ++ preorder_ctrl->indicate_seq = 0xffff; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d indicate_seq:%u\n", __func__, __LINE__, ++ preorder_ctrl->indicate_seq); ++ #endif ++ preorder_ctrl->wend_b = 0xffff; ++ preorder_ctrl->wsize_b = 64;/* max_ampdu_sz;ex. 32(kbytes) -> wsize_b =32 */ ++ } ++ } ++ } ++ ++ return psta; ++ ++} ++ ++/* pnetwork : returns from rtw_joinbss_event_callback */ ++/* ptarget_wlan: found from scanned_queue */ ++static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_network *ptarget_wlan, struct wlan_network *pnetwork) ++{ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct wlan_network *cur_network = &(pmlmepriv->cur_network); ++ ++ DBG_871X("%s\n", __func__); ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\nfw_state:%x, BSSID:"MAC_FMT"\n" ++ , get_fwstate(pmlmepriv), MAC_ARG(pnetwork->network.MacAddress))); ++ ++ ++ /* why not use ptarget_wlan?? */ ++ memcpy(&cur_network->network, &pnetwork->network, pnetwork->network.Length); ++ /* some IEs in pnetwork is wrong, so we should use ptarget_wlan IEs */ ++ cur_network->network.IELength = ptarget_wlan->network.IELength; ++ memcpy(&cur_network->network.IEs[0], &ptarget_wlan->network.IEs[0], MAX_IE_SZ); ++ ++ cur_network->aid = pnetwork->join_res; ++ ++ ++ rtw_set_signal_stat_timer(&padapter->recvpriv); ++ ++ padapter->recvpriv.signal_strength = ptarget_wlan->network.PhyInfo.SignalStrength; ++ padapter->recvpriv.signal_qual = ptarget_wlan->network.PhyInfo.SignalQuality; ++ /* the ptarget_wlan->network.Rssi is raw data, we use ptarget_wlan->network.PhyInfo.SignalStrength instead (has scaled) */ ++ padapter->recvpriv.rssi = translate_percentage_to_dbm(ptarget_wlan->network.PhyInfo.SignalStrength); ++ #if defined(DBG_RX_SIGNAL_DISPLAY_PROCESSING) && 1 ++ DBG_871X(FUNC_ADPT_FMT" signal_strength:%3u, rssi:%3d, signal_qual:%3u" ++ "\n" ++ , FUNC_ADPT_ARG(padapter) ++ , padapter->recvpriv.signal_strength ++ , padapter->recvpriv.rssi ++ , padapter->recvpriv.signal_qual ++ ); ++ #endif ++ ++ rtw_set_signal_stat_timer(&padapter->recvpriv); ++ ++ /* update fw_state will clr _FW_UNDER_LINKING here indirectly */ ++ switch (pnetwork->network.InfrastructureMode) ++ { ++ case Ndis802_11Infrastructure: ++ ++ if (pmlmepriv->fw_state&WIFI_UNDER_WPS) ++ pmlmepriv->fw_state = WIFI_STATION_STATE|WIFI_UNDER_WPS; ++ else ++ pmlmepriv->fw_state = WIFI_STATION_STATE; ++ ++ break; ++ case Ndis802_11IBSS: ++ pmlmepriv->fw_state = WIFI_ADHOC_STATE; ++ break; ++ default: ++ pmlmepriv->fw_state = WIFI_NULL_STATE; ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Invalid network_mode\n")); ++ break; ++ } ++ ++ rtw_update_protection(padapter, (cur_network->network.IEs) + sizeof (struct ndis_802_11_fix_ie), ++ (cur_network->network.IELength)); ++ ++ rtw_update_ht_cap(padapter, cur_network->network.IEs, cur_network->network.IELength, (u8) cur_network->network.Configuration.DSConfig); ++} ++ ++/* Notes: the fucntion could be > passive_level (the same context as Rx tasklet) */ ++/* pnetwork : returns from rtw_joinbss_event_callback */ ++/* ptarget_wlan: found from scanned_queue */ ++/* if join_res > 0, for (fw_state ==WIFI_STATION_STATE), we check if "ptarget_sta" & "ptarget_wlan" exist. */ ++/* if join_res > 0, for (fw_state ==WIFI_ADHOC_STATE), we only check if "ptarget_wlan" exist. */ ++/* if join_res > 0, update "cur_network->network" from "pnetwork->network" if (ptarget_wlan != NULL). */ ++/* */ ++/* define REJOIN */ ++void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) ++{ ++ static u8 retry = 0; ++ u8 timer_cancelled; ++ struct sta_info *ptarget_sta = NULL, *pcur_sta = NULL; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ struct wlan_network *pnetwork = (struct wlan_network *)pbuf; ++ struct wlan_network *cur_network = &(pmlmepriv->cur_network); ++ struct wlan_network *pcur_wlan = NULL, *ptarget_wlan = NULL; ++ unsigned int the_same_macaddr = false; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("joinbss event call back received with res =%d\n", pnetwork->join_res)); ++ ++ rtw_get_encrypt_decrypt_from_registrypriv(adapter); ++ ++ ++ if (pmlmepriv->assoc_ssid.SsidLength == 0) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("@@@@@ joinbss event call back for Any SSid\n")); ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("@@@@@ rtw_joinbss_event_callback for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid)); ++ } ++ ++ the_same_macaddr = !memcmp(pnetwork->network.MacAddress, cur_network->network.MacAddress, ETH_ALEN); ++ ++ pnetwork->network.Length = get_wlan_bssid_ex_sz(&pnetwork->network); ++ if (pnetwork->network.Length > sizeof(struct wlan_bssid_ex)) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n\n ***joinbss_evt_callback return a wrong bss ***\n\n")); ++ return; ++ } ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 0; ++ pmlmepriv->LinkDetectInfo.LowPowerTransitionCount = 0; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\n rtw_joinbss_event_callback !! spin_lock_irqsave\n")); ++ ++ if (pnetwork->join_res > 0) ++ { ++ spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); ++ retry = 0; ++ if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) ++ { ++ /* s1. find ptarget_wlan */ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) ++ { ++ if (the_same_macaddr == true) ++ { ++ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); ++ } ++ else ++ { ++ pcur_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); ++ if (pcur_wlan) pcur_wlan->fixed = false; ++ ++ pcur_sta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress); ++ if (pcur_sta) ++ rtw_free_stainfo(adapter, pcur_sta); ++ ++ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress); ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { ++ if (ptarget_wlan) ptarget_wlan->fixed = true; ++ } ++ } ++ ++ } ++ else ++ { ++ ptarget_wlan = _rtw_find_same_network(&pmlmepriv->scanned_queue, pnetwork); ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { ++ if (ptarget_wlan) ptarget_wlan->fixed = true; ++ } ++ } ++ ++ /* s2. update cur_network */ ++ if (ptarget_wlan) ++ { ++ rtw_joinbss_update_network(adapter, ptarget_wlan, pnetwork); ++ } ++ else ++ { ++ DBG_871X_LEVEL(_drv_always_, "Can't find ptarget_wlan when joinbss_event callback\n"); ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ goto ignore_joinbss_callback; ++ } ++ ++ ++ /* s3. find ptarget_sta & update ptarget_sta after update cur_network only for station mode */ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) ++ { ++ ptarget_sta = rtw_joinbss_update_stainfo(adapter, pnetwork); ++ if (ptarget_sta == NULL) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Can't update stainfo when joinbss_event callback\n")); ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ goto ignore_joinbss_callback; ++ } ++ } ++ ++ /* s4. indicate connect */ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) ++ { ++ pmlmepriv->cur_network_scanned = ptarget_wlan; ++ rtw_indicate_connect(adapter); ++ } ++ else ++ { ++ /* adhoc mode will rtw_indicate_connect when rtw_stassoc_event_callback */ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("adhoc mode, fw_state:%x", get_fwstate(pmlmepriv))); ++ } ++ ++ ++ /* s5. Cancle assoc_timer */ ++ _cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled); ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("Cancle assoc_timer\n")); ++ ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_joinbss_event_callback err: fw_state:%x", get_fwstate(pmlmepriv))); ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ goto ignore_joinbss_callback; ++ } ++ ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ ++ } ++ else if (pnetwork->join_res == -4) ++ { ++ rtw_reset_securitypriv(adapter); ++ _set_timer(&pmlmepriv->assoc_timer, 1); ++ ++ /* rtw_free_assoc_resources(adapter, 1); */ ++ ++ if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == true) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("fail! clear _FW_UNDER_LINKING ^^^fw_state =%x\n", get_fwstate(pmlmepriv))); ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ } ++ ++ } ++ else /* if join_res < 0 (join fails), then try again */ ++ { ++ ++ #ifdef REJOIN ++ res = _FAIL; ++ if (retry < 2) { ++ res = rtw_select_and_join_from_scanned_queue(pmlmepriv); ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_select_and_join_from_scanned_queue again! res:%d\n", res)); ++ } ++ ++ if (res == _SUCCESS) ++ { ++ /* extend time of assoc_timer */ ++ _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); ++ retry++; ++ } ++ else if (res == 2)/* there is no need to wait for join */ ++ { ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ rtw_indicate_connect(adapter); ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Set Assoc_Timer = 1; can't find match ssid in scanned_q\n")); ++ #endif ++ ++ _set_timer(&pmlmepriv->assoc_timer, 1); ++ /* rtw_free_assoc_resources(adapter, 1); */ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ ++ #ifdef REJOIN ++ retry = 0; ++ } ++ #endif ++ } ++ ++ignore_joinbss_callback: ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++} ++ ++void rtw_joinbss_event_callback(struct adapter *adapter, u8 *pbuf) ++{ ++ struct wlan_network *pnetwork = (struct wlan_network *)pbuf; ++ ++ mlmeext_joinbss_event_callback(adapter, pnetwork->join_res); ++ ++ rtw_os_xmit_schedule(adapter); ++} ++ ++/* FOR STA, AP , AD-HOC mode */ ++void rtw_sta_media_status_rpt(struct adapter *adapter, struct sta_info *psta, u32 mstatus) ++{ ++ u16 media_status_rpt; ++ ++ if (psta == NULL) return; ++ ++ media_status_rpt = (u16)((psta->mac_id<<8)|mstatus); /* MACID|OPMODE:1 connect */ ++ rtw_hal_set_hwreg(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status_rpt); ++} ++ ++void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf) ++{ ++ struct sta_info *psta; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ struct stassoc_event *pstassoc = (struct stassoc_event*)pbuf; ++ struct wlan_network *cur_network = &(pmlmepriv->cur_network); ++ struct wlan_network *ptarget_wlan = NULL; ++ ++ if (rtw_access_ctrl(adapter, pstassoc->macaddr) == false) ++ return; ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ { ++ psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr); ++ if (psta) ++ { ++ u8 *passoc_req = NULL; ++ u32 assoc_req_len = 0; ++ ++ rtw_sta_media_status_rpt(adapter, psta, 1); ++ ++#ifndef CONFIG_AUTO_AP_MODE ++ ++ ap_sta_info_defer_update(adapter, psta); ++ ++ /* report to upper layer */ ++ DBG_871X("indicate_sta_assoc_event to upper layer - hostapd\n"); ++ spin_lock_bh(&psta->lock); ++ if (psta->passoc_req && psta->assoc_req_len>0) ++ { ++ passoc_req = rtw_zmalloc(psta->assoc_req_len); ++ if (passoc_req) ++ { ++ assoc_req_len = psta->assoc_req_len; ++ memcpy(passoc_req, psta->passoc_req, assoc_req_len); ++ ++ kfree(psta->passoc_req); ++ psta->passoc_req = NULL; ++ psta->assoc_req_len = 0; ++ } ++ } ++ spin_unlock_bh(&psta->lock); ++ ++ if (passoc_req && assoc_req_len>0) ++ { ++ rtw_cfg80211_indicate_sta_assoc(adapter, passoc_req, assoc_req_len); ++ ++ kfree(passoc_req); ++ } ++#endif /* CONFIG_AUTO_AP_MODE */ ++ } ++ return; ++ } ++ ++ /* for AD-HOC mode */ ++ psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr); ++ if (psta != NULL) ++ { ++ /* the sta have been in sta_info_queue => do nothing */ ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Error: rtw_stassoc_event_callback: sta has been in sta_hash_queue\n")); ++ ++ return; /* between drv has received this event before and fw have not yet to set key to CAM_ENTRY) */ ++ } ++ ++ psta = rtw_alloc_stainfo(&adapter->stapriv, pstassoc->macaddr); ++ if (psta == NULL) { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Can't alloc sta_info when rtw_stassoc_event_callback\n")); ++ return; ++ } ++ ++ /* to do : init sta_info variable */ ++ psta->qos_option = 0; ++ psta->mac_id = (uint)pstassoc->cam_id; ++ /* psta->aid = (uint)pstassoc->cam_id; */ ++ DBG_871X("%s\n", __func__); ++ /* for ad-hoc mode */ ++ rtw_hal_set_odm_var(adapter, HAL_ODM_STA_INFO, psta, true); ++ ++ rtw_sta_media_status_rpt(adapter, psta, 1); ++ ++ if (adapter->securitypriv.dot11AuthAlgrthm ==dot11AuthAlgrthm_8021X) ++ psta->dot118021XPrivacy = adapter->securitypriv.dot11PrivacyAlgrthm; ++ ++ ++ psta->ieee8021x_blocked = false; ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ==true) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ==true)) ++ { ++ if (adapter->stapriv.asoc_sta_count == 2) ++ { ++ spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); ++ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); ++ pmlmepriv->cur_network_scanned = ptarget_wlan; ++ if (ptarget_wlan) ptarget_wlan->fixed = true; ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ /* a sta + bc/mc_stainfo (not Ibss_stainfo) */ ++ rtw_indicate_connect(adapter); ++ } ++ } ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++ ++ mlmeext_sta_add_event_callback(adapter, psta); ++} ++ ++void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) ++{ ++ int mac_id = (-1); ++ struct sta_info *psta; ++ struct wlan_network* pwlan = NULL; ++ struct wlan_bssid_ex *pdev_network = NULL; ++ u8 *pibss = NULL; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ struct stadel_event *pstadel = (struct stadel_event*)pbuf; ++ struct wlan_network *tgt_network = &(pmlmepriv->cur_network); ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ psta = rtw_get_stainfo(&adapter->stapriv, pstadel->macaddr); ++ if (psta) ++ mac_id = psta->mac_id; ++ else ++ mac_id = pstadel->mac_id; ++ ++ DBG_871X("%s(mac_id =%d) =" MAC_FMT "\n", __func__, mac_id, MAC_ARG(pstadel->macaddr)); ++ ++ if (mac_id>= 0) { ++ u16 media_status; ++ media_status = (mac_id<<8)|0; /* MACID|OPMODE:0 means disconnect */ ++ /* for STA, AP, ADHOC mode, report disconnect stauts to FW */ ++ rtw_hal_set_hwreg(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status); ++ } ++ ++ /* if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) */ ++ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) ++ { ++ return; ++ } ++ ++ ++ mlmeext_sta_del_event_callback(adapter); ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) ++ { ++ u16 reason = *((unsigned short *)(pstadel->rsvd)); ++ bool roam = false; ++ struct wlan_network *roam_target = NULL; ++ ++ if (adapter->registrypriv.wifi_spec == 1) { ++ roam = false; ++ } else if (reason == WLAN_REASON_EXPIRATION_CHK && rtw_chk_roam_flags(adapter, RTW_ROAM_ON_EXPIRED)) { ++ roam = true; ++ } else if (reason == WLAN_REASON_ACTIVE_ROAM && rtw_chk_roam_flags(adapter, RTW_ROAM_ACTIVE)) { ++ roam = true; ++ roam_target = pmlmepriv->roam_network; ++ } ++#ifdef CONFIG_INTEL_WIDI ++ else if (adapter->mlmepriv.widi_state == INTEL_WIDI_STATE_CONNECTED) { ++ roam = true; ++ } ++#endif /* CONFIG_INTEL_WIDI */ ++ ++ if (roam == true) { ++ if (rtw_to_roam(adapter) > 0) ++ rtw_dec_to_roam(adapter); /* this stadel_event is caused by roaming, decrease to_roam */ ++ else if (rtw_to_roam(adapter) == 0) ++ rtw_set_to_roam(adapter, adapter->registrypriv.max_roaming_times); ++ } else { ++ rtw_set_to_roam(adapter, 0); ++ } ++ ++ rtw_free_uc_swdec_pending_queue(adapter); ++ ++ rtw_free_assoc_resources(adapter, 1); ++ rtw_indicate_disconnect(adapter); ++ ++ spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); ++ /* remove the network entry in scanned_queue */ ++ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); ++ if (pwlan) { ++ pwlan->fixed = false; ++ rtw_free_network_nolock(adapter, pwlan); ++ } ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ ++#ifdef CONFIG_INTEL_WIDI ++ if (!rtw_to_roam(adapter)) ++ process_intel_widi_disconnect(adapter, 1); ++#endif /* CONFIG_INTEL_WIDI */ ++ ++ _rtw_roaming(adapter, roam_target); ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || ++ check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) ++ { ++ ++ rtw_free_stainfo(adapter, psta); ++ ++ if (adapter->stapriv.asoc_sta_count == 1) /* a sta + bc/mc_stainfo (not Ibss_stainfo) */ ++ { ++ /* rtw_indicate_disconnect(adapter);removed@20091105 */ ++ spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); ++ /* free old ibss network */ ++ /* pwlan = rtw_find_network(&pmlmepriv->scanned_queue, pstadel->macaddr); */ ++ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); ++ if (pwlan) ++ { ++ pwlan->fixed = false; ++ rtw_free_network_nolock(adapter, pwlan); ++ } ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ /* re-create ibss */ ++ pdev_network = &(adapter->registrypriv.dev_network); ++ pibss = adapter->registrypriv.dev_network.MacAddress; ++ ++ memcpy(pdev_network, &tgt_network->network, get_wlan_bssid_ex_sz(&tgt_network->network)); ++ ++ memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); ++ memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); ++ ++ rtw_update_registrypriv_dev_network(adapter); ++ ++ rtw_generate_random_ibss(pibss); ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) ++ { ++ set_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE); ++ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_STATE); ++ } ++ ++ if (rtw_createbss_cmd(adapter)!= _SUCCESS) ++ { ++ ++ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("***Error =>stadel_event_callback: rtw_createbss_cmd status FAIL***\n ")); ++ ++ } ++ ++ ++ } ++ ++ } ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++} ++ ++void rtw_cpwm_event_callback(struct adapter *padapter, u8 *pbuf) ++{ ++ struct reportpwrstate_parm *preportpwrstate; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_cpwm_event_callback !!!\n")); ++ preportpwrstate = (struct reportpwrstate_parm*)pbuf; ++ preportpwrstate->state |= (u8)(adapter_to_pwrctl(padapter)->cpwm_tog + 0x80); ++ cpwm_int_hdl(padapter, preportpwrstate); ++} ++ ++ ++void rtw_wmm_event_callback(struct adapter *padapter, u8 *pbuf) ++{ ++ WMMOnAssocRsp(padapter); ++} ++ ++/* ++* _rtw_join_timeout_handler - Timeout/faliure handler for CMD JoinBss ++* @adapter: pointer to struct adapter structure ++*/ ++void _rtw_join_timeout_handler (struct adapter *adapter) ++{ ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ ++ DBG_871X("%s, fw_state =%x\n", __func__, get_fwstate(pmlmepriv)); ++ ++ if (adapter->bDriverStopped ||adapter->bSurpriseRemoved) ++ return; ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ if (rtw_to_roam(adapter) > 0) { /* join timeout caused by roaming */ ++ while (1) { ++ rtw_dec_to_roam(adapter); ++ if (rtw_to_roam(adapter) != 0) { /* try another */ ++ int do_join_r; ++ DBG_871X("%s try another roaming\n", __func__); ++ if (_SUCCESS!=(do_join_r =rtw_do_join(adapter))) { ++ DBG_871X("%s roaming do_join return %d\n", __func__ , do_join_r); ++ continue; ++ } ++ break; ++ } else { ++#ifdef CONFIG_INTEL_WIDI ++ if (adapter->mlmepriv.widi_state == INTEL_WIDI_STATE_ROAMING) ++ { ++ memset(pmlmepriv->sa_ext, 0x00, L2SDTA_SERVICE_VE_LEN); ++ intel_widi_wk_cmd(adapter, INTEL_WIDI_LISTEN_WK, NULL, 0); ++ DBG_871X("change to widi listen\n"); ++ } ++#endif /* CONFIG_INTEL_WIDI */ ++ DBG_871X("%s We've try roaming but fail\n", __func__); ++ rtw_indicate_disconnect(adapter); ++ break; ++ } ++ } ++ ++ } else ++ { ++ rtw_indicate_disconnect(adapter); ++ free_scanqueue(pmlmepriv);/* */ ++ ++ /* indicate disconnect for the case that join_timeout and check_fwstate != FW_LINKED */ ++ rtw_cfg80211_indicate_disconnect(adapter); ++ ++ } ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++} ++ ++/* ++* rtw_scan_timeout_handler - Timeout/Faliure handler for CMD SiteSurvey ++* @adapter: pointer to struct adapter structure ++*/ ++void rtw_scan_timeout_handler (struct adapter *adapter) ++{ ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ ++ DBG_871X(FUNC_ADPT_FMT" fw_state =%x\n", FUNC_ADPT_ARG(adapter), get_fwstate(pmlmepriv)); ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++ rtw_indicate_scan_done(adapter, true); ++} ++ ++void rtw_mlme_reset_auto_scan_int(struct adapter *adapter) ++{ ++ struct mlme_priv *mlme = &adapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if (pmlmeinfo->VHT_enable) /* disable auto scan when connect to 11AC AP */ ++ { ++ mlme->auto_scan_int_ms = 0; ++ } ++ else if (adapter->registrypriv.wifi_spec && is_client_associated_to_ap(adapter) == true) { ++ mlme->auto_scan_int_ms = 60*1000; ++ } else if (rtw_chk_roam_flags(adapter, RTW_ROAM_ACTIVE)) { ++ if (check_fwstate(mlme, WIFI_STATION_STATE) && check_fwstate(mlme, _FW_LINKED)) ++ mlme->auto_scan_int_ms = mlme->roam_scan_int_ms; ++ } else { ++ mlme->auto_scan_int_ms = 0; /* disabled */ ++ } ++ ++ return; ++} ++ ++static void rtw_auto_scan_handler(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ rtw_mlme_reset_auto_scan_int(padapter); ++ ++ if (pmlmepriv->auto_scan_int_ms != 0 ++ && jiffies_to_msecs(jiffies - pmlmepriv->scan_start_time) > pmlmepriv->auto_scan_int_ms) { ++ ++ if (!padapter->registrypriv.wifi_spec) { ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true) ++ { ++ DBG_871X(FUNC_ADPT_FMT" _FW_UNDER_SURVEY|_FW_UNDER_LINKING\n", FUNC_ADPT_ARG(padapter)); ++ goto exit; ++ } ++ ++ if (pmlmepriv->LinkDetectInfo.bBusyTraffic == true) ++ { ++ DBG_871X(FUNC_ADPT_FMT" exit BusyTraffic\n", FUNC_ADPT_ARG(padapter)); ++ goto exit; ++ } ++ } ++ ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); ++ ++ rtw_set_802_11_bssid_list_scan(padapter, NULL, 0); ++ } ++ ++exit: ++ return; ++} ++ ++void rtw_dynamic_check_timer_handlder(struct adapter *adapter) ++{ ++ if (!adapter) ++ return; ++ ++ if (adapter->hw_init_completed == false) ++ return; ++ ++ if ((adapter->bDriverStopped == true)||(adapter->bSurpriseRemoved == true)) ++ return; ++ ++ if (adapter->net_closed == true) ++ { ++ return; ++ } ++ ++ if (is_primary_adapter(adapter)) ++ DBG_871X("IsBtDisabled =%d, IsBtControlLps =%d\n", rtw_btcoex_IsBtDisabled(adapter), rtw_btcoex_IsBtControlLps(adapter)); ++ ++ if ((adapter_to_pwrctl(adapter)->bFwCurrentInPSMode ==true) ++ && (rtw_btcoex_IsBtControlLps(adapter) == false) ++ ) ++ { ++ u8 bEnterPS; ++ ++ linked_status_chk(adapter); ++ ++ bEnterPS = traffic_status_watchdog(adapter, 1); ++ if (bEnterPS) ++ { ++ /* rtw_lps_ctrl_wk_cmd(adapter, LPS_CTRL_ENTER, 1); */ ++ rtw_hal_dm_watchdog_in_lps(adapter); ++ } ++ else ++ { ++ /* call rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_LEAVE, 1) in traffic_status_watchdog() */ ++ } ++ ++ } ++ else ++ { ++ if (is_primary_adapter(adapter)) ++ { ++ rtw_dynamic_chk_wk_cmd(adapter); ++ } ++ } ++ ++ /* auto site survey */ ++ rtw_auto_scan_handler(adapter); ++} ++ ++ ++inline bool rtw_is_scan_deny(struct adapter *adapter) ++{ ++ struct mlme_priv *mlmepriv = &adapter->mlmepriv; ++ return (atomic_read(&mlmepriv->set_scan_deny) != 0) ? true : false; ++} ++ ++inline void rtw_clear_scan_deny(struct adapter *adapter) ++{ ++ struct mlme_priv *mlmepriv = &adapter->mlmepriv; ++ atomic_set(&mlmepriv->set_scan_deny, 0); ++ ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter)); ++} ++ ++void rtw_set_scan_deny_timer_hdl(struct adapter *adapter) ++{ ++ rtw_clear_scan_deny(adapter); ++} ++ ++void rtw_set_scan_deny(struct adapter *adapter, u32 ms) ++{ ++ struct mlme_priv *mlmepriv = &adapter->mlmepriv; ++ ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter)); ++ atomic_set(&mlmepriv->set_scan_deny, 1); ++ _set_timer(&mlmepriv->set_scan_deny_timer, ms); ++} ++ ++/* ++* Select a new roaming candidate from the original @param candidate and @param competitor ++* @return true: candidate is updated ++* @return false: candidate is not updated ++*/ ++static int rtw_check_roaming_candidate(struct mlme_priv *mlme ++ , struct wlan_network **candidate, struct wlan_network *competitor) ++{ ++ int updated = false; ++ struct adapter *adapter = container_of(mlme, struct adapter, mlmepriv); ++ ++ if (is_same_ess(&competitor->network, &mlme->cur_network.network) == false) ++ goto exit; ++ ++ if (rtw_is_desired_network(adapter, competitor) == false) ++ goto exit; ++ ++ DBG_871X("roam candidate:%s %s("MAC_FMT", ch%3u) rssi:%d, age:%5d\n", ++ (competitor == mlme->cur_network_scanned)?"*":" " , ++ competitor->network.Ssid.Ssid, ++ MAC_ARG(competitor->network.MacAddress), ++ competitor->network.Configuration.DSConfig, ++ (int)competitor->network.Rssi, ++ jiffies_to_msecs(jiffies - competitor->last_scanned) ++ ); ++ ++ /* got specific addr to roam */ ++ if (!is_zero_mac_addr(mlme->roam_tgt_addr)) { ++ if (!memcmp(mlme->roam_tgt_addr, competitor->network.MacAddress, ETH_ALEN)) ++ goto update; ++ else ++ goto exit; ++ } ++ if (jiffies_to_msecs(jiffies - competitor->last_scanned) >= mlme->roam_scanr_exp_ms) ++ goto exit; ++ ++ if (competitor->network.Rssi - mlme->cur_network_scanned->network.Rssi < mlme->roam_rssi_diff_th) ++ goto exit; ++ ++ if (*candidate != NULL && (*candidate)->network.Rssi>=competitor->network.Rssi) ++ goto exit; ++ ++update: ++ *candidate = competitor; ++ updated = true; ++ ++exit: ++ return updated; ++} ++ ++int rtw_select_roaming_candidate(struct mlme_priv *mlme) ++{ ++ int ret = _FAIL; ++ struct list_head *phead; ++ struct adapter *adapter; ++ struct __queue *queue = &(mlme->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ struct wlan_network *candidate = NULL; ++ ++ if (mlme->cur_network_scanned == NULL) { ++ rtw_warn_on(1); ++ return ret; ++ } ++ ++ spin_lock_bh(&(mlme->scanned_queue.lock)); ++ phead = get_list_head(queue); ++ adapter = (struct adapter *)mlme->nic_hdl; ++ ++ mlme->pscanned = get_next(phead); ++ ++ while (phead != mlme->pscanned) { ++ ++ pnetwork = LIST_CONTAINOR(mlme->pscanned, struct wlan_network, list); ++ if (pnetwork == NULL) { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s return _FAIL:(pnetwork == NULL)\n", __func__)); ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ mlme->pscanned = get_next(mlme->pscanned); ++ ++ DBG_871X("%s("MAC_FMT", ch%u) rssi:%d\n" ++ , pnetwork->network.Ssid.Ssid ++ , MAC_ARG(pnetwork->network.MacAddress) ++ , pnetwork->network.Configuration.DSConfig ++ , (int)pnetwork->network.Rssi); ++ ++ rtw_check_roaming_candidate(mlme, &candidate, pnetwork); ++ ++ } ++ ++ if (candidate == NULL) { ++ DBG_871X("%s: return _FAIL(candidate == NULL)\n", __func__); ++ ret = _FAIL; ++ goto exit; ++ } else { ++ DBG_871X("%s: candidate: %s("MAC_FMT", ch:%u)\n", __func__, ++ candidate->network.Ssid.Ssid, MAC_ARG(candidate->network.MacAddress), ++ candidate->network.Configuration.DSConfig); ++ ++ mlme->roam_network = candidate; ++ ++ if (!memcmp(candidate->network.MacAddress, mlme->roam_tgt_addr, ETH_ALEN)) ++ memset(mlme->roam_tgt_addr, 0, ETH_ALEN); ++ } ++ ++ ret = _SUCCESS; ++exit: ++ spin_unlock_bh(&(mlme->scanned_queue.lock)); ++ ++ return ret; ++} ++ ++/* ++* Select a new join candidate from the original @param candidate and @param competitor ++* @return true: candidate is updated ++* @return false: candidate is not updated ++*/ ++static int rtw_check_join_candidate(struct mlme_priv *mlme ++ , struct wlan_network **candidate, struct wlan_network *competitor) ++{ ++ int updated = false; ++ struct adapter *adapter = container_of(mlme, struct adapter, mlmepriv); ++ ++ ++ /* check bssid, if needed */ ++ if (mlme->assoc_by_bssid ==true) { ++ if (memcmp(competitor->network.MacAddress, mlme->assoc_bssid, ETH_ALEN)) ++ goto exit; ++ } ++ ++ /* check ssid, if needed */ ++ if (mlme->assoc_ssid.Ssid[0] && mlme->assoc_ssid.SsidLength) { ++ if (competitor->network.Ssid.SsidLength != mlme->assoc_ssid.SsidLength ++ || memcmp(competitor->network.Ssid.Ssid, mlme->assoc_ssid.Ssid, mlme->assoc_ssid.SsidLength) ++ ) ++ goto exit; ++ } ++ ++ if (rtw_is_desired_network(adapter, competitor) == false) ++ goto exit; ++ ++ if (rtw_to_roam(adapter) > 0) { ++ if (jiffies_to_msecs(jiffies - competitor->last_scanned) >= mlme->roam_scanr_exp_ms ++ || is_same_ess(&competitor->network, &mlme->cur_network.network) == false ++ ) ++ goto exit; ++ } ++ ++ if (*candidate == NULL ||(*candidate)->network.Rssinetwork.Rssi) ++ { ++ *candidate = competitor; ++ updated = true; ++ } ++ ++ if (updated) { ++ DBG_871X("[by_bssid:%u][assoc_ssid:%s]" ++ "[to_roam:%u] " ++ "new candidate: %s("MAC_FMT", ch%u) rssi:%d\n", ++ mlme->assoc_by_bssid, ++ mlme->assoc_ssid.Ssid, ++ rtw_to_roam(adapter), ++ (*candidate)->network.Ssid.Ssid, ++ MAC_ARG((*candidate)->network.MacAddress), ++ (*candidate)->network.Configuration.DSConfig, ++ (int)(*candidate)->network.Rssi ++ ); ++ } ++ ++exit: ++ return updated; ++} ++ ++/* ++Calling context: ++The caller of the sub-routine will be in critical section... ++ ++The caller must hold the following spinlock ++ ++pmlmepriv->lock ++ ++ ++*/ ++ ++int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv) ++{ ++ int ret; ++ struct list_head *phead; ++ struct adapter *adapter; ++ struct __queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ struct wlan_network *candidate = NULL; ++ ++ adapter = (struct adapter *)pmlmepriv->nic_hdl; ++ ++ spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); ++ ++ if (pmlmepriv->roam_network) { ++ candidate = pmlmepriv->roam_network; ++ pmlmepriv->roam_network = NULL; ++ goto candidate_exist; ++ } ++ ++ phead = get_list_head(queue); ++ pmlmepriv->pscanned = get_next(phead); ++ ++ while (phead != pmlmepriv->pscanned) { ++ ++ pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list); ++ if (pnetwork == NULL) { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s return _FAIL:(pnetwork == NULL)\n", __func__)); ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ pmlmepriv->pscanned = get_next(pmlmepriv->pscanned); ++ ++ DBG_871X("%s("MAC_FMT", ch%u) rssi:%d\n" ++ , pnetwork->network.Ssid.Ssid ++ , MAC_ARG(pnetwork->network.MacAddress) ++ , pnetwork->network.Configuration.DSConfig ++ , (int)pnetwork->network.Rssi); ++ ++ rtw_check_join_candidate(pmlmepriv, &candidate, pnetwork); ++ ++ } ++ ++ if (candidate == NULL) { ++ DBG_871X("%s: return _FAIL(candidate == NULL)\n", __func__); ++#ifdef CONFIG_WOWLAN ++ _clr_fwstate_(pmlmepriv, _FW_LINKED|_FW_UNDER_LINKING); ++#endif ++ ret = _FAIL; ++ goto exit; ++ } else { ++ DBG_871X("%s: candidate: %s("MAC_FMT", ch:%u)\n", __func__, ++ candidate->network.Ssid.Ssid, MAC_ARG(candidate->network.MacAddress), ++ candidate->network.Configuration.DSConfig); ++ goto candidate_exist; ++ } ++ ++candidate_exist: ++ ++ /* check for situation of _FW_LINKED */ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) ++ { ++ DBG_871X("%s: _FW_LINKED while ask_for_joinbss!!!\n", __func__); ++ ++ rtw_disassoc_cmd(adapter, 0, true); ++ rtw_indicate_disconnect(adapter); ++ rtw_free_assoc_resources(adapter, 0); ++ } ++ ++ set_fwstate(pmlmepriv, _FW_UNDER_LINKING); ++ ret = rtw_joinbss_cmd(adapter, candidate); ++ ++exit: ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ return ret; ++} ++ ++sint rtw_set_auth(struct adapter * adapter, struct security_priv *psecuritypriv) ++{ ++ struct cmd_obj* pcmd; ++ struct setauth_parm *psetauthparm; ++ struct cmd_priv *pcmdpriv =&(adapter->cmdpriv); ++ sint res = _SUCCESS; ++ ++ pcmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (pcmd == NULL) { ++ res = _FAIL; /* try again */ ++ goto exit; ++ } ++ ++ psetauthparm =(struct setauth_parm*)rtw_zmalloc(sizeof(struct setauth_parm)); ++ if (psetauthparm == NULL) { ++ kfree((unsigned char *)pcmd); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ memset(psetauthparm, 0, sizeof(struct setauth_parm)); ++ psetauthparm->mode =(unsigned char)psecuritypriv->dot11AuthAlgrthm; ++ ++ pcmd->cmdcode = _SetAuth_CMD_; ++ pcmd->parmbuf = (unsigned char *)psetauthparm; ++ pcmd->cmdsz = (sizeof(struct setauth_parm)); ++ pcmd->rsp = NULL; ++ pcmd->rspsz = 0; ++ ++ ++ INIT_LIST_HEAD(&pcmd->list); ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("after enqueue set_auth_cmd, auth_mode =%x\n", psecuritypriv->dot11AuthAlgrthm)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, pcmd); ++ ++exit: ++ return res; ++} ++ ++sint rtw_set_key(struct adapter * adapter, struct security_priv *psecuritypriv, sint keyid, u8 set_tx, bool enqueue) ++{ ++ u8 keylen; ++ struct cmd_obj *pcmd; ++ struct setkey_parm *psetkeyparm; ++ struct cmd_priv *pcmdpriv = &(adapter->cmdpriv); ++ sint res = _SUCCESS; ++ ++ psetkeyparm =(struct setkey_parm*)rtw_zmalloc(sizeof(struct setkey_parm)); ++ if (psetkeyparm == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ memset(psetkeyparm, 0, sizeof(struct setkey_parm)); ++ ++ if (psecuritypriv->dot11AuthAlgrthm ==dot11AuthAlgrthm_8021X) { ++ psetkeyparm->algorithm =(unsigned char)psecuritypriv->dot118021XGrpPrivacy; ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n rtw_set_key: psetkeyparm->algorithm =(unsigned char)psecuritypriv->dot118021XGrpPrivacy =%d\n", psetkeyparm->algorithm)); ++ } ++ else { ++ psetkeyparm->algorithm =(u8)psecuritypriv->dot11PrivacyAlgrthm; ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n rtw_set_key: psetkeyparm->algorithm =(u8)psecuritypriv->dot11PrivacyAlgrthm =%d\n", psetkeyparm->algorithm)); ++ ++ } ++ psetkeyparm->keyid = (u8)keyid;/* 0~3 */ ++ psetkeyparm->set_tx = set_tx; ++ if (is_wep_enc(psetkeyparm->algorithm)) ++ adapter->securitypriv.key_mask |= BIT(psetkeyparm->keyid); ++ ++ DBG_871X("==> rtw_set_key algorithm(%x), keyid(%x), key_mask(%x)\n", psetkeyparm->algorithm, psetkeyparm->keyid, adapter->securitypriv.key_mask); ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n rtw_set_key: psetkeyparm->algorithm =%d psetkeyparm->keyid =(u8)keyid =%d\n", psetkeyparm->algorithm, keyid)); ++ ++ switch (psetkeyparm->algorithm) { ++ ++ case _WEP40_: ++ keylen =5; ++ memcpy(&(psetkeyparm->key[0]), &(psecuritypriv->dot11DefKey[keyid].skey[0]), keylen); ++ break; ++ case _WEP104_: ++ keylen = 13; ++ memcpy(&(psetkeyparm->key[0]), &(psecuritypriv->dot11DefKey[keyid].skey[0]), keylen); ++ break; ++ case _TKIP_: ++ keylen = 16; ++ memcpy(&psetkeyparm->key, &psecuritypriv->dot118021XGrpKey[keyid], keylen); ++ psetkeyparm->grpkey = 1; ++ break; ++ case _AES_: ++ keylen = 16; ++ memcpy(&psetkeyparm->key, &psecuritypriv->dot118021XGrpKey[keyid], keylen); ++ psetkeyparm->grpkey = 1; ++ break; ++ default: ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n rtw_set_key:psecuritypriv->dot11PrivacyAlgrthm = %x (must be 1 or 2 or 4 or 5)\n", psecuritypriv->dot11PrivacyAlgrthm)); ++ res = _FAIL; ++ kfree((unsigned char *)psetkeyparm); ++ goto exit; ++ } ++ ++ ++ if (enqueue) { ++ pcmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); ++ if (pcmd == NULL) { ++ kfree((unsigned char *)psetkeyparm); ++ res = _FAIL; /* try again */ ++ goto exit; ++ } ++ ++ pcmd->cmdcode = _SetKey_CMD_; ++ pcmd->parmbuf = (u8 *)psetkeyparm; ++ pcmd->cmdsz = (sizeof(struct setkey_parm)); ++ pcmd->rsp = NULL; ++ pcmd->rspsz = 0; ++ ++ INIT_LIST_HEAD(&pcmd->list); ++ ++ /* sema_init(&(pcmd->cmd_sem), 0); */ ++ ++ res = rtw_enqueue_cmd(pcmdpriv, pcmd); ++ } ++ else { ++ setkey_hdl(adapter, (u8 *)psetkeyparm); ++ kfree((u8 *) psetkeyparm); ++ } ++exit: ++ return res; ++} ++ ++/* adjust IEs for rtw_joinbss_cmd in WMM */ ++int rtw_restruct_wmm_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len, uint initial_out_len) ++{ ++ unsigned int ielength = 0; ++ unsigned int i, j; ++ ++ i = 12; /* after the fixed IE */ ++ while (i= 0 :if there is pre-auth key, and return the entry id */ ++/* */ ++/* */ ++ ++static int SecIsInPMKIDList(struct adapter *Adapter, u8 *bssid) ++{ ++ struct security_priv *psecuritypriv =&Adapter->securitypriv; ++ int i = 0; ++ ++ do ++ { ++ if ((psecuritypriv->PMKIDList[i].bUsed) && ++ (!memcmp(psecuritypriv->PMKIDList[i].Bssid, bssid, ETH_ALEN))) ++ { ++ break; ++ } ++ else ++ { ++ i++; ++ /* continue; */ ++ } ++ ++ }while (isecuritypriv; ++ ++ if (ie[13]<=20) { ++ /* The RSN IE didn't include the PMK ID, append the PMK information */ ++ ie[ie_len]= 1; ++ ie_len++; ++ ie[ie_len]= 0; /* PMKID count = 0x0100 */ ++ ie_len++; ++ memcpy(&ie[ie_len], &psecuritypriv->PMKIDList[iEntry].PMKID, 16); ++ ++ ie_len+= 16; ++ ie[13]+= 18;/* PMKID length = 2+16 */ ++ ++ } ++ return (ie_len); ++} ++ ++sint rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len) ++{ ++ u8 authmode = 0x0; ++ uint ielength; ++ int iEntry; ++ ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ struct security_priv *psecuritypriv =&adapter->securitypriv; ++ uint ndisauthmode =psecuritypriv->ndisauthtype; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ++ ("+rtw_restruct_sec_ie: ndisauthmode =%d ndissecuritytype =%d\n", ++ ndisauthmode, ndissecuritytype)); ++ ++ /* copy fixed ie only */ ++ memcpy(out_ie, in_ie, 12); ++ ielength = 12; ++ if ((ndisauthmode ==Ndis802_11AuthModeWPA)||(ndisauthmode ==Ndis802_11AuthModeWPAPSK)) ++ authmode = _WPA_IE_ID_; ++ if ((ndisauthmode ==Ndis802_11AuthModeWPA2)||(ndisauthmode ==Ndis802_11AuthModeWPA2PSK)) ++ authmode = _WPA2_IE_ID_; ++ ++ if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) ++ { ++ memcpy(out_ie+ielength, psecuritypriv->wps_ie, psecuritypriv->wps_ie_len); ++ ++ ielength += psecuritypriv->wps_ie_len; ++ } ++ else if ((authmode == _WPA_IE_ID_)||(authmode == _WPA2_IE_ID_)) ++ { ++ /* copy RSN or SSN */ ++ memcpy(&out_ie[ielength], &psecuritypriv->supplicant_ie[0], psecuritypriv->supplicant_ie[1]+2); ++ /* debug for CONFIG_IEEE80211W ++ { ++ int jj; ++ printk("supplicant_ie_length =%d &&&&&&&&&&&&&&&&&&&\n", psecuritypriv->supplicant_ie[1]+2); ++ for (jj = 0; jj < psecuritypriv->supplicant_ie[1]+2; jj++) ++ printk(" %02x ", psecuritypriv->supplicant_ie[jj]); ++ printk("\n"); ++ }*/ ++ ielength+=psecuritypriv->supplicant_ie[1]+2; ++ rtw_report_sec_ie(adapter, authmode, psecuritypriv->supplicant_ie); ++ } ++ ++ iEntry = SecIsInPMKIDList(adapter, pmlmepriv->assoc_bssid); ++ if (iEntry<0) ++ { ++ return ielength; ++ } ++ else ++ { ++ if (authmode == _WPA2_IE_ID_) ++ { ++ ielength =rtw_append_pmkid(adapter, iEntry, out_ie, ielength); ++ } ++ } ++ return ielength; ++} ++ ++void rtw_init_registrypriv_dev_network(struct adapter * adapter) ++{ ++ struct registry_priv* pregistrypriv = &adapter->registrypriv; ++ struct eeprom_priv* peepriv = &adapter->eeprompriv; ++ struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; ++ u8 *myhwaddr = myid(peepriv); ++ ++ memcpy(pdev_network->MacAddress, myhwaddr, ETH_ALEN); ++ ++ memcpy(&pdev_network->Ssid, &pregistrypriv->ssid, sizeof(struct ndis_802_11_ssid)); ++ ++ pdev_network->Configuration.Length =sizeof(struct ndis_802_11_conf); ++ pdev_network->Configuration.BeaconPeriod = 100; ++ pdev_network->Configuration.FHConfig.Length = 0; ++ pdev_network->Configuration.FHConfig.HopPattern = 0; ++ pdev_network->Configuration.FHConfig.HopSet = 0; ++ pdev_network->Configuration.FHConfig.DwellTime = 0; ++} ++ ++void rtw_update_registrypriv_dev_network(struct adapter * adapter) ++{ ++ int sz = 0; ++ struct registry_priv* pregistrypriv = &adapter->registrypriv; ++ struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; ++ struct security_priv*psecuritypriv = &adapter->securitypriv; ++ struct wlan_network *cur_network = &adapter->mlmepriv.cur_network; ++ /* struct xmit_priv *pxmitpriv = &adapter->xmitpriv; */ ++ ++ pdev_network->Privacy = (psecuritypriv->dot11PrivacyAlgrthm > 0 ? 1 : 0) ; /* adhoc no 802.1x */ ++ ++ pdev_network->Rssi = 0; ++ ++ switch (pregistrypriv->wireless_mode) ++ { ++ case WIRELESS_11B: ++ pdev_network->NetworkTypeInUse = (Ndis802_11DS); ++ break; ++ case WIRELESS_11G: ++ case WIRELESS_11BG: ++ case WIRELESS_11_24N: ++ case WIRELESS_11G_24N: ++ case WIRELESS_11BG_24N: ++ pdev_network->NetworkTypeInUse = (Ndis802_11OFDM24); ++ break; ++ case WIRELESS_11A: ++ case WIRELESS_11A_5N: ++ pdev_network->NetworkTypeInUse = (Ndis802_11OFDM5); ++ break; ++ case WIRELESS_11ABGN: ++ if (pregistrypriv->channel > 14) ++ pdev_network->NetworkTypeInUse = (Ndis802_11OFDM5); ++ else ++ pdev_network->NetworkTypeInUse = (Ndis802_11OFDM24); ++ break; ++ default : ++ /* TODO */ ++ break; ++ } ++ ++ pdev_network->Configuration.DSConfig = (pregistrypriv->channel); ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("pregistrypriv->channel =%d, pdev_network->Configuration.DSConfig = 0x%x\n", pregistrypriv->channel, pdev_network->Configuration.DSConfig)); ++ ++ if (cur_network->network.InfrastructureMode == Ndis802_11IBSS) ++ pdev_network->Configuration.ATIMWindow = (0); ++ ++ pdev_network->InfrastructureMode = (cur_network->network.InfrastructureMode); ++ ++ /* 1. Supported rates */ ++ /* 2. IE */ ++ ++ /* rtw_set_supported_rate(pdev_network->SupportedRates, pregistrypriv->wireless_mode) ; will be called in rtw_generate_ie */ ++ sz = rtw_generate_ie(pregistrypriv); ++ ++ pdev_network->IELength = sz; ++ ++ pdev_network->Length = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pdev_network); ++ ++ /* notes: translate IELength & Length after assign the Length to cmdsz in createbss_cmd(); */ ++ /* pdev_network->IELength = cpu_to_le32(sz); */ ++} ++ ++void rtw_get_encrypt_decrypt_from_registrypriv(struct adapter * adapter) ++{ ++} ++ ++/* the fucntion is at passive_level */ ++void rtw_joinbss_reset(struct adapter *padapter) ++{ ++ u8 threshold; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ ++ /* todo: if you want to do something io/reg/hw setting before join_bss, please add code here */ ++ ++ pmlmepriv->num_FortyMHzIntolerant = 0; ++ ++ pmlmepriv->num_sta_no_ht = 0; ++ ++ phtpriv->ampdu_enable = false;/* reset to disabled */ ++ ++ /* TH = 1 => means that invalidate usb rx aggregation */ ++ /* TH = 0 => means that validate usb rx aggregation, use init value. */ ++ if (phtpriv->ht_option) ++ { ++ if (padapter->registrypriv.wifi_spec == 1) ++ threshold = 1; ++ else ++ threshold = 0; ++ rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold)); ++ } ++ else ++ { ++ threshold = 1; ++ rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold)); ++ } ++} ++ ++void rtw_ht_use_default_setting(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ bool bHwLDPCSupport = false, bHwSTBCSupport = false; ++ bool bHwSupportBeamformer = false, bHwSupportBeamformee = false; ++ ++ if (pregistrypriv->wifi_spec) ++ phtpriv->bss_coexist = 1; ++ else ++ phtpriv->bss_coexist = 0; ++ ++ phtpriv->sgi_40m = TEST_FLAG(pregistrypriv->short_gi, BIT1) ? true : false; ++ phtpriv->sgi_20m = TEST_FLAG(pregistrypriv->short_gi, BIT0) ? true : false; ++ ++ /* LDPC support */ ++ rtw_hal_get_def_var(padapter, HAL_DEF_RX_LDPC, (u8 *)&bHwLDPCSupport); ++ CLEAR_FLAGS(phtpriv->ldpc_cap); ++ if (bHwLDPCSupport) ++ { ++ if (TEST_FLAG(pregistrypriv->ldpc_cap, BIT4)) ++ SET_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_RX); ++ } ++ rtw_hal_get_def_var(padapter, HAL_DEF_TX_LDPC, (u8 *)&bHwLDPCSupport); ++ if (bHwLDPCSupport) ++ { ++ if (TEST_FLAG(pregistrypriv->ldpc_cap, BIT5)) ++ SET_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_TX); ++ } ++ if (phtpriv->ldpc_cap) ++ DBG_871X("[HT] Support LDPC = 0x%02X\n", phtpriv->ldpc_cap); ++ ++ /* STBC */ ++ rtw_hal_get_def_var(padapter, HAL_DEF_TX_STBC, (u8 *)&bHwSTBCSupport); ++ CLEAR_FLAGS(phtpriv->stbc_cap); ++ if (bHwSTBCSupport) ++ { ++ if (TEST_FLAG(pregistrypriv->stbc_cap, BIT5)) ++ SET_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX); ++ } ++ rtw_hal_get_def_var(padapter, HAL_DEF_RX_STBC, (u8 *)&bHwSTBCSupport); ++ if (bHwSTBCSupport) ++ { ++ if (TEST_FLAG(pregistrypriv->stbc_cap, BIT4)) ++ SET_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_RX); ++ } ++ if (phtpriv->stbc_cap) ++ DBG_871X("[HT] Support STBC = 0x%02X\n", phtpriv->stbc_cap); ++ ++ /* Beamforming setting */ ++ rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMER, (u8 *)&bHwSupportBeamformer); ++ rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMEE, (u8 *)&bHwSupportBeamformee); ++ CLEAR_FLAGS(phtpriv->beamform_cap); ++ if (TEST_FLAG(pregistrypriv->beamform_cap, BIT4) && bHwSupportBeamformer) ++ { ++ SET_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE); ++ DBG_871X("[HT] Support Beamformer\n"); ++ } ++ if (TEST_FLAG(pregistrypriv->beamform_cap, BIT5) && bHwSupportBeamformee) ++ { ++ SET_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE); ++ DBG_871X("[HT] Support Beamformee\n"); ++ } ++} ++ ++void rtw_build_wmm_ie_ht(struct adapter *padapter, u8 *out_ie, uint *pout_len) ++{ ++ unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; ++ int out_len; ++ u8 *pframe; ++ ++ if (padapter->mlmepriv.qospriv.qos_option == 0) ++ { ++ out_len = *pout_len; ++ pframe = rtw_set_ie(out_ie+out_len, _VENDOR_SPECIFIC_IE_, ++ _WMM_IE_Length_, WMM_IE, pout_len); ++ ++ padapter->mlmepriv.qospriv.qos_option = 1; ++ } ++} ++ ++/* the fucntion is >= passive_level */ ++unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len, u8 channel) ++{ ++ u32 ielen, out_len; ++ enum HT_CAP_AMPDU_FACTOR max_rx_ampdu_factor; ++ unsigned char *p, *pframe; ++ struct rtw_ieee80211_ht_cap ht_capie; ++ u8 cbw40_enable = 0, stbc_rx_enable = 0, rf_type = 0, operation_bw = 0; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ phtpriv->ht_option = false; ++ ++ out_len = *pout_len; ++ ++ memset(&ht_capie, 0, sizeof(struct rtw_ieee80211_ht_cap)); ++ ++ ht_capie.cap_info = cpu_to_le16(IEEE80211_HT_CAP_DSSSCCK40); ++ ++ if (phtpriv->sgi_20m) ++ ht_capie.cap_info |= cpu_to_le16(IEEE80211_HT_CAP_SGI_20); ++ ++ /* Get HT BW */ ++ if (in_ie == NULL) { ++ /* TDLS: TODO 20/40 issue */ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { ++ operation_bw = padapter->mlmeextpriv.cur_bwmode; ++ if (operation_bw > CHANNEL_WIDTH_40) ++ operation_bw = CHANNEL_WIDTH_40; ++ } else ++ /* TDLS: TODO 40? */ ++ operation_bw = CHANNEL_WIDTH_40; ++ } else { ++ p = rtw_get_ie(in_ie, _HT_ADD_INFO_IE_, &ielen, in_len); ++ if (p && (ielen == sizeof(struct ieee80211_ht_addt_info))) { ++ struct HT_info_element *pht_info = (struct HT_info_element *)(p+2); ++ if (pht_info->infos[0] & BIT(2)) { ++ switch (pht_info->infos[0] & 0x3) { ++ case 1: ++ case 3: ++ operation_bw = CHANNEL_WIDTH_40; ++ break; ++ default: ++ operation_bw = CHANNEL_WIDTH_20; ++ break; ++ } ++ } else { ++ operation_bw = CHANNEL_WIDTH_20; ++ } ++ } ++ } ++ ++ /* to disable 40M Hz support while gd_bw_40MHz_en = 0 */ ++ if (channel > 14) { ++ if ((pregistrypriv->bw_mode & 0xf0) > 0) ++ cbw40_enable = 1; ++ } else { ++ if ((pregistrypriv->bw_mode & 0x0f) > 0) ++ cbw40_enable = 1; ++ } ++ ++ if ((cbw40_enable == 1) && (operation_bw == CHANNEL_WIDTH_40)) { ++ ht_capie.cap_info |= cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH); ++ if (phtpriv->sgi_40m) ++ ht_capie.cap_info |= cpu_to_le16(IEEE80211_HT_CAP_SGI_40); ++ } ++ ++ if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX)) ++ ht_capie.cap_info |= cpu_to_le16(IEEE80211_HT_CAP_TX_STBC); ++ ++ /* todo: disable SM power save mode */ ++ ht_capie.cap_info |= cpu_to_le16(IEEE80211_HT_CAP_SM_PS); ++ ++ if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_RX)) { ++ if ((channel <= 14 && pregistrypriv->rx_stbc == 0x1) || /* enable for 2.4GHz */ ++ (pregistrypriv->wifi_spec == 1)) { ++ stbc_rx_enable = 1; ++ DBG_871X("declare supporting RX STBC\n"); ++ } ++ } ++ ++ /* fill default supported_mcs_set */ ++ memcpy(ht_capie.supp_mcs_set, pmlmeext->default_supported_mcs_set, 16); ++ ++ /* update default supported_mcs_set */ ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ ++ switch (rf_type) { ++ case RF_1T1R: ++ if (stbc_rx_enable) ++ ht_capie.cap_info |= cpu_to_le16(IEEE80211_HT_CAP_RX_STBC_1R);/* RX STBC One spatial stream */ ++ ++ set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_1R); ++ break; ++ ++ case RF_2T2R: ++ case RF_1T2R: ++ default: ++ if (stbc_rx_enable) ++ ht_capie.cap_info |= cpu_to_le16(IEEE80211_HT_CAP_RX_STBC_2R);/* RX STBC two spatial stream */ ++ ++ #ifdef CONFIG_DISABLE_MCS13TO15 ++ if (((cbw40_enable == 1) && (operation_bw == CHANNEL_WIDTH_40)) && (pregistrypriv->wifi_spec!= 1)) ++ set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_2R_13TO15_OFF); ++ else ++ set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_2R); ++ #else /* CONFIG_DISABLE_MCS13TO15 */ ++ set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_2R); ++ #endif /* CONFIG_DISABLE_MCS13TO15 */ ++ break; ++ } ++ ++ { ++ u32 rx_packet_offset, max_recvbuf_sz; ++ rtw_hal_get_def_var(padapter, HAL_DEF_RX_PACKET_OFFSET, &rx_packet_offset); ++ rtw_hal_get_def_var(padapter, HAL_DEF_MAX_RECVBUF_SZ, &max_recvbuf_sz); ++ } ++ ++ if (padapter->driver_rx_ampdu_factor != 0xFF) ++ max_rx_ampdu_factor = ++ (enum HT_CAP_AMPDU_FACTOR)padapter->driver_rx_ampdu_factor; ++ else ++ rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, ++ &max_rx_ampdu_factor); ++ ++ /* rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor); */ ++ ht_capie.ampdu_params_info = (max_rx_ampdu_factor&0x03); ++ ++ if (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_) ++ ht_capie.ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&(0x07<<2)); ++ else ++ ht_capie.ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&0x00); ++ ++ pframe = rtw_set_ie(out_ie+out_len, _HT_CAPABILITY_IE_, ++ sizeof(struct rtw_ieee80211_ht_cap), (unsigned char*)&ht_capie, pout_len); ++ ++ phtpriv->ht_option = true; ++ ++ if (in_ie!= NULL) ++ { ++ p = rtw_get_ie(in_ie, _HT_ADD_INFO_IE_, &ielen, in_len); ++ if (p && (ielen ==sizeof(struct ieee80211_ht_addt_info))) ++ { ++ out_len = *pout_len; ++ pframe = rtw_set_ie(out_ie+out_len, _HT_ADD_INFO_IE_, ielen, p+2 , pout_len); ++ } ++ } ++ ++ return (phtpriv->ht_option); ++ ++} ++ ++/* the fucntion is > passive_level (in critical_section) */ ++void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channel) ++{ ++ u8 *p, max_ampdu_sz; ++ int len; ++ /* struct sta_info *bmc_sta, *psta; */ ++ struct rtw_ieee80211_ht_cap *pht_capie; ++ struct ieee80211_ht_addt_info *pht_addtinfo; ++ /* struct recv_reorder_ctrl *preorder_ctrl; */ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ /* struct recv_priv *precvpriv = &padapter->recvpriv; */ ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ /* struct wlan_network *pcur_network = &(pmlmepriv->cur_network);; */ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 cbw40_enable = 0; ++ ++ ++ if (!phtpriv->ht_option) ++ return; ++ ++ if ((!pmlmeinfo->HT_info_enable) || (!pmlmeinfo->HT_caps_enable)) ++ return; ++ ++ DBG_871X("+rtw_update_ht_cap()\n"); ++ ++ /* maybe needs check if ap supports rx ampdu. */ ++ if ((phtpriv->ampdu_enable ==false) && (pregistrypriv->ampdu_enable == 1)) ++ { ++ if (pregistrypriv->wifi_spec == 1) ++ { ++ /* remove this part because testbed AP should disable RX AMPDU */ ++ /* phtpriv->ampdu_enable = false; */ ++ phtpriv->ampdu_enable = true; ++ } ++ else ++ { ++ phtpriv->ampdu_enable = true; ++ } ++ } ++ else if (pregistrypriv->ampdu_enable ==2) ++ { ++ /* remove this part because testbed AP should disable RX AMPDU */ ++ /* phtpriv->ampdu_enable = true; */ ++ } ++ ++ ++ /* check Max Rx A-MPDU Size */ ++ len = 0; ++ p = rtw_get_ie(pie+sizeof (struct ndis_802_11_fix_ie), _HT_CAPABILITY_IE_, &len, ie_len-sizeof (struct ndis_802_11_fix_ie)); ++ if (p && len>0) ++ { ++ pht_capie = (struct rtw_ieee80211_ht_cap *)(p+2); ++ max_ampdu_sz = (pht_capie->ampdu_params_info & IEEE80211_HT_CAP_AMPDU_FACTOR); ++ max_ampdu_sz = 1 << (max_ampdu_sz+3); /* max_ampdu_sz (kbytes); */ ++ ++ /* DBG_871X("rtw_update_ht_cap(): max_ampdu_sz =%d\n", max_ampdu_sz); */ ++ phtpriv->rx_ampdu_maxlen = max_ampdu_sz; ++ ++ } ++ ++ ++ len = 0; ++ p = rtw_get_ie(pie+sizeof (struct ndis_802_11_fix_ie), _HT_ADD_INFO_IE_, &len, ie_len-sizeof (struct ndis_802_11_fix_ie)); ++ if (p && len>0) ++ { ++ pht_addtinfo = (struct ieee80211_ht_addt_info *)(p+2); ++ /* todo: */ ++ } ++ ++ if (channel > 14) { ++ if ((pregistrypriv->bw_mode & 0xf0) > 0) ++ cbw40_enable = 1; ++ } else { ++ if ((pregistrypriv->bw_mode & 0x0f) > 0) ++ cbw40_enable = 1; ++ } ++ ++ /* update cur_bwmode & cur_ch_offset */ ++ if ((cbw40_enable) && ++ (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & ++ BIT(1)) && (pmlmeinfo->HT_info.infos[0] & BIT(2))) { ++ int i; ++ u8 rf_type; ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ ++ /* update the MCS set */ ++ for (i = 0; i < 16; i++) ++ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= pmlmeext->default_supported_mcs_set[i]; ++ ++ /* update the MCS rates */ ++ switch (rf_type) ++ { ++ case RF_1T1R: ++ case RF_1T2R: ++ set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_1R); ++ break; ++ case RF_2T2R: ++ default: ++#ifdef CONFIG_DISABLE_MCS13TO15 ++ if (pmlmeext->cur_bwmode == CHANNEL_WIDTH_40 && pregistrypriv->wifi_spec != 1) ++ set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R_13TO15_OFF); ++ else ++ set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R); ++#else /* CONFIG_DISABLE_MCS13TO15 */ ++ set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R); ++#endif /* CONFIG_DISABLE_MCS13TO15 */ ++ } ++ ++ /* switch to the 40M Hz mode accoring to the AP */ ++ /* pmlmeext->cur_bwmode = CHANNEL_WIDTH_40; */ ++ switch ((pmlmeinfo->HT_info.infos[0] & 0x3)) ++ { ++ case EXTCHNL_OFFSET_UPPER: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ break; ++ ++ case EXTCHNL_OFFSET_LOWER: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ break; ++ ++ default: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ break; ++ } ++ } ++ ++ /* */ ++ /* Config SM Power Save setting */ ++ /* */ ++ pmlmeinfo->SM_PS = ++ (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & ++ 0x0C) >> 2; ++ if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) ++ { ++ DBG_871X("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__); ++ } ++ ++ /* */ ++ /* Config current HT Protection mode. */ ++ /* */ ++ pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3; ++} ++ ++void rtw_issue_addbareq_cmd(struct adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ u8 issued; ++ int priority; ++ struct sta_info *psta = NULL; ++ struct ht_priv *phtpriv; ++ struct pkt_attrib *pattrib =&pxmitframe->attrib; ++ s32 bmcst = IS_MCAST(pattrib->ra); ++ ++ /* if (bmcst || (padapter->mlmepriv.LinkDetectInfo.bTxBusyTraffic == false)) */ ++ if (bmcst || (padapter->mlmepriv.LinkDetectInfo.NumTxOkInPeriod<100)) ++ return; ++ ++ priority = pattrib->priority; ++ ++ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); ++ if (pattrib->psta != psta) ++ { ++ DBG_871X("%s, pattrib->psta(%p) != psta(%p)\n", __func__, pattrib->psta, psta); ++ return; ++ } ++ ++ if (psta == NULL) ++ { ++ DBG_871X("%s, psta ==NUL\n", __func__); ++ return; ++ } ++ ++ if (!(psta->state &_FW_LINKED)) ++ { ++ DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); ++ return; ++ } ++ ++ ++ phtpriv = &psta->htpriv; ++ ++ if ((phtpriv->ht_option ==true) && (phtpriv->ampdu_enable ==true)) ++ { ++ issued = (phtpriv->agg_enable_bitmap>>priority)&0x1; ++ issued |= (phtpriv->candidate_tid_bitmap>>priority)&0x1; ++ ++ if (0 ==issued) ++ { ++ DBG_871X("rtw_issue_addbareq_cmd, p =%d\n", priority); ++ psta->htpriv.candidate_tid_bitmap |= BIT((u8)priority); ++ rtw_addbareq_cmd(padapter, (u8) priority, pattrib->ra); ++ } ++ } ++ ++} ++ ++void rtw_append_exented_cap(struct adapter *padapter, u8 *out_ie, uint *pout_len) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ u8 cap_content[8] = {0}; ++ u8 *pframe; ++ ++ ++ if (phtpriv->bss_coexist) { ++ SET_EXT_CAPABILITY_ELE_BSS_COEXIST(cap_content, 1); ++ } ++ ++ pframe = rtw_set_ie(out_ie+*pout_len, EID_EXTCapability, 8, cap_content , pout_len); ++} ++ ++inline void rtw_set_to_roam(struct adapter *adapter, u8 to_roam) ++{ ++ if (to_roam == 0) ++ adapter->mlmepriv.to_join = false; ++ adapter->mlmepriv.to_roam = to_roam; ++} ++ ++inline u8 rtw_dec_to_roam(struct adapter *adapter) ++{ ++ adapter->mlmepriv.to_roam--; ++ return adapter->mlmepriv.to_roam; ++} ++ ++inline u8 rtw_to_roam(struct adapter *adapter) ++{ ++ return adapter->mlmepriv.to_roam; ++} ++ ++void rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ _rtw_roaming(padapter, tgt_network); ++ spin_unlock_bh(&pmlmepriv->lock); ++} ++void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *cur_network = &pmlmepriv->cur_network; ++ int do_join_r; ++ ++ if (0 < rtw_to_roam(padapter)) { ++ DBG_871X("roaming from %s("MAC_FMT"), length:%d\n", ++ cur_network->network.Ssid.Ssid, MAC_ARG(cur_network->network.MacAddress), ++ cur_network->network.Ssid.SsidLength); ++ memcpy(&pmlmepriv->assoc_ssid, &cur_network->network.Ssid, sizeof(struct ndis_802_11_ssid)); ++ ++ pmlmepriv->assoc_by_bssid = false; ++ ++ while (1) { ++ if (_SUCCESS ==(do_join_r =rtw_do_join(padapter))) { ++ break; ++ } else { ++ DBG_871X("roaming do_join return %d\n", do_join_r); ++ rtw_dec_to_roam(padapter); ++ ++ if (rtw_to_roam(padapter) > 0) { ++ continue; ++ } else { ++ DBG_871X("%s(%d) -to roaming fail, indicate_disconnect\n", __func__, __LINE__); ++ rtw_indicate_disconnect(padapter); ++ break; ++ } ++ } ++ } ++ } ++ ++} ++ ++sint rtw_linked_check(struct adapter *padapter) ++{ ++ if ((check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true) || ++ (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE) == true)) ++ { ++ if (padapter->stapriv.asoc_sta_count > 2) ++ return true; ++ } ++ else ++ { /* Station mode */ ++ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == true) ++ return true; ++ } ++ return false; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_mlme_ext.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_mlme_ext.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_mlme_ext.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_mlme_ext.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,7376 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTW_MLME_EXT_C_ ++ ++#include ++#include ++#include ++ ++ ++static struct mlme_handler mlme_sta_tbl[]={ ++ {WIFI_ASSOCREQ, "OnAssocReq", &OnAssocReq}, ++ {WIFI_ASSOCRSP, "OnAssocRsp", &OnAssocRsp}, ++ {WIFI_REASSOCREQ, "OnReAssocReq", &OnAssocReq}, ++ {WIFI_REASSOCRSP, "OnReAssocRsp", &OnAssocRsp}, ++ {WIFI_PROBEREQ, "OnProbeReq", &OnProbeReq}, ++ {WIFI_PROBERSP, "OnProbeRsp", &OnProbeRsp}, ++ ++ /*---------------------------------------------------------- ++ below 2 are reserved ++ -----------------------------------------------------------*/ ++ {0, "DoReserved", &DoReserved}, ++ {0, "DoReserved", &DoReserved}, ++ {WIFI_BEACON, "OnBeacon", &OnBeacon}, ++ {WIFI_ATIM, "OnATIM", &OnAtim}, ++ {WIFI_DISASSOC, "OnDisassoc", &OnDisassoc}, ++ {WIFI_AUTH, "OnAuth", &OnAuthClient}, ++ {WIFI_DEAUTH, "OnDeAuth", &OnDeAuth}, ++ {WIFI_ACTION, "OnAction", &OnAction}, ++ {WIFI_ACTION_NOACK,"OnActionNoAck", &OnAction}, ++}; ++ ++static struct action_handler OnAction_tbl[]={ ++ {RTW_WLAN_CATEGORY_SPECTRUM_MGMT, "ACTION_SPECTRUM_MGMT", on_action_spct}, ++ {RTW_WLAN_CATEGORY_QOS, "ACTION_QOS", &DoReserved}, ++ {RTW_WLAN_CATEGORY_DLS, "ACTION_DLS", &DoReserved}, ++ {RTW_WLAN_CATEGORY_BACK, "ACTION_BACK", &OnAction_back}, ++ {RTW_WLAN_CATEGORY_PUBLIC, "ACTION_PUBLIC", on_action_public}, ++ {RTW_WLAN_CATEGORY_RADIO_MEASUREMENT, "ACTION_RADIO_MEASUREMENT", &DoReserved}, ++ {RTW_WLAN_CATEGORY_FT, "ACTION_FT", &DoReserved}, ++ {RTW_WLAN_CATEGORY_HT, "ACTION_HT", &OnAction_ht}, ++ {RTW_WLAN_CATEGORY_SA_QUERY, "ACTION_SA_QUERY", &OnAction_sa_query}, ++ {RTW_WLAN_CATEGORY_UNPROTECTED_WNM, "ACTION_UNPROTECTED_WNM", &DoReserved}, ++ {RTW_WLAN_CATEGORY_SELF_PROTECTED, "ACTION_SELF_PROTECTED", &DoReserved}, ++ {RTW_WLAN_CATEGORY_WMM, "ACTION_WMM", &DoReserved}, ++ {RTW_WLAN_CATEGORY_VHT, "ACTION_VHT", &DoReserved}, ++ {RTW_WLAN_CATEGORY_P2P, "ACTION_P2P", &DoReserved}, ++}; ++ ++ ++static u8 null_addr[ETH_ALEN]= {0, 0, 0, 0, 0, 0}; ++ ++/************************************************** ++OUI definitions for the vendor specific IE ++***************************************************/ ++unsigned char RTW_WPA_OUI[] = {0x00, 0x50, 0xf2, 0x01}; ++unsigned char WMM_OUI[] = {0x00, 0x50, 0xf2, 0x02}; ++unsigned char WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04}; ++unsigned char P2P_OUI[] = {0x50, 0x6F, 0x9A, 0x09}; ++unsigned char WFD_OUI[] = {0x50, 0x6F, 0x9A, 0x0A}; ++ ++unsigned char WMM_INFO_OUI[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; ++unsigned char WMM_PARA_OUI[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; ++ ++static unsigned char REALTEK_96B_IE[] = {0x00, 0xe0, 0x4c, 0x02, 0x01, 0x20}; ++ ++/******************************************************** ++ChannelPlan definitions ++*********************************************************/ ++static RT_CHANNEL_PLAN_2G RTW_ChannelPlan2G[RT_CHANNEL_DOMAIN_2G_MAX] = { ++ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, /* 0x00, RT_CHANNEL_DOMAIN_2G_WORLD , Passive scan CH 12, 13 */ ++ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, /* 0x01, RT_CHANNEL_DOMAIN_2G_ETSI1 */ ++ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11}, /* 0x02, RT_CHANNEL_DOMAIN_2G_FCC1 */ ++ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14}, /* 0x03, RT_CHANNEL_DOMAIN_2G_MIKK1 */ ++ {{10, 11, 12, 13}, 4}, /* 0x04, RT_CHANNEL_DOMAIN_2G_ETSI2 */ ++ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14}, /* 0x05, RT_CHANNEL_DOMAIN_2G_GLOBAL , Passive scan CH 12, 13, 14 */ ++ {{}, 0}, /* 0x06, RT_CHANNEL_DOMAIN_2G_NULL */ ++}; ++ ++static RT_CHANNEL_PLAN_5G RTW_ChannelPlan5G[RT_CHANNEL_DOMAIN_5G_MAX] = { ++ {{}, 0}, /* 0x00, RT_CHANNEL_DOMAIN_5G_NULL */ ++ {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 19}, /* 0x01, RT_CHANNEL_DOMAIN_5G_ETSI1 */ ++ {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165}, 24}, /* 0x02, RT_CHANNEL_DOMAIN_5G_ETSI2 */ ++ {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 149, 153, 157, 161, 165}, 22}, /* 0x03, RT_CHANNEL_DOMAIN_5G_ETSI3 */ ++ {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165}, 24}, /* 0x04, RT_CHANNEL_DOMAIN_5G_FCC1 */ ++ {{36, 40, 44, 48, 149, 153, 157, 161, 165}, 9}, /* 0x05, RT_CHANNEL_DOMAIN_5G_FCC2 */ ++ {{36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165}, 13}, /* 0x06, RT_CHANNEL_DOMAIN_5G_FCC3 */ ++ {{36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161}, 12}, /* 0x07, RT_CHANNEL_DOMAIN_5G_FCC4 */ ++ {{149, 153, 157, 161, 165}, 5}, /* 0x08, RT_CHANNEL_DOMAIN_5G_FCC5 */ ++ {{36, 40, 44, 48, 52, 56, 60, 64}, 8}, /* 0x09, RT_CHANNEL_DOMAIN_5G_FCC6 */ ++ {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165}, 20}, /* 0x0A, RT_CHANNEL_DOMAIN_5G_FCC7_IC1 */ ++ {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 149, 153, 157, 161, 165}, 20}, /* 0x0B, RT_CHANNEL_DOMAIN_5G_KCC1 */ ++ {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 19}, /* 0x0C, RT_CHANNEL_DOMAIN_5G_MKK1 */ ++ {{36, 40, 44, 48, 52, 56, 60, 64}, 8}, /* 0x0D, RT_CHANNEL_DOMAIN_5G_MKK2 */ ++ {{100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 11}, /* 0x0E, RT_CHANNEL_DOMAIN_5G_MKK3 */ ++ {{56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165}, 15}, /* 0x0F, RT_CHANNEL_DOMAIN_5G_NCC1 */ ++ {{56, 60, 64, 149, 153, 157, 161, 165}, 8}, /* 0x10, RT_CHANNEL_DOMAIN_5G_NCC2 */ ++ {{149, 153, 157, 161, 165}, 5}, /* 0x11, RT_CHANNEL_DOMAIN_5G_NCC3 */ ++ {{36, 40, 44, 48}, 4}, /* 0x12, RT_CHANNEL_DOMAIN_5G_ETSI4 */ ++ {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165}, 20}, /* 0x13, RT_CHANNEL_DOMAIN_5G_ETSI5 */ ++ {{149, 153, 157, 161}, 4}, /* 0x14, RT_CHANNEL_DOMAIN_5G_FCC8 */ ++ {{36, 40, 44, 48, 52, 56, 60, 64}, 8}, /* 0x15, RT_CHANNEL_DOMAIN_5G_ETSI6 */ ++ {{36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165}, 13}, /* 0x16, RT_CHANNEL_DOMAIN_5G_ETSI7 */ ++ {{36, 40, 44, 48, 149, 153, 157, 161, 165}, 9}, /* 0x17, RT_CHANNEL_DOMAIN_5G_ETSI8 */ ++ {{100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 11}, /* 0x18, RT_CHANNEL_DOMAIN_5G_ETSI9 */ ++ {{149, 153, 157, 161, 165}, 5}, /* 0x19, RT_CHANNEL_DOMAIN_5G_ETSI10 */ ++ {{36, 40, 44, 48, 52, 56, 60, 64, 132, 136, 140, 149, 153, 157, 161, 165}, 16}, /* 0x1A, RT_CHANNEL_DOMAIN_5G_ETSI11 */ ++ {{52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165}, 17}, /* 0x1B, RT_CHANNEL_DOMAIN_5G_NCC4 */ ++ {{149, 153, 157, 161}, 4}, /* 0x1C, RT_CHANNEL_DOMAIN_5G_ETSI12 */ ++ {{36, 40, 44, 48, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165}, 17}, /* 0x1D, RT_CHANNEL_DOMAIN_5G_FCC9 */ ++ {{36, 40, 44, 48, 100, 104, 108, 112, 116, 132, 136, 140}, 12}, /* 0x1E, RT_CHANNEL_DOMAIN_5G_ETSI13 */ ++ {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161}, 20}, /* 0x1F, RT_CHANNEL_DOMAIN_5G_FCC10 */ ++ ++ /* Driver self defined for old channel plan Compatible , Remember to modify if have new channel plan definition ===== */ ++ {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165}, 21}, /* 0x20, RT_CHANNEL_DOMAIN_5G_FCC */ ++ {{36, 40, 44, 48}, 4}, /* 0x21, RT_CHANNEL_DOMAIN_5G_JAPAN_NO_DFS */ ++ {{36, 40, 44, 48, 149, 153, 157, 161}, 8}, /* 0x22, RT_CHANNEL_DOMAIN_5G_FCC4_NO_DFS */ ++}; ++ ++static RT_CHANNEL_PLAN_MAP RTW_ChannelPlanMap[RT_CHANNEL_DOMAIN_MAX] = { ++ /* 0x00 ~ 0x1F , Old Define ===== */ ++ {0x02, 0x20}, /* 0x00, RT_CHANNEL_DOMAIN_FCC */ ++ {0x02, 0x0A}, /* 0x01, RT_CHANNEL_DOMAIN_IC */ ++ {0x01, 0x01}, /* 0x02, RT_CHANNEL_DOMAIN_ETSI */ ++ {0x01, 0x00}, /* 0x03, RT_CHANNEL_DOMAIN_SPAIN */ ++ {0x01, 0x00}, /* 0x04, RT_CHANNEL_DOMAIN_FRANCE */ ++ {0x03, 0x00}, /* 0x05, RT_CHANNEL_DOMAIN_MKK */ ++ {0x03, 0x00}, /* 0x06, RT_CHANNEL_DOMAIN_MKK1 */ ++ {0x01, 0x09}, /* 0x07, RT_CHANNEL_DOMAIN_ISRAEL */ ++ {0x03, 0x09}, /* 0x08, RT_CHANNEL_DOMAIN_TELEC */ ++ {0x03, 0x00}, /* 0x09, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN */ ++ {0x00, 0x00}, /* 0x0A, RT_CHANNEL_DOMAIN_WORLD_WIDE_13 */ ++ {0x02, 0x0F}, /* 0x0B, RT_CHANNEL_DOMAIN_TAIWAN */ ++ {0x01, 0x08}, /* 0x0C, RT_CHANNEL_DOMAIN_CHINA */ ++ {0x02, 0x06}, /* 0x0D, RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO */ ++ {0x02, 0x0B}, /* 0x0E, RT_CHANNEL_DOMAIN_KOREA */ ++ {0x02, 0x09}, /* 0x0F, RT_CHANNEL_DOMAIN_TURKEY */ ++ {0x01, 0x01}, /* 0x10, RT_CHANNEL_DOMAIN_JAPAN */ ++ {0x02, 0x05}, /* 0x11, RT_CHANNEL_DOMAIN_FCC_NO_DFS */ ++ {0x01, 0x21}, /* 0x12, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */ ++ {0x00, 0x04}, /* 0x13, RT_CHANNEL_DOMAIN_WORLD_WIDE_5G */ ++ {0x02, 0x10}, /* 0x14, RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS */ ++ {0x00, 0x21}, /* 0x15, RT_CHANNEL_DOMAIN_ETSI_NO_DFS */ ++ {0x00, 0x22}, /* 0x16, RT_CHANNEL_DOMAIN_KOREA_NO_DFS */ ++ {0x03, 0x21}, /* 0x17, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */ ++ {0x06, 0x08}, /* 0x18, RT_CHANNEL_DOMAIN_PAKISTAN_NO_DFS */ ++ {0x02, 0x08}, /* 0x19, RT_CHANNEL_DOMAIN_TAIWAN2_NO_DFS */ ++ {0x00, 0x00}, /* 0x1A, */ ++ {0x00, 0x00}, /* 0x1B, */ ++ {0x00, 0x00}, /* 0x1C, */ ++ {0x00, 0x00}, /* 0x1D, */ ++ {0x00, 0x00}, /* 0x1E, */ ++ {0x06, 0x04}, /* 0x1F, RT_CHANNEL_DOMAIN_WORLD_WIDE_ONLY_5G */ ++ /* 0x20 ~ 0x7F , New Define ===== */ ++ {0x00, 0x00}, /* 0x20, RT_CHANNEL_DOMAIN_WORLD_NULL */ ++ {0x01, 0x00}, /* 0x21, RT_CHANNEL_DOMAIN_ETSI1_NULL */ ++ {0x02, 0x00}, /* 0x22, RT_CHANNEL_DOMAIN_FCC1_NULL */ ++ {0x03, 0x00}, /* 0x23, RT_CHANNEL_DOMAIN_MKK1_NULL */ ++ {0x04, 0x00}, /* 0x24, RT_CHANNEL_DOMAIN_ETSI2_NULL */ ++ {0x02, 0x04}, /* 0x25, RT_CHANNEL_DOMAIN_FCC1_FCC1 */ ++ {0x00, 0x01}, /* 0x26, RT_CHANNEL_DOMAIN_WORLD_ETSI1 */ ++ {0x03, 0x0C}, /* 0x27, RT_CHANNEL_DOMAIN_MKK1_MKK1 */ ++ {0x00, 0x0B}, /* 0x28, RT_CHANNEL_DOMAIN_WORLD_KCC1 */ ++ {0x00, 0x05}, /* 0x29, RT_CHANNEL_DOMAIN_WORLD_FCC2 */ ++ {0x00, 0x00}, /* 0x2A, */ ++ {0x00, 0x00}, /* 0x2B, */ ++ {0x00, 0x00}, /* 0x2C, */ ++ {0x00, 0x00}, /* 0x2D, */ ++ {0x00, 0x00}, /* 0x2E, */ ++ {0x00, 0x00}, /* 0x2F, */ ++ {0x00, 0x06}, /* 0x30, RT_CHANNEL_DOMAIN_WORLD_FCC3 */ ++ {0x00, 0x07}, /* 0x31, RT_CHANNEL_DOMAIN_WORLD_FCC4 */ ++ {0x00, 0x08}, /* 0x32, RT_CHANNEL_DOMAIN_WORLD_FCC5 */ ++ {0x00, 0x09}, /* 0x33, RT_CHANNEL_DOMAIN_WORLD_FCC6 */ ++ {0x02, 0x0A}, /* 0x34, RT_CHANNEL_DOMAIN_FCC1_FCC7 */ ++ {0x00, 0x02}, /* 0x35, RT_CHANNEL_DOMAIN_WORLD_ETSI2 */ ++ {0x00, 0x03}, /* 0x36, RT_CHANNEL_DOMAIN_WORLD_ETSI3 */ ++ {0x03, 0x0D}, /* 0x37, RT_CHANNEL_DOMAIN_MKK1_MKK2 */ ++ {0x03, 0x0E}, /* 0x38, RT_CHANNEL_DOMAIN_MKK1_MKK3 */ ++ {0x02, 0x0F}, /* 0x39, RT_CHANNEL_DOMAIN_FCC1_NCC1 */ ++ {0x00, 0x00}, /* 0x3A, */ ++ {0x00, 0x00}, /* 0x3B, */ ++ {0x00, 0x00}, /* 0x3C, */ ++ {0x00, 0x00}, /* 0x3D, */ ++ {0x00, 0x00}, /* 0x3E, */ ++ {0x00, 0x00}, /* 0x3F, */ ++ {0x02, 0x10}, /* 0x40, RT_CHANNEL_DOMAIN_FCC1_NCC2 */ ++ {0x05, 0x00}, /* 0x41, RT_CHANNEL_DOMAIN_GLOBAL_NULL */ ++ {0x01, 0x12}, /* 0x42, RT_CHANNEL_DOMAIN_ETSI1_ETSI4 */ ++ {0x02, 0x05}, /* 0x43, RT_CHANNEL_DOMAIN_FCC1_FCC2 */ ++ {0x02, 0x11}, /* 0x44, RT_CHANNEL_DOMAIN_FCC1_NCC3 */ ++ {0x00, 0x13}, /* 0x45, RT_CHANNEL_DOMAIN_WORLD_ETSI5 */ ++ {0x02, 0x14}, /* 0x46, RT_CHANNEL_DOMAIN_FCC1_FCC8 */ ++ {0x00, 0x15}, /* 0x47, RT_CHANNEL_DOMAIN_WORLD_ETSI6 */ ++ {0x00, 0x16}, /* 0x48, RT_CHANNEL_DOMAIN_WORLD_ETSI7 */ ++ {0x00, 0x17}, /* 0x49, RT_CHANNEL_DOMAIN_WORLD_ETSI8 */ ++ {0x00, 0x18}, /* 0x50, RT_CHANNEL_DOMAIN_WORLD_ETSI9 */ ++ {0x00, 0x19}, /* 0x51, RT_CHANNEL_DOMAIN_WORLD_ETSI10 */ ++ {0x00, 0x1A}, /* 0x52, RT_CHANNEL_DOMAIN_WORLD_ETSI11 */ ++ {0x02, 0x1B}, /* 0x53, RT_CHANNEL_DOMAIN_FCC1_NCC4 */ ++ {0x00, 0x1C}, /* 0x54, RT_CHANNEL_DOMAIN_WORLD_ETSI12 */ ++ {0x02, 0x1D}, /* 0x55, RT_CHANNEL_DOMAIN_FCC1_FCC9 */ ++ {0x00, 0x1E}, /* 0x56, RT_CHANNEL_DOMAIN_WORLD_ETSI13 */ ++ {0x02, 0x1F}, /* 0x57, RT_CHANNEL_DOMAIN_FCC1_FCC10 */ ++}; ++ ++static RT_CHANNEL_PLAN_MAP RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03, 0x02}; /* use the conbination for max channel numbers */ ++ ++/* ++ * Search the @param ch in given @param ch_set ++ * @ch_set: the given channel set ++ * @ch: the given channel number ++ * ++ * return the index of channel_num in channel_set, -1 if not found ++ */ ++int rtw_ch_set_search_ch(RT_CHANNEL_INFO *ch_set, const u32 ch) ++{ ++ int i; ++ for (i = 0;ch_set[i].ChannelNum!= 0;i++) { ++ if (ch == ch_set[i].ChannelNum) ++ break; ++ } ++ ++ if (i >= ch_set[i].ChannelNum) ++ return -1; ++ return i; ++} ++ ++/* ++ * Check the @param ch is fit with setband setting of @param adapter ++ * @adapter: the given adapter ++ * @ch: the given channel number ++ * ++ * return true when check valid, false not valid ++ */ ++bool rtw_mlme_band_check(struct adapter *adapter, const u32 ch) ++{ ++ if (adapter->setband == GHZ24_50 /* 2.4G and 5G */ ++ || (adapter->setband == GHZ_24 && ch < 35) /* 2.4G only */ ++ || (adapter->setband == GHZ_50 && ch > 35) /* 5G only */ ++ ) { ++ return true; ++ } ++ return false; ++} ++ ++/**************************************************************************** ++ ++Following are the initialization functions for WiFi MLME ++ ++*****************************************************************************/ ++ ++int init_hw_mlme_ext(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ return _SUCCESS; ++} ++ ++void init_mlme_default_rate_set(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ unsigned char mixed_datarate[NumRates] = {_1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_, _9M_RATE_, _12M_RATE_, _18M_RATE_, _24M_RATE_, _36M_RATE_, _48M_RATE_, _54M_RATE_, 0xff}; ++ unsigned char mixed_basicrate[NumRates] ={_1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_, _12M_RATE_, _24M_RATE_, 0xff,}; ++ unsigned char supported_mcs_set[16] = {0xff, 0xff, 0x00, 0x00, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; ++ ++ memcpy(pmlmeext->datarate, mixed_datarate, NumRates); ++ memcpy(pmlmeext->basicrate, mixed_basicrate, NumRates); ++ ++ memcpy(pmlmeext->default_supported_mcs_set, supported_mcs_set, sizeof(pmlmeext->default_supported_mcs_set)); ++} ++ ++static void init_mlme_ext_priv_value(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ atomic_set(&pmlmeext->event_seq, 0); ++ pmlmeext->mgnt_seq = 0;/* reset to zero when disconnect at client mode */ ++ pmlmeext->sa_query_seq = 0; ++ pmlmeext->mgnt_80211w_IPN = 0; ++ pmlmeext->mgnt_80211w_IPN_rx = 0; ++ pmlmeext->cur_channel = padapter->registrypriv.channel; ++ pmlmeext->cur_bwmode = CHANNEL_WIDTH_20; ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ pmlmeext->retry = 0; ++ ++ pmlmeext->cur_wireless_mode = padapter->registrypriv.wireless_mode; ++ ++ init_mlme_default_rate_set(padapter); ++ ++ if (pmlmeext->cur_channel > 14) ++ pmlmeext->tx_rate = IEEE80211_OFDM_RATE_6MB; ++ else ++ pmlmeext->tx_rate = IEEE80211_CCK_RATE_1MB; ++ ++ pmlmeext->sitesurvey_res.state = SCAN_DISABLE; ++ pmlmeext->sitesurvey_res.channel_idx = 0; ++ pmlmeext->sitesurvey_res.bss_cnt = 0; ++ pmlmeext->scan_abort = false; ++ ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ pmlmeinfo->reauth_count = 0; ++ pmlmeinfo->reassoc_count = 0; ++ pmlmeinfo->link_count = 0; ++ pmlmeinfo->auth_seq = 0; ++ pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; ++ pmlmeinfo->key_index = 0; ++ pmlmeinfo->iv = 0; ++ ++ pmlmeinfo->enc_algo = _NO_PRIVACY_; ++ pmlmeinfo->authModeToggle = 0; ++ ++ memset(pmlmeinfo->chg_txt, 0, 128); ++ ++ pmlmeinfo->slotTime = SHORT_SLOT_TIME; ++ pmlmeinfo->preamble_mode = PREAMBLE_AUTO; ++ ++ pmlmeinfo->dialogToken = 0; ++ ++ pmlmeext->action_public_rxseq = 0xffff; ++ pmlmeext->action_public_dialog_token = 0xff; ++} ++ ++static int has_channel(RT_CHANNEL_INFO *channel_set, ++ u8 chanset_size, ++ u8 chan) { ++ int i; ++ ++ for (i = 0; i < chanset_size; i++) { ++ if (channel_set[i].ChannelNum == chan) { ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++static void init_channel_list(struct adapter *padapter, RT_CHANNEL_INFO *channel_set, ++ u8 chanset_size, ++ struct p2p_channels *channel_list) { ++ ++ struct p2p_oper_class_map op_class[] = { ++ { IEEE80211G, 81, 1, 13, 1, BW20 }, ++ { IEEE80211G, 82, 14, 14, 1, BW20 }, ++ { IEEE80211A, 115, 36, 48, 4, BW20 }, ++ { IEEE80211A, 116, 36, 44, 8, BW40PLUS }, ++ { IEEE80211A, 117, 40, 48, 8, BW40MINUS }, ++ { IEEE80211A, 124, 149, 161, 4, BW20 }, ++ { IEEE80211A, 125, 149, 169, 4, BW20 }, ++ { IEEE80211A, 126, 149, 157, 8, BW40PLUS }, ++ { IEEE80211A, 127, 153, 161, 8, BW40MINUS }, ++ { -1, 0, 0, 0, 0, BW20 } ++ }; ++ ++ int cla, op; ++ ++ cla = 0; ++ ++ for (op = 0; op_class[op].op_class; op++) { ++ u8 ch; ++ struct p2p_oper_class_map *o = &op_class[op]; ++ struct p2p_reg_class *reg = NULL; ++ ++ for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { ++ if (!has_channel(channel_set, chanset_size, ch)) { ++ continue; ++ } ++ ++ if ((0 == padapter->registrypriv.ht_enable) && (8 == o->inc)) ++ continue; ++ ++ if ((0 < (padapter->registrypriv.bw_mode & 0xf0)) && ++ ((BW40MINUS == o->bw) || (BW40PLUS == o->bw))) ++ continue; ++ ++ if (reg == NULL) { ++ reg = &channel_list->reg_class[cla]; ++ cla++; ++ reg->reg_class = o->op_class; ++ reg->channels = 0; ++ } ++ reg->channel[reg->channels] = ch; ++ reg->channels++; ++ } ++ } ++ channel_list->reg_classes = cla; ++ ++} ++ ++static u8 init_channel_set(struct adapter *padapter, u8 ChannelPlan, RT_CHANNEL_INFO *channel_set) ++{ ++ u8 index, chanset_size = 0; ++ u8 b5GBand = false, b2_4GBand = false; ++ u8 Index2G = 0, Index5G = 0; ++ ++ memset(channel_set, 0, sizeof(RT_CHANNEL_INFO)*MAX_CHANNEL_NUM); ++ ++ if (ChannelPlan >= RT_CHANNEL_DOMAIN_MAX && ChannelPlan != RT_CHANNEL_DOMAIN_REALTEK_DEFINE) ++ { ++ DBG_871X("ChannelPlan ID %x error !!!!!\n", ChannelPlan); ++ return chanset_size; ++ } ++ ++ if (IsSupported24G(padapter->registrypriv.wireless_mode)) ++ { ++ b2_4GBand = true; ++ if (RT_CHANNEL_DOMAIN_REALTEK_DEFINE == ChannelPlan) ++ Index2G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index2G; ++ else ++ Index2G = RTW_ChannelPlanMap[ChannelPlan].Index2G; ++ } ++ ++ if (b2_4GBand) ++ { ++ for (index = 0;index= 1 && channel_set[chanset_size].ChannelNum <= 11) ++ channel_set[chanset_size].ScanType = SCAN_ACTIVE; ++ else if ((channel_set[chanset_size].ChannelNum >= 12 && channel_set[chanset_size].ChannelNum <= 14)) ++ channel_set[chanset_size].ScanType = SCAN_PASSIVE; ++ } ++ else if (RT_CHANNEL_DOMAIN_WORLD_WIDE_13 == ChannelPlan || ++ RT_CHANNEL_DOMAIN_WORLD_WIDE_5G == ChannelPlan || ++ RT_CHANNEL_DOMAIN_2G_WORLD == Index2G)/* channel 12~13, passive scan */ ++ { ++ if (channel_set[chanset_size].ChannelNum <= 11) ++ channel_set[chanset_size].ScanType = SCAN_ACTIVE; ++ else ++ channel_set[chanset_size].ScanType = SCAN_PASSIVE; ++ } ++ else ++ { ++ channel_set[chanset_size].ScanType = SCAN_ACTIVE; ++ } ++ ++ chanset_size++; ++ } ++ } ++ ++ if (b5GBand) ++ { ++ for (index = 0;index= 149) { ++ channel_set[chanset_size].ChannelNum = RTW_ChannelPlan5G[Index5G].Channel[index]; ++ if (RT_CHANNEL_DOMAIN_WORLD_WIDE_5G == ChannelPlan)/* passive scan for all 5G channels */ ++ channel_set[chanset_size].ScanType = SCAN_PASSIVE; ++ else ++ channel_set[chanset_size].ScanType = SCAN_ACTIVE; ++ DBG_871X("%s(): channel_set[%d].ChannelNum = %d\n", __func__, chanset_size, channel_set[chanset_size].ChannelNum); ++ chanset_size++; ++ } ++ } ++ } ++ ++ DBG_871X("%s ChannelPlan ID %x Chan num:%d \n", __func__, ChannelPlan, chanset_size); ++ return chanset_size; ++} ++ ++int init_mlme_ext_priv(struct adapter *padapter) ++{ ++ int res = _SUCCESS; ++ struct registry_priv* pregistrypriv = &padapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ /* We don't need to memset padapter->XXX to zero, because adapter is allocated by vzalloc(). */ ++ /* memset((u8 *)pmlmeext, 0, sizeof(struct mlme_ext_priv)); */ ++ ++ pmlmeext->padapter = padapter; ++ ++ /* fill_fwpriv(padapter, &(pmlmeext->fwpriv)); */ ++ ++ init_mlme_ext_priv_value(padapter); ++ pmlmeinfo->bAcceptAddbaReq = pregistrypriv->bAcceptAddbaReq; ++ ++ init_mlme_ext_timer(padapter); ++ ++ init_mlme_ap_info(padapter); ++ ++ pmlmeext->max_chan_nums = init_channel_set(padapter, pmlmepriv->ChannelPlan, pmlmeext->channel_set); ++ init_channel_list(padapter, pmlmeext->channel_set, pmlmeext->max_chan_nums, &pmlmeext->channel_list); ++ pmlmeext->last_scan_time = 0; ++ pmlmeext->chan_scan_time = SURVEY_TO; ++ pmlmeext->mlmeext_init = true; ++ pmlmeext->active_keep_alive_check = true; ++ ++#ifdef DBG_FIXED_CHAN ++ pmlmeext->fixed_chan = 0xFF; ++#endif ++ ++ return res; ++ ++} ++ ++void free_mlme_ext_priv (struct mlme_ext_priv *pmlmeext) ++{ ++ struct adapter *padapter = pmlmeext->padapter; ++ ++ if (!padapter) ++ return; ++ ++ if (padapter->bDriverStopped == true) ++ { ++ del_timer_sync(&pmlmeext->survey_timer); ++ del_timer_sync(&pmlmeext->link_timer); ++ /* del_timer_sync(&pmlmeext->ADDBA_timer); */ ++ } ++} ++ ++static void _mgt_dispatcher(struct adapter *padapter, struct mlme_handler *ptable, union recv_frame *precv_frame) ++{ ++ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ ++ if (ptable->func) ++ { ++ /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */ ++ if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) && ++ memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN)) ++ { ++ return; ++ } ++ ++ ptable->func(padapter, precv_frame); ++ } ++ ++} ++ ++void mgt_dispatcher(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ int index; ++ struct mlme_handler *ptable; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(pframe)); ++ struct dvobj_priv *psdpriv = padapter->dvobj; ++ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ++ ("+mgt_dispatcher: type(0x%x) subtype(0x%x)\n", ++ GetFrameType(pframe), GetFrameSubType(pframe))); ++ ++ if (GetFrameType(pframe) != WIFI_MGT_TYPE) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("mgt_dispatcher: type(0x%x) error!\n", GetFrameType(pframe))); ++ return; ++ } ++ ++ /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */ ++ if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) && ++ memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN)) ++ { ++ return; ++ } ++ ++ ptable = mlme_sta_tbl; ++ ++ index = GetFrameSubType(pframe) >> 4; ++ ++ if (index >= (sizeof(mlme_sta_tbl) /sizeof(struct mlme_handler))) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Currently we do not support reserved sub-fr-type =%d\n", index)); ++ return; ++ } ++ ptable += index; ++ ++ if (psta != NULL) ++ { ++ if (GetRetry(pframe)) ++ { ++ if (precv_frame->u.hdr.attrib.seq_num == psta->RxMgmtFrameSeqNum) ++ { ++ /* drop the duplicate management frame */ ++ pdbgpriv->dbg_rx_dup_mgt_frame_drop_count++; ++ DBG_871X("Drop duplicate management frame with seq_num = %d.\n", precv_frame->u.hdr.attrib.seq_num); ++ return; ++ } ++ } ++ psta->RxMgmtFrameSeqNum = precv_frame->u.hdr.attrib.seq_num; ++ } ++ ++ switch (GetFrameSubType(pframe)) ++ { ++ case WIFI_AUTH: ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ++ ptable->func = &OnAuth; ++ else ++ ptable->func = &OnAuthClient; ++ /* pass through */ ++ case WIFI_ASSOCREQ: ++ case WIFI_REASSOCREQ: ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++ break; ++ case WIFI_PROBEREQ: ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++ break; ++ case WIFI_BEACON: ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++ break; ++ case WIFI_ACTION: ++ /* if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) */ ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++ break; ++ default: ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++ break; ++ } ++} ++ ++/**************************************************************************** ++ ++Following are the callback functions for each subtype of the management frames ++ ++*****************************************************************************/ ++ ++unsigned int OnProbeReq(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ unsigned int ielen; ++ unsigned char *p; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *cur = &(pmlmeinfo->network); ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint len = precv_frame->u.hdr.len; ++ u8 is_valid_p2p_probereq = false; ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) ++ { ++ return _SUCCESS; ++ } ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == false && ++ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE) ==false) ++ { ++ return _SUCCESS; ++ } ++ ++ ++ /* DBG_871X("+OnProbeReq\n"); */ ++ ++#ifdef CONFIG_AUTO_AP_MODE ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == true && ++ pmlmepriv->cur_network.join_res == true) ++ { ++ struct sta_info *psta; ++ u8 *mac_addr, *peer_addr; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 RC_OUI[4]={0x00, 0xE0, 0x4C, 0x0A}; ++ /* EID[1] + EID_LEN[1] + RC_OUI[4] + MAC[6] + PairingID[2] + ChannelNum[2] */ ++ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _VENDOR_SPECIFIC_IE_, (int *)&ielen, ++ len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); ++ ++ if (!p || ielen != 14) ++ goto _non_rc_device; ++ ++ if (memcmp(p+2, RC_OUI, sizeof(RC_OUI))) ++ goto _non_rc_device; ++ ++ if (memcmp(p+6, get_sa(pframe), ETH_ALEN)) ++ { ++ DBG_871X("%s, do rc pairing ("MAC_FMT"), but mac addr mismatch!("MAC_FMT")\n", __func__, ++ MAC_ARG(get_sa(pframe)), MAC_ARG(p+6)); ++ ++ goto _non_rc_device; ++ } ++ ++ DBG_871X("%s, got the pairing device("MAC_FMT")\n", __func__, MAC_ARG(get_sa(pframe))); ++ ++ /* new a station */ ++ psta = rtw_get_stainfo(pstapriv, get_sa(pframe)); ++ if (psta == NULL) ++ { ++ /* allocate a new one */ ++ DBG_871X("going to alloc stainfo for rc ="MAC_FMT"\n", MAC_ARG(get_sa(pframe))); ++ psta = rtw_alloc_stainfo(pstapriv, get_sa(pframe)); ++ if (psta == NULL) ++ { ++ /* TODO: */ ++ DBG_871X(" Exceed the upper limit of supported clients...\n"); ++ return _SUCCESS; ++ } ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ if (list_empty(&psta->asoc_list)) ++ { ++ psta->expire_to = pstapriv->expire_to; ++ list_add_tail(&psta->asoc_list, &pstapriv->asoc_list); ++ pstapriv->asoc_list_cnt++; ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ /* generate pairing ID */ ++ mac_addr = myid(&(padapter->eeprompriv)); ++ peer_addr = psta->hwaddr; ++ psta->pid = (u16)(((mac_addr[4]<<8) + mac_addr[5]) + ((peer_addr[4]<<8) + peer_addr[5])); ++ ++ /* update peer stainfo */ ++ psta->isrc = true; ++ /* psta->aid = 0; */ ++ /* psta->mac_id = 2; */ ++ ++ /* get a unique AID */ ++ if (psta->aid > 0) { ++ DBG_871X("old AID %d\n", psta->aid); ++ } else { ++ for (psta->aid = 1; psta->aid <= NUM_STA; psta->aid++) ++ if (pstapriv->sta_aid[psta->aid - 1] == NULL) ++ break; ++ ++ if (psta->aid > pstapriv->max_num_sta) { ++ psta->aid = 0; ++ DBG_871X("no room for more AIDs\n"); ++ return _SUCCESS; ++ } else { ++ pstapriv->sta_aid[psta->aid - 1] = psta; ++ DBG_871X("allocate new AID = (%d)\n", psta->aid); ++ } ++ } ++ ++ psta->qos_option = 1; ++ psta->bw_mode = CHANNEL_WIDTH_20; ++ psta->ieee8021x_blocked = false; ++ psta->htpriv.ht_option = true; ++ psta->htpriv.ampdu_enable = false; ++ psta->htpriv.sgi_20m = false; ++ psta->htpriv.sgi_40m = false; ++ psta->htpriv.ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ psta->htpriv.agg_enable_bitmap = 0x0;/* reset */ ++ psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */ ++ ++ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true); ++ ++ memset((void*)&psta->sta_stats, 0, sizeof(struct stainfo_stats)); ++ ++ spin_lock_bh(&psta->lock); ++ psta->state |= _FW_LINKED; ++ spin_unlock_bh(&psta->lock); ++ ++ report_add_sta_event(padapter, psta->hwaddr, psta->aid); ++ ++ } ++ ++ issue_probersp(padapter, get_sa(pframe), false); ++ ++ return _SUCCESS; ++ ++ } ++ ++_non_rc_device: ++ ++ return _SUCCESS; ++ ++#endif /* CONFIG_AUTO_AP_MODE */ ++ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ielen, ++ len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); ++ ++ ++ /* check (wildcard) SSID */ ++ if (p != NULL) ++ { ++ if (is_valid_p2p_probereq == true) ++ { ++ goto _issue_probersp; ++ } ++ ++ if ((ielen != 0 && false ==!memcmp((void *)(p+2), (void *)cur->Ssid.Ssid, cur->Ssid.SsidLength)) ++ || (ielen == 0 && pmlmeinfo->hidden_ssid_mode) ++ ) ++ { ++ return _SUCCESS; ++ } ++ ++_issue_probersp: ++ if (((check_fwstate(pmlmepriv, _FW_LINKED) == true && ++ pmlmepriv->cur_network.join_res == true)) || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) ++ { ++ /* DBG_871X("+issue_probersp during ap mode\n"); */ ++ issue_probersp(padapter, get_sa(pframe), is_valid_p2p_probereq); ++ } ++ ++ } ++ ++ return _SUCCESS; ++ ++} ++ ++unsigned int OnProbeRsp(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) ++ { ++ report_survey_event(padapter, precv_frame); ++ return _SUCCESS; ++ } ++ ++ return _SUCCESS; ++ ++} ++ ++unsigned int OnBeacon(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ int cam_idx; ++ struct sta_info *psta; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint len = precv_frame->u.hdr.len; ++ struct wlan_bssid_ex *pbss; ++ int ret = _SUCCESS; ++ u8 *p = NULL; ++ u32 ielen = 0; ++ ++ p = rtw_get_ie(pframe + sizeof(struct ieee80211_hdr_3addr) + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ielen, precv_frame->u.hdr.len -sizeof(struct ieee80211_hdr_3addr) - _BEACON_IE_OFFSET_); ++ if ((p != NULL) && (ielen > 0)) ++ { ++ if ((*(p + 1 + ielen) == 0x2D) && (*(p + 2 + ielen) != 0x2D)) ++ { ++ /* Invalid value 0x2D is detected in Extended Supported Rates (ESR) IE. Try to fix the IE length to avoid failed Beacon parsing. */ ++ DBG_871X("[WIFIDBG] Error in ESR IE is detected in Beacon of BSSID:"MAC_FMT". Fix the length of ESR IE to avoid failed Beacon parsing.\n", MAC_ARG(GetAddr3Ptr(pframe))); ++ *(p + 1) = ielen - 1; ++ } ++ } ++ ++ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) ++ { ++ report_survey_event(padapter, precv_frame); ++ return _SUCCESS; ++ } ++ ++ if (!memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)) ++ { ++ if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) ++ { ++ /* we should update current network before auth, or some IE is wrong */ ++ pbss = (struct wlan_bssid_ex*)rtw_malloc(sizeof(struct wlan_bssid_ex)); ++ if (pbss) { ++ if (collect_bss_info(padapter, precv_frame, pbss) == _SUCCESS) { ++ update_network(&(pmlmepriv->cur_network.network), pbss, padapter, true); ++ rtw_get_bcn_info(&(pmlmepriv->cur_network)); ++ } ++ kfree((u8 *)pbss); ++ } ++ ++ /* check the vendor of the assoc AP */ ++ pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pframe+sizeof(struct ieee80211_hdr_3addr), len-sizeof(struct ieee80211_hdr_3addr)); ++ ++ /* update TSF Value */ ++ update_TSF(pmlmeext, pframe, len); ++ ++ /* reset for adaptive_early_32k */ ++ pmlmeext->adaptive_tsf_done = false; ++ pmlmeext->DrvBcnEarly = 0xff; ++ pmlmeext->DrvBcnTimeOut = 0xff; ++ pmlmeext->bcn_cnt = 0; ++ memset(pmlmeext->bcn_delay_cnt, 0, sizeof(pmlmeext->bcn_delay_cnt)); ++ memset(pmlmeext->bcn_delay_ratio, 0, sizeof(pmlmeext->bcn_delay_ratio)); ++ ++ /* start auth */ ++ start_clnt_auth(padapter); ++ ++ return _SUCCESS; ++ } ++ ++ if (((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) && (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) ++ { ++ if ((psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe))) != NULL) ++ { ++ ret = rtw_check_bcn_info(padapter, pframe, len); ++ if (!ret) { ++ DBG_871X_LEVEL(_drv_always_, "ap has changed, disconnect now\n "); ++ receive_disconnect(padapter, pmlmeinfo->network.MacAddress , 0); ++ return _SUCCESS; ++ } ++ /* update WMM, ERP in the beacon */ ++ /* todo: the timer is used instead of the number of the beacon received */ ++ if ((sta_rx_pkts(psta) & 0xf) == 0) ++ { ++ /* DBG_871X("update_bcn_info\n"); */ ++ update_beacon_info(padapter, pframe, len, psta); ++ } ++ ++ adaptive_early_32k(pmlmeext, pframe, len); ++ } ++ } ++ else if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) ++ { ++ if ((psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe))) != NULL) ++ { ++ /* update WMM, ERP in the beacon */ ++ /* todo: the timer is used instead of the number of the beacon received */ ++ if ((sta_rx_pkts(psta) & 0xf) == 0) ++ { ++ /* DBG_871X("update_bcn_info\n"); */ ++ update_beacon_info(padapter, pframe, len, psta); ++ } ++ } ++ else ++ { ++ /* allocate a new CAM entry for IBSS station */ ++ if ((cam_idx = allocate_fw_sta_entry(padapter)) == NUM_STA) ++ { ++ goto _END_ONBEACON_; ++ } ++ ++ /* get supported rate */ ++ if (update_sta_support_rate(padapter, (pframe + WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_), (len - WLAN_HDR_A3_LEN - _BEACON_IE_OFFSET_), cam_idx) == _FAIL) ++ { ++ pmlmeinfo->FW_sta_info[cam_idx].status = 0; ++ goto _END_ONBEACON_; ++ } ++ ++ /* update TSF Value */ ++ update_TSF(pmlmeext, pframe, len); ++ ++ /* report sta add event */ ++ report_add_sta_event(padapter, GetAddr2Ptr(pframe), cam_idx); ++ } ++ } ++ } ++ ++_END_ONBEACON_: ++ ++ return _SUCCESS; ++ ++} ++ ++unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ unsigned int auth_mode, seq, ie_len; ++ unsigned char *sa, *p; ++ u16 algorithm; ++ int status; ++ static struct sta_info stat; ++ struct sta_info *pstat = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint len = precv_frame->u.hdr.len; ++ u8 offset = 0; ++ ++ if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) ++ return _FAIL; ++ ++ DBG_871X("+OnAuth\n"); ++ ++ sa = GetAddr2Ptr(pframe); ++ ++ auth_mode = psecuritypriv->dot11AuthAlgrthm; ++ ++ if (GetPrivacy(pframe)) ++ { ++ u8 *iv; ++ struct rx_pkt_attrib *prxattrib = &(precv_frame->u.hdr.attrib); ++ ++ prxattrib->hdrlen = WLAN_HDR_A3_LEN; ++ prxattrib->encrypt = _WEP40_; ++ ++ iv = pframe+prxattrib->hdrlen; ++ prxattrib->key_index = ((iv[3]>>6)&0x3); ++ ++ prxattrib->iv_len = 4; ++ prxattrib->icv_len = 4; ++ ++ rtw_wep_decrypt(padapter, (u8 *)precv_frame); ++ ++ offset = 4; ++ } ++ ++ algorithm = le16_to_cpu(*(__le16*)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset)); ++ seq = le16_to_cpu(*(__le16*)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 2)); ++ ++ DBG_871X("auth alg =%x, seq =%X\n", algorithm, seq); ++ ++ if (auth_mode == 2 && ++ psecuritypriv->dot11PrivacyAlgrthm != _WEP40_ && ++ psecuritypriv->dot11PrivacyAlgrthm != _WEP104_) ++ auth_mode = 0; ++ ++ if ((algorithm > 0 && auth_mode == 0) || /* rx a shared-key auth but shared not enabled */ ++ (algorithm == 0 && auth_mode == 1)) /* rx a open-system auth but shared-key is enabled */ ++ { ++ DBG_871X("auth rejected due to bad alg [alg =%d, auth_mib =%d] %02X%02X%02X%02X%02X%02X\n", ++ algorithm, auth_mode, sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]); ++ ++ status = _STATS_NO_SUPP_ALG_; ++ ++ goto auth_fail; ++ } ++ ++ if (rtw_access_ctrl(padapter, sa) == false) ++ { ++ status = _STATS_UNABLE_HANDLE_STA_; ++ goto auth_fail; ++ } ++ ++ pstat = rtw_get_stainfo(pstapriv, sa); ++ if (pstat == NULL) ++ { ++ ++ /* allocate a new one */ ++ DBG_871X("going to alloc stainfo for sa ="MAC_FMT"\n", MAC_ARG(sa)); ++ pstat = rtw_alloc_stainfo(pstapriv, sa); ++ if (pstat == NULL) ++ { ++ DBG_871X(" Exceed the upper limit of supported clients...\n"); ++ status = _STATS_UNABLE_HANDLE_STA_; ++ goto auth_fail; ++ } ++ ++ pstat->state = WIFI_FW_AUTH_NULL; ++ pstat->auth_seq = 0; ++ ++ /* pstat->flags = 0; */ ++ /* pstat->capability = 0; */ ++ } ++ else ++ { ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ if (list_empty(&pstat->asoc_list) ==false) ++ { ++ list_del_init(&pstat->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ if (pstat->expire_to > 0) ++ { ++ /* TODO: STA re_auth within expire_to */ ++ } ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ if (seq == 1) { ++ /* TODO: STA re_auth and auth timeout */ ++ } ++ } ++ ++ spin_lock_bh(&pstapriv->auth_list_lock); ++ if (list_empty(&pstat->auth_list)) ++ { ++ ++ list_add_tail(&pstat->auth_list, &pstapriv->auth_list); ++ pstapriv->auth_list_cnt++; ++ } ++ spin_unlock_bh(&pstapriv->auth_list_lock); ++ ++ if (pstat->auth_seq == 0) ++ pstat->expire_to = pstapriv->auth_to; ++ ++ ++ if ((pstat->auth_seq + 1) != seq) ++ { ++ DBG_871X("(1)auth rejected because out of seq [rx_seq =%d, exp_seq =%d]!\n", ++ seq, pstat->auth_seq+1); ++ status = _STATS_OUT_OF_AUTH_SEQ_; ++ goto auth_fail; ++ } ++ ++ if (algorithm == 0 && (auth_mode == 0 || auth_mode == 2 || auth_mode == 3)) ++ { ++ if (seq == 1) ++ { ++ pstat->state &= ~WIFI_FW_AUTH_NULL; ++ pstat->state |= WIFI_FW_AUTH_SUCCESS; ++ pstat->expire_to = pstapriv->assoc_to; ++ pstat->authalg = algorithm; ++ } ++ else ++ { ++ DBG_871X("(2)auth rejected because out of seq [rx_seq =%d, exp_seq =%d]!\n", ++ seq, pstat->auth_seq+1); ++ status = _STATS_OUT_OF_AUTH_SEQ_; ++ goto auth_fail; ++ } ++ } ++ else /* shared system or auto authentication */ ++ { ++ if (seq == 1) { ++ /* prepare for the challenging txt... */ ++ memset((void *)pstat->chg_txt, 78, 128); ++ ++ pstat->state &= ~WIFI_FW_AUTH_NULL; ++ pstat->state |= WIFI_FW_AUTH_STATE; ++ pstat->authalg = algorithm; ++ pstat->auth_seq = 2; ++ } ++ else if (seq == 3) ++ { ++ /* checking for challenging txt... */ ++ DBG_871X("checking for challenging txt...\n"); ++ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + 4 + _AUTH_IE_OFFSET_ , _CHLGETXT_IE_, (int *)&ie_len, ++ len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_ - 4); ++ ++ if ((p == NULL) || (ie_len<= 0)) ++ { ++ DBG_871X("auth rejected because challenge failure!(1)\n"); ++ status = _STATS_CHALLENGE_FAIL_; ++ goto auth_fail; ++ } ++ ++ if (!memcmp((void *)(p + 2), pstat->chg_txt, 128)) ++ { ++ pstat->state &= (~WIFI_FW_AUTH_STATE); ++ pstat->state |= WIFI_FW_AUTH_SUCCESS; ++ /* challenging txt is correct... */ ++ pstat->expire_to = pstapriv->assoc_to; ++ } ++ else ++ { ++ DBG_871X("auth rejected because challenge failure!\n"); ++ status = _STATS_CHALLENGE_FAIL_; ++ goto auth_fail; ++ } ++ } ++ else ++ { ++ DBG_871X("(3)auth rejected because out of seq [rx_seq =%d, exp_seq =%d]!\n", ++ seq, pstat->auth_seq+1); ++ status = _STATS_OUT_OF_AUTH_SEQ_; ++ goto auth_fail; ++ } ++ } ++ ++ ++ /* Now, we are going to issue_auth... */ ++ pstat->auth_seq = seq + 1; ++ ++ issue_auth(padapter, pstat, (unsigned short)(_STATS_SUCCESSFUL_)); ++ ++ if (pstat->state & WIFI_FW_AUTH_SUCCESS) ++ pstat->auth_seq = 0; ++ ++ ++ return _SUCCESS; ++ ++auth_fail: ++ ++ if (pstat) ++ rtw_free_stainfo(padapter , pstat); ++ ++ pstat = &stat; ++ memset((char *)pstat, '\0', sizeof(stat)); ++ pstat->auth_seq = 2; ++ memcpy(pstat->hwaddr, sa, 6); ++ ++ issue_auth(padapter, pstat, (unsigned short)status); ++ ++ return _FAIL; ++ ++} ++ ++unsigned int OnAuthClient(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ unsigned int seq, len, status, algthm, offset; ++ unsigned char *p; ++ unsigned int go2asoc = 0; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint pkt_len = precv_frame->u.hdr.len; ++ ++ DBG_871X("%s\n", __func__); ++ ++ /* check A1 matches or not */ ++ if (memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN)) ++ return _SUCCESS; ++ ++ if (!(pmlmeinfo->state & WIFI_FW_AUTH_STATE)) ++ return _SUCCESS; ++ ++ offset = (GetPrivacy(pframe))? 4: 0; ++ ++ algthm = le16_to_cpu(*(__le16 *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset)); ++ seq = le16_to_cpu(*(__le16 *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 2)); ++ status = le16_to_cpu(*(__le16 *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 4)); ++ ++ if (status != 0) ++ { ++ DBG_871X("clnt auth fail, status: %d\n", status); ++ if (status == 13)/* pmlmeinfo->auth_algo == dot11AuthAlgrthm_Auto) */ ++ { ++ if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ++ pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; ++ else ++ pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared; ++ /* pmlmeinfo->reauth_count = 0; */ ++ } ++ ++ set_link_timer(pmlmeext, 1); ++ goto authclnt_fail; ++ } ++ ++ if (seq == 2) ++ { ++ if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ++ { ++ /* legendary shared system */ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _AUTH_IE_OFFSET_, _CHLGETXT_IE_, (int *)&len, ++ pkt_len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_); ++ ++ if (p == NULL) ++ { ++ /* DBG_871X("marc: no challenge text?\n"); */ ++ goto authclnt_fail; ++ } ++ ++ memcpy((void *)(pmlmeinfo->chg_txt), (void *)(p + 2), len); ++ pmlmeinfo->auth_seq = 3; ++ issue_auth(padapter, NULL, 0); ++ set_link_timer(pmlmeext, REAUTH_TO); ++ ++ return _SUCCESS; ++ } ++ else ++ { ++ /* open system */ ++ go2asoc = 1; ++ } ++ } ++ else if (seq == 4) ++ { ++ if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ++ { ++ go2asoc = 1; ++ } ++ else ++ { ++ goto authclnt_fail; ++ } ++ } ++ else ++ { ++ /* this is also illegal */ ++ /* DBG_871X("marc: clnt auth failed due to illegal seq =%x\n", seq); */ ++ goto authclnt_fail; ++ } ++ ++ if (go2asoc) ++ { ++ DBG_871X_LEVEL(_drv_always_, "auth success, start assoc\n"); ++ start_clnt_assoc(padapter); ++ return _SUCCESS; ++ } ++ ++authclnt_fail: ++ ++ /* pmlmeinfo->state &= ~(WIFI_FW_AUTH_STATE); */ ++ ++ return _FAIL; ++ ++} ++ ++unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ u16 capab_info, listen_interval; ++ struct rtw_ieee802_11_elems elems; ++ struct sta_info *pstat; ++ unsigned char reassoc, *p, *pos, *wpa_ie; ++ unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; ++ int i, ie_len, wpa_ie_len, left; ++ unsigned char supportRate[16]; ++ int supportRateNum; ++ unsigned short status = _STATS_SUCCESSFUL_; ++ unsigned short frame_type, ie_offset = 0; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *cur = &(pmlmeinfo->network); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint pkt_len = precv_frame->u.hdr.len; ++ ++ if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) ++ return _FAIL; ++ ++ frame_type = GetFrameSubType(pframe); ++ if (frame_type == WIFI_ASSOCREQ) ++ { ++ reassoc = 0; ++ ie_offset = _ASOCREQ_IE_OFFSET_; ++ } ++ else /* WIFI_REASSOCREQ */ ++ { ++ reassoc = 1; ++ ie_offset = _REASOCREQ_IE_OFFSET_; ++ } ++ ++ ++ if (pkt_len < IEEE80211_3ADDR_LEN + ie_offset) { ++ DBG_871X("handle_assoc(reassoc =%d) - too short payload (len =%lu)" ++ "\n", reassoc, (unsigned long)pkt_len); ++ return _FAIL; ++ } ++ ++ pstat = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); ++ if (pstat == (struct sta_info *)NULL) ++ { ++ status = _RSON_CLS2_; ++ goto asoc_class2_error; ++ } ++ ++ capab_info = RTW_GET_LE16(pframe + WLAN_HDR_A3_LEN); ++ /* capab_info = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN)); */ ++ /* listen_interval = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN+2)); */ ++ listen_interval = RTW_GET_LE16(pframe + WLAN_HDR_A3_LEN+2); ++ ++ left = pkt_len - (IEEE80211_3ADDR_LEN + ie_offset); ++ pos = pframe + (IEEE80211_3ADDR_LEN + ie_offset); ++ ++ ++ DBG_871X("%s\n", __func__); ++ ++ /* check if this stat has been successfully authenticated/assocated */ ++ if (!((pstat->state) & WIFI_FW_AUTH_SUCCESS)) ++ { ++ if (!((pstat->state) & WIFI_FW_ASSOC_SUCCESS)) ++ { ++ status = _RSON_CLS2_; ++ goto asoc_class2_error; ++ } ++ else ++ { ++ pstat->state &= (~WIFI_FW_ASSOC_SUCCESS); ++ pstat->state |= WIFI_FW_ASSOC_STATE; ++ } ++ } ++ else ++ { ++ pstat->state &= (~WIFI_FW_AUTH_SUCCESS); ++ pstat->state |= WIFI_FW_ASSOC_STATE; ++ } ++ ++ ++ pstat->capability = capab_info; ++ ++ /* now parse all ieee802_11 ie to point to elems */ ++ if (rtw_ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed || ++ !elems.ssid) { ++ DBG_871X("STA " MAC_FMT " sent invalid association request\n", ++ MAC_ARG(pstat->hwaddr)); ++ status = _STATS_FAILURE_; ++ goto OnAssocReqFail; ++ } ++ ++ ++ /* now we should check all the fields... */ ++ /* checking SSID */ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SSID_IE_, &ie_len, ++ pkt_len - WLAN_HDR_A3_LEN - ie_offset); ++ if (p == NULL) ++ { ++ status = _STATS_FAILURE_; ++ } ++ ++ if (ie_len == 0) /* broadcast ssid, however it is not allowed in assocreq */ ++ status = _STATS_FAILURE_; ++ else ++ { ++ /* check if ssid match */ ++ if (memcmp((void *)(p+2), cur->Ssid.Ssid, cur->Ssid.SsidLength)) ++ status = _STATS_FAILURE_; ++ ++ if (ie_len != cur->Ssid.SsidLength) ++ status = _STATS_FAILURE_; ++ } ++ ++ if (_STATS_SUCCESSFUL_ != status) ++ goto OnAssocReqFail; ++ ++ /* check if the supported rate is ok */ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SUPPORTEDRATES_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset); ++ if (p == NULL) { ++ DBG_871X("Rx a sta assoc-req which supported rate is empty!\n"); ++ /* use our own rate set as statoin used */ ++ /* memcpy(supportRate, AP_BSSRATE, AP_BSSRATE_LEN); */ ++ /* supportRateNum = AP_BSSRATE_LEN; */ ++ ++ status = _STATS_FAILURE_; ++ goto OnAssocReqFail; ++ } ++ else { ++ memcpy(supportRate, p+2, ie_len); ++ supportRateNum = ie_len; ++ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _EXT_SUPPORTEDRATES_IE_ , &ie_len, ++ pkt_len - WLAN_HDR_A3_LEN - ie_offset); ++ if (p != NULL) { ++ ++ if (supportRateNum<=sizeof(supportRate)) ++ { ++ memcpy(supportRate+supportRateNum, p+2, ie_len); ++ supportRateNum += ie_len; ++ } ++ } ++ } ++ ++ /* todo: mask supportRate between AP & STA -> move to update raid */ ++ /* get_matched_rate(pmlmeext, supportRate, &supportRateNum, 0); */ ++ ++ /* update station supportRate */ ++ pstat->bssratelen = supportRateNum; ++ memcpy(pstat->bssrateset, supportRate, supportRateNum); ++ UpdateBrateTblForSoftAP(pstat->bssrateset, pstat->bssratelen); ++ ++ /* check RSN/WPA/WPS */ ++ pstat->dot8021xalg = 0; ++ pstat->wpa_psk = 0; ++ pstat->wpa_group_cipher = 0; ++ pstat->wpa2_group_cipher = 0; ++ pstat->wpa_pairwise_cipher = 0; ++ pstat->wpa2_pairwise_cipher = 0; ++ memset(pstat->wpa_ie, 0, sizeof(pstat->wpa_ie)); ++ if ((psecuritypriv->wpa_psk & BIT(1)) && elems.rsn_ie) { ++ ++ int group_cipher = 0, pairwise_cipher = 0; ++ ++ wpa_ie = elems.rsn_ie; ++ wpa_ie_len = elems.rsn_ie_len; ++ ++ if (rtw_parse_wpa2_ie(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) ++ { ++ pstat->dot8021xalg = 1;/* psk, todo:802.1x */ ++ pstat->wpa_psk |= BIT(1); ++ ++ pstat->wpa2_group_cipher = group_cipher&psecuritypriv->wpa2_group_cipher; ++ pstat->wpa2_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa2_pairwise_cipher; ++ ++ if (!pstat->wpa2_group_cipher) ++ status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; ++ ++ if (!pstat->wpa2_pairwise_cipher) ++ status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; ++ } ++ else ++ { ++ status = WLAN_STATUS_INVALID_IE; ++ } ++ ++ } else if ((psecuritypriv->wpa_psk & BIT(0)) && elems.wpa_ie) { ++ ++ int group_cipher = 0, pairwise_cipher = 0; ++ ++ wpa_ie = elems.wpa_ie; ++ wpa_ie_len = elems.wpa_ie_len; ++ ++ if (rtw_parse_wpa_ie(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) ++ { ++ pstat->dot8021xalg = 1;/* psk, todo:802.1x */ ++ pstat->wpa_psk |= BIT(0); ++ ++ pstat->wpa_group_cipher = group_cipher&psecuritypriv->wpa_group_cipher; ++ pstat->wpa_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa_pairwise_cipher; ++ ++ if (!pstat->wpa_group_cipher) ++ status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; ++ ++ if (!pstat->wpa_pairwise_cipher) ++ status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; ++ ++ } ++ else ++ { ++ status = WLAN_STATUS_INVALID_IE; ++ } ++ ++ } else { ++ wpa_ie = NULL; ++ wpa_ie_len = 0; ++ } ++ ++ if (_STATS_SUCCESSFUL_ != status) ++ goto OnAssocReqFail; ++ ++ pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); ++ if (wpa_ie == NULL) { ++ if (elems.wps_ie) { ++ DBG_871X("STA included WPS IE in " ++ "(Re)Association Request - assume WPS is " ++ "used\n"); ++ pstat->flags |= WLAN_STA_WPS; ++ /* wpabuf_free(sta->wps_ie); */ ++ /* sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4, */ ++ /* elems.wps_ie_len - 4); */ ++ } else { ++ DBG_871X("STA did not include WPA/RSN IE " ++ "in (Re)Association Request - possible WPS " ++ "use\n"); ++ pstat->flags |= WLAN_STA_MAYBE_WPS; ++ } ++ ++ ++ /* AP support WPA/RSN, and sta is going to do WPS, but AP is not ready */ ++ /* that the selected registrar of AP is _FLASE */ ++ if ((psecuritypriv->wpa_psk >0) ++ && (pstat->flags & (WLAN_STA_WPS|WLAN_STA_MAYBE_WPS))) ++ { ++ if (pmlmepriv->wps_beacon_ie) ++ { ++ u8 selected_registrar = 0; ++ ++ rtw_get_wps_attr_content(pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len, WPS_ATTR_SELECTED_REGISTRAR , &selected_registrar, NULL); ++ ++ if (!selected_registrar) ++ { ++ DBG_871X("selected_registrar is false , or AP is not ready to do WPS\n"); ++ ++ status = _STATS_UNABLE_HANDLE_STA_; ++ ++ goto OnAssocReqFail; ++ } ++ } ++ } ++ ++ } ++ else ++ { ++ int copy_len; ++ ++ if (psecuritypriv->wpa_psk == 0) ++ { ++ DBG_871X("STA " MAC_FMT ": WPA/RSN IE in association " ++ "request, but AP don't support WPA/RSN\n", MAC_ARG(pstat->hwaddr)); ++ ++ status = WLAN_STATUS_INVALID_IE; ++ ++ goto OnAssocReqFail; ++ ++ } ++ ++ if (elems.wps_ie) { ++ DBG_871X("STA included WPS IE in " ++ "(Re)Association Request - WPS is " ++ "used\n"); ++ pstat->flags |= WLAN_STA_WPS; ++ copy_len = 0; ++ } ++ else ++ { ++ copy_len = ((wpa_ie_len+2) > sizeof(pstat->wpa_ie)) ? (sizeof(pstat->wpa_ie)):(wpa_ie_len+2); ++ } ++ ++ ++ if (copy_len>0) ++ memcpy(pstat->wpa_ie, wpa_ie-2, copy_len); ++ ++ } ++ ++ ++ /* check if there is WMM IE & support WWM-PS */ ++ pstat->flags &= ~WLAN_STA_WME; ++ pstat->qos_option = 0; ++ pstat->qos_info = 0; ++ pstat->has_legacy_ac = true; ++ pstat->uapsd_vo = 0; ++ pstat->uapsd_vi = 0; ++ pstat->uapsd_be = 0; ++ pstat->uapsd_bk = 0; ++ if (pmlmepriv->qospriv.qos_option) ++ { ++ p = pframe + WLAN_HDR_A3_LEN + ie_offset; ie_len = 0; ++ for (;;) ++ { ++ p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset); ++ if (p != NULL) { ++ if (!memcmp(p+2, WMM_IE, 6)) { ++ ++ pstat->flags |= WLAN_STA_WME; ++ ++ pstat->qos_option = 1; ++ pstat->qos_info = *(p+8); ++ ++ pstat->max_sp_len = (pstat->qos_info>>5)&0x3; ++ ++ if ((pstat->qos_info&0xf) != 0xf) ++ pstat->has_legacy_ac = true; ++ else ++ pstat->has_legacy_ac = false; ++ ++ if (pstat->qos_info&0xf) ++ { ++ if (pstat->qos_info&BIT(0)) ++ pstat->uapsd_vo = BIT(0)|BIT(1); ++ else ++ pstat->uapsd_vo = 0; ++ ++ if (pstat->qos_info&BIT(1)) ++ pstat->uapsd_vi = BIT(0)|BIT(1); ++ else ++ pstat->uapsd_vi = 0; ++ ++ if (pstat->qos_info&BIT(2)) ++ pstat->uapsd_bk = BIT(0)|BIT(1); ++ else ++ pstat->uapsd_bk = 0; ++ ++ if (pstat->qos_info&BIT(3)) ++ pstat->uapsd_be = BIT(0)|BIT(1); ++ else ++ pstat->uapsd_be = 0; ++ ++ } ++ ++ break; ++ } ++ } ++ else { ++ break; ++ } ++ p = p + ie_len + 2; ++ } ++ } ++ ++ /* save HT capabilities in the sta object */ ++ memset(&pstat->htpriv.ht_cap, 0, sizeof(struct rtw_ieee80211_ht_cap)); ++ if (elems.ht_capabilities && elems.ht_capabilities_len >= sizeof(struct rtw_ieee80211_ht_cap)) ++ { ++ pstat->flags |= WLAN_STA_HT; ++ ++ pstat->flags |= WLAN_STA_WME; ++ ++ memcpy(&pstat->htpriv.ht_cap, elems.ht_capabilities, sizeof(struct rtw_ieee80211_ht_cap)); ++ ++ } else ++ pstat->flags &= ~WLAN_STA_HT; ++ ++ ++ if ((pmlmepriv->htpriv.ht_option == false) && (pstat->flags&WLAN_STA_HT)) ++ { ++ status = _STATS_FAILURE_; ++ goto OnAssocReqFail; ++ } ++ ++ ++ if ((pstat->flags & WLAN_STA_HT) && ++ ((pstat->wpa2_pairwise_cipher&WPA_CIPHER_TKIP) || ++ (pstat->wpa_pairwise_cipher&WPA_CIPHER_TKIP))) ++ { ++ DBG_871X("HT: " MAC_FMT " tried to " ++ "use TKIP with HT association\n", MAC_ARG(pstat->hwaddr)); ++ ++ /* status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; */ ++ /* goto OnAssocReqFail; */ ++ } ++ pstat->flags |= WLAN_STA_NONERP; ++ for (i = 0; i < pstat->bssratelen; i++) { ++ if ((pstat->bssrateset[i] & 0x7f) > 22) { ++ pstat->flags &= ~WLAN_STA_NONERP; ++ break; ++ } ++ } ++ ++ if (pstat->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) ++ pstat->flags |= WLAN_STA_SHORT_PREAMBLE; ++ else ++ pstat->flags &= ~WLAN_STA_SHORT_PREAMBLE; ++ ++ ++ ++ if (status != _STATS_SUCCESSFUL_) ++ goto OnAssocReqFail; ++ ++ /* TODO: identify_proprietary_vendor_ie(); */ ++ /* Realtek proprietary IE */ ++ /* identify if this is Broadcom sta */ ++ /* identify if this is ralink sta */ ++ /* Customer proprietary IE */ ++ ++ ++ ++ /* get a unique AID */ ++ if (pstat->aid > 0) { ++ DBG_871X(" old AID %d\n", pstat->aid); ++ } else { ++ for (pstat->aid = 1; pstat->aid <= NUM_STA; pstat->aid++) ++ if (pstapriv->sta_aid[pstat->aid - 1] == NULL) ++ break; ++ ++ /* if (pstat->aid > NUM_STA) { */ ++ if (pstat->aid > pstapriv->max_num_sta) { ++ ++ pstat->aid = 0; ++ ++ DBG_871X(" no room for more AIDs\n"); ++ ++ status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; ++ ++ goto OnAssocReqFail; ++ ++ ++ } else { ++ pstapriv->sta_aid[pstat->aid - 1] = pstat; ++ DBG_871X("allocate new AID = (%d)\n", pstat->aid); ++ } ++ } ++ ++ ++ pstat->state &= (~WIFI_FW_ASSOC_STATE); ++ pstat->state |= WIFI_FW_ASSOC_SUCCESS; ++ ++ spin_lock_bh(&pstapriv->auth_list_lock); ++ if (!list_empty(&pstat->auth_list)) ++ { ++ list_del_init(&pstat->auth_list); ++ pstapriv->auth_list_cnt--; ++ } ++ spin_unlock_bh(&pstapriv->auth_list_lock); ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ if (list_empty(&pstat->asoc_list)) ++ { ++ pstat->expire_to = pstapriv->expire_to; ++ list_add_tail(&pstat->asoc_list, &pstapriv->asoc_list); ++ pstapriv->asoc_list_cnt++; ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ /* now the station is qualified to join our BSS... */ ++ if (pstat && (pstat->state & WIFI_FW_ASSOC_SUCCESS) && (_STATS_SUCCESSFUL_==status)) ++ { ++ /* 1 bss_cap_update & sta_info_update */ ++ bss_cap_update_on_sta_join(padapter, pstat); ++ sta_info_update(padapter, pstat); ++ ++ /* 2 issue assoc rsp before notify station join event. */ ++ if (frame_type == WIFI_ASSOCREQ) ++ issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP); ++ else ++ issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP); ++ ++ spin_lock_bh(&pstat->lock); ++ if (pstat->passoc_req) ++ { ++ kfree(pstat->passoc_req); ++ pstat->passoc_req = NULL; ++ pstat->assoc_req_len = 0; ++ } ++ ++ pstat->passoc_req = rtw_zmalloc(pkt_len); ++ if (pstat->passoc_req) ++ { ++ memcpy(pstat->passoc_req, pframe, pkt_len); ++ pstat->assoc_req_len = pkt_len; ++ } ++ spin_unlock_bh(&pstat->lock); ++ ++ /* 3-(1) report sta add event */ ++ report_add_sta_event(padapter, pstat->hwaddr, pstat->aid); ++ } ++ ++ return _SUCCESS; ++ ++asoc_class2_error: ++ ++ issue_deauth(padapter, (void *)GetAddr2Ptr(pframe), status); ++ ++ return _FAIL; ++ ++OnAssocReqFail: ++ ++ pstat->aid = 0; ++ if (frame_type == WIFI_ASSOCREQ) ++ issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP); ++ else ++ issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP); ++ ++ return _FAIL; ++} ++ ++unsigned int OnAssocRsp(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ uint i; ++ int res; ++ unsigned short status; ++ struct ndis_80211_var_ie * pIE; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ /* struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); */ ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint pkt_len = precv_frame->u.hdr.len; ++ ++ DBG_871X("%s\n", __func__); ++ ++ /* check A1 matches or not */ ++ if (memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN)) ++ return _SUCCESS; ++ ++ if (!(pmlmeinfo->state & (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE))) ++ return _SUCCESS; ++ ++ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) ++ return _SUCCESS; ++ ++ del_timer_sync(&pmlmeext->link_timer); ++ ++ /* status */ ++ if ((status = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN + 2))) > 0) ++ { ++ DBG_871X("assoc reject, status code: %d\n", status); ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ res = -4; ++ goto report_assoc_result; ++ } ++ ++ /* get capabilities */ ++ pmlmeinfo->capability = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); ++ ++ /* set slot time */ ++ pmlmeinfo->slotTime = (pmlmeinfo->capability & BIT(10))? 9: 20; ++ ++ /* AID */ ++ res = pmlmeinfo->aid = (int)(le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN + 4))&0x3fff); ++ ++ /* following are moved to join event callback function */ ++ /* to handle HT, WMM, rate adaptive, update MAC reg */ ++ /* for not to handle the synchronous IO in the tasklet */ ++ for (i = (6 + WLAN_HDR_A3_LEN); i < pkt_len;) ++ { ++ pIE = (struct ndis_80211_var_ie *)(pframe + i); ++ ++ switch (pIE->ElementID) ++ { ++ case _VENDOR_SPECIFIC_IE_: ++ if (!memcmp(pIE->data, WMM_PARA_OUI, 6)) /* WMM */ ++ { ++ WMM_param_handler(padapter, pIE); ++ } ++ break; ++ ++ case _HT_CAPABILITY_IE_: /* HT caps */ ++ HT_caps_handler(padapter, pIE); ++ break; ++ ++ case _HT_EXTRA_INFO_IE_: /* HT info */ ++ HT_info_handler(padapter, pIE); ++ break; ++ ++ case _ERPINFO_IE_: ++ ERP_IE_handler(padapter, pIE); ++ ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++ ++ pmlmeinfo->state &= (~WIFI_FW_ASSOC_STATE); ++ pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; ++ ++ /* Update Basic Rate Table for spec, 2010-12-28 , by thomas */ ++ UpdateBrateTbl(padapter, pmlmeinfo->network.SupportedRates); ++ ++report_assoc_result: ++ if (res > 0) { ++ rtw_buf_update(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len, pframe, pkt_len); ++ } else { ++ rtw_buf_free(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len); ++ } ++ ++ report_join_res(padapter, res); ++ ++ return _SUCCESS; ++} ++ ++unsigned int OnDeAuth(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ unsigned short reason; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ ++ /* check A3 */ ++ if (memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)) ++ return _SUCCESS; ++ ++ reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); ++ ++ DBG_871X("%s Reason code(%d)\n", __func__, reason); ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ++ { ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ /* spin_lock_bh(&(pstapriv->sta_hash_lock)); */ ++ /* rtw_free_stainfo(padapter, psta); */ ++ /* spin_unlock_bh(&(pstapriv->sta_hash_lock)); */ ++ ++ DBG_871X_LEVEL(_drv_always_, "ap recv deauth reason code(%d) sta:%pM\n", ++ reason, GetAddr2Ptr(pframe)); ++ ++ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); ++ if (psta) ++ { ++ u8 updated = false; ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ if (list_empty(&psta->asoc_list) ==false) ++ { ++ list_del_init(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ updated = ap_free_sta(padapter, psta, false, reason); ++ ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ associated_clients_update(padapter, updated); ++ } ++ ++ ++ return _SUCCESS; ++ } ++ else ++ { ++ int ignore_received_deauth = 0; ++ ++ /* Commented by Albert 20130604 */ ++ /* Before sending the auth frame to start the STA/GC mode connection with AP/GO, */ ++ /* we will send the deauth first. */ ++ /* However, the Win8.1 with BRCM Wi-Fi will send the deauth with reason code 6 to us after receieving our deauth. */ ++ /* Added the following code to avoid this case. */ ++ if ((pmlmeinfo->state & WIFI_FW_AUTH_STATE) || ++ (pmlmeinfo->state & WIFI_FW_ASSOC_STATE)) ++ { ++ if (reason == WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA) ++ { ++ ignore_received_deauth = 1; ++ } else if (WLAN_REASON_PREV_AUTH_NOT_VALID == reason) { ++ /* TODO: 802.11r */ ++ ignore_received_deauth = 1; ++ } ++ } ++ ++ DBG_871X_LEVEL(_drv_always_, "sta recv deauth reason code(%d) sta:%pM, ignore = %d\n", ++ reason, GetAddr3Ptr(pframe), ignore_received_deauth); ++ ++ if (0 == ignore_received_deauth) ++ { ++ receive_disconnect(padapter, GetAddr3Ptr(pframe) , reason); ++ } ++ } ++ pmlmepriv->LinkDetectInfo.bBusyTraffic = false; ++ return _SUCCESS; ++ ++} ++ ++unsigned int OnDisassoc(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ unsigned short reason; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ ++ /* check A3 */ ++ if (memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)) ++ return _SUCCESS; ++ ++ reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); ++ ++ DBG_871X("%s Reason code(%d)\n", __func__, reason); ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ++ { ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ /* spin_lock_bh(&(pstapriv->sta_hash_lock)); */ ++ /* rtw_free_stainfo(padapter, psta); */ ++ /* spin_unlock_bh(&(pstapriv->sta_hash_lock)); */ ++ ++ DBG_871X_LEVEL(_drv_always_, "ap recv disassoc reason code(%d) sta:%pM\n", ++ reason, GetAddr2Ptr(pframe)); ++ ++ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); ++ if (psta) ++ { ++ u8 updated = false; ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ if (list_empty(&psta->asoc_list) ==false) ++ { ++ list_del_init(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ updated = ap_free_sta(padapter, psta, false, reason); ++ ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ associated_clients_update(padapter, updated); ++ } ++ ++ return _SUCCESS; ++ } ++ else ++ { ++ DBG_871X_LEVEL(_drv_always_, "sta recv disassoc reason code(%d) sta:%pM\n", ++ reason, GetAddr3Ptr(pframe)); ++ ++ receive_disconnect(padapter, GetAddr3Ptr(pframe), reason); ++ } ++ pmlmepriv->LinkDetectInfo.bBusyTraffic = false; ++ return _SUCCESS; ++ ++} ++ ++unsigned int OnAtim(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ DBG_871X("%s\n", __func__); ++ return _SUCCESS; ++} ++ ++unsigned int on_action_spct(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ unsigned int ret = _FAIL; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ u8 *frame_body = (u8 *)(pframe + sizeof(struct ieee80211_hdr_3addr)); ++ u8 category; ++ u8 action; ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev)); ++ ++ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); ++ ++ if (!psta) ++ goto exit; ++ ++ category = frame_body[0]; ++ if (category != RTW_WLAN_CATEGORY_SPECTRUM_MGMT) ++ goto exit; ++ ++ action = frame_body[1]; ++ switch (action) { ++ case RTW_WLAN_ACTION_SPCT_MSR_REQ: ++ case RTW_WLAN_ACTION_SPCT_MSR_RPRT: ++ case RTW_WLAN_ACTION_SPCT_TPC_REQ: ++ case RTW_WLAN_ACTION_SPCT_TPC_RPRT: ++ case RTW_WLAN_ACTION_SPCT_CHL_SWITCH: ++ break; ++ default: ++ break; ++ } ++ ++exit: ++ return ret; ++} ++ ++unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ u8 *addr; ++ struct sta_info *psta = NULL; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ unsigned char *frame_body; ++ unsigned char category, action; ++ unsigned short tid, status, reason_code = 0; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ DBG_871X("%s\n", __func__); ++ ++ /* check RA matches or not */ ++ if (memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN))/* for if1, sta/ap mode */ ++ return _SUCCESS; ++ ++ if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) ++ if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) ++ return _SUCCESS; ++ ++ addr = GetAddr2Ptr(pframe); ++ psta = rtw_get_stainfo(pstapriv, addr); ++ ++ if (psta == NULL) ++ return _SUCCESS; ++ ++ frame_body = (unsigned char *)(pframe + sizeof(struct ieee80211_hdr_3addr)); ++ ++ category = frame_body[0]; ++ if (category == RTW_WLAN_CATEGORY_BACK)/* representing Block Ack */ ++ { ++ if (!pmlmeinfo->HT_enable) ++ { ++ return _SUCCESS; ++ } ++ ++ action = frame_body[1]; ++ DBG_871X("%s, action =%d\n", __func__, action); ++ switch (action) ++ { ++ case RTW_WLAN_ACTION_ADDBA_REQ: /* ADDBA request */ ++ ++ memcpy(&(pmlmeinfo->ADDBA_req), &(frame_body[2]), sizeof(struct ADDBA_request)); ++ /* process_addba_req(padapter, (u8 *)&(pmlmeinfo->ADDBA_req), GetAddr3Ptr(pframe)); */ ++ process_addba_req(padapter, (u8 *)&(pmlmeinfo->ADDBA_req), addr); ++ ++ if (pmlmeinfo->bAcceptAddbaReq == true) ++ { ++ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_ADDBA_RESP, 0); ++ } ++ else ++ { ++ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_ADDBA_RESP, 37);/* reject ADDBA Req */ ++ } ++ ++ break; ++ ++ case RTW_WLAN_ACTION_ADDBA_RESP: /* ADDBA response */ ++ status = RTW_GET_LE16(&frame_body[3]); ++ tid = ((frame_body[5] >> 2) & 0x7); ++ ++ if (status == 0) ++ { /* successful */ ++ DBG_871X("agg_enable for TID =%d\n", tid); ++ psta->htpriv.agg_enable_bitmap |= 1 << tid; ++ psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); ++ } ++ else ++ { ++ psta->htpriv.agg_enable_bitmap &= ~BIT(tid); ++ } ++ ++ if (psta->state & WIFI_STA_ALIVE_CHK_STATE) ++ { ++ DBG_871X("%s alive check - rx ADDBA response\n", __func__); ++ psta->htpriv.agg_enable_bitmap &= ~BIT(tid); ++ psta->expire_to = pstapriv->expire_to; ++ psta->state ^= WIFI_STA_ALIVE_CHK_STATE; ++ } ++ ++ /* DBG_871X("marc: ADDBA RSP: %x\n", pmlmeinfo->agg_enable_bitmap); */ ++ break; ++ ++ case RTW_WLAN_ACTION_DELBA: /* DELBA */ ++ if ((frame_body[3] & BIT(3)) == 0) ++ { ++ psta->htpriv.agg_enable_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf)); ++ psta->htpriv.candidate_tid_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf)); ++ ++ /* reason_code = frame_body[4] | (frame_body[5] << 8); */ ++ reason_code = RTW_GET_LE16(&frame_body[4]); ++ } ++ else if ((frame_body[3] & BIT(3)) == BIT(3)) ++ { ++ tid = (frame_body[3] >> 4) & 0x0F; ++ ++ preorder_ctrl = &psta->recvreorder_ctrl[tid]; ++ preorder_ctrl->enable = false; ++ preorder_ctrl->indicate_seq = 0xffff; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d indicate_seq:%u\n", __func__, __LINE__, ++ preorder_ctrl->indicate_seq); ++ #endif ++ } ++ ++ DBG_871X("%s(): DELBA: %x(%x)\n", __func__, pmlmeinfo->agg_enable_bitmap, reason_code); ++ /* todo: how to notify the host while receiving DELETE BA */ ++ break; ++ ++ default: ++ break; ++ } ++ } ++ return _SUCCESS; ++} ++ ++static s32 rtw_action_public_decache(union recv_frame *recv_frame, s32 token) ++{ ++ struct adapter *adapter = recv_frame->u.hdr.adapter; ++ struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv); ++ u8 *frame = recv_frame->u.hdr.rx_data; ++ u16 seq_ctrl = ((recv_frame->u.hdr.attrib.seq_num&0xffff) << 4) | ++ (recv_frame->u.hdr.attrib.frag_num & 0xf); ++ ++ if (GetRetry(frame)) { ++ if (token >= 0) { ++ if ((seq_ctrl == mlmeext->action_public_rxseq) ++ && (token == mlmeext->action_public_dialog_token)) ++ { ++ DBG_871X(FUNC_ADPT_FMT" seq_ctrl = 0x%x, rxseq = 0x%x, token:%d\n", ++ FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq, token); ++ return _FAIL; ++ } ++ } else { ++ if (seq_ctrl == mlmeext->action_public_rxseq) { ++ DBG_871X(FUNC_ADPT_FMT" seq_ctrl = 0x%x, rxseq = 0x%x\n", ++ FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq); ++ return _FAIL; ++ } ++ } ++ } ++ ++ mlmeext->action_public_rxseq = seq_ctrl; ++ ++ if (token >= 0) ++ mlmeext->action_public_dialog_token = token; ++ ++ return _SUCCESS; ++} ++ ++static unsigned int on_action_public_p2p(union recv_frame *precv_frame) ++{ ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ u8 *frame_body; ++ u8 dialogToken = 0; ++ ++ frame_body = (unsigned char *)(pframe + sizeof(struct ieee80211_hdr_3addr)); ++ ++ dialogToken = frame_body[7]; ++ ++ if (rtw_action_public_decache(precv_frame, dialogToken) == _FAIL) ++ return _FAIL; ++ ++ return _SUCCESS; ++} ++ ++static unsigned int on_action_public_vendor(union recv_frame *precv_frame) ++{ ++ unsigned int ret = _FAIL; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr); ++ ++ if (!memcmp(frame_body + 2, P2P_OUI, 4)) { ++ ret = on_action_public_p2p(precv_frame); ++ } ++ ++ return ret; ++} ++ ++static unsigned int on_action_public_default(union recv_frame *precv_frame, u8 action) ++{ ++ unsigned int ret = _FAIL; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ uint frame_len = precv_frame->u.hdr.len; ++ u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr); ++ u8 token; ++ struct adapter *adapter = precv_frame->u.hdr.adapter; ++ int cnt = 0; ++ char msg[64]; ++ ++ token = frame_body[2]; ++ ++ if (rtw_action_public_decache(precv_frame, token) == _FAIL) ++ goto exit; ++ ++ cnt += sprintf((msg+cnt), "%s(token:%u)", action_public_str(action), token); ++ rtw_cfg80211_rx_action(adapter, pframe, frame_len, msg); ++ ++ ret = _SUCCESS; ++ ++exit: ++ return ret; ++} ++ ++unsigned int on_action_public(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ unsigned int ret = _FAIL; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr); ++ u8 category, action; ++ ++ /* check RA matches or not */ ++ if (memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN)) ++ goto exit; ++ ++ category = frame_body[0]; ++ if (category != RTW_WLAN_CATEGORY_PUBLIC) ++ goto exit; ++ ++ action = frame_body[1]; ++ switch (action) { ++ case ACT_PUBLIC_VENDOR: ++ ret = on_action_public_vendor(precv_frame); ++ break; ++ default: ++ ret = on_action_public_default(precv_frame, action); ++ break; ++ } ++ ++exit: ++ return ret; ++} ++ ++unsigned int OnAction_ht(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr); ++ u8 category, action; ++ ++ /* check RA matches or not */ ++ if (memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN)) ++ goto exit; ++ ++ category = frame_body[0]; ++ if (category != RTW_WLAN_CATEGORY_HT) ++ goto exit; ++ ++ action = frame_body[1]; ++ switch (action) { ++ case RTW_WLAN_ACTION_HT_COMPRESS_BEAMFORMING: ++ break; ++ default: ++ break; ++ } ++ ++exit: ++ ++ return _SUCCESS; ++} ++ ++unsigned int OnAction_sa_query(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ unsigned short tid; ++ /* Baron */ ++ ++ DBG_871X("OnAction_sa_query\n"); ++ ++ switch (pframe[WLAN_HDR_A3_LEN+1]) ++ { ++ case 0: /* SA Query req */ ++ memcpy(&tid, &pframe[WLAN_HDR_A3_LEN+2], sizeof(unsigned short)); ++ DBG_871X("OnAction_sa_query request, action =%d, tid =%04x\n", pframe[WLAN_HDR_A3_LEN+1], tid); ++ issue_action_SA_Query(padapter, GetAddr2Ptr(pframe), 1, tid); ++ break; ++ ++ case 1: /* SA Query rsp */ ++ del_timer_sync(&pmlmeext->sa_query_timer); ++ DBG_871X("OnAction_sa_query response, action =%d, tid =%04x, cancel timer\n", pframe[WLAN_HDR_A3_LEN+1], pframe[WLAN_HDR_A3_LEN+2]); ++ break; ++ default: ++ break; ++ } ++ if (0) ++ { ++ int pp; ++ printk("pattrib->pktlen = %d =>", pattrib->pkt_len); ++ for (pp = 0;pp< pattrib->pkt_len; pp++) ++ printk(" %02x ", pframe[pp]); ++ printk("\n"); ++ } ++ ++ return _SUCCESS; ++} ++ ++unsigned int OnAction(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ int i; ++ unsigned char category; ++ struct action_handler *ptable; ++ unsigned char *frame_body; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ ++ frame_body = (unsigned char *)(pframe + sizeof(struct ieee80211_hdr_3addr)); ++ ++ category = frame_body[0]; ++ ++ for (i = 0; i < sizeof(OnAction_tbl)/sizeof(struct action_handler); i++) ++ { ++ ptable = &OnAction_tbl[i]; ++ ++ if (category == ptable->num) ++ ptable->func(padapter, precv_frame); ++ ++ } ++ ++ return _SUCCESS; ++ ++} ++ ++unsigned int DoReserved(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ ++ /* DBG_871X("rcvd mgt frame(%x, %x)\n", (GetFrameSubType(pframe) >> 4), *(unsigned int *)GetAddr1Ptr(pframe)); */ ++ return _SUCCESS; ++} ++ ++static struct xmit_frame *_alloc_mgtxmitframe(struct xmit_priv *pxmitpriv, bool once) ++{ ++ struct xmit_frame *pmgntframe; ++ struct xmit_buf *pxmitbuf; ++ ++ if (once) ++ pmgntframe = rtw_alloc_xmitframe_once(pxmitpriv); ++ else ++ pmgntframe = rtw_alloc_xmitframe_ext(pxmitpriv); ++ ++ if (pmgntframe == NULL) { ++ DBG_871X(FUNC_ADPT_FMT" alloc xmitframe fail, once:%d\n", FUNC_ADPT_ARG(pxmitpriv->adapter), once); ++ goto exit; ++ } ++ ++ if ((pxmitbuf = rtw_alloc_xmitbuf_ext(pxmitpriv)) == NULL) { ++ DBG_871X(FUNC_ADPT_FMT" alloc xmitbuf fail\n", FUNC_ADPT_ARG(pxmitpriv->adapter)); ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ pmgntframe = NULL; ++ goto exit; ++ } ++ ++ pmgntframe->frame_tag = MGNT_FRAMETAG; ++ pmgntframe->pxmitbuf = pxmitbuf; ++ pmgntframe->buf_addr = pxmitbuf->pbuf; ++ pxmitbuf->priv_data = pmgntframe; ++ ++exit: ++ return pmgntframe; ++ ++} ++ ++inline struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv) ++{ ++ return _alloc_mgtxmitframe(pxmitpriv, false); ++} ++ ++/**************************************************************************** ++ ++Following are some TX fuctions for WiFi MLME ++ ++*****************************************************************************/ ++ ++void update_mgnt_tx_rate(struct adapter *padapter, u8 rate) ++{ ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ ++ pmlmeext->tx_rate = rate; ++ /* DBG_871X("%s(): rate = %x\n", __func__, rate); */ ++} ++ ++void update_mgntframe_attrib(struct adapter *padapter, struct pkt_attrib *pattrib) ++{ ++ u8 wireless_mode; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ ++ /* memset((u8 *)(pattrib), 0, sizeof(struct pkt_attrib)); */ ++ ++ pattrib->hdrlen = 24; ++ pattrib->nr_frags = 1; ++ pattrib->priority = 7; ++ pattrib->mac_id = 0; ++ pattrib->qsel = 0x12; ++ ++ pattrib->pktlen = 0; ++ ++ if (pmlmeext->tx_rate == IEEE80211_CCK_RATE_1MB) ++ wireless_mode = WIRELESS_11B; ++ else ++ wireless_mode = WIRELESS_11G; ++ pattrib->raid = rtw_get_mgntframe_raid(padapter, wireless_mode); ++ pattrib->rate = pmlmeext->tx_rate; ++ ++ pattrib->encrypt = _NO_PRIVACY_; ++ pattrib->bswenc = false; ++ ++ pattrib->qos_en = false; ++ pattrib->ht_en = false; ++ pattrib->bwmode = CHANNEL_WIDTH_20; ++ pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ pattrib->sgi = false; ++ ++ pattrib->seqnum = pmlmeext->mgnt_seq; ++ ++ pattrib->retry_ctrl = true; ++ ++ pattrib->mbssid = 0; ++ ++} ++ ++void update_mgntframe_attrib_addr(struct adapter *padapter, struct xmit_frame *pmgntframe) ++{ ++ u8 *pframe; ++ struct pkt_attrib *pattrib = &pmgntframe->attrib; ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ ++ memcpy(pattrib->ra, GetAddr1Ptr(pframe), ETH_ALEN); ++ memcpy(pattrib->ta, GetAddr2Ptr(pframe), ETH_ALEN); ++} ++ ++void dump_mgntframe(struct adapter *padapter, struct xmit_frame *pmgntframe) ++{ ++ if (padapter->bSurpriseRemoved == true || ++ padapter->bDriverStopped == true) ++ { ++ rtw_free_xmitbuf(&padapter->xmitpriv, pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(&padapter->xmitpriv, pmgntframe); ++ return; ++ } ++ ++ rtw_hal_mgnt_xmit(padapter, pmgntframe); ++} ++ ++s32 dump_mgntframe_and_wait(struct adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms) ++{ ++ s32 ret = _FAIL; ++ _irqL irqL; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf; ++ struct submit_ctx sctx; ++ ++ if (padapter->bSurpriseRemoved == true || ++ padapter->bDriverStopped == true) ++ { ++ rtw_free_xmitbuf(&padapter->xmitpriv, pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(&padapter->xmitpriv, pmgntframe); ++ return ret; ++ } ++ ++ rtw_sctx_init(&sctx, timeout_ms); ++ pxmitbuf->sctx = &sctx; ++ ++ ret = rtw_hal_mgnt_xmit(padapter, pmgntframe); ++ ++ if (ret == _SUCCESS) ++ ret = rtw_sctx_wait(&sctx, __func__); ++ ++ spin_lock_irqsave(&pxmitpriv->lock_sctx, irqL); ++ pxmitbuf->sctx = NULL; ++ spin_unlock_irqrestore(&pxmitpriv->lock_sctx, irqL); ++ ++ return ret; ++} ++ ++s32 dump_mgntframe_and_wait_ack(struct adapter *padapter, struct xmit_frame *pmgntframe) ++{ ++ static u8 seq_no = 0; ++ s32 ret = _FAIL; ++ u32 timeout_ms = 500;/* 500ms */ ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ if (padapter->bSurpriseRemoved == true || ++ padapter->bDriverStopped == true) ++ { ++ rtw_free_xmitbuf(&padapter->xmitpriv, pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(&padapter->xmitpriv, pmgntframe); ++ return -1; ++ } ++ ++ if (mutex_lock_interruptible(&pxmitpriv->ack_tx_mutex) == 0) { ++ pxmitpriv->ack_tx = true; ++ pxmitpriv->seq_no = seq_no++; ++ pmgntframe->ack_report = 1; ++ if (rtw_hal_mgnt_xmit(padapter, pmgntframe) == _SUCCESS) { ++ ret = rtw_ack_tx_wait(pxmitpriv, timeout_ms); ++ } ++ ++ pxmitpriv->ack_tx = false; ++ mutex_unlock(&pxmitpriv->ack_tx_mutex); ++ } ++ ++ return ret; ++} ++ ++static int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode) ++{ ++ u8 *ssid_ie; ++ sint ssid_len_ori; ++ int len_diff = 0; ++ ++ ssid_ie = rtw_get_ie(ies, WLAN_EID_SSID, &ssid_len_ori, ies_len); ++ ++ /* DBG_871X("%s hidden_ssid_mode:%u, ssid_ie:%p, ssid_len_ori:%d\n", __func__, hidden_ssid_mode, ssid_ie, ssid_len_ori); */ ++ ++ if (ssid_ie && ssid_len_ori>0) ++ { ++ switch (hidden_ssid_mode) ++ { ++ case 1: ++ { ++ u8 *next_ie = ssid_ie + 2 + ssid_len_ori; ++ u32 remain_len = 0; ++ ++ remain_len = ies_len -(next_ie-ies); ++ ++ ssid_ie[1] = 0; ++ memcpy(ssid_ie+2, next_ie, remain_len); ++ len_diff -= ssid_len_ori; ++ ++ break; ++ } ++ case 2: ++ memset(&ssid_ie[2], 0, ssid_len_ori); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return len_diff; ++} ++ ++void issue_beacon(struct adapter *padapter, int timeout_ms) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ unsigned int rate_len; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); ++ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ /* DBG_871X("%s\n", __func__); */ ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ DBG_871X("%s, alloc mgnt frame fail\n", __func__); ++ return; ++ } ++ ++ spin_lock_bh(&pmlmepriv->bcn_update_lock); ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ pattrib->qsel = 0x10; ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ ++ ++ fctrl = &(pwlanhdr->frame_control); ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); ++ /* pmlmeext->mgnt_seq++; */ ++ SetFrameSubType(pframe, WIFI_BEACON); ++ ++ pframe += sizeof(struct ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof (struct ieee80211_hdr_3addr); ++ ++ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) ++ { ++ /* DBG_871X("ie len =%d\n", cur_network->IELength); */ ++ { ++ int len_diff; ++ memcpy(pframe, cur_network->IEs, cur_network->IELength); ++ len_diff = update_hidden_ssid( ++ pframe+_BEACON_IE_OFFSET_ ++ , cur_network->IELength-_BEACON_IE_OFFSET_ ++ , pmlmeinfo->hidden_ssid_mode ++ ); ++ pframe += (cur_network->IELength+len_diff); ++ pattrib->pktlen += (cur_network->IELength+len_diff); ++ } ++ ++ { ++ u8 *wps_ie; ++ uint wps_ielen; ++ u8 sr = 0; ++ wps_ie = rtw_get_wps_ie(pmgntframe->buf_addr+TXDESC_OFFSET+sizeof (struct ieee80211_hdr_3addr)+_BEACON_IE_OFFSET_, ++ pattrib->pktlen-sizeof (struct ieee80211_hdr_3addr)-_BEACON_IE_OFFSET_, NULL, &wps_ielen); ++ if (wps_ie && wps_ielen>0) { ++ rtw_get_wps_attr_content(wps_ie, wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, (u8 *)(&sr), NULL); ++ } ++ if (sr != 0) ++ set_fwstate(pmlmepriv, WIFI_UNDER_WPS); ++ else ++ _clr_fwstate_(pmlmepriv, WIFI_UNDER_WPS); ++ } ++ ++ goto _issue_bcn; ++ ++ } ++ ++ /* below for ad-hoc mode */ ++ ++ /* timestamp will be inserted by hardware */ ++ pframe += 8; ++ pattrib->pktlen += 8; ++ ++ /* beacon interval: 2 bytes */ ++ ++ memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ /* capability info: 2 bytes */ ++ ++ memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ /* SSID */ ++ pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen); ++ ++ /* supported rates... */ ++ rate_len = rtw_get_rateset_len(cur_network->SupportedRates); ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8)? 8: rate_len), cur_network->SupportedRates, &pattrib->pktlen); ++ ++ /* DS parameter set */ ++ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pattrib->pktlen); ++ ++ /* if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) */ ++ { ++ u8 erpinfo = 0; ++ u32 ATIMWindow; ++ /* IBSS Parameter Set... */ ++ /* ATIMWindow = cur->Configuration.ATIMWindow; */ ++ ATIMWindow = 0; ++ pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pattrib->pktlen); ++ ++ /* ERP IE */ ++ pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pattrib->pktlen); ++ } ++ ++ ++ /* EXTERNDED SUPPORTED RATE */ ++ if (rate_len > 8) ++ { ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pattrib->pktlen); ++ } ++ ++ ++ /* todo:HT for adhoc */ ++ ++_issue_bcn: ++ ++ pmlmepriv->update_bcn = false; ++ ++ spin_unlock_bh(&pmlmepriv->bcn_update_lock); ++ ++ if ((pattrib->pktlen + TXDESC_SIZE) > 512) ++ { ++ DBG_871X("beacon frame too large\n"); ++ return; ++ } ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ /* DBG_871X("issue bcn_sz =%d\n", pattrib->last_txcmdsz); */ ++ if (timeout_ms > 0) ++ dump_mgntframe_and_wait(padapter, pmgntframe, timeout_ms); ++ else ++ dump_mgntframe(padapter, pmgntframe); ++ ++} ++ ++void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p_probereq) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ unsigned char *mac, *bssid; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ ++ u8 *pwps_ie; ++ uint wps_ielen; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); ++ unsigned int rate_len; ++ ++ /* DBG_871X("%s\n", __func__); */ ++ ++ if (da == NULL) ++ return; ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ DBG_871X("%s, alloc mgnt frame fail\n", __func__); ++ return; ++ } ++ ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ ++ mac = myid(&(padapter->eeprompriv)); ++ bssid = cur_network->MacAddress; ++ ++ fctrl = &(pwlanhdr->frame_control); ++ *(fctrl) = 0; ++ memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, mac, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(fctrl, WIFI_PROBERSP); ++ ++ pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr); ++ pattrib->pktlen = pattrib->hdrlen; ++ pframe += pattrib->hdrlen; ++ ++ ++ if (cur_network->IELength>MAX_IE_SZ) ++ return; ++ ++ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) ++ { ++ pwps_ie = rtw_get_wps_ie(cur_network->IEs+_FIXED_IE_LENGTH_, cur_network->IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen); ++ ++ /* inerset & update wps_probe_resp_ie */ ++ if ((pmlmepriv->wps_probe_resp_ie!= NULL) && pwps_ie && (wps_ielen>0)) ++ { ++ uint wps_offset, remainder_ielen; ++ u8 *premainder_ie; ++ ++ wps_offset = (uint)(pwps_ie - cur_network->IEs); ++ ++ premainder_ie = pwps_ie + wps_ielen; ++ ++ remainder_ielen = cur_network->IELength - wps_offset - wps_ielen; ++ ++ memcpy(pframe, cur_network->IEs, wps_offset); ++ pframe += wps_offset; ++ pattrib->pktlen += wps_offset; ++ ++ wps_ielen = (uint)pmlmepriv->wps_probe_resp_ie[1];/* to get ie data len */ ++ if ((wps_offset+wps_ielen+2)<=MAX_IE_SZ) ++ { ++ memcpy(pframe, pmlmepriv->wps_probe_resp_ie, wps_ielen+2); ++ pframe += wps_ielen+2; ++ pattrib->pktlen += wps_ielen+2; ++ } ++ ++ if ((wps_offset+wps_ielen+2+remainder_ielen)<=MAX_IE_SZ) ++ { ++ memcpy(pframe, premainder_ie, remainder_ielen); ++ pframe += remainder_ielen; ++ pattrib->pktlen += remainder_ielen; ++ } ++ } ++ else ++ { ++ memcpy(pframe, cur_network->IEs, cur_network->IELength); ++ pframe += cur_network->IELength; ++ pattrib->pktlen += cur_network->IELength; ++ } ++ ++ /* retrieve SSID IE from cur_network->Ssid */ ++ { ++ u8 *ssid_ie; ++ sint ssid_ielen; ++ sint ssid_ielen_diff; ++ u8 buf[MAX_IE_SZ]; ++ u8 *ies = pmgntframe->buf_addr+TXDESC_OFFSET+sizeof(struct ieee80211_hdr_3addr); ++ ++ ssid_ie = rtw_get_ie(ies+_FIXED_IE_LENGTH_, _SSID_IE_, &ssid_ielen, ++ (pframe-ies)-_FIXED_IE_LENGTH_); ++ ++ ssid_ielen_diff = cur_network->Ssid.SsidLength - ssid_ielen; ++ ++ if (ssid_ie && cur_network->Ssid.SsidLength) { ++ uint remainder_ielen; ++ u8 *remainder_ie; ++ remainder_ie = ssid_ie+2; ++ remainder_ielen = (pframe-remainder_ie); ++ ++ if (remainder_ielen > MAX_IE_SZ) { ++ DBG_871X_LEVEL(_drv_warning_, FUNC_ADPT_FMT" remainder_ielen > MAX_IE_SZ\n", FUNC_ADPT_ARG(padapter)); ++ remainder_ielen = MAX_IE_SZ; ++ } ++ ++ memcpy(buf, remainder_ie, remainder_ielen); ++ memcpy(remainder_ie+ssid_ielen_diff, buf, remainder_ielen); ++ *(ssid_ie+1) = cur_network->Ssid.SsidLength; ++ memcpy(ssid_ie+2, cur_network->Ssid.Ssid, cur_network->Ssid.SsidLength); ++ ++ pframe += ssid_ielen_diff; ++ pattrib->pktlen += ssid_ielen_diff; ++ } ++ } ++ } ++ else ++ { ++ /* timestamp will be inserted by hardware */ ++ pframe += 8; ++ pattrib->pktlen += 8; ++ ++ /* beacon interval: 2 bytes */ ++ ++ memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ /* capability info: 2 bytes */ ++ ++ memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ /* below for ad-hoc mode */ ++ ++ /* SSID */ ++ pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen); ++ ++ /* supported rates... */ ++ rate_len = rtw_get_rateset_len(cur_network->SupportedRates); ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8)? 8: rate_len), cur_network->SupportedRates, &pattrib->pktlen); ++ ++ /* DS parameter set */ ++ pframe =rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pattrib->pktlen); ++ ++ if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) ++ { ++ u8 erpinfo = 0; ++ u32 ATIMWindow; ++ /* IBSS Parameter Set... */ ++ /* ATIMWindow = cur->Configuration.ATIMWindow; */ ++ ATIMWindow = 0; ++ pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pattrib->pktlen); ++ ++ /* ERP IE */ ++ pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pattrib->pktlen); ++ } ++ ++ ++ /* EXTERNDED SUPPORTED RATE */ ++ if (rate_len > 8) ++ { ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pattrib->pktlen); ++ } ++ ++ ++ /* todo:HT for adhoc */ ++ ++ } ++ ++#ifdef CONFIG_AUTO_AP_MODE ++{ ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ DBG_871X("(%s)\n", __func__); ++ ++ /* check rc station */ ++ psta = rtw_get_stainfo(pstapriv, da); ++ if (psta && psta->isrc && psta->pid>0) ++ { ++ u8 RC_OUI[4]={0x00, 0xE0, 0x4C, 0x0A}; ++ u8 RC_INFO[14] = {0}; ++ /* EID[1] + EID_LEN[1] + RC_OUI[4] + MAC[6] + PairingID[2] + ChannelNum[2] */ ++ u16 cu_ch = (u16)cur_network->Configuration.DSConfig; ++ ++ DBG_871X("%s, reply rc(pid = 0x%x) device "MAC_FMT" in ch =%d\n", __func__, ++ psta->pid, MAC_ARG(psta->hwaddr), cu_ch); ++ ++ /* append vendor specific ie */ ++ memcpy(RC_INFO, RC_OUI, sizeof(RC_OUI)); ++ memcpy(&RC_INFO[4], mac, ETH_ALEN); ++ memcpy(&RC_INFO[10], (u8 *)&psta->pid, 2); ++ memcpy(&RC_INFO[12], (u8 *)&cu_ch, 2); ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, sizeof(RC_INFO), RC_INFO, &pattrib->pktlen); ++ } ++} ++#endif /* CONFIG_AUTO_AP_MODE */ ++ ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ ++ dump_mgntframe(padapter, pmgntframe); ++ ++ return; ++ ++} ++ ++static int _issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da, u8 ch, bool append_wps, int wait_ack) ++{ ++ int ret = _FAIL; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ unsigned char *mac; ++ unsigned char bssrate[NumRates]; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ int bssrate_len = 0; ++ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+issue_probereq\n")); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ goto exit; ++ } ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ ++ mac = myid(&(padapter->eeprompriv)); ++ ++ fctrl = &(pwlanhdr->frame_control); ++ *(fctrl) = 0; ++ ++ if (da) ++ { ++ /* unicast probe request frame */ ++ memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, da, ETH_ALEN); ++ } ++ else ++ { ++ /* broadcast probe request frame */ ++ memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN); ++ } ++ ++ memcpy(pwlanhdr->addr2, mac, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_PROBEREQ); ++ ++ pframe += sizeof (struct ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof (struct ieee80211_hdr_3addr); ++ ++ if (pssid) ++ pframe = rtw_set_ie(pframe, _SSID_IE_, pssid->SsidLength, pssid->Ssid, &(pattrib->pktlen)); ++ else ++ pframe = rtw_set_ie(pframe, _SSID_IE_, 0, NULL, &(pattrib->pktlen)); ++ ++ get_rate_set(padapter, bssrate, &bssrate_len); ++ ++ if (bssrate_len > 8) ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen)); ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen)); ++ } ++ else ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen)); ++ } ++ ++ if (ch) ++ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, &ch, &pattrib->pktlen); ++ ++ if (append_wps) { ++ /* add wps_ie for wps2.0 */ ++ if (pmlmepriv->wps_probe_req_ie_len>0 && pmlmepriv->wps_probe_req_ie) { ++ memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len); ++ pframe += pmlmepriv->wps_probe_req_ie_len; ++ pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len; ++ } ++ } ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("issuing probe_req, tx_len =%d\n", pattrib->last_txcmdsz)); ++ ++ if (wait_ack) { ++ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); ++ } else { ++ dump_mgntframe(padapter, pmgntframe); ++ ret = _SUCCESS; ++ } ++ ++exit: ++ return ret; ++} ++ ++inline void issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da) ++{ ++ _issue_probereq(padapter, pssid, da, 0, 1, false); ++} ++ ++int issue_probereq_ex(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da, u8 ch, bool append_wps, ++ int try_cnt, int wait_ms) ++{ ++ int ret; ++ int i = 0; ++ ++ do ++ { ++ ret = _issue_probereq(padapter, pssid, da, ch, append_wps, wait_ms>0?true:false); ++ ++ i++; ++ ++ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) ++ break; ++ ++ if (i < try_cnt && wait_ms > 0 && ret == _FAIL) ++ msleep(wait_ms); ++ ++ }while ((ixmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ __le16 le_tmp; ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_control); ++ *(fctrl) = 0; ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_AUTH); ++ ++ pframe += sizeof(struct ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); ++ ++ ++ if (psta)/* for AP mode */ ++ { ++ memcpy(pwlanhdr->addr1, psta->hwaddr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ /* setting auth algo number */ ++ val16 = (u16)psta->authalg; ++ ++ if (status != _STATS_SUCCESSFUL_) ++ val16 = 0; ++ ++ if (val16) { ++ use_shared_key = 1; ++ } ++ le_tmp = cpu_to_le16(val16); ++ ++ pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&le_tmp, &(pattrib->pktlen)); ++ ++ /* setting auth seq number */ ++ val16 =(u16)psta->auth_seq; ++ le_tmp = cpu_to_le16(val16); ++ pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&le_tmp, &(pattrib->pktlen)); ++ ++ /* setting status code... */ ++ val16 = status; ++ le_tmp = cpu_to_le16(val16); ++ pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&le_tmp, &(pattrib->pktlen)); ++ ++ /* added challenging text... */ ++ if ((psta->auth_seq == 2) && (psta->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) ++ { ++ pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, psta->chg_txt, &(pattrib->pktlen)); ++ } ++ } ++ else ++ { ++ memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ ++ /* setting auth algo number */ ++ val16 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared)? 1: 0;/* 0:OPEN System, 1:Shared key */ ++ if (val16) { ++ use_shared_key = 1; ++ } ++ le_tmp = cpu_to_le16(val16); ++ /* DBG_871X("%s auth_algo = %s auth_seq =%d\n", __func__, (pmlmeinfo->auth_algo == 0)?"OPEN":"SHARED", pmlmeinfo->auth_seq); */ ++ ++ /* setting IV for auth seq #3 */ ++ if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) ++ { ++ __le32 le_tmp32; ++ ++ /* DBG_871X("==> iv(%d), key_index(%d)\n", pmlmeinfo->iv, pmlmeinfo->key_index); */ ++ val32 = ((pmlmeinfo->iv++) | (pmlmeinfo->key_index << 30)); ++ le_tmp32 = cpu_to_le32(val32); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&le_tmp32, &(pattrib->pktlen)); ++ ++ pattrib->iv_len = 4; ++ } ++ ++ pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&le_tmp, &(pattrib->pktlen)); ++ ++ /* setting auth seq number */ ++ le_tmp = cpu_to_le16(pmlmeinfo->auth_seq); ++ pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&le_tmp, &(pattrib->pktlen)); ++ ++ ++ /* setting status code... */ ++ le_tmp = cpu_to_le16(status); ++ pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&le_tmp, &(pattrib->pktlen)); ++ ++ /* then checking to see if sending challenging text... */ ++ if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) ++ { ++ pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, pmlmeinfo->chg_txt, &(pattrib->pktlen)); ++ ++ SetPrivacy(fctrl); ++ ++ pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr); ++ ++ pattrib->encrypt = _WEP40_; ++ ++ pattrib->icv_len = 4; ++ ++ pattrib->pktlen += pattrib->icv_len; ++ ++ } ++ ++ } ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ rtw_wep_encrypt(padapter, (u8 *)pmgntframe); ++ DBG_871X("%s\n", __func__); ++ dump_mgntframe(padapter, pmgntframe); ++ ++ return; ++} ++ ++ ++void issue_asocrsp(struct adapter *padapter, unsigned short status, struct sta_info *pstat, int pkt_type) ++{ ++ struct xmit_frame *pmgntframe; ++ struct ieee80211_hdr *pwlanhdr; ++ struct pkt_attrib *pattrib; ++ unsigned char *pbuf, *pframe; ++ unsigned short val; ++ __le16 *fctrl; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); ++ u8 *ie = pnetwork->IEs; ++ __le16 lestatus, le_tmp; ++ ++ DBG_871X("%s\n", __func__); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_control); ++ *(fctrl) = 0; ++ ++ memcpy((void *)GetAddr1Ptr(pwlanhdr), pstat->hwaddr, ETH_ALEN); ++ memcpy((void *)GetAddr2Ptr(pwlanhdr), myid(&(padapter->eeprompriv)), ETH_ALEN); ++ memcpy((void *)GetAddr3Ptr(pwlanhdr), get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ if ((pkt_type == WIFI_ASSOCRSP) || (pkt_type == WIFI_REASSOCRSP)) ++ SetFrameSubType(pwlanhdr, pkt_type); ++ else ++ return; ++ ++ pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr); ++ pattrib->pktlen += pattrib->hdrlen; ++ pframe += pattrib->hdrlen; ++ ++ /* capability */ ++ val = *(unsigned short *)rtw_get_capability_from_ie(ie); ++ ++ pframe = rtw_set_fixed_ie(pframe, _CAPABILITY_ , (unsigned char *)&val, &(pattrib->pktlen)); ++ ++ lestatus = cpu_to_le16(status); ++ pframe = rtw_set_fixed_ie(pframe , _STATUS_CODE_ , (unsigned char *)&lestatus, &(pattrib->pktlen)); ++ ++ le_tmp = cpu_to_le16(pstat->aid | BIT(14) | BIT(15)); ++ pframe = rtw_set_fixed_ie(pframe, _ASOC_ID_ , (unsigned char *)&le_tmp, &(pattrib->pktlen)); ++ ++ if (pstat->bssratelen <= 8) ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, pstat->bssratelen, pstat->bssrateset, &(pattrib->pktlen)); ++ } ++ else ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pstat->bssrateset, &(pattrib->pktlen)); ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (pstat->bssratelen-8), pstat->bssrateset+8, &(pattrib->pktlen)); ++ } ++ ++ if ((pstat->flags & WLAN_STA_HT) && (pmlmepriv->htpriv.ht_option)) ++ { ++ uint ie_len = 0; ++ ++ /* FILL HT CAP INFO IE */ ++ /* p = hostapd_eid_ht_capabilities_info(hapd, p); */ ++ pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); ++ if (pbuf && ie_len>0) ++ { ++ memcpy(pframe, pbuf, ie_len+2); ++ pframe += (ie_len+2); ++ pattrib->pktlen +=(ie_len+2); ++ } ++ ++ /* FILL HT ADD INFO IE */ ++ /* p = hostapd_eid_ht_operation(hapd, p); */ ++ pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); ++ if (pbuf && ie_len>0) ++ { ++ memcpy(pframe, pbuf, ie_len+2); ++ pframe += (ie_len+2); ++ pattrib->pktlen +=(ie_len+2); ++ } ++ ++ } ++ ++ /* FILL WMM IE */ ++ if ((pstat->flags & WLAN_STA_WME) && (pmlmepriv->qospriv.qos_option)) ++ { ++ uint ie_len = 0; ++ unsigned char WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; ++ ++ for (pbuf = ie + _BEACON_IE_OFFSET_; ;pbuf+= (ie_len + 2)) ++ { ++ pbuf = rtw_get_ie(pbuf, _VENDOR_SPECIFIC_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); ++ if (pbuf && !memcmp(pbuf+2, WMM_PARA_IE, 6)) ++ { ++ memcpy(pframe, pbuf, ie_len+2); ++ pframe += (ie_len+2); ++ pattrib->pktlen +=(ie_len+2); ++ ++ break; ++ } ++ ++ if ((pbuf == NULL) || (ie_len == 0)) ++ { ++ break; ++ } ++ } ++ ++ } ++ ++ ++ if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) ++ { ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6 , REALTEK_96B_IE, &(pattrib->pktlen)); ++ } ++ ++ /* add WPS IE ie for wps 2.0 */ ++ if (pmlmepriv->wps_assoc_resp_ie && pmlmepriv->wps_assoc_resp_ie_len>0) ++ { ++ memcpy(pframe, pmlmepriv->wps_assoc_resp_ie, pmlmepriv->wps_assoc_resp_ie_len); ++ ++ pframe += pmlmepriv->wps_assoc_resp_ie_len; ++ pattrib->pktlen += pmlmepriv->wps_assoc_resp_ie_len; ++ } ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++void issue_assocreq(struct adapter *padapter) ++{ ++ int ret = _FAIL; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ __le16 val16; ++ unsigned int i, j, index = 0; ++ unsigned char bssrate[NumRates], sta_bssrate[NumRates]; ++ struct ndis_80211_var_ie * pIE; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ int bssrate_len = 0, sta_bssrate_len = 0; ++ u8 vs_ie_length = 0; ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ goto exit; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_control); ++ *(fctrl) = 0; ++ memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ASSOCREQ); ++ ++ pframe += sizeof(struct ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); ++ ++ /* caps */ ++ memcpy(pframe, rtw_get_capability_from_ie(pmlmeinfo->network.IEs), 2); ++ ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ /* listen interval */ ++ /* todo: listen interval for power saving */ ++ val16 = cpu_to_le16(3); ++ memcpy(pframe , (unsigned char *)&val16, 2); ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ /* SSID */ ++ pframe = rtw_set_ie(pframe, _SSID_IE_, pmlmeinfo->network.Ssid.SsidLength, pmlmeinfo->network.Ssid.Ssid, &(pattrib->pktlen)); ++ ++ /* supported rate & extended supported rate */ ++ ++ /* Check if the AP's supported rates are also supported by STA. */ ++ get_rate_set(padapter, sta_bssrate, &sta_bssrate_len); ++ /* DBG_871X("sta_bssrate_len =%d\n", sta_bssrate_len); */ ++ ++ if (pmlmeext->cur_channel == 14)/* for JAPAN, channel 14 can only uses B Mode(CCK) */ ++ { ++ sta_bssrate_len = 4; ++ } ++ ++ ++ /* for (i = 0; i < sta_bssrate_len; i++) { */ ++ /* DBG_871X("sta_bssrate[%d]=%02X\n", i, sta_bssrate[i]); */ ++ /* */ ++ ++ for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { ++ if (pmlmeinfo->network.SupportedRates[i] == 0) break; ++ DBG_871X("network.SupportedRates[%d]=%02X\n", i, pmlmeinfo->network.SupportedRates[i]); ++ } ++ ++ ++ for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { ++ if (pmlmeinfo->network.SupportedRates[i] == 0) break; ++ ++ ++ /* Check if the AP's supported rates are also supported by STA. */ ++ for (j = 0; j < sta_bssrate_len; j++) { ++ /* Avoid the proprietary data rate (22Mbps) of Handlink WSG-4000 AP */ ++ if ((pmlmeinfo->network.SupportedRates[i]|IEEE80211_BASIC_RATE_MASK) ++ == (sta_bssrate[j]|IEEE80211_BASIC_RATE_MASK)) { ++ /* DBG_871X("match i = %d, j =%d\n", i, j); */ ++ break; ++ } else { ++ /* DBG_871X("not match: %02X != %02X\n", (pmlmeinfo->network.SupportedRates[i]|IEEE80211_BASIC_RATE_MASK), (sta_bssrate[j]|IEEE80211_BASIC_RATE_MASK)); */ ++ } ++ } ++ ++ if (j == sta_bssrate_len) { ++ /* the rate is not supported by STA */ ++ DBG_871X("%s(): the rate[%d]=%02X is not supported by STA!\n", __func__, i, pmlmeinfo->network.SupportedRates[i]); ++ } else { ++ /* the rate is supported by STA */ ++ bssrate[index++] = pmlmeinfo->network.SupportedRates[i]; ++ } ++ } ++ ++ bssrate_len = index; ++ DBG_871X("bssrate_len = %d\n", bssrate_len); ++ ++ if (bssrate_len == 0) { ++ rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ goto exit; /* don't connect to AP if no joint supported rate */ ++ } ++ ++ ++ if (bssrate_len > 8) ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen)); ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen)); ++ } ++ else ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen)); ++ } ++ ++ /* vendor specific IE, such as WPA, WMM, WPS */ ++ for (i = sizeof(struct ndis_802_11_fix_ie); i < pmlmeinfo->network.IELength;) ++ { ++ pIE = (struct ndis_80211_var_ie *)(pmlmeinfo->network.IEs + i); ++ ++ switch (pIE->ElementID) ++ { ++ case _VENDOR_SPECIFIC_IE_: ++ if ((!memcmp(pIE->data, RTW_WPA_OUI, 4)) || ++ (!memcmp(pIE->data, WMM_OUI, 4)) || ++ (!memcmp(pIE->data, WPS_OUI, 4))) ++ { ++ vs_ie_length = pIE->Length; ++ if ((!padapter->registrypriv.wifi_spec) && (!memcmp(pIE->data, WPS_OUI, 4))) ++ { ++ /* Commented by Kurt 20110629 */ ++ /* In some older APs, WPS handshake */ ++ /* would be fail if we append vender extensions informations to AP */ ++ ++ vs_ie_length = 14; ++ } ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, vs_ie_length, pIE->data, &(pattrib->pktlen)); ++ } ++ break; ++ ++ case EID_WPA2: ++ pframe = rtw_set_ie(pframe, EID_WPA2, pIE->Length, pIE->data, &(pattrib->pktlen)); ++ break; ++ case EID_HTCapability: ++ if (padapter->mlmepriv.htpriv.ht_option ==true) { ++ if (!(is_ap_in_tkip(padapter))) ++ { ++ memcpy(&(pmlmeinfo->HT_caps), pIE->data, sizeof(struct HT_caps_element)); ++ pframe = rtw_set_ie(pframe, EID_HTCapability, pIE->Length , (u8 *)(&(pmlmeinfo->HT_caps)), &(pattrib->pktlen)); ++ } ++ } ++ break; ++ ++ case EID_EXTCapability: ++ if (padapter->mlmepriv.htpriv.ht_option ==true) { ++ pframe = rtw_set_ie(pframe, EID_EXTCapability, pIE->Length, pIE->data, &(pattrib->pktlen)); ++ } ++ break; ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++ ++ if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) ++ { ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6 , REALTEK_96B_IE, &(pattrib->pktlen)); ++ } ++ ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ dump_mgntframe(padapter, pmgntframe); ++ ++ ret = _SUCCESS; ++ ++exit: ++ if (ret == _SUCCESS) ++ rtw_buf_update(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len, (u8 *)pwlanhdr, pattrib->pktlen); ++ else ++ rtw_buf_free(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len); ++ ++ return; ++} ++ ++/* when wait_ack is ture, this function shoule be called at process context */ ++static int _issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int wait_ack) ++{ ++ int ret = _FAIL; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct xmit_priv *pxmitpriv; ++ struct mlme_ext_priv *pmlmeext; ++ struct mlme_ext_info *pmlmeinfo; ++ ++ /* DBG_871X("%s:%d\n", __func__, power_mode); */ ++ ++ if (!padapter) ++ goto exit; ++ ++ pxmitpriv = &(padapter->xmitpriv); ++ pmlmeext = &(padapter->mlmeextpriv); ++ pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ goto exit; ++ } ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ pattrib->retry_ctrl = false; ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_control); ++ *(fctrl) = 0; ++ ++ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) ++ { ++ SetFrDs(fctrl); ++ } ++ else if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) ++ { ++ SetToDs(fctrl); ++ } ++ ++ if (power_mode) ++ { ++ SetPwrMgt(fctrl); ++ } ++ ++ memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_DATA_NULL); ++ ++ pframe += sizeof(struct ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ if (wait_ack) ++ { ++ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); ++ } ++ else ++ { ++ dump_mgntframe(padapter, pmgntframe); ++ ret = _SUCCESS; ++ } ++ ++exit: ++ return ret; ++} ++ ++/* ++ * [IMPORTANT] Don't call this function in interrupt context ++ * ++ * When wait_ms > 0, this function shoule be called at process context ++ * da == NULL for station mode ++ */ ++int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms) ++{ ++ int ret; ++ int i = 0; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct sta_info *psta; ++ ++ ++ /* da == NULL, assum it's null data for sta to ap*/ ++ if (da == NULL) ++ da = get_my_bssid(&(pmlmeinfo->network)); ++ ++ psta = rtw_get_stainfo(&padapter->stapriv, da); ++ if (psta) { ++ if (power_mode) ++ rtw_hal_macid_sleep(padapter, psta->mac_id); ++ else ++ rtw_hal_macid_wakeup(padapter, psta->mac_id); ++ } else { ++ DBG_871X(FUNC_ADPT_FMT ": Can't find sta info for " MAC_FMT ", skip macid %s!!\n", ++ FUNC_ADPT_ARG(padapter), MAC_ARG(da), power_mode?"sleep":"wakeup"); ++ rtw_warn_on(1); ++ } ++ ++ do { ++ ret = _issue_nulldata(padapter, da, power_mode, wait_ms>0?true:false); ++ ++ i++; ++ ++ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) ++ break; ++ ++ if (i < try_cnt && wait_ms > 0 && ret == _FAIL) ++ msleep(wait_ms); ++ ++ }while ((imlmeextpriv; ++ pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ /* da == NULL, assum it's null data for sta to ap*/ ++ if (da == NULL) ++ da = get_my_bssid(&(pmlmeinfo->network)); ++ ++ ret = _issue_nulldata(padapter, da, 0, false); ++ ++ return ret; ++} ++ ++/* when wait_ack is ture, this function shoule be called at process context */ ++static int _issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int wait_ack) ++{ ++ int ret = _FAIL; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ u16 *qc; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ DBG_871X("%s\n", __func__); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ goto exit; ++ } ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ pattrib->hdrlen +=2; ++ pattrib->qos_en = true; ++ pattrib->eosp = 1; ++ pattrib->ack_policy = 0; ++ pattrib->mdata = 0; ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_control); ++ *(fctrl) = 0; ++ ++ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) ++ { ++ SetFrDs(fctrl); ++ } ++ else if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) ++ { ++ SetToDs(fctrl); ++ } ++ ++ if (pattrib->mdata) ++ SetMData(fctrl); ++ ++ qc = (unsigned short *)(pframe + pattrib->hdrlen - 2); ++ ++ SetPriority(qc, tid); ++ ++ SetEOSP(qc, pattrib->eosp); ++ ++ SetAckpolicy(qc, pattrib->ack_policy); ++ ++ memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_QOS_DATA_NULL); ++ ++ pframe += sizeof(struct ieee80211_qos_hdr); ++ pattrib->pktlen = sizeof(struct ieee80211_qos_hdr); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ if (wait_ack) ++ { ++ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); ++ } ++ else ++ { ++ dump_mgntframe(padapter, pmgntframe); ++ ret = _SUCCESS; ++ } ++ ++exit: ++ return ret; ++} ++ ++/* when wait_ms >0 , this function shoule be called at process context */ ++/* da == NULL for station mode */ ++int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int try_cnt, int wait_ms) ++{ ++ int ret; ++ int i = 0; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ /* da == NULL, assum it's null data for sta to ap*/ ++ if (da == NULL) ++ da = get_my_bssid(&(pmlmeinfo->network)); ++ ++ do ++ { ++ ret = _issue_qos_nulldata(padapter, da, tid, wait_ms>0?true:false); ++ ++ i++; ++ ++ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) ++ break; ++ ++ if (i < try_cnt && wait_ms > 0 && ret == _FAIL) ++ msleep(wait_ms); ++ ++ }while ((ixmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ int ret = _FAIL; ++ __le16 le_tmp; ++ ++ /* DBG_871X("%s to "MAC_FMT"\n", __func__, MAC_ARG(da)); */ ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ goto exit; ++ } ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ pattrib->retry_ctrl = false; ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_control); ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_DEAUTH); ++ ++ pframe += sizeof(struct ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); ++ ++ le_tmp = cpu_to_le16(reason); ++ pframe = rtw_set_fixed_ie(pframe, _RSON_CODE_ , (unsigned char *)&le_tmp, &(pattrib->pktlen)); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ ++ if (wait_ack) ++ { ++ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); ++ } ++ else ++ { ++ dump_mgntframe(padapter, pmgntframe); ++ ret = _SUCCESS; ++ } ++ ++exit: ++ return ret; ++} ++ ++int issue_deauth(struct adapter *padapter, unsigned char *da, unsigned short reason) ++{ ++ DBG_871X("%s to "MAC_FMT"\n", __func__, MAC_ARG(da)); ++ return _issue_deauth(padapter, da, reason, false); ++} ++ ++int issue_deauth_ex(struct adapter *padapter, u8 *da, unsigned short reason, int try_cnt, ++ int wait_ms) ++{ ++ int ret; ++ int i = 0; ++ ++ do ++ { ++ ret = _issue_deauth(padapter, da, reason, wait_ms>0?true:false); ++ ++ i++; ++ ++ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) ++ break; ++ ++ if (i < try_cnt && wait_ms > 0 && ret == _FAIL) ++ msleep(wait_ms); ++ ++ }while ((ixmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ __le16 le_tmp; ++ ++ DBG_871X("%s\n", __func__); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ DBG_871X("%s: alloc_mgtxmitframe fail\n", __func__); ++ return; ++ } ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_control); ++ *(fctrl) = 0; ++ ++ if (raddr) ++ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); ++ else ++ memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &category, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &action, &pattrib->pktlen); ++ ++ switch (action) ++ { ++ case 0: /* SA Query req */ ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&pmlmeext->sa_query_seq, &pattrib->pktlen); ++ pmlmeext->sa_query_seq++; ++ /* send sa query request to AP, AP should reply sa query response in 1 second */ ++ set_sa_query_timer(pmlmeext, 1000); ++ break; ++ ++ case 1: /* SA Query rsp */ ++ le_tmp = cpu_to_le16(tid); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); ++ break; ++ default: ++ break; ++ } ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned char action, unsigned short status) ++{ ++ u8 category = RTW_WLAN_CATEGORY_BACK; ++ u16 start_seq; ++ u16 BA_para_set; ++ u16 reason_code; ++ u16 BA_timeout_value; ++ u16 BA_starting_seqctrl = 0; ++ enum HT_CAP_AMPDU_FACTOR max_rx_ampdu_factor; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ u8 *pframe; ++ struct ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ __le16 le_tmp; ++ ++ DBG_871X("%s, category =%d, action =%d, status =%d\n", __func__, category, action, status); ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_control); ++ *(fctrl) = 0; ++ ++ /* memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); */ ++ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ ++ if (category == 3) { ++ switch (action) { ++ case 0: /* ADDBA req */ ++ do { ++ pmlmeinfo->dialogToken++; ++ } while (pmlmeinfo->dialogToken == 0); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->dialogToken), &(pattrib->pktlen)); ++ ++ if (rtw_btcoex_IsBTCoexCtrlAMPDUSize(padapter)) { ++ /* A-MSDU NOT Supported */ ++ BA_para_set = 0; ++ /* immediate Block Ack */ ++ BA_para_set |= (1 << 1) & IEEE80211_ADDBA_PARAM_POLICY_MASK; ++ /* TID */ ++ BA_para_set |= (status << 2) & IEEE80211_ADDBA_PARAM_TID_MASK; ++ /* max buffer size is 8 MSDU */ ++ BA_para_set |= (8 << 6) & RTW_IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; ++ } else { ++ BA_para_set = (0x1002 | ((status & 0xf) << 2)); /* immediate ack & 64 buffer size */ ++ } ++ le_tmp = cpu_to_le16(BA_para_set); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); ++ ++ BA_timeout_value = 5000;/* 5ms */ ++ le_tmp = cpu_to_le16(BA_timeout_value); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); ++ ++ /* if ((psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress)) != NULL) */ ++ if ((psta = rtw_get_stainfo(pstapriv, raddr)) != NULL) { ++ start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07]&0xfff) + 1; ++ ++ DBG_871X("BA_starting_seqctrl = %d for TID =%d\n", start_seq, status & 0x07); ++ ++ psta->BA_starting_seqctrl[status & 0x07] = start_seq; ++ ++ BA_starting_seqctrl = start_seq << 4; ++ } ++ ++ le_tmp = cpu_to_le16(BA_starting_seqctrl); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); ++ break; ++ ++ case 1: /* ADDBA rsp */ ++ pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->ADDBA_req.dialog_token), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&status), &(pattrib->pktlen)); ++ if (padapter->driver_rx_ampdu_factor != 0xFF) ++ max_rx_ampdu_factor = ++ (enum HT_CAP_AMPDU_FACTOR)padapter->driver_rx_ampdu_factor; ++ else ++ rtw_hal_get_def_var(padapter, ++ HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor); ++ ++ if (MAX_AMPDU_FACTOR_64K == max_rx_ampdu_factor) ++ BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); /* 64 buffer size */ ++ else if (MAX_AMPDU_FACTOR_32K == max_rx_ampdu_factor) ++ BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0800); /* 32 buffer size */ ++ else if (MAX_AMPDU_FACTOR_16K == max_rx_ampdu_factor) ++ BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0400); /* 16 buffer size */ ++ else if (MAX_AMPDU_FACTOR_8K == max_rx_ampdu_factor) ++ BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0200); /* 8 buffer size */ ++ else ++ BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); /* 64 buffer size */ ++ ++ if (rtw_btcoex_IsBTCoexCtrlAMPDUSize(padapter) && ++ padapter->driver_rx_ampdu_factor == 0xFF) { ++ /* max buffer size is 8 MSDU */ ++ BA_para_set &= ~RTW_IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; ++ BA_para_set |= (8 << 6) & RTW_IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; ++ } ++ ++ if (pregpriv->ampdu_amsdu == 0)/* disabled */ ++ le_tmp = cpu_to_le16(BA_para_set & ~BIT(0)); ++ else if (pregpriv->ampdu_amsdu == 1)/* enabled */ ++ le_tmp = cpu_to_le16(BA_para_set | BIT(0)); ++ else /* auto */ ++ le_tmp = cpu_to_le16(BA_para_set); ++ ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(pmlmeinfo->ADDBA_req.BA_timeout_value)), &(pattrib->pktlen)); ++ break; ++ case 2:/* DELBA */ ++ BA_para_set = (status & 0x1F) << 3; ++ le_tmp = cpu_to_le16(BA_para_set); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); ++ ++ reason_code = 37; ++ le_tmp = cpu_to_le16(reason_code); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++static void issue_action_BSSCoexistPacket(struct adapter *padapter) ++{ ++ struct list_head *plist, *phead; ++ unsigned char category, action; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct wlan_network *pnetwork = NULL; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct __queue *queue = &(pmlmepriv->scanned_queue); ++ u8 InfoContent[16] = {0}; ++ u8 ICS[8][15]; ++ ++ if ((pmlmepriv->num_FortyMHzIntolerant == 0) || (pmlmepriv->num_sta_no_ht == 0)) ++ return; ++ ++ if (true == pmlmeinfo->bwmode_updated) ++ return; ++ ++ ++ DBG_871X("%s\n", __func__); ++ ++ ++ category = RTW_WLAN_CATEGORY_PUBLIC; ++ action = ACT_PUBLIC_BSSCOEXIST; ++ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ return; ++ } ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_control); ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); ++ ++ ++ /* */ ++ if (pmlmepriv->num_FortyMHzIntolerant>0) ++ { ++ u8 iedata = 0; ++ ++ iedata |= BIT(2);/* 20 MHz BSS Width Request */ ++ ++ pframe = rtw_set_ie(pframe, EID_BSSCoexistence, 1, &iedata, &(pattrib->pktlen)); ++ ++ } ++ ++ ++ /* */ ++ memset(ICS, 0, sizeof(ICS)); ++ if (pmlmepriv->num_sta_no_ht>0) ++ { ++ int i; ++ ++ spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); ++ ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ while (1) ++ { ++ int len; ++ u8 *p; ++ struct wlan_bssid_ex *pbss_network; ++ ++ if (phead == plist) ++ break; ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ ++ plist = get_next(plist); ++ ++ pbss_network = (struct wlan_bssid_ex *)&pnetwork->network; ++ ++ p = rtw_get_ie(pbss_network->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pbss_network->IELength - _FIXED_IE_LENGTH_); ++ if ((p == NULL) || (len == 0))/* non-HT */ ++ { ++ if ((pbss_network->Configuration.DSConfig<= 0) || (pbss_network->Configuration.DSConfig>14)) ++ continue; ++ ++ ICS[0][pbss_network->Configuration.DSConfig]= 1; ++ ++ if (ICS[0][0] == 0) ++ ICS[0][0] = 1; ++ } ++ ++ } ++ ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ ++ ++ for (i = 0;i<8;i++) ++ { ++ if (ICS[i][0] == 1) ++ { ++ int j, k = 0; ++ ++ InfoContent[k] = i; ++ /* SET_BSS_INTOLERANT_ELE_REG_CLASS(InfoContent, i); */ ++ k++; ++ ++ for (j = 1;j<= 14;j++) ++ { ++ if (ICS[i][j]== 1) ++ { ++ if (k<16) ++ { ++ InfoContent[k] = j; /* channel number */ ++ /* SET_BSS_INTOLERANT_ELE_CHANNEL(InfoContent+k, j); */ ++ k++; ++ } ++ } ++ } ++ ++ pframe = rtw_set_ie(pframe, EID_BSSIntolerantChlReport, k, InfoContent, &(pattrib->pktlen)); ++ ++ } ++ ++ } ++ ++ ++ } ++ ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr) ++{ ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *psta = NULL; ++ /* struct recv_reorder_ctrl *preorder_ctrl; */ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u16 tid; ++ ++ if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) ++ if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) ++ return _SUCCESS; ++ ++ psta = rtw_get_stainfo(pstapriv, addr); ++ if (psta == NULL) ++ return _SUCCESS; ++ ++ /* DBG_871X("%s:%s\n", __func__, (initiator == 0)?"RX_DIR":"TX_DIR"); */ ++ ++ if (initiator == 0) /* recipient */ ++ { ++ for (tid = 0;tidrecvreorder_ctrl[tid].enable == true) ++ { ++ DBG_871X("rx agg disable tid(%d)\n", tid); ++ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid <<1) |initiator)&0x1F)); ++ psta->recvreorder_ctrl[tid].enable = false; ++ psta->recvreorder_ctrl[tid].indicate_seq = 0xffff; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d indicate_seq:%u\n", __func__, __LINE__, ++ psta->recvreorder_ctrl[tid].indicate_seq); ++ #endif ++ } ++ } ++ } ++ else if (initiator == 1)/* originator */ ++ { ++ /* DBG_871X("tx agg_enable_bitmap(0x%08x)\n", psta->htpriv.agg_enable_bitmap); */ ++ for (tid = 0;tidhtpriv.agg_enable_bitmap & BIT(tid)) ++ { ++ DBG_871X("tx agg disable tid(%d)\n", tid); ++ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid <<1) |initiator)&0x1F)); ++ psta->htpriv.agg_enable_bitmap &= ~BIT(tid); ++ psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); ++ ++ } ++ } ++ } ++ ++ return _SUCCESS; ++ ++} ++ ++unsigned int send_beacon(struct adapter *padapter) ++{ ++ u8 bxmitok = false; ++ int issue = 0; ++ int poll = 0; ++ unsigned long start = jiffies; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL); ++ rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL); ++ do{ ++ issue_beacon(padapter, 100); ++ issue++; ++ do { ++ yield(); ++ rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bxmitok)); ++ poll++; ++ }while ((poll%10)!= 0 && false == bxmitok && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); ++ ++ }while (false == bxmitok && issue<100 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); ++ ++ if (padapter->bSurpriseRemoved || padapter->bDriverStopped) ++ { ++ return _FAIL; ++ } ++ ++ ++ if (false == bxmitok) ++ { ++ DBG_871X("%s fail! %u ms\n", __func__, jiffies_to_msecs(jiffies - start)); ++ return _FAIL; ++ } ++ else ++ { ++ unsigned long passing_time = jiffies_to_msecs(jiffies - start); ++ ++ if (passing_time > 100 || issue > 3) ++ DBG_871X("%s success, issue:%d, poll:%d, %lu ms\n", __func__, issue, poll, passing_time); ++ /* else */ ++ /* DBG_871X("%s success, issue:%d, poll:%d, %u ms\n", __func__, issue, poll, passing_time); */ ++ ++ return _SUCCESS; ++ } ++} ++ ++/**************************************************************************** ++ ++Following are some utitity fuctions for WiFi MLME ++ ++*****************************************************************************/ ++ ++void site_survey(struct adapter *padapter) ++{ ++ unsigned char survey_channel = 0, val8; ++ RT_SCAN_TYPE ScanType = SCAN_PASSIVE; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u32 initialgain = 0; ++ u32 channel_scan_time_ms = 0; ++ ++ { ++ struct rtw_ieee80211_channel *ch; ++ if (pmlmeext->sitesurvey_res.channel_idx < pmlmeext->sitesurvey_res.ch_num) { ++ ch = &pmlmeext->sitesurvey_res.ch[pmlmeext->sitesurvey_res.channel_idx]; ++ survey_channel = ch->hw_value; ++ ScanType = (ch->flags & RTW_IEEE80211_CHAN_PASSIVE_SCAN) ? SCAN_PASSIVE : SCAN_ACTIVE; ++ } ++ } ++ ++ DBG_871X(FUNC_ADPT_FMT" ch:%u (cnt:%u) at %dms, %c%c%c\n" ++ , FUNC_ADPT_ARG(padapter) ++ , survey_channel ++ , pmlmeext->sitesurvey_res.channel_idx ++ , jiffies_to_msecs(jiffies - padapter->mlmepriv.scan_start_time) ++ , ScanType?'A':'P', pmlmeext->sitesurvey_res.scan_mode?'A':'P' ++ , pmlmeext->sitesurvey_res.ssid[0].SsidLength?'S':' ' ++ ); ++#ifdef DBG_FIXED_CHAN ++ DBG_871X(FUNC_ADPT_FMT" fixed_chan:%u\n", pmlmeext->fixed_chan); ++#endif ++ ++ if (survey_channel != 0) ++ { ++ /* PAUSE 4-AC Queue when site_survey */ ++ /* rtw_hal_get_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ ++ /* val8 |= 0x0f; */ ++ /* rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ ++ if (pmlmeext->sitesurvey_res.channel_idx == 0) ++ { ++#ifdef DBG_FIXED_CHAN ++ if (pmlmeext->fixed_chan != 0xff) ++ set_channel_bwmode(padapter, pmlmeext->fixed_chan, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20); ++ else ++#endif ++ set_channel_bwmode(padapter, survey_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20); ++ } ++ else ++ { ++#ifdef DBG_FIXED_CHAN ++ if (pmlmeext->fixed_chan!= 0xff) ++ SelectChannel(padapter, pmlmeext->fixed_chan); ++ else ++#endif ++ SelectChannel(padapter, survey_channel); ++ } ++ ++ if (ScanType == SCAN_ACTIVE) /* obey the channel plan setting... */ ++ { ++ { ++ int i; ++ for (i = 0;isitesurvey_res.ssid[i].SsidLength) { ++ /* IOT issue, When wifi_spec is not set, send one probe req without WPS IE. */ ++ if (padapter->registrypriv.wifi_spec) ++ issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL); ++ else ++ issue_probereq_ex(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL, 0, 0, 0, 0); ++ issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL); ++ } ++ } ++ ++ if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) { ++ /* IOT issue, When wifi_spec is not set, send one probe req without WPS IE. */ ++ if (padapter->registrypriv.wifi_spec) ++ issue_probereq(padapter, NULL, NULL); ++ else ++ issue_probereq_ex(padapter, NULL, NULL, 0, 0, 0, 0); ++ issue_probereq(padapter, NULL, NULL); ++ } ++ } ++ } ++ ++ channel_scan_time_ms = pmlmeext->chan_scan_time; ++ ++ set_survey_timer(pmlmeext, channel_scan_time_ms); ++#if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) ++ { ++ struct noise_info info; ++ info.bPauseDIG = false; ++ info.IGIValue = 0; ++ info.max_time = channel_scan_time_ms/2;/* ms */ ++ info.chan = survey_channel; ++ rtw_hal_set_odm_var(padapter, HAL_ODM_NOISE_MONITOR,&info, false); ++ } ++#endif ++ ++ } ++ else ++ { ++ ++ /* channel number is 0 or this channel is not valid. */ ++ ++ { ++ pmlmeext->sitesurvey_res.state = SCAN_COMPLETE; ++ ++ /* switch back to the original channel */ ++ /* SelectChannel(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset); */ ++ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ ++ /* flush 4-AC Queue after site_survey */ ++ /* val8 = 0; */ ++ /* rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ ++ ++ /* config MSR */ ++ Set_MSR(padapter, (pmlmeinfo->state & 0x3)); ++ ++ initialgain = 0xff; /* restore RX GAIN */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); ++ /* turn on dynamic functions */ ++ Restore_DM_Func_Flag(padapter); ++ /* Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); */ ++ ++ if (is_client_associated_to_ap(padapter) == true) ++ { ++ issue_nulldata(padapter, NULL, 0, 3, 500); ++ } ++ ++ val8 = 0; /* survey done */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ ++ report_surveydone_event(padapter); ++ ++ pmlmeext->chan_scan_time = SURVEY_TO; ++ pmlmeext->sitesurvey_res.state = SCAN_DISABLE; ++ ++ issue_action_BSSCoexistPacket(padapter); ++ issue_action_BSSCoexistPacket(padapter); ++ issue_action_BSSCoexistPacket(padapter); ++ } ++ } ++ ++ return; ++ ++} ++ ++/* collect bss info from Beacon and Probe request/response frames. */ ++u8 collect_bss_info(struct adapter *padapter, union recv_frame *precv_frame, struct wlan_bssid_ex *bssid) ++{ ++ int i; ++ u32 len; ++ u8 *p; ++ u16 val16, subtype; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ u32 packet_len = precv_frame->u.hdr.len; ++ u8 ie_offset; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ __le32 le32_tmp; ++ ++ len = packet_len - sizeof(struct ieee80211_hdr_3addr); ++ ++ if (len > MAX_IE_SZ) ++ { ++ /* DBG_871X("IE too long for survey event\n"); */ ++ return _FAIL; ++ } ++ ++ memset(bssid, 0, sizeof(struct wlan_bssid_ex)); ++ ++ subtype = GetFrameSubType(pframe); ++ ++ if (subtype ==WIFI_BEACON) { ++ bssid->Reserved[0] = 1; ++ ie_offset = _BEACON_IE_OFFSET_; ++ } else { ++ /* FIXME : more type */ ++ if (subtype == WIFI_PROBERSP) { ++ ie_offset = _PROBERSP_IE_OFFSET_; ++ bssid->Reserved[0] = 3; ++ } ++ else if (subtype == WIFI_PROBEREQ) { ++ ie_offset = _PROBEREQ_IE_OFFSET_; ++ bssid->Reserved[0] = 2; ++ } ++ else { ++ bssid->Reserved[0] = 0; ++ ie_offset = _FIXED_IE_LENGTH_; ++ } ++ } ++ ++ bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len; ++ ++ /* below is to copy the information element */ ++ bssid->IELength = len; ++ memcpy(bssid->IEs, (pframe + sizeof(struct ieee80211_hdr_3addr)), bssid->IELength); ++ ++ /* get the signal strength */ ++ bssid->Rssi = precv_frame->u.hdr.attrib.phy_info.RecvSignalPower; /* in dBM.raw data */ ++ bssid->PhyInfo.SignalQuality = precv_frame->u.hdr.attrib.phy_info.SignalQuality;/* in percentage */ ++ bssid->PhyInfo.SignalStrength = precv_frame->u.hdr.attrib.phy_info.SignalStrength;/* in percentage */ ++ ++ /* checking SSID */ ++ if ((p = rtw_get_ie(bssid->IEs + ie_offset, _SSID_IE_, &len, bssid->IELength - ie_offset)) == NULL) ++ { ++ DBG_871X("marc: cannot find SSID for survey event\n"); ++ return _FAIL; ++ } ++ ++ if (*(p + 1)) ++ { ++ if (len > NDIS_802_11_LENGTH_SSID) ++ { ++ DBG_871X("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); ++ return _FAIL; ++ } ++ memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1)); ++ bssid->Ssid.SsidLength = *(p + 1); ++ } ++ else ++ { ++ bssid->Ssid.SsidLength = 0; ++ } ++ ++ memset(bssid->SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX); ++ ++ /* checking rate info... */ ++ i = 0; ++ p = rtw_get_ie(bssid->IEs + ie_offset, _SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); ++ if (p != NULL) ++ { ++ if (len > NDIS_802_11_LENGTH_RATES_EX) ++ { ++ DBG_871X("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); ++ return _FAIL; ++ } ++ memcpy(bssid->SupportedRates, (p + 2), len); ++ i = len; ++ } ++ ++ p = rtw_get_ie(bssid->IEs + ie_offset, _EXT_SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); ++ if (p != NULL) ++ { ++ if (len > (NDIS_802_11_LENGTH_RATES_EX-i)) ++ { ++ DBG_871X("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); ++ return _FAIL; ++ } ++ memcpy(bssid->SupportedRates + i, (p + 2), len); ++ } ++ ++ bssid->NetworkTypeInUse = Ndis802_11OFDM24; ++ ++ if (bssid->IELength < 12) ++ return _FAIL; ++ ++ /* Checking for DSConfig */ ++ p = rtw_get_ie(bssid->IEs + ie_offset, _DSSET_IE_, &len, bssid->IELength - ie_offset); ++ ++ bssid->Configuration.DSConfig = 0; ++ bssid->Configuration.Length = 0; ++ ++ if (p) ++ { ++ bssid->Configuration.DSConfig = *(p + 2); ++ } ++ else ++ {/* In 5G, some ap do not have DSSET IE */ ++ /* checking HT info for channel */ ++ p = rtw_get_ie(bssid->IEs + ie_offset, _HT_ADD_INFO_IE_, &len, bssid->IELength - ie_offset); ++ if (p) ++ { ++ struct HT_info_element *HT_info = (struct HT_info_element *)(p + 2); ++ bssid->Configuration.DSConfig = HT_info->primary_channel; ++ } ++ else ++ { /* use current channel */ ++ bssid->Configuration.DSConfig = rtw_get_oper_ch(padapter); ++ } ++ } ++ ++ memcpy(&le32_tmp, rtw_get_beacon_interval_from_ie(bssid->IEs), 2); ++ bssid->Configuration.BeaconPeriod = le32_to_cpu(le32_tmp); ++ ++ val16 = rtw_get_capability((struct wlan_bssid_ex *)bssid); ++ ++ if (val16 & BIT(0)) { ++ bssid->InfrastructureMode = Ndis802_11Infrastructure; ++ memcpy(bssid->MacAddress, GetAddr2Ptr(pframe), ETH_ALEN); ++ } else { ++ bssid->InfrastructureMode = Ndis802_11IBSS; ++ memcpy(bssid->MacAddress, GetAddr3Ptr(pframe), ETH_ALEN); ++ } ++ ++ if (val16 & BIT(4)) ++ bssid->Privacy = 1; ++ else ++ bssid->Privacy = 0; ++ ++ bssid->Configuration.ATIMWindow = 0; ++ ++ /* 20/40 BSS Coexistence check */ ++ if ((pregistrypriv->wifi_spec == 1) && (false == pmlmeinfo->bwmode_updated)) ++ { ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ p = rtw_get_ie(bssid->IEs + ie_offset, _HT_CAPABILITY_IE_, &len, bssid->IELength - ie_offset); ++ if (p && len>0) ++ { ++ struct HT_caps_element *pHT_caps; ++ pHT_caps = (struct HT_caps_element *)(p + 2); ++ ++ if (le16_to_cpu(pHT_caps->u.HT_cap_element.HT_caps_info) & BIT(14)) ++ pmlmepriv->num_FortyMHzIntolerant++; ++ } else { ++ pmlmepriv->num_sta_no_ht++; ++ } ++ } ++ ++#ifdef CONFIG_INTEL_WIDI ++ /* process_intel_widi_query_or_tigger(padapter, bssid); */ ++ if (process_intel_widi_query_or_tigger(padapter, bssid)) ++ { ++ return _FAIL; ++ } ++#endif /* CONFIG_INTEL_WIDI */ ++ ++ #if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) & 1 ++ if (strcmp(bssid->Ssid.Ssid, DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) == 0) { ++ DBG_871X("Receiving %s("MAC_FMT", DSConfig:%u) from ch%u with ss:%3u, sq:%3u, RawRSSI:%3ld\n" ++ , bssid->Ssid.Ssid, MAC_ARG(bssid->MacAddress), bssid->Configuration.DSConfig ++ , rtw_get_oper_ch(padapter) ++ , bssid->PhyInfo.SignalStrength, bssid->PhyInfo.SignalQuality, bssid->Rssi ++ ); ++ } ++ #endif ++ ++ /* mark bss info receving from nearby channel as SignalQuality 101 */ ++ if (bssid->Configuration.DSConfig != rtw_get_oper_ch(padapter)) ++ { ++ bssid->PhyInfo.SignalQuality = 101; ++ } ++ ++ return _SUCCESS; ++} ++ ++void start_create_ibss(struct adapter *padapter) ++{ ++ unsigned short caps; ++ u8 val8; ++ u8 join_type; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex*)(&(pmlmeinfo->network)); ++ pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig; ++ pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork); ++ ++ /* update wireless mode */ ++ update_wireless_mode(padapter); ++ ++ /* udpate capability */ ++ caps = rtw_get_capability((struct wlan_bssid_ex *)pnetwork); ++ update_capinfo(padapter, caps); ++ if (caps&cap_IBSS)/* adhoc master */ ++ { ++ val8 = 0xcf; ++ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_DO_IQK, NULL); ++ ++ /* switch channel */ ++ /* SelectChannel(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE); */ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20); ++ ++ beacon_timing_control(padapter); ++ ++ /* set msr to WIFI_FW_ADHOC_STATE */ ++ pmlmeinfo->state = WIFI_FW_ADHOC_STATE; ++ Set_MSR(padapter, (pmlmeinfo->state & 0x3)); ++ ++ /* issue beacon */ ++ if (send_beacon(padapter) == _FAIL) ++ { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("issuing beacon frame fail....\n")); ++ ++ report_join_res(padapter, -1); ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ } ++ else ++ { ++ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, padapter->registrypriv.dev_network.MacAddress); ++ join_type = 0; ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); ++ ++ report_join_res(padapter, 1); ++ pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; ++ rtw_indicate_connect(padapter); ++ } ++ } ++ else ++ { ++ DBG_871X("start_create_ibss, invalid cap:%x\n", caps); ++ return; ++ } ++ /* update bc/mc sta_info */ ++ update_bmc_sta(padapter); ++ ++} ++ ++void start_clnt_join(struct adapter *padapter) ++{ ++ unsigned short caps; ++ u8 val8; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex*)(&(pmlmeinfo->network)); ++ int beacon_timeout; ++ ++ /* update wireless mode */ ++ update_wireless_mode(padapter); ++ ++ /* udpate capability */ ++ caps = rtw_get_capability((struct wlan_bssid_ex *)pnetwork); ++ update_capinfo(padapter, caps); ++ if (caps&cap_ESS) ++ { ++ Set_MSR(padapter, WIFI_FW_STATION_STATE); ++ ++ val8 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X)? 0xcc: 0xcf; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); ++ ++ /* Because of AP's not receiving deauth before */ ++ /* AP may: 1)not response auth or 2)deauth us after link is complete */ ++ /* issue deauth before issuing auth to deal with the situation */ ++ ++ /* Commented by Albert 2012/07/21 */ ++ /* For the Win8 P2P connection, it will be hard to have a successful connection if this Wi-Fi doesn't connect to it. */ ++ { ++ /* To avoid connecting to AP fail during resume process, change retry count from 5 to 1 */ ++ issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, 1, 100); ++ } ++ ++ /* here wait for receiving the beacon to start auth */ ++ /* and enable a timer */ ++ beacon_timeout = decide_wait_for_beacon_timeout(pmlmeinfo->bcn_interval); ++ set_link_timer(pmlmeext, beacon_timeout); ++ _set_timer(&padapter->mlmepriv.assoc_timer, ++ (REAUTH_TO * REAUTH_LIMIT) + (REASSOC_TO*REASSOC_LIMIT) +beacon_timeout); ++ ++ pmlmeinfo->state = WIFI_FW_AUTH_NULL | WIFI_FW_STATION_STATE; ++ } ++ else if (caps&cap_IBSS) /* adhoc client */ ++ { ++ Set_MSR(padapter, WIFI_FW_ADHOC_STATE); ++ ++ val8 = 0xcf; ++ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); ++ ++ beacon_timing_control(padapter); ++ ++ pmlmeinfo->state = WIFI_FW_ADHOC_STATE; ++ ++ report_join_res(padapter, 1); ++ } ++ else ++ { ++ /* DBG_871X("marc: invalid cap:%x\n", caps); */ ++ return; ++ } ++ ++} ++ ++void start_clnt_auth(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ del_timer_sync(&pmlmeext->link_timer); ++ ++ pmlmeinfo->state &= (~WIFI_FW_AUTH_NULL); ++ pmlmeinfo->state |= WIFI_FW_AUTH_STATE; ++ ++ pmlmeinfo->auth_seq = 1; ++ pmlmeinfo->reauth_count = 0; ++ pmlmeinfo->reassoc_count = 0; ++ pmlmeinfo->link_count = 0; ++ pmlmeext->retry = 0; ++ ++ ++ DBG_871X_LEVEL(_drv_always_, "start auth\n"); ++ issue_auth(padapter, NULL, 0); ++ ++ set_link_timer(pmlmeext, REAUTH_TO); ++ ++} ++ ++ ++void start_clnt_assoc(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ del_timer_sync(&pmlmeext->link_timer); ++ ++ pmlmeinfo->state &= (~(WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE)); ++ pmlmeinfo->state |= (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE); ++ ++ issue_assocreq(padapter); ++ ++ set_link_timer(pmlmeext, REASSOC_TO); ++} ++ ++unsigned int receive_disconnect(struct adapter *padapter, unsigned char *MacAddr, unsigned short reason) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ /* check A3 */ ++ if (!(!memcmp(MacAddr, get_my_bssid(&pmlmeinfo->network), ETH_ALEN))) ++ return _SUCCESS; ++ ++ DBG_871X("%s\n", __func__); ++ ++ if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) ++ { ++ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) ++ { ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ report_del_sta_event(padapter, MacAddr, reason); ++ ++ } ++ else if (pmlmeinfo->state & WIFI_FW_LINKING_STATE) ++ { ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ report_join_res(padapter, -2); ++ } ++ } ++ ++ return _SUCCESS; ++} ++ ++static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid) ++{ ++ struct registry_priv *pregistrypriv; ++ struct mlme_ext_priv *pmlmeext; ++ RT_CHANNEL_INFO *chplan_new; ++ u8 channel; ++ u8 i; ++ ++ ++ pregistrypriv = &padapter->registrypriv; ++ pmlmeext = &padapter->mlmeextpriv; ++ ++ /* Adjust channel plan by AP Country IE */ ++ if (pregistrypriv->enable80211d && ++ (!pmlmeext->update_channel_plan_by_ap_done)) ++ { ++ u8 *ie, *p; ++ u32 len; ++ RT_CHANNEL_PLAN chplan_ap; ++ RT_CHANNEL_INFO chplan_sta[MAX_CHANNEL_NUM]; ++ u8 country[4]; ++ u8 fcn; /* first channel number */ ++ u8 noc; /* number of channel */ ++ u8 j, k; ++ ++ ie = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _COUNTRY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); ++ if (!ie) return; ++ if (len < 6) return; ++ ++ ie += 2; ++ p = ie; ++ ie += len; ++ ++ memset(country, 0, 4); ++ memcpy(country, p, 3); ++ p += 3; ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ++ ("%s: 802.11d country =%s\n", __func__, country)); ++ ++ i = 0; ++ while ((ie - p) >= 3) ++ { ++ fcn = *(p++); ++ noc = *(p++); ++ p++; ++ ++ for (j = 0; j < noc; j++) ++ { ++ if (fcn <= 14) channel = fcn + j; /* 2.4 GHz */ ++ else channel = fcn + j*4; /* 5 GHz */ ++ ++ chplan_ap.Channel[i++] = channel; ++ } ++ } ++ chplan_ap.Len = i; ++ ++#ifdef CONFIG_DEBUG_RTL871X ++ i = 0; ++ DBG_871X("%s: AP[%s] channel plan {", __func__, bssid->Ssid.Ssid); ++ while ((i < chplan_ap.Len) && (chplan_ap.Channel[i] != 0)) ++ { ++ DBG_8192C("%02d,", chplan_ap.Channel[i]); ++ i++; ++ } ++ DBG_871X("}\n"); ++#endif ++ ++ memcpy(chplan_sta, pmlmeext->channel_set, sizeof(chplan_sta)); ++#ifdef CONFIG_DEBUG_RTL871X ++ i = 0; ++ DBG_871X("%s: STA channel plan {", __func__); ++ while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) ++ { ++ DBG_871X("%02d(%c),", chplan_sta[i].ChannelNum, chplan_sta[i].ScanType ==SCAN_PASSIVE?'p':'a'); ++ i++; ++ } ++ DBG_871X("}\n"); ++#endif ++ ++ memset(pmlmeext->channel_set, 0, sizeof(pmlmeext->channel_set)); ++ chplan_new = pmlmeext->channel_set; ++ ++ i = j = k = 0; ++ if (pregistrypriv->wireless_mode & WIRELESS_11G) ++ { ++ do { ++ if ((i == MAX_CHANNEL_NUM) || ++ (chplan_sta[i].ChannelNum == 0) || ++ (chplan_sta[i].ChannelNum > 14)) ++ break; ++ ++ if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] > 14)) ++ break; ++ ++ if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) ++ { ++ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; ++ chplan_new[k].ScanType = SCAN_ACTIVE; ++ i++; ++ j++; ++ k++; ++ } ++ else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) ++ { ++ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; ++/* chplan_new[k].ScanType = chplan_sta[i].ScanType; */ ++ chplan_new[k].ScanType = SCAN_PASSIVE; ++ i++; ++ k++; ++ } ++ else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) ++ { ++ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; ++ chplan_new[k].ScanType = SCAN_ACTIVE; ++ j++; ++ k++; ++ } ++ } while (1); ++ ++ /* change AP not support channel to Passive scan */ ++ while ((i < MAX_CHANNEL_NUM) && ++ (chplan_sta[i].ChannelNum != 0) && ++ (chplan_sta[i].ChannelNum <= 14)) ++ { ++ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; ++/* chplan_new[k].ScanType = chplan_sta[i].ScanType; */ ++ chplan_new[k].ScanType = SCAN_PASSIVE; ++ i++; ++ k++; ++ } ++ ++ /* add channel AP supported */ ++ while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) ++ { ++ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; ++ chplan_new[k].ScanType = SCAN_ACTIVE; ++ j++; ++ k++; ++ } ++ } ++ else ++ { ++ /* keep original STA 2.4G channel plan */ ++ while ((i < MAX_CHANNEL_NUM) && ++ (chplan_sta[i].ChannelNum != 0) && ++ (chplan_sta[i].ChannelNum <= 14)) ++ { ++ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; ++ chplan_new[k].ScanType = chplan_sta[i].ScanType; ++ i++; ++ k++; ++ } ++ ++ /* skip AP 2.4G channel plan */ ++ while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) ++ { ++ j++; ++ } ++ } ++ ++ if (pregistrypriv->wireless_mode & WIRELESS_11A) ++ { ++ do { ++ if ((i == MAX_CHANNEL_NUM) || ++ (chplan_sta[i].ChannelNum == 0)) ++ break; ++ ++ if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] == 0)) ++ break; ++ ++ if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) ++ { ++ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; ++ chplan_new[k].ScanType = SCAN_ACTIVE; ++ i++; ++ j++; ++ k++; ++ } ++ else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) ++ { ++ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; ++/* chplan_new[k].ScanType = chplan_sta[i].ScanType; */ ++ chplan_new[k].ScanType = SCAN_PASSIVE; ++ i++; ++ k++; ++ } ++ else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) ++ { ++ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; ++ chplan_new[k].ScanType = SCAN_ACTIVE; ++ j++; ++ k++; ++ } ++ } while (1); ++ ++ /* change AP not support channel to Passive scan */ ++ while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) ++ { ++ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; ++/* chplan_new[k].ScanType = chplan_sta[i].ScanType; */ ++ chplan_new[k].ScanType = SCAN_PASSIVE; ++ i++; ++ k++; ++ } ++ ++ /* add channel AP supported */ ++ while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] != 0)) ++ { ++ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; ++ chplan_new[k].ScanType = SCAN_ACTIVE; ++ j++; ++ k++; ++ } ++ } ++ else ++ { ++ /* keep original STA 5G channel plan */ ++ while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) ++ { ++ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; ++ chplan_new[k].ScanType = chplan_sta[i].ScanType; ++ i++; ++ k++; ++ } ++ } ++ ++ pmlmeext->update_channel_plan_by_ap_done = 1; ++ ++#ifdef CONFIG_DEBUG_RTL871X ++ k = 0; ++ DBG_871X("%s: new STA channel plan {", __func__); ++ while ((k < MAX_CHANNEL_NUM) && (chplan_new[k].ChannelNum != 0)) ++ { ++ DBG_871X("%02d(%c),", chplan_new[k].ChannelNum, chplan_new[k].ScanType ==SCAN_PASSIVE?'p':'c'); ++ k++; ++ } ++ DBG_871X("}\n"); ++#endif ++ } ++ ++ /* If channel is used by AP, set channel scan type to active */ ++ channel = bssid->Configuration.DSConfig; ++ chplan_new = pmlmeext->channel_set; ++ i = 0; ++ while ((i < MAX_CHANNEL_NUM) && (chplan_new[i].ChannelNum != 0)) ++ { ++ if (chplan_new[i].ChannelNum == channel) ++ { ++ if (chplan_new[i].ScanType == SCAN_PASSIVE) ++ { ++ /* 5G Bnad 2, 3 (DFS) doesn't change to active scan */ ++ if (channel >= 52 && channel <= 144) ++ break; ++ ++ chplan_new[i].ScanType = SCAN_ACTIVE; ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ++ ("%s: change channel %d scan type from passive to active\n", ++ __func__, channel)); ++ } ++ break; ++ } ++ i++; ++ } ++} ++ ++/**************************************************************************** ++ ++Following are the functions to report events ++ ++*****************************************************************************/ ++ ++void report_survey_event(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ struct cmd_obj *pcmd_obj; ++ u8 *pevtcmd; ++ u32 cmdsz; ++ struct survey_event *psurvey_evt; ++ struct C2HEvent_Header *pc2h_evt_hdr; ++ struct mlme_ext_priv *pmlmeext; ++ struct cmd_priv *pcmdpriv; ++ /* u8 *pframe = precv_frame->u.hdr.rx_data; */ ++ /* uint len = precv_frame->u.hdr.len; */ ++ ++ if (!padapter) ++ return; ++ ++ pmlmeext = &padapter->mlmeextpriv; ++ pcmdpriv = &padapter->cmdpriv; ++ ++ ++ if ((pcmd_obj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj))) == NULL) ++ { ++ return; ++ } ++ ++ cmdsz = (sizeof(struct survey_event) + sizeof(struct C2HEvent_Header)); ++ if ((pevtcmd = (u8 *)rtw_zmalloc(cmdsz)) == NULL) ++ { ++ kfree((u8 *)pcmd_obj); ++ return; ++ } ++ ++ INIT_LIST_HEAD(&pcmd_obj->list); ++ ++ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); ++ pcmd_obj->cmdsz = cmdsz; ++ pcmd_obj->parmbuf = pevtcmd; ++ ++ pcmd_obj->rsp = NULL; ++ pcmd_obj->rspsz = 0; ++ ++ pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd); ++ pc2h_evt_hdr->len = sizeof(struct survey_event); ++ pc2h_evt_hdr->ID = GEN_EVT_CODE(_Survey); ++ pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); ++ ++ psurvey_evt = (struct survey_event*)(pevtcmd + sizeof(struct C2HEvent_Header)); ++ ++ if (collect_bss_info(padapter, precv_frame, (struct wlan_bssid_ex *)&psurvey_evt->bss) == _FAIL) ++ { ++ kfree((u8 *)pcmd_obj); ++ kfree((u8 *)pevtcmd); ++ return; ++ } ++ ++ process_80211d(padapter, &psurvey_evt->bss); ++ ++ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); ++ ++ pmlmeext->sitesurvey_res.bss_cnt++; ++ ++ return; ++ ++} ++ ++void report_surveydone_event(struct adapter *padapter) ++{ ++ struct cmd_obj *pcmd_obj; ++ u8 *pevtcmd; ++ u32 cmdsz; ++ struct surveydone_event *psurveydone_evt; ++ struct C2HEvent_Header *pc2h_evt_hdr; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ if ((pcmd_obj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj))) == NULL) ++ { ++ return; ++ } ++ ++ cmdsz = (sizeof(struct surveydone_event) + sizeof(struct C2HEvent_Header)); ++ if ((pevtcmd = (u8 *)rtw_zmalloc(cmdsz)) == NULL) ++ { ++ kfree((u8 *)pcmd_obj); ++ return; ++ } ++ ++ INIT_LIST_HEAD(&pcmd_obj->list); ++ ++ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); ++ pcmd_obj->cmdsz = cmdsz; ++ pcmd_obj->parmbuf = pevtcmd; ++ ++ pcmd_obj->rsp = NULL; ++ pcmd_obj->rspsz = 0; ++ ++ pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd); ++ pc2h_evt_hdr->len = sizeof(struct surveydone_event); ++ pc2h_evt_hdr->ID = GEN_EVT_CODE(_SurveyDone); ++ pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); ++ ++ psurveydone_evt = (struct surveydone_event*)(pevtcmd + sizeof(struct C2HEvent_Header)); ++ psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt; ++ ++ DBG_871X("survey done event(%x) band:%d for "ADPT_FMT"\n", psurveydone_evt->bss_cnt, padapter->setband, ADPT_ARG(padapter)); ++ ++ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); ++ ++ return; ++ ++} ++ ++void report_join_res(struct adapter *padapter, int res) ++{ ++ struct cmd_obj *pcmd_obj; ++ u8 *pevtcmd; ++ u32 cmdsz; ++ struct joinbss_event *pjoinbss_evt; ++ struct C2HEvent_Header *pc2h_evt_hdr; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ if ((pcmd_obj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj))) == NULL) ++ { ++ return; ++ } ++ ++ cmdsz = (sizeof(struct joinbss_event) + sizeof(struct C2HEvent_Header)); ++ if ((pevtcmd = (u8 *)rtw_zmalloc(cmdsz)) == NULL) ++ { ++ kfree((u8 *)pcmd_obj); ++ return; ++ } ++ ++ INIT_LIST_HEAD(&pcmd_obj->list); ++ ++ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); ++ pcmd_obj->cmdsz = cmdsz; ++ pcmd_obj->parmbuf = pevtcmd; ++ ++ pcmd_obj->rsp = NULL; ++ pcmd_obj->rspsz = 0; ++ ++ pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd); ++ pc2h_evt_hdr->len = sizeof(struct joinbss_event); ++ pc2h_evt_hdr->ID = GEN_EVT_CODE(_JoinBss); ++ pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); ++ ++ pjoinbss_evt = (struct joinbss_event*)(pevtcmd + sizeof(struct C2HEvent_Header)); ++ memcpy((unsigned char *)(&(pjoinbss_evt->network.network)), &(pmlmeinfo->network), sizeof(struct wlan_bssid_ex)); ++ pjoinbss_evt->network.join_res = pjoinbss_evt->network.aid = res; ++ ++ DBG_871X("report_join_res(%d)\n", res); ++ ++ ++ rtw_joinbss_event_prehandle(padapter, (u8 *)&pjoinbss_evt->network); ++ ++ ++ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); ++ ++ return; ++ ++} ++ ++void report_wmm_edca_update(struct adapter *padapter) ++{ ++ struct cmd_obj *pcmd_obj; ++ u8 *pevtcmd; ++ u32 cmdsz; ++ struct wmm_event *pwmm_event; ++ struct C2HEvent_Header *pc2h_evt_hdr; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ if ((pcmd_obj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj))) == NULL) ++ { ++ return; ++ } ++ ++ cmdsz = (sizeof(struct wmm_event) + sizeof(struct C2HEvent_Header)); ++ if ((pevtcmd = (u8 *)rtw_zmalloc(cmdsz)) == NULL) ++ { ++ kfree((u8 *)pcmd_obj); ++ return; ++ } ++ ++ INIT_LIST_HEAD(&pcmd_obj->list); ++ ++ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); ++ pcmd_obj->cmdsz = cmdsz; ++ pcmd_obj->parmbuf = pevtcmd; ++ ++ pcmd_obj->rsp = NULL; ++ pcmd_obj->rspsz = 0; ++ ++ pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd); ++ pc2h_evt_hdr->len = sizeof(struct wmm_event); ++ pc2h_evt_hdr->ID = GEN_EVT_CODE(_WMM); ++ pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); ++ ++ pwmm_event = (struct wmm_event*)(pevtcmd + sizeof(struct C2HEvent_Header)); ++ pwmm_event->wmm = 0; ++ ++ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); ++ ++ return; ++ ++} ++ ++void report_del_sta_event(struct adapter *padapter, unsigned char* MacAddr, unsigned short reason) ++{ ++ struct cmd_obj *pcmd_obj; ++ u8 *pevtcmd; ++ u32 cmdsz; ++ struct sta_info *psta; ++ int mac_id; ++ struct stadel_event *pdel_sta_evt; ++ struct C2HEvent_Header *pc2h_evt_hdr; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ if ((pcmd_obj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj))) == NULL) ++ { ++ return; ++ } ++ ++ cmdsz = (sizeof(struct stadel_event) + sizeof(struct C2HEvent_Header)); ++ if ((pevtcmd = (u8 *)rtw_zmalloc(cmdsz)) == NULL) ++ { ++ kfree((u8 *)pcmd_obj); ++ return; ++ } ++ ++ INIT_LIST_HEAD(&pcmd_obj->list); ++ ++ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); ++ pcmd_obj->cmdsz = cmdsz; ++ pcmd_obj->parmbuf = pevtcmd; ++ ++ pcmd_obj->rsp = NULL; ++ pcmd_obj->rspsz = 0; ++ ++ pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd); ++ pc2h_evt_hdr->len = sizeof(struct stadel_event); ++ pc2h_evt_hdr->ID = GEN_EVT_CODE(_DelSTA); ++ pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); ++ ++ pdel_sta_evt = (struct stadel_event*)(pevtcmd + sizeof(struct C2HEvent_Header)); ++ memcpy((unsigned char *)(&(pdel_sta_evt->macaddr)), MacAddr, ETH_ALEN); ++ memcpy((unsigned char *)(pdel_sta_evt->rsvd), (unsigned char *)(&reason), 2); ++ ++ ++ psta = rtw_get_stainfo(&padapter->stapriv, MacAddr); ++ if (psta) ++ mac_id = (int)psta->mac_id; ++ else ++ mac_id = (-1); ++ ++ pdel_sta_evt->mac_id = mac_id; ++ ++ DBG_871X("report_del_sta_event: delete STA, mac_id =%d\n", mac_id); ++ ++ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); ++ ++ return; ++} ++ ++void report_add_sta_event(struct adapter *padapter, unsigned char* MacAddr, int cam_idx) ++{ ++ struct cmd_obj *pcmd_obj; ++ u8 *pevtcmd; ++ u32 cmdsz; ++ struct stassoc_event *padd_sta_evt; ++ struct C2HEvent_Header *pc2h_evt_hdr; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ if ((pcmd_obj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj))) == NULL) ++ { ++ return; ++ } ++ ++ cmdsz = (sizeof(struct stassoc_event) + sizeof(struct C2HEvent_Header)); ++ if ((pevtcmd = (u8 *)rtw_zmalloc(cmdsz)) == NULL) ++ { ++ kfree((u8 *)pcmd_obj); ++ return; ++ } ++ ++ INIT_LIST_HEAD(&pcmd_obj->list); ++ ++ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); ++ pcmd_obj->cmdsz = cmdsz; ++ pcmd_obj->parmbuf = pevtcmd; ++ ++ pcmd_obj->rsp = NULL; ++ pcmd_obj->rspsz = 0; ++ ++ pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd); ++ pc2h_evt_hdr->len = sizeof(struct stassoc_event); ++ pc2h_evt_hdr->ID = GEN_EVT_CODE(_AddSTA); ++ pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); ++ ++ padd_sta_evt = (struct stassoc_event*)(pevtcmd + sizeof(struct C2HEvent_Header)); ++ memcpy((unsigned char *)(&(padd_sta_evt->macaddr)), MacAddr, ETH_ALEN); ++ padd_sta_evt->cam_id = cam_idx; ++ ++ DBG_871X("report_add_sta_event: add STA\n"); ++ ++ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); ++ ++ return; ++} ++ ++ ++bool rtw_port_switch_chk(struct adapter *adapter) ++{ ++ bool switch_needed = false; ++ return switch_needed; ++} ++ ++/**************************************************************************** ++ ++Following are the event callback functions ++ ++*****************************************************************************/ ++ ++/* for sta/adhoc mode */ ++void update_sta_info(struct adapter *padapter, struct sta_info *psta) ++{ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ /* ERP */ ++ VCS_update(padapter, psta); ++ ++ /* HT */ ++ if (pmlmepriv->htpriv.ht_option) ++ { ++ psta->htpriv.ht_option = true; ++ ++ psta->htpriv.ampdu_enable = pmlmepriv->htpriv.ampdu_enable; ++ ++ psta->htpriv.rx_ampdu_min_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para&IEEE80211_HT_CAP_AMPDU_DENSITY)>>2; ++ ++ if (support_short_GI(padapter, &(pmlmeinfo->HT_caps), CHANNEL_WIDTH_20)) ++ psta->htpriv.sgi_20m = true; ++ ++ if (support_short_GI(padapter, &(pmlmeinfo->HT_caps), CHANNEL_WIDTH_40)) ++ psta->htpriv.sgi_40m = true; ++ ++ psta->qos_option = true; ++ ++ psta->htpriv.ldpc_cap = pmlmepriv->htpriv.ldpc_cap; ++ psta->htpriv.stbc_cap = pmlmepriv->htpriv.stbc_cap; ++ psta->htpriv.beamform_cap = pmlmepriv->htpriv.beamform_cap; ++ ++ memcpy(&psta->htpriv.ht_cap, &pmlmeinfo->HT_caps, sizeof(struct rtw_ieee80211_ht_cap)); ++ } ++ else ++ { ++ psta->htpriv.ht_option = false; ++ ++ psta->htpriv.ampdu_enable = false; ++ ++ psta->htpriv.sgi_20m = false; ++ psta->htpriv.sgi_40m = false; ++ psta->qos_option = false; ++ ++ } ++ ++ psta->htpriv.ch_offset = pmlmeext->cur_ch_offset; ++ ++ psta->htpriv.agg_enable_bitmap = 0x0;/* reset */ ++ psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */ ++ ++ psta->bw_mode = pmlmeext->cur_bwmode; ++ ++ /* QoS */ ++ if (pmlmepriv->qospriv.qos_option) ++ psta->qos_option = true; ++ ++ update_ldpc_stbc_cap(psta); ++ ++ spin_lock_bh(&psta->lock); ++ psta->state = _FW_LINKED; ++ spin_unlock_bh(&psta->lock); ++ ++} ++ ++static void rtw_mlmeext_disconnect(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex*)(&(pmlmeinfo->network)); ++ u8 state_backup = (pmlmeinfo->state&0x03); ++ ++ /* set_opmode_cmd(padapter, infra_client_with_mlme); */ ++ ++ /* ++ * For safety, prevent from keeping macid sleep. ++ * If we can sure all power mode enter/leave are paired, ++ * this check can be removed. ++ * Lucas@20131113 ++ */ ++ /* wakeup macid after disconnect. */ ++ { ++ struct sta_info *psta; ++ psta = rtw_get_stainfo(&padapter->stapriv, get_my_bssid(pnetwork)); ++ if (psta) ++ rtw_hal_macid_wakeup(padapter, psta->mac_id); ++ } ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, NULL); ++ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr); ++ ++ /* set MSR to no link state -> infra. mode */ ++ Set_MSR(padapter, _HW_STATE_STATION_); ++ ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ ++ if (state_backup == WIFI_FW_STATION_STATE) ++ { ++ if (rtw_port_switch_chk(padapter) == true) { ++ rtw_hal_set_hwreg(padapter, HW_VAR_PORT_SWITCH, NULL); ++ { ++ struct adapter *port0_iface = dvobj_get_port0_adapter(adapter_to_dvobj(padapter)); ++ if (port0_iface) ++ rtw_lps_ctrl_wk_cmd(port0_iface, LPS_CTRL_CONNECT, 0); ++ } ++ } ++ } ++ ++ /* switch to the 20M Hz mode after disconnect */ ++ pmlmeext->cur_bwmode = CHANNEL_WIDTH_20; ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ ++ flush_all_cam_entry(padapter); ++ ++ del_timer_sync(&pmlmeext->link_timer); ++ ++ /* pmlmepriv->LinkDetectInfo.TrafficBusyState = false; */ ++ pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 0; ++ pmlmepriv->LinkDetectInfo.LowPowerTransitionCount = 0; ++ ++} ++ ++void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 join_type; ++ struct sta_info *psta; ++ if (join_res < 0) ++ { ++ join_type = 1; ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); ++ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr); ++ ++ goto exit_mlmeext_joinbss_event_callback; ++ } ++ ++ if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) ++ { ++ /* update bc/mc sta_info */ ++ update_bmc_sta(padapter); ++ } ++ ++ ++ /* turn on dynamic functions */ ++ Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); ++ ++ /* update IOT-releated issue */ ++ update_IOT_info(padapter); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, cur_network->SupportedRates); ++ ++ /* BCN interval */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&pmlmeinfo->bcn_interval)); ++ ++ /* udpate capability */ ++ update_capinfo(padapter, pmlmeinfo->capability); ++ ++ /* WMM, Update EDCA param */ ++ WMMOnAssocRsp(padapter); ++ ++ /* HT */ ++ HTOnAssocRsp(padapter); ++ ++ /* Set cur_channel&cur_bwmode&cur_ch_offset */ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ ++ psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress); ++ if (psta) /* only for infra. mode */ ++ { ++ pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta; ++ ++ /* DBG_871X("set_sta_rate\n"); */ ++ ++ psta->wireless_mode = pmlmeext->cur_wireless_mode; ++ ++ /* set per sta rate after updating HT cap. */ ++ set_sta_rate(padapter, psta); ++ ++ rtw_sta_media_status_rpt(padapter, psta, 1); ++ ++ /* wakeup macid after join bss successfully to ensure ++ the subsequent data frames can be sent out normally */ ++ rtw_hal_macid_wakeup(padapter, psta->mac_id); ++ } ++ ++ if (rtw_port_switch_chk(padapter) == true) ++ rtw_hal_set_hwreg(padapter, HW_VAR_PORT_SWITCH, NULL); ++ ++ join_type = 2; ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); ++ ++ if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) ++ { ++ /* correcting TSF */ ++ correct_TSF(padapter, pmlmeext); ++ ++ /* set_link_timer(pmlmeext, DISCONNECT_TO); */ ++ } ++ ++ if (get_iface_type(padapter) == IFACE_PORT0) ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_CONNECT, 0); ++ ++exit_mlmeext_joinbss_event_callback: ++ ++ DBG_871X("=>%s\n", __func__); ++ ++} ++ ++/* currently only adhoc mode will go here */ ++void mlmeext_sta_add_event_callback(struct adapter *padapter, struct sta_info *psta) ++{ ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 join_type; ++ ++ DBG_871X("%s\n", __func__); ++ ++ if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) ++ { ++ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)/* adhoc master or sta_count>1 */ ++ { ++ /* nothing to do */ ++ } ++ else/* adhoc client */ ++ { ++ /* update TSF Value */ ++ /* update_TSF(pmlmeext, pframe, len); */ ++ ++ /* correcting TSF */ ++ correct_TSF(padapter, pmlmeext); ++ ++ /* start beacon */ ++ if (send_beacon(padapter) == _FAIL) ++ { ++ pmlmeinfo->FW_sta_info[psta->mac_id].status = 0; ++ ++ pmlmeinfo->state ^= WIFI_FW_ADHOC_STATE; ++ ++ return; ++ } ++ ++ pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; ++ ++ } ++ ++ join_type = 2; ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); ++ } ++ ++ pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta; ++ ++ psta->bssratelen = rtw_get_rateset_len(pmlmeinfo->FW_sta_info[psta->mac_id].SupportedRates); ++ memcpy(psta->bssrateset, pmlmeinfo->FW_sta_info[psta->mac_id].SupportedRates, psta->bssratelen); ++ ++ /* update adhoc sta_info */ ++ update_sta_info(padapter, psta); ++ ++ rtw_hal_update_sta_rate_mask(padapter, psta); ++ ++ /* ToDo: HT for Ad-hoc */ ++ psta->wireless_mode = rtw_check_network_type(psta->bssrateset, psta->bssratelen, pmlmeext->cur_channel); ++ psta->raid = rtw_hal_networktype_to_raid(padapter, psta); ++ ++ /* rate radaptive */ ++ Update_RA_Entry(padapter, psta); ++} ++ ++void mlmeext_sta_del_event_callback(struct adapter *padapter) ++{ ++ if (is_client_associated_to_ap(padapter) || is_IBSS_empty(padapter)) ++ rtw_mlmeext_disconnect(padapter); ++} ++ ++/**************************************************************************** ++ ++Following are the functions for the timer handlers ++ ++*****************************************************************************/ ++void _linked_info_dump(struct adapter *padapter) ++{ ++ int i; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ int UndecoratedSmoothedPWDB; ++ struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); ++ ++ if (padapter->bLinkInfoDump) { ++ ++ DBG_871X("\n ============["ADPT_FMT"] linked status check ===================\n", ADPT_ARG(padapter)); ++ ++ if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) ++ { ++ rtw_hal_get_def_var(padapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &UndecoratedSmoothedPWDB); ++ ++ DBG_871X("AP[" MAC_FMT "] - UndecoratedSmoothedPWDB:%d\n", ++ MAC_ARG(padapter->mlmepriv.cur_network.network.MacAddress), UndecoratedSmoothedPWDB); ++ } ++ else if ((pmlmeinfo->state&0x03) == _HW_STATE_AP_) ++ { ++ struct list_head *phead, *plist; ++ ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ phead = &pstapriv->asoc_list; ++ plist = get_next(phead); ++ while (phead != plist) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); ++ plist = get_next(plist); ++ ++ DBG_871X("STA[" MAC_FMT "]:UndecoratedSmoothedPWDB:%d\n", ++ MAC_ARG(psta->hwaddr), psta->rssi_stat.UndecoratedSmoothedPWDB); ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ } ++ for (i = 0; imacid[i] == true) ++ { ++ if (i != 1) /* skip bc/mc sta */ ++ /* tx info ============ */ ++ rtw_hal_get_def_var(padapter, HW_DEF_RA_INFO_DUMP, &i); ++ } ++ } ++ rtw_hal_set_def_var(padapter, HAL_DEF_DBG_RX_INFO_DUMP, NULL); ++ ++ ++ } ++ ++ ++} ++ ++static u8 chk_ap_is_alive(struct adapter *padapter, struct sta_info *psta) ++{ ++ u8 ret = false; ++ ++ #ifdef DBG_EXPIRATION_CHK ++ DBG_871X(FUNC_ADPT_FMT" rx:"STA_PKTS_FMT", beacon:%llu, probersp_to_self:%llu" ++ /*", probersp_bm:%llu, probersp_uo:%llu, probereq:%llu, BI:%u"*/ ++ ", retry:%u\n" ++ , FUNC_ADPT_ARG(padapter) ++ , STA_RX_PKTS_DIFF_ARG(psta) ++ , psta->sta_stats.rx_beacon_pkts - psta->sta_stats.last_rx_beacon_pkts ++ , psta->sta_stats.rx_probersp_pkts - psta->sta_stats.last_rx_probersp_pkts ++ /*, psta->sta_stats.rx_probersp_bm_pkts - psta->sta_stats.last_rx_probersp_bm_pkts ++ , psta->sta_stats.rx_probersp_uo_pkts - psta->sta_stats.last_rx_probersp_uo_pkts ++ , psta->sta_stats.rx_probereq_pkts - psta->sta_stats.last_rx_probereq_pkts ++ , pmlmeinfo->bcn_interval*/ ++ , pmlmeext->retry ++ ); ++ ++ DBG_871X(FUNC_ADPT_FMT" tx_pkts:%llu, link_count:%u\n", FUNC_ADPT_ARG(padapter) ++ , padapter->xmitpriv.tx_pkts ++ , pmlmeinfo->link_count ++ ); ++ #endif ++ ++ if ((sta_rx_data_pkts(psta) == sta_last_rx_data_pkts(psta)) ++ && sta_rx_beacon_pkts(psta) == sta_last_rx_beacon_pkts(psta) ++ && sta_rx_probersp_pkts(psta) == sta_last_rx_probersp_pkts(psta) ++ ) ++ { ++ ret = false; ++ } ++ else ++ { ++ ret = true; ++ } ++ ++ sta_update_last_rx_pkts(psta); ++ ++ return ret; ++} ++ ++void linked_status_chk(struct adapter *padapter) ++{ ++ u32 i; ++ struct sta_info *psta; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ ++ if (is_client_associated_to_ap(padapter)) ++ { ++ /* linked infrastructure client mode */ ++ ++ int tx_chk = _SUCCESS, rx_chk = _SUCCESS; ++ int rx_chk_limit; ++ int link_count_limit; ++ ++ #if defined(DBG_ROAMING_TEST) ++ rx_chk_limit = 1; ++ #else ++ rx_chk_limit = 8; ++ #endif ++ link_count_limit = 7; /* 16 sec */ ++ ++ /* Marked by Kurt 20130715 */ ++ /* For WiDi 3.5 and latered on, they don't ask WiDi sink to do roaming, so we could not check rx limit that strictly. */ ++ /* todo: To check why we under miracast session, rx_chk would be false */ ++ /* ifdef CONFIG_INTEL_WIDI */ ++ /* if (padapter->mlmepriv.widi_state != INTEL_WIDI_STATE_NONE) */ ++ /* rx_chk_limit = 1; */ ++ /* endif */ ++ ++ if ((psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress)) != NULL) ++ { ++ if (chk_ap_is_alive(padapter, psta) == false) ++ rx_chk = _FAIL; ++ ++ if (pxmitpriv->last_tx_pkts == pxmitpriv->tx_pkts) ++ tx_chk = _FAIL; ++ ++ { ++ if (rx_chk != _SUCCESS) { ++ if (pmlmeext->retry == 0) { ++ #ifdef DBG_EXPIRATION_CHK ++ DBG_871X("issue_probereq to trigger probersp, retry =%d\n", pmlmeext->retry); ++ #endif ++ issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress, 0, 0, 0, 0); ++ issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress, 0, 0, 0, 0); ++ issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress, 0, 0, 0, 0); ++ } ++ } ++ ++ if (tx_chk != _SUCCESS && pmlmeinfo->link_count++ == link_count_limit) { ++ #ifdef DBG_EXPIRATION_CHK ++ DBG_871X("%s issue_nulldata 0\n", __func__); ++ #endif ++ tx_chk = issue_nulldata_in_interrupt(padapter, NULL); ++ } ++ } ++ ++ if (rx_chk == _FAIL) { ++ pmlmeext->retry++; ++ if (pmlmeext->retry > rx_chk_limit) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" disconnect or roaming\n", ++ FUNC_ADPT_ARG(padapter)); ++ receive_disconnect(padapter, pmlmeinfo->network.MacAddress ++ , WLAN_REASON_EXPIRATION_CHK); ++ return; ++ } ++ } else { ++ pmlmeext->retry = 0; ++ } ++ ++ if (tx_chk == _FAIL) { ++ pmlmeinfo->link_count %= (link_count_limit+1); ++ } else { ++ pxmitpriv->last_tx_pkts = pxmitpriv->tx_pkts; ++ pmlmeinfo->link_count = 0; ++ } ++ ++ } /* end of if ((psta = rtw_get_stainfo(pstapriv, passoc_res->network.MacAddress)) != NULL) */ ++ } ++ else if (is_client_associated_to_ibss(padapter)) ++ { ++ /* linked IBSS mode */ ++ /* for each assoc list entry to check the rx pkt counter */ ++ for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) ++ { ++ if (pmlmeinfo->FW_sta_info[i].status == 1) ++ { ++ psta = pmlmeinfo->FW_sta_info[i].psta; ++ ++ if (NULL ==psta) continue; ++ ++ if (pmlmeinfo->FW_sta_info[i].rx_pkt == sta_rx_pkts(psta)) ++ { ++ ++ if (pmlmeinfo->FW_sta_info[i].retry<3) ++ { ++ pmlmeinfo->FW_sta_info[i].retry++; ++ } ++ else ++ { ++ pmlmeinfo->FW_sta_info[i].retry = 0; ++ pmlmeinfo->FW_sta_info[i].status = 0; ++ report_del_sta_event(padapter, psta->hwaddr ++ , 65535/* indicate disconnect caused by no rx */ ++ ); ++ } ++ } ++ else ++ { ++ pmlmeinfo->FW_sta_info[i].retry = 0; ++ pmlmeinfo->FW_sta_info[i].rx_pkt = (u32)sta_rx_pkts(psta); ++ } ++ } ++ } ++ ++ /* set_link_timer(pmlmeext, DISCONNECT_TO); */ ++ ++ } ++ ++} ++ ++void survey_timer_hdl(struct adapter *padapter) ++{ ++ struct cmd_obj *ph2c; ++ struct sitesurvey_parm *psurveyPara; ++ struct cmd_priv *pcmdpriv =&padapter->cmdpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ /* DBG_871X("marc: survey timer\n"); */ ++ ++ /* issue rtw_sitesurvey_cmd */ ++ if (pmlmeext->sitesurvey_res.state > SCAN_START) ++ { ++ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) ++ { ++ pmlmeext->sitesurvey_res.channel_idx++; ++ } ++ ++ if (pmlmeext->scan_abort == true) ++ { ++ { ++ pmlmeext->sitesurvey_res.channel_idx = pmlmeext->sitesurvey_res.ch_num; ++ DBG_871X("%s idx:%d\n", __func__ ++ , pmlmeext->sitesurvey_res.channel_idx ++ ); ++ } ++ ++ pmlmeext->scan_abort = false;/* reset */ ++ } ++ ++ if ((ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj))) == NULL) ++ { ++ goto exit_survey_timer_hdl; ++ } ++ ++ if ((psurveyPara = (struct sitesurvey_parm*)rtw_zmalloc(sizeof(struct sitesurvey_parm))) == NULL) ++ { ++ kfree((unsigned char *)ph2c); ++ goto exit_survey_timer_hdl; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey)); ++ rtw_enqueue_cmd(pcmdpriv, ph2c); ++ } ++ ++ ++exit_survey_timer_hdl: ++ ++ return; ++} ++ ++void link_timer_hdl(struct adapter *padapter) ++{ ++ /* static unsigned int rx_pkt = 0; */ ++ /* static u64 tx_cnt = 0; */ ++ /* struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); */ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ /* struct sta_priv *pstapriv = &padapter->stapriv; */ ++ ++ ++ if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) ++ { ++ DBG_871X("link_timer_hdl:no beacon while connecting\n"); ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ report_join_res(padapter, -3); ++ } ++ else if (pmlmeinfo->state & WIFI_FW_AUTH_STATE) ++ { ++ /* re-auth timer */ ++ if (++pmlmeinfo->reauth_count > REAUTH_LIMIT) ++ { ++ /* if (pmlmeinfo->auth_algo != dot11AuthAlgrthm_Auto) */ ++ /* */ ++ pmlmeinfo->state = 0; ++ report_join_res(padapter, -1); ++ return; ++ /* */ ++ /* else */ ++ /* */ ++ /* pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared; */ ++ /* pmlmeinfo->reauth_count = 0; */ ++ /* */ ++ } ++ ++ DBG_871X("link_timer_hdl: auth timeout and try again\n"); ++ pmlmeinfo->auth_seq = 1; ++ issue_auth(padapter, NULL, 0); ++ set_link_timer(pmlmeext, REAUTH_TO); ++ } ++ else if (pmlmeinfo->state & WIFI_FW_ASSOC_STATE) ++ { ++ /* re-assoc timer */ ++ if (++pmlmeinfo->reassoc_count > REASSOC_LIMIT) ++ { ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ report_join_res(padapter, -2); ++ return; ++ } ++ ++ DBG_871X("link_timer_hdl: assoc timeout and try again\n"); ++ issue_assocreq(padapter); ++ set_link_timer(pmlmeext, REASSOC_TO); ++ } ++ ++ return; ++} ++ ++void addba_timer_hdl(struct sta_info *psta) ++{ ++ struct ht_priv *phtpriv; ++ ++ if (!psta) ++ return; ++ ++ phtpriv = &psta->htpriv; ++ ++ if ((phtpriv->ht_option ==true) && (phtpriv->ampdu_enable ==true)) ++ { ++ if (phtpriv->candidate_tid_bitmap) ++ phtpriv->candidate_tid_bitmap = 0x0; ++ ++ } ++} ++ ++void sa_query_timer_hdl(struct adapter *padapter) ++{ ++ struct mlme_priv * pmlmepriv = &padapter->mlmepriv; ++ /* disconnect */ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) ++ { ++ rtw_disassoc_cmd(padapter, 0, true); ++ rtw_indicate_disconnect(padapter); ++ rtw_free_assoc_resources(padapter, 1); ++ } ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++ DBG_871X("SA query timeout disconnect\n"); ++} ++ ++u8 NULL_hdl(struct adapter *padapter, u8 *pbuf) ++{ ++ return H2C_SUCCESS; ++} ++ ++#ifdef CONFIG_AUTO_AP_MODE ++static int rtw_auto_ap_start_beacon(struct adapter *adapter) ++{ ++ int ret = 0; ++ u8 *pbuf = NULL; ++ uint len; ++ u8 supportRate[16]; ++ int sz = 0, rateLen; ++ u8 *ie; ++ u8 wireless_mode, oper_channel; ++ u8 ssid[3] = {0}; /* hidden ssid */ ++ u32 ssid_len = sizeof(ssid); ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) ++ return -EINVAL; ++ ++ ++ len = 128; ++ pbuf = rtw_zmalloc(len); ++ if (!pbuf) ++ return -ENOMEM; ++ ++ ++ /* generate beacon */ ++ ie = pbuf; ++ ++ /* timestamp will be inserted by hardware */ ++ sz += 8; ++ ie += sz; ++ ++ /* beacon interval : 2bytes */ ++ *(u16*)ie = cpu_to_le16((u16)100);/* BCN_INTERVAL = 100; */ ++ sz += 2; ++ ie += 2; ++ ++ /* capability info */ ++ *(u16*)ie = 0; ++ *(u16*)ie |= cpu_to_le16(cap_ESS); ++ *(u16*)ie |= cpu_to_le16(cap_ShortPremble); ++ /* u16*)ie |= cpu_to_le16(cap_Privacy); */ ++ sz += 2; ++ ie += 2; ++ ++ /* SSID */ ++ ie = rtw_set_ie(ie, _SSID_IE_, ssid_len, ssid, &sz); ++ ++ /* supported rates */ ++ wireless_mode = WIRELESS_11BG_24N; ++ rtw_set_supported_rate(supportRate, wireless_mode) ; ++ rateLen = rtw_get_rateset_len(supportRate); ++ if (rateLen > 8) ++ { ++ ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, 8, supportRate, &sz); ++ } ++ else ++ { ++ ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, rateLen, supportRate, &sz); ++ } ++ ++ ++ /* DS parameter set */ ++ if (check_buddy_fwstate(adapter, _FW_LINKED) && ++ check_buddy_fwstate(adapter, WIFI_STATION_STATE)) ++ { ++ struct adapter * pbuddystruct adapter = adapter->pbuddystruct adapter; ++ struct mlme_ext_priv *pbuddy_mlmeext = &pbuddystruct adapter->mlmeextpriv; ++ ++ oper_channel = pbuddy_mlmeext->cur_channel; ++ } ++ else ++ { ++ oper_channel = adapter_to_dvobj(adapter)->oper_channel; ++ } ++ ie = rtw_set_ie(ie, _DSSET_IE_, 1, &oper_channel, &sz); ++ ++ /* ext supported rates */ ++ if (rateLen > 8) ++ { ++ ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (supportRate + 8), &sz); ++ } ++ ++ DBG_871X("%s, start auto ap beacon sz =%d\n", __func__, sz); ++ ++ /* lunch ap mode & start to issue beacon */ ++ if (rtw_check_beacon_data(adapter, pbuf, sz) == _SUCCESS) ++ { ++ ++ } ++ else ++ { ++ ret = -EINVAL; ++ } ++ ++ ++ kfree(pbuf); ++ ++ return ret; ++ ++} ++#endif/* CONFIG_AUTO_AP_MODE */ ++ ++u8 setopmode_hdl(struct adapter *padapter, u8 *pbuf) ++{ ++ u8 type; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct setopmode_parm *psetop = (struct setopmode_parm *)pbuf; ++ ++ if (psetop->mode == Ndis802_11APMode) ++ { ++ pmlmeinfo->state = WIFI_FW_AP_STATE; ++ type = _HW_STATE_AP_; ++ /* start_ap_mode(padapter); */ ++ } ++ else if (psetop->mode == Ndis802_11Infrastructure) ++ { ++ pmlmeinfo->state &= ~(BIT(0)|BIT(1));/* clear state */ ++ pmlmeinfo->state |= WIFI_FW_STATION_STATE;/* set to STATION_STATE */ ++ type = _HW_STATE_STATION_; ++ } ++ else if (psetop->mode == Ndis802_11IBSS) ++ { ++ type = _HW_STATE_ADHOC_; ++ } ++ else ++ { ++ type = _HW_STATE_NOLINK_; ++ } ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_SET_OPMODE, (u8 *)(&type)); ++ /* Set_NETYPE0_MSR(padapter, type); */ ++ ++ ++#ifdef CONFIG_AUTO_AP_MODE ++ if (psetop->mode == Ndis802_11APMode) ++ rtw_auto_ap_start_beacon(padapter); ++#endif ++ ++ if (rtw_port_switch_chk(padapter) == true) ++ { ++ rtw_hal_set_hwreg(padapter, HW_VAR_PORT_SWITCH, NULL); ++ ++ if (psetop->mode == Ndis802_11APMode) ++ adapter_to_pwrctl(padapter)->fw_psmode_iface_id = 0xff; /* ap mode won't dowload rsvd pages */ ++ else if (psetop->mode == Ndis802_11Infrastructure) { ++ struct adapter *port0_iface = dvobj_get_port0_adapter(adapter_to_dvobj(padapter)); ++ if (port0_iface) ++ rtw_lps_ctrl_wk_cmd(port0_iface, LPS_CTRL_CONNECT, 0); ++ } ++ } ++ ++ if (psetop->mode == Ndis802_11APMode) ++ { ++ /* Do this after port switch to */ ++ /* prevent from downloading rsvd page to wrong port */ ++ rtw_btcoex_MediaStatusNotify(padapter, 1); /* connect */ ++ } ++ ++ return H2C_SUCCESS; ++ ++} ++ ++u8 createbss_hdl(struct adapter *padapter, u8 *pbuf) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex*)(&(pmlmeinfo->network)); ++ struct joinbss_parm *pparm = (struct joinbss_parm *)pbuf; ++ /* u32 initialgain; */ ++ ++ if (pmlmeinfo->state == WIFI_FW_AP_STATE) { ++ struct wlan_bssid_ex *network = &padapter->mlmepriv.cur_network.network; ++ start_bss_network(padapter, (u8 *)network); ++ return H2C_SUCCESS; ++ } ++ ++ /* below is for ad-hoc master */ ++ if (pparm->network.InfrastructureMode == Ndis802_11IBSS) ++ { ++ rtw_joinbss_reset(padapter); ++ ++ pmlmeext->cur_bwmode = CHANNEL_WIDTH_20; ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ pmlmeinfo->ERP_enable = 0; ++ pmlmeinfo->WMM_enable = 0; ++ pmlmeinfo->HT_enable = 0; ++ pmlmeinfo->HT_caps_enable = 0; ++ pmlmeinfo->HT_info_enable = 0; ++ pmlmeinfo->agg_enable_bitmap = 0; ++ pmlmeinfo->candidate_tid_bitmap = 0; ++ ++ /* disable dynamic functions, such as high power, DIG */ ++ Save_DM_Func_Flag(padapter); ++ Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, false); ++ ++ /* config the initial gain under linking, need to write the BB registers */ ++ /* initialgain = 0x1E; */ ++ /* rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); */ ++ ++ /* cancel link timer */ ++ del_timer_sync(&pmlmeext->link_timer); ++ ++ /* clear CAM */ ++ flush_all_cam_entry(padapter); ++ ++ memcpy(pnetwork, pbuf, FIELD_OFFSET(struct wlan_bssid_ex, IELength)); ++ pnetwork->IELength = ((struct wlan_bssid_ex *)pbuf)->IELength; ++ ++ if (pnetwork->IELength>MAX_IE_SZ)/* Check pbuf->IELength */ ++ return H2C_PARAMETERS_ERROR; ++ ++ memcpy(pnetwork->IEs, ((struct wlan_bssid_ex *)pbuf)->IEs, pnetwork->IELength); ++ ++ start_create_ibss(padapter); ++ ++ } ++ ++ return H2C_SUCCESS; ++ ++} ++ ++u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf) ++{ ++ u8 join_type; ++ struct ndis_80211_var_ie * pIE; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex*)(&(pmlmeinfo->network)); ++ u32 i; ++ u8 cbw40_enable = 0; ++ /* u32 initialgain; */ ++ /* u32 acparm; */ ++ u8 ch, bw, offset; ++ ++ /* check already connecting to AP or not */ ++ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) ++ { ++ if (pmlmeinfo->state & WIFI_FW_STATION_STATE) ++ { ++ issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, 1, 100); ++ } ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ ++ /* clear CAM */ ++ flush_all_cam_entry(padapter); ++ ++ del_timer_sync(&pmlmeext->link_timer); ++ ++ /* set MSR to nolink -> infra. mode */ ++ /* Set_MSR(padapter, _HW_STATE_NOLINK_); */ ++ Set_MSR(padapter, _HW_STATE_STATION_); ++ ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, NULL); ++ } ++ ++ rtw_joinbss_reset(padapter); ++ ++ pmlmeext->cur_bwmode = CHANNEL_WIDTH_20; ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ pmlmeinfo->ERP_enable = 0; ++ pmlmeinfo->WMM_enable = 0; ++ pmlmeinfo->HT_enable = 0; ++ pmlmeinfo->HT_caps_enable = 0; ++ pmlmeinfo->HT_info_enable = 0; ++ pmlmeinfo->agg_enable_bitmap = 0; ++ pmlmeinfo->candidate_tid_bitmap = 0; ++ pmlmeinfo->bwmode_updated = false; ++ /* pmlmeinfo->assoc_AP_vendor = HT_IOT_PEER_MAX; */ ++ pmlmeinfo->VHT_enable = 0; ++ ++ memcpy(pnetwork, pbuf, FIELD_OFFSET(struct wlan_bssid_ex, IELength)); ++ pnetwork->IELength = ((struct wlan_bssid_ex *)pbuf)->IELength; ++ ++ if (pnetwork->IELength>MAX_IE_SZ)/* Check pbuf->IELength */ ++ return H2C_PARAMETERS_ERROR; ++ ++ memcpy(pnetwork->IEs, ((struct wlan_bssid_ex *)pbuf)->IEs, pnetwork->IELength); ++ ++ pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig; ++ pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork); ++ ++ /* Check AP vendor to move rtw_joinbss_cmd() */ ++ /* pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->IEs, pnetwork->IELength); */ ++ ++ /* sizeof(struct ndis_802_11_fix_ie) */ ++ for (i = _FIXED_IE_LENGTH_; i < pnetwork->IELength;) ++ { ++ pIE = (struct ndis_80211_var_ie *)(pnetwork->IEs + i); ++ ++ switch (pIE->ElementID) ++ { ++ case _VENDOR_SPECIFIC_IE_:/* Get WMM IE. */ ++ if (!memcmp(pIE->data, WMM_OUI, 4)) ++ { ++ WMM_param_handler(padapter, pIE); ++ } ++ break; ++ ++ case _HT_CAPABILITY_IE_: /* Get HT Cap IE. */ ++ pmlmeinfo->HT_caps_enable = 1; ++ break; ++ ++ case _HT_EXTRA_INFO_IE_: /* Get HT Info IE. */ ++ pmlmeinfo->HT_info_enable = 1; ++ ++ /* spec case only for cisco's ap because cisco's ap issue assoc rsp using mcs rate @40MHz or @20MHz */ ++ { ++ struct HT_info_element *pht_info = (struct HT_info_element *)(pIE->data); ++ ++ if (pnetwork->Configuration.DSConfig > 14) { ++ if ((pregpriv->bw_mode >> 4) > CHANNEL_WIDTH_20) ++ cbw40_enable = 1; ++ } else { ++ if ((pregpriv->bw_mode & 0x0f) > CHANNEL_WIDTH_20) ++ cbw40_enable = 1; ++ } ++ ++ if ((cbw40_enable) && (pht_info->infos[0] & BIT(2))) ++ { ++ /* switch to the 40M Hz mode according to the AP */ ++ pmlmeext->cur_bwmode = CHANNEL_WIDTH_40; ++ switch (pht_info->infos[0] & 0x3) ++ { ++ case 1: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ break; ++ ++ case 3: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ break; ++ ++ default: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ pmlmeext->cur_bwmode = CHANNEL_WIDTH_20; ++ break; ++ } ++ ++ DBG_871X("set HT ch/bw before connected\n"); ++ } ++ } ++ break; ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++ ++ /* check channel, bandwidth, offset and switch */ ++ if (rtw_chk_start_clnt_join(padapter, &ch, &bw, &offset) == _FAIL) { ++ report_join_res(padapter, (-4)); ++ return H2C_SUCCESS; ++ } ++ ++ /* disable dynamic functions, such as high power, DIG */ ++ /* Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, false); */ ++ ++ /* config the initial gain under linking, need to write the BB registers */ ++ /* initialgain = 0x1E; */ ++ /* rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); */ ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pmlmeinfo->network.MacAddress); ++ join_type = 0; ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); ++ rtw_hal_set_hwreg(padapter, HW_VAR_DO_IQK, NULL); ++ ++ set_channel_bwmode(padapter, ch, offset, bw); ++ ++ /* cancel link timer */ ++ del_timer_sync(&pmlmeext->link_timer); ++ ++ start_clnt_join(padapter); ++ ++ return H2C_SUCCESS; ++ ++} ++ ++u8 disconnect_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ struct disconnect_parm *param = (struct disconnect_parm *)pbuf; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex*)(&(pmlmeinfo->network)); ++ u8 val8; ++ ++ if (is_client_associated_to_ap(padapter)) ++ { ++ issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, param->deauth_timeout_ms/100, 100); ++ } ++ ++ if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) ++ { ++ /* Stop BCN */ ++ val8 = 0; ++ rtw_hal_set_hwreg(padapter, HW_VAR_BCN_FUNC, (u8 *)(&val8)); ++ } ++ ++ rtw_mlmeext_disconnect(padapter); ++ ++ rtw_free_uc_swdec_pending_queue(padapter); ++ ++ return H2C_SUCCESS; ++} ++ ++static int rtw_scan_ch_decision(struct adapter *padapter, struct rtw_ieee80211_channel *out, ++ u32 out_num, struct rtw_ieee80211_channel *in, u32 in_num) ++{ ++ int i, j; ++ int set_idx; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ /* clear first */ ++ memset(out, 0, sizeof(struct rtw_ieee80211_channel)*out_num); ++ ++ /* acquire channels from in */ ++ j = 0; ++ for (i = 0;ichannel_set, in[i].hw_value)) >= 0 ++ && rtw_mlme_band_check(padapter, in[i].hw_value) == true ++ ) ++ { ++ if (j >= out_num) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" out_num:%u not enough\n", ++ FUNC_ADPT_ARG(padapter), out_num); ++ break; ++ } ++ ++ memcpy(&out[j], &in[i], sizeof(struct rtw_ieee80211_channel)); ++ ++ if (pmlmeext->channel_set[set_idx].ScanType == SCAN_PASSIVE) ++ out[j].flags |= RTW_IEEE80211_CHAN_PASSIVE_SCAN; ++ ++ j++; ++ } ++ if (j>=out_num) ++ break; ++ } ++ ++ /* if out is empty, use channel_set as default */ ++ if (j == 0) { ++ for (i = 0;imax_chan_nums;i++) { ++ ++ DBG_871X(FUNC_ADPT_FMT" ch:%u\n", FUNC_ADPT_ARG(padapter), pmlmeext->channel_set[i].ChannelNum); ++ ++ if (rtw_mlme_band_check(padapter, pmlmeext->channel_set[i].ChannelNum) == true) { ++ ++ if (j >= out_num) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" out_num:%u not enough\n", ++ FUNC_ADPT_ARG(padapter), out_num); ++ break; ++ } ++ ++ out[j].hw_value = pmlmeext->channel_set[i].ChannelNum; ++ ++ if (pmlmeext->channel_set[i].ScanType == SCAN_PASSIVE) ++ out[j].flags |= RTW_IEEE80211_CHAN_PASSIVE_SCAN; ++ ++ j++; ++ } ++ } ++ } ++ ++ return j; ++} ++ ++u8 sitesurvey_cmd_hdl(struct adapter *padapter, u8 *pbuf) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct sitesurvey_parm *pparm = (struct sitesurvey_parm *)pbuf; ++ u8 bdelayscan = false; ++ u8 val8; ++ u32 initialgain; ++ u32 i; ++ ++ if (pmlmeext->sitesurvey_res.state == SCAN_DISABLE) ++ { ++ pmlmeext->sitesurvey_res.state = SCAN_START; ++ pmlmeext->sitesurvey_res.bss_cnt = 0; ++ pmlmeext->sitesurvey_res.channel_idx = 0; ++ ++ for (i = 0;issid[i].SsidLength) { ++ memcpy(pmlmeext->sitesurvey_res.ssid[i].Ssid, pparm->ssid[i].Ssid, IW_ESSID_MAX_SIZE); ++ pmlmeext->sitesurvey_res.ssid[i].SsidLength = pparm->ssid[i].SsidLength; ++ } else { ++ pmlmeext->sitesurvey_res.ssid[i].SsidLength = 0; ++ } ++ } ++ ++ pmlmeext->sitesurvey_res.ch_num = rtw_scan_ch_decision(padapter ++ , pmlmeext->sitesurvey_res.ch, RTW_CHANNEL_SCAN_AMOUNT ++ , pparm->ch, pparm->ch_num ++ ); ++ ++ pmlmeext->sitesurvey_res.scan_mode = pparm->scan_mode; ++ ++ /* issue null data if associating to the AP */ ++ if (is_client_associated_to_ap(padapter) == true) ++ { ++ pmlmeext->sitesurvey_res.state = SCAN_TXNULL; ++ ++ issue_nulldata(padapter, NULL, 1, 3, 500); ++ ++ bdelayscan = true; ++ } ++ if (bdelayscan) ++ { ++ /* delay 50ms to protect nulldata(1). */ ++ set_survey_timer(pmlmeext, 50); ++ return H2C_SUCCESS; ++ } ++ } ++ ++ if ((pmlmeext->sitesurvey_res.state == SCAN_START) || (pmlmeext->sitesurvey_res.state == SCAN_TXNULL)) ++ { ++ /* disable dynamic functions, such as high power, DIG */ ++ Save_DM_Func_Flag(padapter); ++ Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, false); ++ ++ /* config the initial gain under scaning, need to write the BB registers */ ++ initialgain = 0x1e; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); ++ ++ /* set MSR to no link state */ ++ Set_MSR(padapter, _HW_STATE_NOLINK_); ++ ++ val8 = 1; /* under site survey */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ ++ pmlmeext->sitesurvey_res.state = SCAN_PROCESS; ++ } ++ ++ site_survey(padapter); ++ ++ return H2C_SUCCESS; ++ ++} ++ ++u8 setauth_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ struct setauth_parm *pparm = (struct setauth_parm *)pbuf; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if (pparm->mode < 4) ++ { ++ pmlmeinfo->auth_algo = pparm->mode; ++ } ++ ++ return H2C_SUCCESS; ++} ++ ++u8 setkey_hdl(struct adapter *padapter, u8 *pbuf) ++{ ++ u16 ctrl = 0; ++ s16 cam_id = 0; ++ struct setkey_parm *pparm = (struct setkey_parm *)pbuf; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ unsigned char null_addr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ++ u8 *addr; ++ ++ /* main tx key for wep. */ ++ if (pparm->set_tx) ++ pmlmeinfo->key_index = pparm->keyid; ++ ++ cam_id = rtw_camid_alloc(padapter, NULL, pparm->keyid); ++ ++ if (cam_id < 0) { ++ } else { ++ if (cam_id > 3) /* not default key, searched by A2 */ ++ addr = get_bssid(&padapter->mlmepriv); ++ else ++ addr = null_addr; ++ ++ ctrl = BIT(15) | BIT6 |((pparm->algorithm) << 2) | pparm->keyid; ++ write_cam(padapter, cam_id, ctrl, addr, pparm->key); ++ DBG_871X_LEVEL(_drv_always_, "set group key camid:%d, addr:"MAC_FMT", kid:%d, type:%s\n" ++ , cam_id, MAC_ARG(addr), pparm->keyid, security_type_str(pparm->algorithm)); ++ } ++ ++ if (cam_id >= 0 && cam_id <=3) ++ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_DK_CFG, (u8 *)true); ++ ++ /* allow multicast packets to driver */ ++ padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_ON_RCR_AM, null_addr); ++ ++ return H2C_SUCCESS; ++} ++ ++u8 set_stakey_hdl(struct adapter *padapter, u8 *pbuf) ++{ ++ u16 ctrl = 0; ++ s16 cam_id = 0; ++ u8 ret = H2C_SUCCESS; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct set_stakey_parm *pparm = (struct set_stakey_parm *)pbuf; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *psta; ++ ++ if (pparm->algorithm == _NO_PRIVACY_) ++ goto write_to_cam; ++ ++ psta = rtw_get_stainfo(pstapriv, pparm->addr); ++ if (!psta) { ++ DBG_871X_LEVEL(_drv_always_, "%s sta:"MAC_FMT" not found\n", __func__, MAC_ARG(pparm->addr)); ++ ret = H2C_REJECTED; ++ goto exit; ++ } ++ ++ pmlmeinfo->enc_algo = pparm->algorithm; ++ cam_id = rtw_camid_alloc(padapter, psta, 0); ++ if (cam_id < 0) ++ goto exit; ++ ++write_to_cam: ++ if (pparm->algorithm == _NO_PRIVACY_) { ++ while ((cam_id = rtw_camid_search(padapter, pparm->addr, -1)) >= 0) { ++ DBG_871X_LEVEL(_drv_always_, "clear key for addr:"MAC_FMT", camid:%d\n", MAC_ARG(pparm->addr), cam_id); ++ clear_cam_entry(padapter, cam_id); ++ rtw_camid_free(padapter, cam_id); ++ } ++ } else { ++ DBG_871X_LEVEL(_drv_always_, "set pairwise key camid:%d, addr:"MAC_FMT", kid:%d, type:%s\n", ++ cam_id, MAC_ARG(pparm->addr), pparm->keyid, security_type_str(pparm->algorithm)); ++ ctrl = BIT(15) | ((pparm->algorithm) << 2) | pparm->keyid; ++ write_cam(padapter, cam_id, ctrl, pparm->addr, pparm->key); ++ } ++ ret = H2C_SUCCESS_RSP; ++ ++exit: ++ return ret; ++} ++ ++u8 add_ba_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ struct addBaReq_parm *pparm = (struct addBaReq_parm *)pbuf; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, pparm->addr); ++ ++ if (!psta) ++ return H2C_SUCCESS; ++ ++ if (((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && (pmlmeinfo->HT_enable)) || ++ ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) ++ { ++ /* pmlmeinfo->ADDBA_retry_count = 0; */ ++ /* pmlmeinfo->candidate_tid_bitmap |= (0x1 << pparm->tid); */ ++ /* psta->htpriv.candidate_tid_bitmap |= BIT(pparm->tid); */ ++ issue_action_BA(padapter, pparm->addr, RTW_WLAN_ACTION_ADDBA_REQ, (u16)pparm->tid); ++ /* _set_timer(&pmlmeext->ADDBA_timer, ADDBA_TO); */ ++ _set_timer(&psta->addba_retry_timer, ADDBA_TO); ++ } ++ else ++ { ++ psta->htpriv.candidate_tid_bitmap &= ~BIT(pparm->tid); ++ } ++ return H2C_SUCCESS; ++} ++ ++ ++u8 chk_bmc_sleepq_cmd(struct adapter *padapter) ++{ ++ struct cmd_obj *ph2c; ++ struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); ++ u8 res = _SUCCESS; ++ ++ if ((ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj))) == NULL) ++ { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_parm_rsp(ph2c, GEN_CMD_CODE(_ChkBMCSleepq)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ return res; ++} ++ ++u8 set_tx_beacon_cmd(struct adapter *padapter) ++{ ++ struct cmd_obj *ph2c; ++ struct Tx_Beacon_param *ptxBeacon_parm; ++ struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u8 res = _SUCCESS; ++ int len_diff = 0; ++ ++ if ((ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj))) == NULL) ++ { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ if ((ptxBeacon_parm = (struct Tx_Beacon_param *)rtw_zmalloc(sizeof(struct Tx_Beacon_param))) == NULL) ++ { ++ kfree((unsigned char *)ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ memcpy(&(ptxBeacon_parm->network), &(pmlmeinfo->network), sizeof(struct wlan_bssid_ex)); ++ ++ len_diff = update_hidden_ssid( ++ ptxBeacon_parm->network.IEs+_BEACON_IE_OFFSET_ ++ , ptxBeacon_parm->network.IELength-_BEACON_IE_OFFSET_ ++ , pmlmeinfo->hidden_ssid_mode ++ ); ++ ptxBeacon_parm->network.IELength += len_diff; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, ptxBeacon_parm, GEN_CMD_CODE(_TX_Beacon)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ return res; ++} ++ ++ ++u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ u8 evt_code, evt_seq; ++ u16 evt_sz; ++ uint *peventbuf; ++ void (*event_callback)(struct adapter *dev, u8 *pbuf); ++ struct evt_priv *pevt_priv = &(padapter->evtpriv); ++ ++ if (pbuf == NULL) ++ goto _abort_event_; ++ ++ peventbuf = (uint*)pbuf; ++ evt_sz = (u16)(*peventbuf&0xffff); ++ evt_seq = (u8)((*peventbuf>>24)&0x7f); ++ evt_code = (u8)((*peventbuf>>16)&0xff); ++ ++ ++ #ifdef CHECK_EVENT_SEQ ++ /* checking event sequence... */ ++ if (evt_seq != (atomic_read(&pevt_priv->event_seq) & 0x7f)) ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("Evetn Seq Error! %d vs %d\n", (evt_seq & 0x7f), (atomic_read(&pevt_priv->event_seq) & 0x7f))); ++ ++ pevt_priv->event_seq = (evt_seq+1)&0x7f; ++ ++ goto _abort_event_; ++ } ++ #endif ++ ++ /* checking if event code is valid */ ++ if (evt_code >= MAX_C2HEVT) ++ { ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nEvent Code(%d) mismatch!\n", evt_code)); ++ goto _abort_event_; ++ } ++ ++ /* checking if event size match the event parm size */ ++ if ((wlanevents[evt_code].parmsize != 0) && ++ (wlanevents[evt_code].parmsize != evt_sz)) ++ { ++ ++ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nEvent(%d) Parm Size mismatch (%d vs %d)!\n", ++ evt_code, wlanevents[evt_code].parmsize, evt_sz)); ++ goto _abort_event_; ++ ++ } ++ ++ atomic_inc(&pevt_priv->event_seq); ++ ++ peventbuf += 2; ++ ++ if (peventbuf) ++ { ++ event_callback = wlanevents[evt_code].event_callback; ++ event_callback(padapter, (u8 *)peventbuf); ++ ++ pevt_priv->evt_done_cnt++; ++ } ++ ++ ++_abort_event_: ++ ++ ++ return H2C_SUCCESS; ++ ++} ++ ++u8 h2c_msg_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ if (!pbuf) ++ return H2C_PARAMETERS_ERROR; ++ ++ return H2C_SUCCESS; ++} ++ ++u8 chk_bmc_sleepq_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ struct sta_info *psta_bmc; ++ struct list_head *xmitframe_plist, *xmitframe_phead; ++ struct xmit_frame *pxmitframe = NULL; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ /* for BC/MC Frames */ ++ psta_bmc = rtw_get_bcmc_stainfo(padapter); ++ if (!psta_bmc) ++ return H2C_SUCCESS; ++ ++ if ((pstapriv->tim_bitmap&BIT(0)) && (psta_bmc->sleepq_len>0)) ++ { ++ msleep(10);/* 10ms, ATIM(HIQ) Windows */ ++ ++ /* spin_lock_bh(&psta_bmc->sleep_q.lock); */ ++ spin_lock_bh(&pxmitpriv->lock); ++ ++ xmitframe_phead = get_list_head(&psta_bmc->sleep_q); ++ xmitframe_plist = get_next(xmitframe_phead); ++ ++ while (xmitframe_phead != xmitframe_plist) ++ { ++ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); ++ ++ xmitframe_plist = get_next(xmitframe_plist); ++ ++ list_del_init(&pxmitframe->list); ++ ++ psta_bmc->sleepq_len--; ++ if (psta_bmc->sleepq_len>0) ++ pxmitframe->attrib.mdata = 1; ++ else ++ pxmitframe->attrib.mdata = 0; ++ ++ pxmitframe->attrib.triggered = 1; ++ ++ if (xmitframe_hiq_filter(pxmitframe) == true) ++ pxmitframe->attrib.qsel = 0x11;/* HIQ */ ++ ++ rtw_hal_xmitframe_enqueue(padapter, pxmitframe); ++ } ++ ++ /* spin_unlock_bh(&psta_bmc->sleep_q.lock); */ ++ spin_unlock_bh(&pxmitpriv->lock); ++ ++ /* check hi queue and bmc_sleepq */ ++ rtw_chk_hi_queue_cmd(padapter); ++ } ++ ++ return H2C_SUCCESS; ++} ++ ++u8 tx_beacon_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ if (send_beacon(padapter) == _FAIL) ++ { ++ DBG_871X("issue_beacon, fail!\n"); ++ return H2C_PARAMETERS_ERROR; ++ } ++ ++ /* tx bc/mc frames after update TIM */ ++ chk_bmc_sleepq_hdl(padapter, NULL); ++ ++ return H2C_SUCCESS; ++} ++ ++int rtw_chk_start_clnt_join(struct adapter *padapter, u8 *ch, u8 *bw, u8 *offset) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ unsigned char cur_ch = pmlmeext->cur_channel; ++ unsigned char cur_bw = pmlmeext->cur_bwmode; ++ unsigned char cur_ch_offset = pmlmeext->cur_ch_offset; ++ bool connect_allow = true; ++ ++ if (!ch || !bw || !offset) { ++ rtw_warn_on(1); ++ connect_allow = false; ++ } ++ ++ if (connect_allow == true) { ++ DBG_871X("start_join_set_ch_bw: ch =%d, bwmode =%d, ch_offset =%d\n", cur_ch, cur_bw, cur_ch_offset); ++ *ch = cur_ch; ++ *bw = cur_bw; ++ *offset = cur_ch_offset; ++ } ++ ++ return connect_allow == true ? _SUCCESS : _FAIL; ++} ++ ++/* Find union about ch, bw, ch_offset of all linked/linking interfaces */ ++int rtw_get_ch_setting_union(struct adapter *adapter, u8 *ch, u8 *bw, u8 *offset) ++{ ++ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); ++ struct adapter *iface; ++ struct mlme_ext_priv *mlmeext; ++ u8 ch_ret = 0; ++ u8 bw_ret = CHANNEL_WIDTH_20; ++ u8 offset_ret = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ if (ch) ++ *ch = 0; ++ if (bw) ++ *bw = CHANNEL_WIDTH_20; ++ if (offset) ++ *offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ iface = dvobj->padapters; ++ mlmeext = &iface->mlmeextpriv; ++ ++ if (!check_fwstate(&iface->mlmepriv, _FW_LINKED|_FW_UNDER_LINKING)) ++ return 0; ++ ++ ch_ret = mlmeext->cur_channel; ++ bw_ret = mlmeext->cur_bwmode; ++ offset_ret = mlmeext->cur_ch_offset; ++ ++ return 1; ++} ++ ++u8 set_ch_hdl(struct adapter *padapter, u8 *pbuf) ++{ ++ struct set_ch_parm *set_ch_parm; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ if (!pbuf) ++ return H2C_PARAMETERS_ERROR; ++ ++ set_ch_parm = (struct set_ch_parm *)pbuf; ++ ++ DBG_871X(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n", ++ FUNC_NDEV_ARG(padapter->pnetdev), ++ set_ch_parm->ch, set_ch_parm->bw, set_ch_parm->ch_offset); ++ ++ pmlmeext->cur_channel = set_ch_parm->ch; ++ pmlmeext->cur_ch_offset = set_ch_parm->ch_offset; ++ pmlmeext->cur_bwmode = set_ch_parm->bw; ++ ++ set_channel_bwmode(padapter, set_ch_parm->ch, set_ch_parm->ch_offset, set_ch_parm->bw); ++ ++ return H2C_SUCCESS; ++} ++ ++u8 set_chplan_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ struct SetChannelPlan_param *setChannelPlan_param; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ if (!pbuf) ++ return H2C_PARAMETERS_ERROR; ++ ++ setChannelPlan_param = (struct SetChannelPlan_param *)pbuf; ++ ++ pmlmeext->max_chan_nums = init_channel_set(padapter, setChannelPlan_param->channel_plan, pmlmeext->channel_set); ++ init_channel_list(padapter, pmlmeext->channel_set, pmlmeext->max_chan_nums, &pmlmeext->channel_list); ++ ++ if ((padapter->rtw_wdev != NULL) && (padapter->rtw_wdev->wiphy)) { ++ struct regulatory_request request; ++ request.initiator = NL80211_REGDOM_SET_BY_DRIVER; ++ rtw_reg_notifier(padapter->rtw_wdev->wiphy, &request); ++ } ++ ++ return H2C_SUCCESS; ++} ++ ++u8 led_blink_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ struct LedBlink_param *ledBlink_param; ++ ++ if (!pbuf) ++ return H2C_PARAMETERS_ERROR; ++ ++ ledBlink_param = (struct LedBlink_param *)pbuf; ++ return H2C_SUCCESS; ++} ++ ++u8 set_csa_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ return H2C_REJECTED; ++} ++ ++/* TDLS_ESTABLISHED : write RCR DATA BIT */ ++/* TDLS_CS_OFF : go back to the channel linked with AP, terminating channel switch procedure */ ++/* TDLS_INIT_CH_SEN : init channel sensing, receive all data and mgnt frame */ ++/* TDLS_DONE_CH_SEN: channel sensing and report candidate channel */ ++/* TDLS_OFF_CH : first time set channel to off channel */ ++/* TDLS_BASE_CH : go back tp the channel linked with AP when set base channel as target channel */ ++/* TDLS_P_OFF_CH : periodically go to off channel */ ++/* TDLS_P_BASE_CH : periodically go back to base channel */ ++/* TDLS_RS_RCR : restore RCR */ ++/* TDLS_TEAR_STA : free tdls sta */ ++u8 tdls_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ return H2C_REJECTED; ++} ++ ++u8 run_in_thread_hdl(struct adapter *padapter, u8 *pbuf) ++{ ++ struct RunInThread_param *p; ++ ++ ++ if (NULL == pbuf) ++ return H2C_PARAMETERS_ERROR; ++ p = (struct RunInThread_param*)pbuf; ++ ++ if (p->func) ++ p->func(p->context); ++ ++ return H2C_SUCCESS; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_odm.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_odm.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_odm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_odm.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,195 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2013 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++ ++static const char *odm_comp_str[] = { ++ /* BIT0 */"ODM_COMP_DIG", ++ /* BIT1 */"ODM_COMP_RA_MASK", ++ /* BIT2 */"ODM_COMP_DYNAMIC_TXPWR", ++ /* BIT3 */"ODM_COMP_FA_CNT", ++ /* BIT4 */"ODM_COMP_RSSI_MONITOR", ++ /* BIT5 */"ODM_COMP_CCK_PD", ++ /* BIT6 */"ODM_COMP_ANT_DIV", ++ /* BIT7 */"ODM_COMP_PWR_SAVE", ++ /* BIT8 */"ODM_COMP_PWR_TRAIN", ++ /* BIT9 */"ODM_COMP_RATE_ADAPTIVE", ++ /* BIT10 */"ODM_COMP_PATH_DIV", ++ /* BIT11 */"ODM_COMP_PSD", ++ /* BIT12 */"ODM_COMP_DYNAMIC_PRICCA", ++ /* BIT13 */"ODM_COMP_RXHP", ++ /* BIT14 */"ODM_COMP_MP", ++ /* BIT15 */"ODM_COMP_DYNAMIC_ATC", ++ /* BIT16 */"ODM_COMP_EDCA_TURBO", ++ /* BIT17 */"ODM_COMP_EARLY_MODE", ++ /* BIT18 */NULL, ++ /* BIT19 */NULL, ++ /* BIT20 */NULL, ++ /* BIT21 */NULL, ++ /* BIT22 */NULL, ++ /* BIT23 */NULL, ++ /* BIT24 */"ODM_COMP_TX_PWR_TRACK", ++ /* BIT25 */"ODM_COMP_RX_GAIN_TRACK", ++ /* BIT26 */"ODM_COMP_CALIBRATION", ++ /* BIT27 */NULL, ++ /* BIT28 */NULL, ++ /* BIT29 */NULL, ++ /* BIT30 */"ODM_COMP_COMMON", ++ /* BIT31 */"ODM_COMP_INIT", ++}; ++ ++#define RTW_ODM_COMP_MAX 32 ++ ++static const char *odm_ability_str[] = { ++ /* BIT0 */"ODM_BB_DIG", ++ /* BIT1 */"ODM_BB_RA_MASK", ++ /* BIT2 */"ODM_BB_DYNAMIC_TXPWR", ++ /* BIT3 */"ODM_BB_FA_CNT", ++ /* BIT4 */"ODM_BB_RSSI_MONITOR", ++ /* BIT5 */"ODM_BB_CCK_PD", ++ /* BIT6 */"ODM_BB_ANT_DIV", ++ /* BIT7 */"ODM_BB_PWR_SAVE", ++ /* BIT8 */"ODM_BB_PWR_TRAIN", ++ /* BIT9 */"ODM_BB_RATE_ADAPTIVE", ++ /* BIT10 */"ODM_BB_PATH_DIV", ++ /* BIT11 */"ODM_BB_PSD", ++ /* BIT12 */"ODM_BB_RXHP", ++ /* BIT13 */"ODM_BB_ADAPTIVITY", ++ /* BIT14 */"ODM_BB_DYNAMIC_ATC", ++ /* BIT15 */NULL, ++ /* BIT16 */"ODM_MAC_EDCA_TURBO", ++ /* BIT17 */"ODM_MAC_EARLY_MODE", ++ /* BIT18 */NULL, ++ /* BIT19 */NULL, ++ /* BIT20 */NULL, ++ /* BIT21 */NULL, ++ /* BIT22 */NULL, ++ /* BIT23 */NULL, ++ /* BIT24 */"ODM_RF_TX_PWR_TRACK", ++ /* BIT25 */"ODM_RF_RX_GAIN_TRACK", ++ /* BIT26 */"ODM_RF_CALIBRATION", ++}; ++ ++#define RTW_ODM_ABILITY_MAX 27 ++ ++static const char *odm_dbg_level_str[] = { ++ NULL, ++ "ODM_DBG_OFF", ++ "ODM_DBG_SERIOUS", ++ "ODM_DBG_WARNING", ++ "ODM_DBG_LOUD", ++ "ODM_DBG_TRACE", ++}; ++ ++#define RTW_ODM_DBG_LEVEL_NUM 6 ++ ++void rtw_odm_dbg_comp_msg(void *sel, struct adapter *adapter) ++{ ++ u64 dbg_comp; ++ int i; ++ ++ rtw_hal_get_def_var(adapter, HW_DEF_ODM_DBG_FLAG, &dbg_comp); ++ DBG_871X_SEL_NL(sel, "odm.DebugComponents = 0x%016llx\n", dbg_comp); ++ for (i = 0;iodmpriv; ++ ++ DBG_871X_SEL_NL(sel, "%10s %16s %8s %10s %11s %14s\n" ++ , "TH_L2H_ini", "TH_EDCCA_HL_diff", "IGI_Base", "ForceEDCCA", "AdapEn_RSSI", "IGI_LowerBound"); ++ DBG_871X_SEL_NL(sel, "0x%-8x %-16d 0x%-6x %-10d %-11u %-14u\n" ++ , (u8)odm->TH_L2H_ini ++ , odm->TH_EDCCA_HL_diff ++ , odm->IGI_Base ++ , odm->ForceEDCCA ++ , odm->AdapEn_RSSI ++ , odm->IGI_LowerBound ++ ); ++} ++ ++void rtw_odm_adaptivity_parm_set(struct adapter *adapter, s8 TH_L2H_ini, s8 TH_EDCCA_HL_diff, ++ s8 IGI_Base, bool ForceEDCCA, u8 AdapEn_RSSI, u8 IGI_LowerBound) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(adapter); ++ DM_ODM_T *odm = &pHalData->odmpriv; ++ ++ odm->TH_L2H_ini = TH_L2H_ini; ++ odm->TH_EDCCA_HL_diff = TH_EDCCA_HL_diff; ++ odm->IGI_Base = IGI_Base; ++ odm->ForceEDCCA = ForceEDCCA; ++ odm->AdapEn_RSSI = AdapEn_RSSI; ++ odm->IGI_LowerBound = IGI_LowerBound; ++} ++ ++void rtw_odm_get_perpkt_rssi(void *sel, struct adapter *adapter) ++{ ++ struct hal_com_data *hal_data = GET_HAL_DATA(adapter); ++ DM_ODM_T *odm = &(hal_data->odmpriv); ++ ++ DBG_871X_SEL_NL(sel,"RxRate = %s, RSSI_A = %d(%%), RSSI_B = %d(%%)\n", ++ HDATA_RATE(odm->RxRate), odm->RSSI_A, odm->RSSI_B); ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_pwrctrl.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_pwrctrl.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_pwrctrl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_pwrctrl.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,1521 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTW_PWRCTRL_C_ ++ ++#include ++#include ++#include ++#include ++ ++ ++void _ips_enter(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ ++ pwrpriv->bips_processing = true; ++ ++ /* syn ips_mode with request */ ++ pwrpriv->ips_mode = pwrpriv->ips_mode_req; ++ ++ pwrpriv->ips_enter_cnts++; ++ DBG_871X("==>ips_enter cnts:%d\n", pwrpriv->ips_enter_cnts); ++ ++ if (rf_off == pwrpriv->change_rfpwrstate) ++ { ++ pwrpriv->bpower_saving = true; ++ DBG_871X_LEVEL(_drv_always_, "nolinked power save enter\n"); ++ ++ if (pwrpriv->ips_mode == IPS_LEVEL_2) ++ pwrpriv->bkeepfwalive = true; ++ ++ rtw_ips_pwr_down(padapter); ++ pwrpriv->rf_pwrstate = rf_off; ++ } ++ pwrpriv->bips_processing = false; ++ ++} ++ ++void ips_enter(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ ++ ++ rtw_btcoex_IpsNotify(padapter, pwrpriv->ips_mode_req); ++ ++ down(&pwrpriv->lock); ++ _ips_enter(padapter); ++ up(&pwrpriv->lock); ++} ++ ++int _ips_leave(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ int result = _SUCCESS; ++ ++ if ((pwrpriv->rf_pwrstate == rf_off) && (!pwrpriv->bips_processing)) ++ { ++ pwrpriv->bips_processing = true; ++ pwrpriv->change_rfpwrstate = rf_on; ++ pwrpriv->ips_leave_cnts++; ++ DBG_871X("==>ips_leave cnts:%d\n", pwrpriv->ips_leave_cnts); ++ ++ if ((result = rtw_ips_pwr_up(padapter)) == _SUCCESS) { ++ pwrpriv->rf_pwrstate = rf_on; ++ } ++ DBG_871X_LEVEL(_drv_always_, "nolinked power save leave\n"); ++ ++ DBG_871X("==> ips_leave.....LED(0x%08x)...\n", rtw_read32(padapter, 0x4c)); ++ pwrpriv->bips_processing = false; ++ ++ pwrpriv->bkeepfwalive = false; ++ pwrpriv->bpower_saving = false; ++ } ++ ++ return result; ++} ++ ++int ips_leave(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ int ret; ++ ++ if (!is_primary_adapter(padapter)) ++ return _SUCCESS; ++ ++ down(&pwrpriv->lock); ++ ret = _ips_leave(padapter); ++ up(&pwrpriv->lock); ++ ++ if (_SUCCESS == ret) ++ rtw_btcoex_IpsNotify(padapter, IPS_NONE); ++ ++ return ret; ++} ++ ++static bool rtw_pwr_unassociated_idle(struct adapter *adapter) ++{ ++ struct adapter *buddy = adapter->pbuddy_adapter; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ struct xmit_priv *pxmit_priv = &adapter->xmitpriv; ++ ++ bool ret = false; ++ ++ if (adapter_to_pwrctl(adapter)->bpower_saving ==true) { ++ /* DBG_871X("%s: already in LPS or IPS mode\n", __func__); */ ++ goto exit; ++ } ++ ++ if (time_before(jiffies, adapter_to_pwrctl(adapter)->ips_deny_time)) { ++ /* DBG_871X("%s ips_deny_time\n", __func__); */ ++ goto exit; ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) ++ || check_fwstate(pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) ++ || check_fwstate(pmlmepriv, WIFI_AP_STATE) ++ || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) ++ ) { ++ goto exit; ++ } ++ ++ /* consider buddy, if exist */ ++ if (buddy) { ++ struct mlme_priv *b_pmlmepriv = &(buddy->mlmepriv); ++ ++ if (check_fwstate(b_pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) ++ || check_fwstate(b_pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) ++ || check_fwstate(b_pmlmepriv, WIFI_AP_STATE) ++ || check_fwstate(b_pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) ++ ) { ++ goto exit; ++ } ++ } ++ ++ if (pxmit_priv->free_xmitbuf_cnt != NR_XMITBUFF || ++ pxmit_priv->free_xmit_extbuf_cnt != NR_XMIT_EXTBUFF) { ++ DBG_871X_LEVEL(_drv_always_, "There are some pkts to transmit\n"); ++ DBG_871X_LEVEL(_drv_always_, "free_xmitbuf_cnt: %d, free_xmit_extbuf_cnt: %d\n", ++ pxmit_priv->free_xmitbuf_cnt, pxmit_priv->free_xmit_extbuf_cnt); ++ goto exit; ++ } ++ ++ ret = true; ++ ++exit: ++ return ret; ++} ++ ++ ++/* ++ * ATTENTION: ++ *rtw_ps_processor() doesn't handle LPS. ++ */ ++void rtw_ps_processor(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct dvobj_priv *psdpriv = padapter->dvobj; ++ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; ++ u32 ps_deny = 0; ++ ++ down(&adapter_to_pwrctl(padapter)->lock); ++ ps_deny = rtw_ps_deny_get(padapter); ++ up(&adapter_to_pwrctl(padapter)->lock); ++ if (ps_deny != 0) ++ { ++ DBG_871X(FUNC_ADPT_FMT ": ps_deny = 0x%08X, skip power save!\n", ++ FUNC_ADPT_ARG(padapter), ps_deny); ++ goto exit; ++ } ++ ++ if (pwrpriv->bInSuspend == true) {/* system suspend or autosuspend */ ++ pdbgpriv->dbg_ps_insuspend_cnt++; ++ DBG_871X("%s, pwrpriv->bInSuspend == true ignore this process\n", __func__); ++ return; ++ } ++ ++ pwrpriv->ps_processing = true; ++ ++ if (pwrpriv->ips_mode_req == IPS_NONE) ++ goto exit; ++ ++ if (rtw_pwr_unassociated_idle(padapter) == false) ++ goto exit; ++ ++ if ((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts%4) == 0)) ++ { ++ DBG_871X("==>%s\n", __func__); ++ pwrpriv->change_rfpwrstate = rf_off; ++ { ++ ips_enter(padapter); ++ } ++ } ++exit: ++ pwrpriv->ps_processing = false; ++ return; ++} ++ ++void pwr_state_check_handler(RTW_TIMER_HDL_ARGS); ++void pwr_state_check_handler(RTW_TIMER_HDL_ARGS) ++{ ++ struct adapter *padapter = (struct adapter *)FunctionContext; ++ rtw_ps_cmd(padapter); ++} ++ ++void traffic_check_for_leave_lps(struct adapter *padapter, u8 tx, u32 tx_packets) ++{ ++ static unsigned long start_time = 0; ++ static u32 xmit_cnt = 0; ++ u8 bLeaveLPS = false; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ ++ ++ if (tx) /* from tx */ ++ { ++ xmit_cnt += tx_packets; ++ ++ if (start_time == 0) ++ start_time = jiffies; ++ ++ if (jiffies_to_msecs(jiffies - start_time) > 2000) /* 2 sec == watch dog timer */ ++ { ++ if (xmit_cnt > 8) ++ { ++ if ((adapter_to_pwrctl(padapter)->bLeisurePs) ++ && (adapter_to_pwrctl(padapter)->pwr_mode != PS_MODE_ACTIVE) ++ && (rtw_btcoex_IsBtControlLps(padapter) == false) ++ ) ++ { ++ DBG_871X("leave lps via Tx = %d\n", xmit_cnt); ++ bLeaveLPS = true; ++ } ++ } ++ ++ start_time = jiffies; ++ xmit_cnt = 0; ++ } ++ ++ } ++ else /* from rx path */ ++ { ++ if (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 4/*2*/) ++ { ++ if ((adapter_to_pwrctl(padapter)->bLeisurePs) ++ && (adapter_to_pwrctl(padapter)->pwr_mode != PS_MODE_ACTIVE) ++ && (rtw_btcoex_IsBtControlLps(padapter) == false) ++ ) ++ { ++ DBG_871X("leave lps via Rx = %d\n", pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod); ++ bLeaveLPS = true; ++ } ++ } ++ } ++ ++ if (bLeaveLPS) ++ { ++ /* DBG_871X("leave lps via %s, Tx = %d, Rx = %d\n", tx?"Tx":"Rx", pmlmepriv->LinkDetectInfo.NumTxOkInPeriod, pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod); */ ++ /* rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_LEAVE, 1); */ ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_LEAVE, tx?0:1); ++ } ++} ++ ++/* ++ * Description: ++ *This function MUST be called under power lock protect ++ * ++ * Parameters ++ *padapter ++ *pslv power state level, only could be PS_STATE_S0 ~ PS_STATE_S4 ++ * ++ */ ++void rtw_set_rpwm(struct adapter *padapter, u8 pslv) ++{ ++ u8 rpwm; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ u8 cpwm_orig; ++ ++ pslv = PS_STATE(pslv); ++ ++ if (pwrpriv->brpwmtimeout == true) ++ { ++ DBG_871X("%s: RPWM timeout, force to set RPWM(0x%02X) again!\n", __func__, pslv); ++ } ++ else ++ { ++ if ((pwrpriv->rpwm == pslv) ++ || ((pwrpriv->rpwm >= PS_STATE_S2) && (pslv >= PS_STATE_S2))) ++ { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ++ ("%s: Already set rpwm[0x%02X], new = 0x%02X!\n", __func__, pwrpriv->rpwm, pslv)); ++ return; ++ } ++ } ++ ++ if ((padapter->bSurpriseRemoved == true) || ++ (padapter->hw_init_completed == false)) ++ { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ++ ("%s: SurpriseRemoved(%d) hw_init_completed(%d)\n", ++ __func__, padapter->bSurpriseRemoved, padapter->hw_init_completed)); ++ ++ pwrpriv->cpwm = PS_STATE_S4; ++ ++ return; ++ } ++ ++ if (padapter->bDriverStopped == true) ++ { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ++ ("%s: change power state(0x%02X) when DriverStopped\n", __func__, pslv)); ++ ++ if (pslv < PS_STATE_S2) { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ++ ("%s: Reject to enter PS_STATE(0x%02X) lower than S2 when DriverStopped!!\n", __func__, pslv)); ++ return; ++ } ++ } ++ ++ rpwm = pslv | pwrpriv->tog; ++ /* only when from PS_STATE S0/S1 to S2 and higher needs ACK */ ++ if ((pwrpriv->cpwm < PS_STATE_S2) && (pslv >= PS_STATE_S2)) ++ rpwm |= PS_ACK; ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ++ ("rtw_set_rpwm: rpwm = 0x%02x cpwm = 0x%02x\n", rpwm, pwrpriv->cpwm)); ++ ++ pwrpriv->rpwm = pslv; ++ ++ cpwm_orig = 0; ++ if (rpwm & PS_ACK) ++ { ++ rtw_hal_get_hwreg(padapter, HW_VAR_CPWM, &cpwm_orig); ++ } ++ ++ if (rpwm & PS_ACK) ++ _set_timer(&pwrpriv->pwr_rpwm_timer, LPS_RPWM_WAIT_MS); ++ rtw_hal_set_hwreg(padapter, HW_VAR_SET_RPWM, (u8 *)(&rpwm)); ++ ++ pwrpriv->tog += 0x80; ++ ++ /* No LPS 32K, No Ack */ ++ if (rpwm & PS_ACK) ++ { ++ unsigned long start_time; ++ u8 cpwm_now; ++ u8 poll_cnt = 0; ++ ++ start_time = jiffies; ++ ++ /* polling cpwm */ ++ do { ++ mdelay(1); ++ poll_cnt++; ++ rtw_hal_get_hwreg(padapter, HW_VAR_CPWM, &cpwm_now); ++ if ((cpwm_orig ^ cpwm_now) & 0x80) ++ { ++ pwrpriv->cpwm = PS_STATE_S4; ++ pwrpriv->cpwm_tog = cpwm_now & PS_TOGGLE; ++ break; ++ } ++ ++ if (jiffies_to_msecs(jiffies - start_time) > LPS_RPWM_WAIT_MS) ++ { ++ DBG_871X("%s: polling cpwm timeout! poll_cnt =%d, cpwm_orig =%02x, cpwm_now =%02x\n", __func__, poll_cnt, cpwm_orig, cpwm_now); ++ _set_timer(&pwrpriv->pwr_rpwm_timer, 1); ++ break; ++ } ++ } while (1); ++ } ++ else ++ { ++ pwrpriv->cpwm = pslv; ++ } ++} ++ ++static u8 PS_RDY_CHECK(struct adapter *padapter) ++{ ++ unsigned long curr_time, delta_time; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) ++ if (true == pwrpriv->bInSuspend && pwrpriv->wowlan_mode) ++ return true; ++ else if (true == pwrpriv->bInSuspend && pwrpriv->wowlan_ap_mode) ++ return true; ++ else if (true == pwrpriv->bInSuspend) ++ return false; ++#else ++ if (true == pwrpriv->bInSuspend) ++ return false; ++#endif ++ ++ curr_time = jiffies; ++ ++ delta_time = curr_time -pwrpriv->DelayLPSLastTimeStamp; ++ ++ if (delta_time < LPS_DELAY_TIME) ++ { ++ return false; ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_SITE_MONITOR) ++ || check_fwstate(pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) ++ || check_fwstate(pmlmepriv, WIFI_AP_STATE) ++ || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) ++ || rtw_is_scan_deny(padapter) ++ ) ++ return false; ++ ++ if ((padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) && (padapter->securitypriv.binstallGrpkey == false)) ++ { ++ DBG_871X("Group handshake still in progress !!!\n"); ++ return false; ++ } ++ ++ if (!rtw_cfg80211_pwr_mgmt(padapter)) ++ return false; ++ ++ return true; ++} ++ ++void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_ant_mode, const char *msg) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) ++ struct debug_priv *pdbgpriv = &padapter->dvobj->drv_dbg; ++#endif ++ ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ++ ("%s: PowerMode =%d Smart_PS =%d\n", ++ __func__, ps_mode, smart_ps)); ++ ++ if (ps_mode > PM_Card_Disable) { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ("ps_mode:%d error\n", ps_mode)); ++ return; ++ } ++ ++ if (pwrpriv->pwr_mode == ps_mode) ++ { ++ if (PS_MODE_ACTIVE == ps_mode) return; ++ } ++ ++ down(&pwrpriv->lock); ++ ++ /* if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) */ ++ if (ps_mode == PS_MODE_ACTIVE) ++ { ++ if (1 ++ && (((rtw_btcoex_IsBtControlLps(padapter) == false) ++ ) ++ || ((rtw_btcoex_IsBtControlLps(padapter) == true) ++ && (rtw_btcoex_IsLpsOn(padapter) == false)) ++ ) ++ ) ++ { ++ DBG_871X(FUNC_ADPT_FMT" Leave 802.11 power save - %s\n", ++ FUNC_ADPT_ARG(padapter), msg); ++ ++ pwrpriv->pwr_mode = ps_mode; ++ rtw_set_rpwm(padapter, PS_STATE_S4); ++ ++#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) ++ if (pwrpriv->wowlan_mode == true || ++ pwrpriv->wowlan_ap_mode == true) ++ { ++ unsigned long start_time; ++ u32 delay_ms; ++ u8 val8; ++ delay_ms = 20; ++ start_time = jiffies; ++ do { ++ rtw_hal_get_hwreg(padapter, HW_VAR_SYS_CLKR, &val8); ++ if (!(val8 & BIT(4))) { /* 0x08 bit4 = 1 --> in 32k, bit4 = 0 --> leave 32k */ ++ pwrpriv->cpwm = PS_STATE_S4; ++ break; ++ } ++ if (jiffies_to_msecs(jiffies - start_time) > delay_ms) ++ { ++ DBG_871X("%s: Wait for FW 32K leave more than %u ms!!!\n", ++ __func__, delay_ms); ++ pdbgpriv->dbg_wow_leave_ps_fail_cnt++; ++ break; ++ } ++ msleep(1); ++ } while (1); ++ } ++#endif ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); ++ pwrpriv->bFwCurrentInPSMode = false; ++ ++ rtw_btcoex_LpsNotify(padapter, ps_mode); ++ } ++ } ++ else ++ { ++ if ((PS_RDY_CHECK(padapter) && check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE)) ++ || ((rtw_btcoex_IsBtControlLps(padapter) == true) ++ && (rtw_btcoex_IsLpsOn(padapter) == true)) ++ ) ++ { ++ u8 pslv; ++ ++ DBG_871X(FUNC_ADPT_FMT" Enter 802.11 power save - %s\n", ++ FUNC_ADPT_ARG(padapter), msg); ++ ++ rtw_btcoex_LpsNotify(padapter, ps_mode); ++ ++ pwrpriv->bFwCurrentInPSMode = true; ++ pwrpriv->pwr_mode = ps_mode; ++ pwrpriv->smart_ps = smart_ps; ++ pwrpriv->bcn_ant_mode = bcn_ant_mode; ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); ++ ++ pslv = PS_STATE_S2; ++ if (pwrpriv->alives == 0) ++ pslv = PS_STATE_S0; ++ ++ if ((rtw_btcoex_IsBtDisabled(padapter) == false) ++ && (rtw_btcoex_IsBtControlLps(padapter) == true)) ++ { ++ u8 val8; ++ ++ val8 = rtw_btcoex_LpsVal(padapter); ++ if (val8 & BIT(4)) ++ pslv = PS_STATE_S2; ++ } ++ ++ rtw_set_rpwm(padapter, pslv); ++ } ++ } ++ ++ up(&pwrpriv->lock); ++} ++ ++/* ++ * Return: ++ *0: Leave OK ++ *-1: Timeout ++ *-2: Other error ++ */ ++s32 LPS_RF_ON_check(struct adapter *padapter, u32 delay_ms) ++{ ++ unsigned long start_time; ++ u8 bAwake = false; ++ s32 err = 0; ++ ++ ++ start_time = jiffies; ++ while (1) ++ { ++ rtw_hal_get_hwreg(padapter, HW_VAR_FWLPS_RF_ON, &bAwake); ++ if (true == bAwake) ++ break; ++ ++ if (true == padapter->bSurpriseRemoved) ++ { ++ err = -2; ++ DBG_871X("%s: device surprise removed!!\n", __func__); ++ break; ++ } ++ ++ if (jiffies_to_msecs(jiffies - start_time) > delay_ms) ++ { ++ err = -1; ++ DBG_871X("%s: Wait for FW LPS leave more than %u ms!!!\n", __func__, delay_ms); ++ break; ++ } ++ msleep(1); ++ } ++ ++ return err; ++} ++ ++/* */ ++/* Description: */ ++/* Enter the leisure power save mode. */ ++/* */ ++void LPS_Enter(struct adapter *padapter, const char *msg) ++{ ++ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj); ++ int n_assoc_iface = 0; ++ char buf[32] = {0}; ++ ++ if (rtw_btcoex_IsBtControlLps(padapter) == true) ++ return; ++ ++ /* Skip lps enter request if number of assocated adapters is not 1 */ ++ if (check_fwstate(&(dvobj->padapters->mlmepriv), WIFI_ASOC_STATE)) ++ n_assoc_iface++; ++ if (n_assoc_iface != 1) ++ return; ++ ++ /* Skip lps enter request for adapter not port0 */ ++ if (get_iface_type(padapter) != IFACE_PORT0) ++ return; ++ ++ if (PS_RDY_CHECK(dvobj->padapters) == false) ++ return; ++ ++ if (pwrpriv->bLeisurePs) { ++ /* Idle for a while if we connect to AP a while ago. */ ++ if (pwrpriv->LpsIdleCount >= 2) /* 4 Sec */ ++ { ++ if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) ++ { ++ sprintf(buf, "WIFI-%s", msg); ++ pwrpriv->bpower_saving = true; ++ rtw_set_ps_mode(padapter, pwrpriv->power_mgnt, padapter->registrypriv.smart_ps, 0, buf); ++ } ++ } ++ else ++ pwrpriv->LpsIdleCount++; ++ } ++ ++/* DBG_871X("-LeisurePSEnter\n"); */ ++} ++ ++/* */ ++/* Description: */ ++/* Leave the leisure power save mode. */ ++/* */ ++void LPS_Leave(struct adapter *padapter, const char *msg) ++{ ++#define LPS_LEAVE_TIMEOUT_MS 100 ++ ++ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj); ++ char buf[32] = {0}; ++ ++/* DBG_871X("+LeisurePSLeave\n"); */ ++ ++ if (rtw_btcoex_IsBtControlLps(padapter) == true) ++ return; ++ ++ if (pwrpriv->bLeisurePs) ++ { ++ if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) ++ { ++ sprintf(buf, "WIFI-%s", msg); ++ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, buf); ++ ++ if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) ++ LPS_RF_ON_check(padapter, LPS_LEAVE_TIMEOUT_MS); ++ } ++ } ++ ++ pwrpriv->bpower_saving = false; ++/* DBG_871X("-LeisurePSLeave\n"); */ ++ ++} ++ ++void LeaveAllPowerSaveModeDirect(struct adapter * Adapter) ++{ ++ struct adapter * pri_padapter = GET_PRIMARY_ADAPTER(Adapter); ++ struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(Adapter); ++ ++ DBG_871X("%s.....\n", __func__); ++ ++ if (true == Adapter->bSurpriseRemoved) ++ { ++ DBG_871X(FUNC_ADPT_FMT ": bSurpriseRemoved =%d Skip!\n", ++ FUNC_ADPT_ARG(Adapter), Adapter->bSurpriseRemoved); ++ return; ++ } ++ ++ if ((check_fwstate(pmlmepriv, _FW_LINKED) == true)) ++ { /* connect */ ++ ++ if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) { ++ DBG_871X("%s: Driver Already Leave LPS\n", __func__); ++ return; ++ } ++ ++ down(&pwrpriv->lock); ++ ++ rtw_set_rpwm(Adapter, PS_STATE_S4); ++ ++ up(&pwrpriv->lock); ++ ++ rtw_lps_ctrl_wk_cmd(pri_padapter, LPS_CTRL_LEAVE, 0); ++ } ++ else ++ { ++ if (pwrpriv->rf_pwrstate == rf_off) ++ { ++ if (false == ips_leave(pri_padapter)) ++ { ++ DBG_871X("======> ips_leave fail.............\n"); ++ } ++ } ++ } ++} ++ ++/* */ ++/* Description: Leave all power save mode: LPS, FwLPS, IPS if needed. */ ++/* Move code to function by tynli. 2010.03.26. */ ++/* */ ++void LeaveAllPowerSaveMode(struct adapter * Adapter) ++{ ++ struct dvobj_priv *dvobj = adapter_to_dvobj(Adapter); ++ u8 enqueue = 0; ++ int n_assoc_iface = 0; ++ ++ if (!Adapter->bup) { ++ DBG_871X(FUNC_ADPT_FMT ": bup =%d Skip!\n", ++ FUNC_ADPT_ARG(Adapter), Adapter->bup); ++ return; ++ } ++ ++ if (Adapter->bSurpriseRemoved) { ++ DBG_871X(FUNC_ADPT_FMT ": bSurpriseRemoved =%d Skip!\n", ++ FUNC_ADPT_ARG(Adapter), Adapter->bSurpriseRemoved); ++ return; ++ } ++ ++ if (check_fwstate(&(dvobj->padapters->mlmepriv), WIFI_ASOC_STATE)) ++ n_assoc_iface++; ++ ++ if (n_assoc_iface) { /* connect */ ++ enqueue = 1; ++ ++ rtw_lps_ctrl_wk_cmd(Adapter, LPS_CTRL_LEAVE, enqueue); ++ ++ LPS_Leave_check(Adapter); ++ } else { ++ if (adapter_to_pwrctl(Adapter)->rf_pwrstate == rf_off) { ++ if (false == ips_leave(Adapter)) ++ DBG_871X("======> ips_leave fail.............\n"); ++ } ++ } ++} ++ ++void LPS_Leave_check( ++ struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv; ++ unsigned long start_time; ++ u8 bReady; ++ ++ pwrpriv = adapter_to_pwrctl(padapter); ++ ++ bReady = false; ++ start_time = jiffies; ++ ++ yield(); ++ ++ while (1) ++ { ++ down(&pwrpriv->lock); ++ ++ if ((padapter->bSurpriseRemoved == true) ++ || (padapter->hw_init_completed == false) ++ || (pwrpriv->pwr_mode == PS_MODE_ACTIVE) ++ ) ++ { ++ bReady = true; ++ } ++ ++ up(&pwrpriv->lock); ++ ++ if (true == bReady) ++ break; ++ ++ if (jiffies_to_msecs(jiffies - start_time)>100) ++ { ++ DBG_871X("Wait for cpwm event than 100 ms!!!\n"); ++ break; ++ } ++ msleep(1); ++ } ++} ++ ++/* ++ * Caller:ISR handler... ++ * ++ * This will be called when CPWM interrupt is up. ++ * ++ * using to update cpwn of drv; and drv willl make a decision to up or down pwr level ++ */ ++void cpwm_int_hdl( ++ struct adapter *padapter, ++ struct reportpwrstate_parm *preportpwrstate) ++{ ++ struct pwrctrl_priv *pwrpriv; ++ ++ pwrpriv = adapter_to_pwrctl(padapter); ++ ++ down(&pwrpriv->lock); ++ ++ if (pwrpriv->rpwm < PS_STATE_S2) ++ { ++ DBG_871X("%s: Redundant CPWM Int. RPWM = 0x%02X CPWM = 0x%02x\n", __func__, pwrpriv->rpwm, pwrpriv->cpwm); ++ up(&pwrpriv->lock); ++ goto exit; ++ } ++ ++ pwrpriv->cpwm = PS_STATE(preportpwrstate->state); ++ pwrpriv->cpwm_tog = preportpwrstate->state & PS_TOGGLE; ++ ++ if (pwrpriv->cpwm >= PS_STATE_S2) ++ { ++ if (pwrpriv->alives & CMD_ALIVE) ++ up(&padapter->cmdpriv.cmd_queue_sema); ++ ++ if (pwrpriv->alives & XMIT_ALIVE) ++ up(&padapter->xmitpriv.xmit_sema); ++ } ++ ++ up(&pwrpriv->lock); ++ ++exit: ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ++ ("cpwm_int_hdl: cpwm = 0x%02x\n", pwrpriv->cpwm)); ++} ++ ++static void cpwm_event_callback(struct work_struct *work) ++{ ++ struct pwrctrl_priv *pwrpriv = container_of(work, struct pwrctrl_priv, cpwm_event); ++ struct dvobj_priv *dvobj = pwrctl_to_dvobj(pwrpriv); ++ struct adapter *adapter = dvobj->if1; ++ struct reportpwrstate_parm report; ++ ++ /* DBG_871X("%s\n", __func__); */ ++ ++ report.state = PS_STATE_S2; ++ cpwm_int_hdl(adapter, &report); ++} ++ ++static void rpwmtimeout_workitem_callback(struct work_struct *work) ++{ ++ struct adapter *padapter; ++ struct dvobj_priv *dvobj; ++ struct pwrctrl_priv *pwrpriv; ++ ++ ++ pwrpriv = container_of(work, struct pwrctrl_priv, rpwmtimeoutwi); ++ dvobj = pwrctl_to_dvobj(pwrpriv); ++ padapter = dvobj->if1; ++/* DBG_871X("+%s: rpwm = 0x%02X cpwm = 0x%02X\n", __func__, pwrpriv->rpwm, pwrpriv->cpwm); */ ++ ++ down(&pwrpriv->lock); ++ if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2)) ++ { ++ DBG_871X("%s: rpwm = 0x%02X cpwm = 0x%02X CPWM done!\n", __func__, pwrpriv->rpwm, pwrpriv->cpwm); ++ goto exit; ++ } ++ up(&pwrpriv->lock); ++ ++ if (rtw_read8(padapter, 0x100) != 0xEA) ++ { ++ struct reportpwrstate_parm report; ++ ++ report.state = PS_STATE_S2; ++ DBG_871X("\n%s: FW already leave 32K!\n\n", __func__); ++ cpwm_int_hdl(padapter, &report); ++ ++ return; ++ } ++ ++ down(&pwrpriv->lock); ++ ++ if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2)) ++ { ++ DBG_871X("%s: cpwm =%d, nothing to do!\n", __func__, pwrpriv->cpwm); ++ goto exit; ++ } ++ pwrpriv->brpwmtimeout = true; ++ rtw_set_rpwm(padapter, pwrpriv->rpwm); ++ pwrpriv->brpwmtimeout = false; ++ ++exit: ++ up(&pwrpriv->lock); ++} ++ ++/* ++ * This function is a timer handler, can't do any IO in it. ++ */ ++static void pwr_rpwm_timeout_handler(void *FunctionContext) ++{ ++ struct adapter *padapter; ++ struct pwrctrl_priv *pwrpriv; ++ ++ ++ padapter = (struct adapter *)FunctionContext; ++ pwrpriv = adapter_to_pwrctl(padapter); ++ DBG_871X("+%s: rpwm = 0x%02X cpwm = 0x%02X\n", __func__, pwrpriv->rpwm, pwrpriv->cpwm); ++ ++ if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2)) ++ { ++ DBG_871X("+%s: cpwm =%d, nothing to do!\n", __func__, pwrpriv->cpwm); ++ return; ++ } ++ ++ _set_workitem(&pwrpriv->rpwmtimeoutwi); ++} ++ ++__inline static void register_task_alive(struct pwrctrl_priv *pwrctrl, u32 tag) ++{ ++ pwrctrl->alives |= tag; ++} ++ ++__inline static void unregister_task_alive(struct pwrctrl_priv *pwrctrl, u32 tag) ++{ ++ pwrctrl->alives &= ~tag; ++} ++ ++ ++/* ++ * Description: ++ *Check if the fw_pwrstate is okay for I/O. ++ *If not (cpwm is less than S2), then the sub-routine ++ *will raise the cpwm to be greater than or equal to S2. ++ * ++ *Calling Context: Passive ++ * ++ *Constraint: ++ * 1. this function will request pwrctrl->lock ++ * ++ * Return Value: ++ *_SUCCESS hardware is ready for I/O ++ *_FAIL can't I/O right now ++ */ ++s32 rtw_register_task_alive(struct adapter *padapter, u32 task) ++{ ++ s32 res; ++ struct pwrctrl_priv *pwrctrl; ++ u8 pslv; ++ ++ res = _SUCCESS; ++ pwrctrl = adapter_to_pwrctl(padapter); ++ pslv = PS_STATE_S2; ++ ++ down(&pwrctrl->lock); ++ ++ register_task_alive(pwrctrl, task); ++ ++ if (pwrctrl->bFwCurrentInPSMode == true) ++ { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ++ ("%s: task = 0x%x cpwm = 0x%02x alives = 0x%08x\n", ++ __func__, task, pwrctrl->cpwm, pwrctrl->alives)); ++ ++ if (pwrctrl->cpwm < pslv) ++ { ++ if (pwrctrl->cpwm < PS_STATE_S2) ++ res = _FAIL; ++ if (pwrctrl->rpwm < pslv) ++ rtw_set_rpwm(padapter, pslv); ++ } ++ } ++ ++ up(&pwrctrl->lock); ++ ++ if (_FAIL == res) ++ { ++ if (pwrctrl->cpwm >= PS_STATE_S2) ++ res = _SUCCESS; ++ } ++ return res; ++} ++ ++/* ++ * Description: ++ *If task is done, call this func. to power down firmware again. ++ * ++ *Constraint: ++ * 1. this function will request pwrctrl->lock ++ * ++ * Return Value: ++ *none ++ */ ++void rtw_unregister_task_alive(struct adapter *padapter, u32 task) ++{ ++ struct pwrctrl_priv *pwrctrl; ++ u8 pslv; ++ ++ pwrctrl = adapter_to_pwrctl(padapter); ++ pslv = PS_STATE_S0; ++ ++ if ((rtw_btcoex_IsBtDisabled(padapter) == false) ++ && (rtw_btcoex_IsBtControlLps(padapter) == true)) ++ { ++ u8 val8; ++ ++ val8 = rtw_btcoex_LpsVal(padapter); ++ if (val8 & BIT(4)) ++ pslv = PS_STATE_S2; ++ } ++ ++ down(&pwrctrl->lock); ++ ++ unregister_task_alive(pwrctrl, task); ++ ++ if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) ++ && (pwrctrl->bFwCurrentInPSMode == true)) ++ { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ++ ("%s: cpwm = 0x%02x alives = 0x%08x\n", ++ __func__, pwrctrl->cpwm, pwrctrl->alives)); ++ ++ if (pwrctrl->cpwm > pslv) ++ { ++ if ((pslv >= PS_STATE_S2) || (pwrctrl->alives == 0)) ++ rtw_set_rpwm(padapter, pslv); ++ } ++ } ++ ++ up(&pwrctrl->lock); ++} ++ ++/* ++ * Caller: rtw_xmit_thread ++ * ++ * Check if the fw_pwrstate is okay for xmit. ++ * If not (cpwm is less than S3), then the sub-routine ++ * will raise the cpwm to be greater than or equal to S3. ++ * ++ * Calling Context: Passive ++ * ++ * Return Value: ++ * _SUCCESS rtw_xmit_thread can write fifo/txcmd afterwards. ++ * _FAIL rtw_xmit_thread can not do anything. ++ */ ++s32 rtw_register_tx_alive(struct adapter *padapter) ++{ ++ s32 res; ++ struct pwrctrl_priv *pwrctrl; ++ u8 pslv; ++ ++ res = _SUCCESS; ++ pwrctrl = adapter_to_pwrctl(padapter); ++ pslv = PS_STATE_S2; ++ ++ down(&pwrctrl->lock); ++ ++ register_task_alive(pwrctrl, XMIT_ALIVE); ++ ++ if (pwrctrl->bFwCurrentInPSMode == true) ++ { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ++ ("rtw_register_tx_alive: cpwm = 0x%02x alives = 0x%08x\n", ++ pwrctrl->cpwm, pwrctrl->alives)); ++ ++ if (pwrctrl->cpwm < pslv) ++ { ++ if (pwrctrl->cpwm < PS_STATE_S2) ++ res = _FAIL; ++ if (pwrctrl->rpwm < pslv) ++ rtw_set_rpwm(padapter, pslv); ++ } ++ } ++ ++ up(&pwrctrl->lock); ++ ++ if (_FAIL == res) ++ { ++ if (pwrctrl->cpwm >= PS_STATE_S2) ++ res = _SUCCESS; ++ } ++ return res; ++} ++ ++/* ++ * Caller: rtw_cmd_thread ++ * ++ * Check if the fw_pwrstate is okay for issuing cmd. ++ * If not (cpwm should be is less than S2), then the sub-routine ++ * will raise the cpwm to be greater than or equal to S2. ++ * ++ * Calling Context: Passive ++ * ++ * Return Value: ++ *_SUCCESS rtw_cmd_thread can issue cmds to firmware afterwards. ++ *_FAIL rtw_cmd_thread can not do anything. ++ */ ++s32 rtw_register_cmd_alive(struct adapter *padapter) ++{ ++ s32 res; ++ struct pwrctrl_priv *pwrctrl; ++ u8 pslv; ++ ++ res = _SUCCESS; ++ pwrctrl = adapter_to_pwrctl(padapter); ++ pslv = PS_STATE_S2; ++ ++ down(&pwrctrl->lock); ++ ++ register_task_alive(pwrctrl, CMD_ALIVE); ++ ++ if (pwrctrl->bFwCurrentInPSMode == true) ++ { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_info_, ++ ("rtw_register_cmd_alive: cpwm = 0x%02x alives = 0x%08x\n", ++ pwrctrl->cpwm, pwrctrl->alives)); ++ ++ if (pwrctrl->cpwm < pslv) ++ { ++ if (pwrctrl->cpwm < PS_STATE_S2) ++ res = _FAIL; ++ if (pwrctrl->rpwm < pslv) ++ rtw_set_rpwm(padapter, pslv); ++ } ++ } ++ ++ up(&pwrctrl->lock); ++ ++ if (_FAIL == res) ++ { ++ if (pwrctrl->cpwm >= PS_STATE_S2) ++ res = _SUCCESS; ++ } ++ return res; ++} ++ ++/* ++ * Caller: ISR ++ * ++ * If ISR's txdone, ++ * No more pkts for TX, ++ * Then driver shall call this fun. to power down firmware again. ++ */ ++void rtw_unregister_tx_alive(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrctrl; ++ u8 pslv; ++ ++ pwrctrl = adapter_to_pwrctl(padapter); ++ pslv = PS_STATE_S0; ++ ++ if ((rtw_btcoex_IsBtDisabled(padapter) == false) ++ && (rtw_btcoex_IsBtControlLps(padapter) == true)) ++ { ++ u8 val8; ++ ++ val8 = rtw_btcoex_LpsVal(padapter); ++ if (val8 & BIT(4)) ++ pslv = PS_STATE_S2; ++ } ++ ++ down(&pwrctrl->lock); ++ ++ unregister_task_alive(pwrctrl, XMIT_ALIVE); ++ ++ if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) ++ && (pwrctrl->bFwCurrentInPSMode == true)) ++ { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ++ ("%s: cpwm = 0x%02x alives = 0x%08x\n", ++ __func__, pwrctrl->cpwm, pwrctrl->alives)); ++ ++ if (pwrctrl->cpwm > pslv) ++ { ++ if ((pslv >= PS_STATE_S2) || (pwrctrl->alives == 0)) ++ rtw_set_rpwm(padapter, pslv); ++ } ++ } ++ ++ up(&pwrctrl->lock); ++} ++ ++/* ++ * Caller: ISR ++ * ++ * If all commands have been done, ++ * and no more command to do, ++ * then driver shall call this fun. to power down firmware again. ++ */ ++void rtw_unregister_cmd_alive(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrctrl; ++ u8 pslv; ++ ++ pwrctrl = adapter_to_pwrctl(padapter); ++ pslv = PS_STATE_S0; ++ ++ if ((rtw_btcoex_IsBtDisabled(padapter) == false) ++ && (rtw_btcoex_IsBtControlLps(padapter) == true)) ++ { ++ u8 val8; ++ ++ val8 = rtw_btcoex_LpsVal(padapter); ++ if (val8 & BIT(4)) ++ pslv = PS_STATE_S2; ++ } ++ ++ down(&pwrctrl->lock); ++ ++ unregister_task_alive(pwrctrl, CMD_ALIVE); ++ ++ if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) ++ && (pwrctrl->bFwCurrentInPSMode == true)) ++ { ++ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_info_, ++ ("%s: cpwm = 0x%02x alives = 0x%08x\n", ++ __func__, pwrctrl->cpwm, pwrctrl->alives)); ++ ++ if (pwrctrl->cpwm > pslv) ++ { ++ if ((pslv >= PS_STATE_S2) || (pwrctrl->alives == 0)) ++ rtw_set_rpwm(padapter, pslv); ++ } ++ } ++ ++ up(&pwrctrl->lock); ++} ++ ++void rtw_init_pwrctrl_priv(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); ++ ++ sema_init(&pwrctrlpriv->lock, 1); ++ sema_init(&pwrctrlpriv->check_32k_lock, 1); ++ pwrctrlpriv->rf_pwrstate = rf_on; ++ pwrctrlpriv->ips_enter_cnts = 0; ++ pwrctrlpriv->ips_leave_cnts = 0; ++ pwrctrlpriv->bips_processing = false; ++ ++ pwrctrlpriv->ips_mode = padapter->registrypriv.ips_mode; ++ pwrctrlpriv->ips_mode_req = padapter->registrypriv.ips_mode; ++ ++ pwrctrlpriv->pwr_state_check_interval = RTW_PWR_STATE_CHK_INTERVAL; ++ pwrctrlpriv->pwr_state_check_cnts = 0; ++ pwrctrlpriv->bInternalAutoSuspend = false; ++ pwrctrlpriv->bInSuspend = false; ++ pwrctrlpriv->bkeepfwalive = false; ++ ++ pwrctrlpriv->LpsIdleCount = 0; ++ pwrctrlpriv->power_mgnt =padapter->registrypriv.power_mgnt;/* PS_MODE_MIN; */ ++ pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt)?true:false; ++ ++ pwrctrlpriv->bFwCurrentInPSMode = false; ++ ++ pwrctrlpriv->rpwm = 0; ++ pwrctrlpriv->cpwm = PS_STATE_S4; ++ ++ pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE; ++ pwrctrlpriv->smart_ps = padapter->registrypriv.smart_ps; ++ pwrctrlpriv->bcn_ant_mode = 0; ++ pwrctrlpriv->dtim = 0; ++ ++ pwrctrlpriv->tog = 0x80; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_SET_RPWM, (u8 *)(&pwrctrlpriv->rpwm)); ++ ++ _init_workitem(&pwrctrlpriv->cpwm_event, cpwm_event_callback, NULL); ++ ++ pwrctrlpriv->brpwmtimeout = false; ++ _init_workitem(&pwrctrlpriv->rpwmtimeoutwi, rpwmtimeout_workitem_callback, NULL); ++ _init_timer(&pwrctrlpriv->pwr_rpwm_timer, padapter->pnetdev, pwr_rpwm_timeout_handler, padapter); ++ ++ rtw_init_timer(&pwrctrlpriv->pwr_state_check_timer, padapter, pwr_state_check_handler); ++ ++ pwrctrlpriv->wowlan_mode = false; ++ pwrctrlpriv->wowlan_ap_mode = false; ++ ++#ifdef CONFIG_PNO_SUPPORT ++ pwrctrlpriv->pno_inited = false; ++ pwrctrlpriv->pnlo_info = NULL; ++ pwrctrlpriv->pscan_info = NULL; ++ pwrctrlpriv->pno_ssid_list = NULL; ++ pwrctrlpriv->pno_in_resume = true; ++#endif ++} ++ ++ ++void rtw_free_pwrctrl_priv(struct adapter * adapter) ++{ ++ /* memset((unsigned char *)pwrctrlpriv, 0, sizeof(struct pwrctrl_priv)); */ ++ ++#ifdef CONFIG_PNO_SUPPORT ++ if (pwrctrlpriv->pnlo_info != NULL) ++ printk("****** pnlo_info memory leak********\n"); ++ ++ if (pwrctrlpriv->pscan_info != NULL) ++ printk("****** pscan_info memory leak********\n"); ++ ++ if (pwrctrlpriv->pno_ssid_list != NULL) ++ printk("****** pno_ssid_list memory leak********\n"); ++#endif ++} ++ ++inline void rtw_set_ips_deny(struct adapter *padapter, u32 ms) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ pwrpriv->ips_deny_time = jiffies + msecs_to_jiffies(ms); ++} ++ ++/* ++* rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend ++* @adapter: pointer to struct adapter structure ++* @ips_deffer_ms: the ms wiil prevent from falling into IPS after wakeup ++* Return _SUCCESS or _FAIL ++*/ ++ ++int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *caller) ++{ ++ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj); ++ struct mlme_priv *pmlmepriv; ++ int ret = _SUCCESS; ++ unsigned long start = jiffies; ++ unsigned long deny_time = jiffies + msecs_to_jiffies(ips_deffer_ms); ++ ++ /* for LPS */ ++ LeaveAllPowerSaveMode(padapter); ++ ++ /* IPS still bound with primary adapter */ ++ padapter = GET_PRIMARY_ADAPTER(padapter); ++ pmlmepriv = &padapter->mlmepriv; ++ ++ if (time_before(pwrpriv->ips_deny_time, deny_time)) ++ pwrpriv->ips_deny_time = deny_time; ++ ++ ++ if (pwrpriv->ps_processing) { ++ DBG_871X("%s wait ps_processing...\n", __func__); ++ while (pwrpriv->ps_processing && jiffies_to_msecs(jiffies - start) <= 3000) ++ msleep(10); ++ if (pwrpriv->ps_processing) ++ DBG_871X("%s wait ps_processing timeout\n", __func__); ++ else ++ DBG_871X("%s wait ps_processing done\n", __func__); ++ } ++ ++ if (pwrpriv->bInternalAutoSuspend == false && pwrpriv->bInSuspend) { ++ DBG_871X("%s wait bInSuspend...\n", __func__); ++ while (pwrpriv->bInSuspend ++ && jiffies_to_msecs(jiffies - start) <= 3000 ++ ) { ++ msleep(10); ++ } ++ if (pwrpriv->bInSuspend) ++ DBG_871X("%s wait bInSuspend timeout\n", __func__); ++ else ++ DBG_871X("%s wait bInSuspend done\n", __func__); ++ } ++ ++ /* System suspend is not allowed to wakeup */ ++ if ((pwrpriv->bInternalAutoSuspend == false) && (true == pwrpriv->bInSuspend)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ /* block??? */ ++ if ((pwrpriv->bInternalAutoSuspend == true) && (padapter->net_closed == true)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ /* I think this should be check in IPS, LPS, autosuspend functions... */ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) ++ { ++ ret = _SUCCESS; ++ goto exit; ++ } ++ ++ if (rf_off == pwrpriv->rf_pwrstate) ++ { ++ { ++ DBG_8192C("%s call ips_leave....\n", __func__); ++ if (_FAIL == ips_leave(padapter)) ++ { ++ DBG_8192C("======> ips_leave fail.............\n"); ++ ret = _FAIL; ++ goto exit; ++ } ++ } ++ } ++ ++ /* TODO: the following checking need to be merged... */ ++ if (padapter->bDriverStopped ++ || !padapter->bup ++ || !padapter->hw_init_completed ++ ) { ++ DBG_8192C("%s: bDriverStopped =%d, bup =%d, hw_init_completed =%u\n" ++ , caller ++ , padapter->bDriverStopped ++ , padapter->bup ++ , padapter->hw_init_completed); ++ ret = false; ++ goto exit; ++ } ++ ++exit: ++ deny_time = jiffies + msecs_to_jiffies(ips_deffer_ms); ++ if (time_before(pwrpriv->ips_deny_time, deny_time)) ++ pwrpriv->ips_deny_time = deny_time; ++ return ret; ++ ++} ++ ++int rtw_pm_set_lps(struct adapter *padapter, u8 mode) ++{ ++ int ret = 0; ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); ++ ++ if (mode < PS_MODE_NUM) ++ { ++ if (pwrctrlpriv->power_mgnt !=mode) ++ { ++ if (PS_MODE_ACTIVE == mode) ++ { ++ LeaveAllPowerSaveMode(padapter); ++ } ++ else ++ { ++ pwrctrlpriv->LpsIdleCount = 2; ++ } ++ pwrctrlpriv->power_mgnt = mode; ++ pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt)?true:false; ++ } ++ } ++ else ++ { ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++int rtw_pm_set_ips(struct adapter *padapter, u8 mode) ++{ ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); ++ ++ if (mode == IPS_NORMAL || mode == IPS_LEVEL_2) { ++ rtw_ips_mode_req(pwrctrlpriv, mode); ++ DBG_871X("%s %s\n", __func__, mode == IPS_NORMAL?"IPS_NORMAL":"IPS_LEVEL_2"); ++ return 0; ++ } ++ else if (mode ==IPS_NONE) { ++ rtw_ips_mode_req(pwrctrlpriv, mode); ++ DBG_871X("%s %s\n", __func__, "IPS_NONE"); ++ if ((padapter->bSurpriseRemoved == 0) && (_FAIL == rtw_pwr_wakeup(padapter))) ++ return -EFAULT; ++ } ++ else { ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++/* ++ * ATTENTION: ++ *This function will request pwrctrl LOCK! ++ */ ++void rtw_ps_deny(struct adapter *padapter, enum PS_DENY_REASON reason) ++{ ++ struct pwrctrl_priv *pwrpriv; ++ ++/* DBG_871X("+" FUNC_ADPT_FMT ": Request PS deny for %d (0x%08X)\n", */ ++/* FUNC_ADPT_ARG(padapter), reason, BIT(reason)); */ ++ ++ pwrpriv = adapter_to_pwrctl(padapter); ++ ++ down(&pwrpriv->lock); ++ if (pwrpriv->ps_deny & BIT(reason)) ++ { ++ DBG_871X(FUNC_ADPT_FMT ": [WARNING] Reason %d had been set before!!\n", ++ FUNC_ADPT_ARG(padapter), reason); ++ } ++ pwrpriv->ps_deny |= BIT(reason); ++ up(&pwrpriv->lock); ++ ++/* DBG_871X("-" FUNC_ADPT_FMT ": Now PS deny for 0x%08X\n", */ ++/* FUNC_ADPT_ARG(padapter), pwrpriv->ps_deny); */ ++} ++ ++/* ++ * ATTENTION: ++ *This function will request pwrctrl LOCK! ++ */ ++void rtw_ps_deny_cancel(struct adapter *padapter, enum PS_DENY_REASON reason) ++{ ++ struct pwrctrl_priv *pwrpriv; ++ ++ ++/* DBG_871X("+" FUNC_ADPT_FMT ": Cancel PS deny for %d(0x%08X)\n", */ ++/* FUNC_ADPT_ARG(padapter), reason, BIT(reason)); */ ++ ++ pwrpriv = adapter_to_pwrctl(padapter); ++ ++ down(&pwrpriv->lock); ++ if ((pwrpriv->ps_deny & BIT(reason)) == 0) ++ { ++ DBG_871X(FUNC_ADPT_FMT ": [ERROR] Reason %d had been canceled before!!\n", ++ FUNC_ADPT_ARG(padapter), reason); ++ } ++ pwrpriv->ps_deny &= ~BIT(reason); ++ up(&pwrpriv->lock); ++ ++/* DBG_871X("-" FUNC_ADPT_FMT ": Now PS deny for 0x%08X\n", */ ++/* FUNC_ADPT_ARG(padapter), pwrpriv->ps_deny); */ ++} ++ ++/* ++ * ATTENTION: ++ *Before calling this function pwrctrl lock should be occupied already, ++ *otherwise it may return incorrect value. ++ */ ++u32 rtw_ps_deny_get(struct adapter *padapter) ++{ ++ u32 deny; ++ ++ ++ deny = adapter_to_pwrctl(padapter)->ps_deny; ++ ++ return deny; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_recv.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_recv.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_recv.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_recv.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,2931 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTW_RECV_C_ ++ ++#include ++#include ++#include ++#include ++ ++static u8 SNAP_ETH_TYPE_IPX[2] = {0x81, 0x37}; ++static u8 SNAP_ETH_TYPE_APPLETALK_AARP[2] = {0x80, 0xf3}; ++ ++u8 rtw_rfc1042_header[] = ++{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; ++/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ ++u8 rtw_bridge_tunnel_header[] = ++{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; ++ ++void rtw_signal_stat_timer_hdl(RTW_TIMER_HDL_ARGS); ++ ++void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv) ++{ ++ memset((u8 *)psta_recvpriv, 0, sizeof (struct sta_recv_priv)); ++ ++ spin_lock_init(&psta_recvpriv->lock); ++ ++ /* for (i = 0; iblk_strms[i]); */ ++ ++ _rtw_init_queue(&psta_recvpriv->defrag_q); ++} ++ ++sint _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter) ++{ ++ sint i; ++ union recv_frame *precvframe; ++ sint res = _SUCCESS; ++ ++ /* We don't need to memset padapter->XXX to zero, because adapter is allocated by vzalloc(). */ ++ /* memset((unsigned char *)precvpriv, 0, sizeof (struct recv_priv)); */ ++ ++ spin_lock_init(&precvpriv->lock); ++ ++ _rtw_init_queue(&precvpriv->free_recv_queue); ++ _rtw_init_queue(&precvpriv->recv_pending_queue); ++ _rtw_init_queue(&precvpriv->uc_swdec_pending_queue); ++ ++ precvpriv->adapter = padapter; ++ ++ precvpriv->free_recvframe_cnt = NR_RECVFRAME; ++ ++ precvpriv->pallocated_frame_buf = vzalloc(NR_RECVFRAME * sizeof(union recv_frame) + RXFRAME_ALIGN_SZ); ++ ++ if (precvpriv->pallocated_frame_buf == NULL) { ++ res = _FAIL; ++ goto exit; ++ } ++ /* memset(precvpriv->pallocated_frame_buf, 0, NR_RECVFRAME * sizeof(union recv_frame) + RXFRAME_ALIGN_SZ); */ ++ ++ precvpriv->precv_frame_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_frame_buf), RXFRAME_ALIGN_SZ); ++ /* precvpriv->precv_frame_buf = precvpriv->pallocated_frame_buf + RXFRAME_ALIGN_SZ - */ ++ /* ((SIZE_PTR) (precvpriv->pallocated_frame_buf) &(RXFRAME_ALIGN_SZ-1)); */ ++ ++ precvframe = (union recv_frame*) precvpriv->precv_frame_buf; ++ ++ ++ for (i = 0; i < NR_RECVFRAME ; i++) ++ { ++ INIT_LIST_HEAD(&(precvframe->u.list)); ++ ++ list_add_tail(&(precvframe->u.list), &(precvpriv->free_recv_queue.queue)); ++ ++ res = rtw_os_recv_resource_alloc(padapter, precvframe); ++ ++ precvframe->u.hdr.len = 0; ++ ++ precvframe->u.hdr.adapter =padapter; ++ precvframe++; ++ ++ } ++ ++ res = rtw_hal_init_recv_priv(padapter); ++ ++ rtw_init_timer(&precvpriv->signal_stat_timer, padapter, rtw_signal_stat_timer_hdl); ++ ++ precvpriv->signal_stat_sampling_interval = 2000; /* ms */ ++ ++ rtw_set_signal_stat_timer(precvpriv); ++ ++exit: ++ return res; ++} ++ ++void _rtw_free_recv_priv (struct recv_priv *precvpriv) ++{ ++ struct adapter *padapter = precvpriv->adapter; ++ ++ rtw_free_uc_swdec_pending_queue(padapter); ++ ++ rtw_os_recv_resource_free(precvpriv); ++ ++ if (precvpriv->pallocated_frame_buf) { ++ vfree(precvpriv->pallocated_frame_buf); ++ } ++ ++ rtw_hal_free_recv_priv(padapter); ++} ++ ++union recv_frame *_rtw_alloc_recvframe (struct __queue *pfree_recv_queue) ++{ ++ ++ union recv_frame *precvframe; ++ struct list_head *plist, *phead; ++ struct adapter *padapter; ++ struct recv_priv *precvpriv; ++ ++ if (list_empty(&pfree_recv_queue->queue)) ++ { ++ precvframe = NULL; ++ } ++ else ++ { ++ phead = get_list_head(pfree_recv_queue); ++ ++ plist = get_next(phead); ++ ++ precvframe = LIST_CONTAINOR(plist, union recv_frame, u); ++ ++ list_del_init(&precvframe->u.hdr.list); ++ padapter =precvframe->u.hdr.adapter; ++ if (padapter != NULL) { ++ precvpriv =&padapter->recvpriv; ++ if (pfree_recv_queue == &precvpriv->free_recv_queue) ++ precvpriv->free_recvframe_cnt--; ++ } ++ } ++ return precvframe; ++} ++ ++union recv_frame *rtw_alloc_recvframe (struct __queue *pfree_recv_queue) ++{ ++ union recv_frame *precvframe; ++ ++ spin_lock_bh(&pfree_recv_queue->lock); ++ ++ precvframe = _rtw_alloc_recvframe(pfree_recv_queue); ++ ++ spin_unlock_bh(&pfree_recv_queue->lock); ++ ++ return precvframe; ++} ++ ++int rtw_free_recvframe(union recv_frame *precvframe, struct __queue *pfree_recv_queue) ++{ ++ struct adapter *padapter =precvframe->u.hdr.adapter; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++ rtw_os_free_recvframe(precvframe); ++ ++ ++ spin_lock_bh(&pfree_recv_queue->lock); ++ ++ list_del_init(&(precvframe->u.hdr.list)); ++ ++ precvframe->u.hdr.len = 0; ++ ++ list_add_tail(&(precvframe->u.hdr.list), get_list_head(pfree_recv_queue)); ++ ++ if (padapter != NULL) { ++ if (pfree_recv_queue == &precvpriv->free_recv_queue) ++ precvpriv->free_recvframe_cnt++; ++ } ++ spin_unlock_bh(&pfree_recv_queue->lock); ++ return _SUCCESS; ++} ++ ++ ++ ++ ++sint _rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue) ++{ ++ ++ struct adapter *padapter =precvframe->u.hdr.adapter; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++ /* INIT_LIST_HEAD(&(precvframe->u.hdr.list)); */ ++ list_del_init(&(precvframe->u.hdr.list)); ++ ++ ++ list_add_tail(&(precvframe->u.hdr.list), get_list_head(queue)); ++ ++ if (padapter != NULL) { ++ if (queue == &precvpriv->free_recv_queue) ++ precvpriv->free_recvframe_cnt++; ++ } ++ return _SUCCESS; ++} ++ ++sint rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue) ++{ ++ sint ret; ++ ++ /* _spinlock(&pfree_recv_queue->lock); */ ++ spin_lock_bh(&queue->lock); ++ ret = _rtw_enqueue_recvframe(precvframe, queue); ++ /* spin_unlock(&pfree_recv_queue->lock); */ ++ spin_unlock_bh(&queue->lock); ++ ++ return ret; ++} ++ ++/* ++sint rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue) ++{ ++ return rtw_free_recvframe(precvframe, queue); ++} ++*/ ++ ++ ++ ++ ++/* ++caller : defrag ; recvframe_chk_defrag in recv_thread (passive) ++pframequeue: defrag_queue : will be accessed in recv_thread (passive) ++ ++using spinlock to protect ++ ++*/ ++ ++void rtw_free_recvframe_queue(struct __queue *pframequeue, struct __queue *pfree_recv_queue) ++{ ++ union recv_frame *precvframe; ++ struct list_head *plist, *phead; ++ ++ spin_lock(&pframequeue->lock); ++ ++ phead = get_list_head(pframequeue); ++ plist = get_next(phead); ++ ++ while (phead != plist) ++ { ++ precvframe = LIST_CONTAINOR(plist, union recv_frame, u); ++ ++ plist = get_next(plist); ++ ++ rtw_free_recvframe(precvframe, pfree_recv_queue); ++ } ++ ++ spin_unlock(&pframequeue->lock); ++} ++ ++u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter) ++{ ++ u32 cnt = 0; ++ union recv_frame *pending_frame; ++ while ((pending_frame =rtw_alloc_recvframe(&adapter->recvpriv.uc_swdec_pending_queue))) { ++ rtw_free_recvframe(pending_frame, &adapter->recvpriv.free_recv_queue); ++ cnt++; ++ } ++ ++ if (cnt) ++ DBG_871X(FUNC_ADPT_FMT" dequeue %d\n", FUNC_ADPT_ARG(adapter), cnt); ++ ++ return cnt; ++} ++ ++ ++sint rtw_enqueue_recvbuf_to_head(struct recv_buf *precvbuf, struct __queue *queue) ++{ ++ spin_lock_bh(&queue->lock); ++ ++ list_del_init(&precvbuf->list); ++ list_add(&precvbuf->list, get_list_head(queue)); ++ ++ spin_unlock_bh(&queue->lock); ++ ++ return _SUCCESS; ++} ++ ++sint rtw_enqueue_recvbuf(struct recv_buf *precvbuf, struct __queue *queue) ++{ ++ spin_lock_bh(&queue->lock); ++ ++ list_del_init(&precvbuf->list); ++ ++ list_add_tail(&precvbuf->list, get_list_head(queue)); ++ spin_unlock_bh(&queue->lock); ++ return _SUCCESS; ++ ++} ++ ++struct recv_buf *rtw_dequeue_recvbuf (struct __queue *queue) ++{ ++ struct recv_buf *precvbuf; ++ struct list_head *plist, *phead; ++ ++ spin_lock_bh(&queue->lock); ++ ++ if (list_empty(&queue->queue)) ++ { ++ precvbuf = NULL; ++ } ++ else ++ { ++ phead = get_list_head(queue); ++ ++ plist = get_next(phead); ++ ++ precvbuf = LIST_CONTAINOR(plist, struct recv_buf, list); ++ ++ list_del_init(&precvbuf->list); ++ ++ } ++ ++ spin_unlock_bh(&queue->lock); ++ ++ return precvbuf; ++ ++} ++ ++sint recvframe_chkmic(struct adapter *adapter, union recv_frame *precvframe); ++sint recvframe_chkmic(struct adapter *adapter, union recv_frame *precvframe) { ++ ++ sint i, res = _SUCCESS; ++ u32 datalen; ++ u8 miccode[8]; ++ u8 bmic_err =false, brpt_micerror = true; ++ u8 *pframe, *payload,*pframemic; ++ u8 *mickey; ++ /* u8 *iv, rxdata_key_idx = 0; */ ++ struct sta_info *stainfo; ++ struct rx_pkt_attrib *prxattrib =&precvframe->u.hdr.attrib; ++ struct security_priv *psecuritypriv =&adapter->securitypriv; ++ ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ stainfo =rtw_get_stainfo(&adapter->stapriv ,&prxattrib->ta[0]); ++ ++ if (prxattrib->encrypt == _TKIP_) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic:prxattrib->encrypt == _TKIP_\n")); ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic:da = 0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", ++ prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2], prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5])); ++ ++ /* calculate mic code */ ++ if (stainfo!= NULL) ++ { ++ if (IS_MCAST(prxattrib->ra)) ++ { ++ /* mickey =&psecuritypriv->dot118021XGrprxmickey.skey[0]; */ ++ /* iv = precvframe->u.hdr.rx_data+prxattrib->hdrlen; */ ++ /* rxdata_key_idx =(((iv[3])>>6)&0x3) ; */ ++ mickey =&psecuritypriv->dot118021XGrprxmickey[prxattrib->key_index].skey[0]; ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic: bcmc key\n")); ++ /* DBG_871X("\n recvframe_chkmic: bcmc key psecuritypriv->dot118021XGrpKeyid(%d), pmlmeinfo->key_index(%d) , recv key_id(%d)\n", */ ++ /* psecuritypriv->dot118021XGrpKeyid, pmlmeinfo->key_index, rxdata_key_idx); */ ++ ++ if (psecuritypriv->binstallGrpkey ==false) ++ { ++ res = _FAIL; ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n")); ++ DBG_871X("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n"); ++ goto exit; ++ } ++ } ++ else { ++ mickey =&stainfo->dot11tkiprxmickey.skey[0]; ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n recvframe_chkmic: unicast key\n")); ++ } ++ ++ datalen =precvframe->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len-prxattrib->icv_len-8;/* icv_len included the mic code */ ++ pframe =precvframe->u.hdr.rx_data; ++ payload =pframe+prxattrib->hdrlen+prxattrib->iv_len; ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n prxattrib->iv_len =%d prxattrib->icv_len =%d\n", prxattrib->iv_len, prxattrib->icv_len)); ++ ++ ++ rtw_seccalctkipmic(mickey, pframe, payload, datalen ,&miccode[0], (unsigned char)prxattrib->priority); /* care the length of the data */ ++ ++ pframemic =payload+datalen; ++ ++ bmic_err =false; ++ ++ for (i = 0;i<8;i++) { ++ if (miccode[i] != *(pframemic+i)) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chkmic:miccode[%d](%02x) != *(pframemic+%d)(%02x) ", i, miccode[i], i,*(pframemic+i))); ++ bmic_err =true; ++ } ++ } ++ ++ ++ if (bmic_err ==true) { ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n *(pframemic-8)-*(pframemic-1) = 0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", ++ *(pframemic-8),*(pframemic-7),*(pframemic-6),*(pframemic-5),*(pframemic-4),*(pframemic-3),*(pframemic-2),*(pframemic-1))); ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n *(pframemic-16)-*(pframemic-9) = 0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", ++ *(pframemic-16),*(pframemic-15),*(pframemic-14),*(pframemic-13),*(pframemic-12),*(pframemic-11),*(pframemic-10),*(pframemic-9))); ++ ++ { ++ uint i; ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n ======demp packet (len =%d) ======\n", precvframe->u.hdr.len)); ++ for (i = 0;iu.hdr.len;i =i+8) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x", ++ *(precvframe->u.hdr.rx_data+i),*(precvframe->u.hdr.rx_data+i+1), ++ *(precvframe->u.hdr.rx_data+i+2),*(precvframe->u.hdr.rx_data+i+3), ++ *(precvframe->u.hdr.rx_data+i+4),*(precvframe->u.hdr.rx_data+i+5), ++ *(precvframe->u.hdr.rx_data+i+6),*(precvframe->u.hdr.rx_data+i+7))); ++ } ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n ======demp packet end [len =%d]======\n", precvframe->u.hdr.len)); ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n hrdlen =%d,\n", prxattrib->hdrlen)); ++ } ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("ra = 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x psecuritypriv->binstallGrpkey =%d ", ++ prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2], ++ prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5], psecuritypriv->binstallGrpkey)); ++ ++ /* double check key_index for some timing issue , */ ++ /* cannot compare with psecuritypriv->dot118021XGrpKeyid also cause timing issue */ ++ if ((IS_MCAST(prxattrib->ra) ==true) && (prxattrib->key_index != pmlmeinfo->key_index)) ++ brpt_micerror = false; ++ ++ if ((prxattrib->bdecrypted ==true) && (brpt_micerror == true)) ++ { ++ rtw_handle_tkip_mic_err(adapter, (u8)IS_MCAST(prxattrib->ra)); ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted =%d ", prxattrib->bdecrypted)); ++ DBG_871X(" mic error :prxattrib->bdecrypted =%d\n", prxattrib->bdecrypted); ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted =%d ", prxattrib->bdecrypted)); ++ DBG_871X(" mic error :prxattrib->bdecrypted =%d\n", prxattrib->bdecrypted); ++ } ++ ++ res = _FAIL; ++ ++ } ++ else { ++ /* mic checked ok */ ++ if ((psecuritypriv->bcheck_grpkey ==false) && (IS_MCAST(prxattrib->ra) ==true)) { ++ psecuritypriv->bcheck_grpkey =true; ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("psecuritypriv->bcheck_grpkey =true")); ++ } ++ } ++ ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chkmic: rtw_get_stainfo == NULL!!!\n")); ++ } ++ ++ recvframe_pull_tail(precvframe, 8); ++ ++ } ++ ++exit: ++ return res; ++ ++} ++ ++/* decrypt and set the ivlen, icvlen of the recv_frame */ ++union recv_frame * decryptor(struct adapter *padapter, union recv_frame *precv_frame); ++union recv_frame * decryptor(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ ++ struct rx_pkt_attrib *prxattrib = &precv_frame->u.hdr.attrib; ++ struct security_priv *psecuritypriv =&padapter->securitypriv; ++ union recv_frame *return_packet =precv_frame; ++ u32 res = _SUCCESS; ++ ++ DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt); ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("prxstat->decrypted =%x prxattrib->encrypt = 0x%03x\n", prxattrib->bdecrypted, prxattrib->encrypt)); ++ ++ if (prxattrib->encrypt>0) ++ { ++ u8 *iv = precv_frame->u.hdr.rx_data+prxattrib->hdrlen; ++ prxattrib->key_index = (((iv[3])>>6)&0x3) ; ++ ++ if (prxattrib->key_index > WEP_KEYS) ++ { ++ DBG_871X("prxattrib->key_index(%d) > WEP_KEYS\n", prxattrib->key_index); ++ ++ switch (prxattrib->encrypt) { ++ case _WEP40_: ++ case _WEP104_: ++ prxattrib->key_index = psecuritypriv->dot11PrivacyKeyIndex; ++ break; ++ case _TKIP_: ++ case _AES_: ++ default: ++ prxattrib->key_index = psecuritypriv->dot118021XGrpKeyid; ++ break; ++ } ++ } ++ } ++ ++ if ((prxattrib->encrypt>0) && ((prxattrib->bdecrypted == 0) ||(psecuritypriv->sw_decrypt ==true))) ++ { ++ psecuritypriv->hw_decrypted =false; ++ ++ #ifdef DBG_RX_DECRYPTOR ++ DBG_871X("[%s] %d:prxstat->bdecrypted:%d, prxattrib->encrypt:%d, Setting psecuritypriv->hw_decrypted = %d\n", ++ __func__, ++ __LINE__, ++ prxattrib->bdecrypted, ++ prxattrib->encrypt, ++ psecuritypriv->hw_decrypted); ++ #endif ++ ++ switch (prxattrib->encrypt) { ++ case _WEP40_: ++ case _WEP104_: ++ DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_wep); ++ rtw_wep_decrypt(padapter, (u8 *)precv_frame); ++ break; ++ case _TKIP_: ++ DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_tkip); ++ res = rtw_tkip_decrypt(padapter, (u8 *)precv_frame); ++ break; ++ case _AES_: ++ DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_aes); ++ res = rtw_aes_decrypt(padapter, (u8 *)precv_frame); ++ break; ++ default: ++ break; ++ } ++ } ++ else if (prxattrib->bdecrypted == 1 ++ && prxattrib->encrypt >0 ++ && (psecuritypriv->busetkipkey == 1 || prxattrib->encrypt != _TKIP_) ++ ) ++ { ++ DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_hw); ++ ++ psecuritypriv->hw_decrypted =true; ++ #ifdef DBG_RX_DECRYPTOR ++ DBG_871X("[%s] %d:prxstat->bdecrypted:%d, prxattrib->encrypt:%d, Setting psecuritypriv->hw_decrypted = %d\n", ++ __func__, ++ __LINE__, ++ prxattrib->bdecrypted, ++ prxattrib->encrypt, ++ psecuritypriv->hw_decrypted); ++ ++ #endif ++ } ++ else { ++ DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_unknown); ++ #ifdef DBG_RX_DECRYPTOR ++ DBG_871X("[%s] %d:prxstat->bdecrypted:%d, prxattrib->encrypt:%d, Setting psecuritypriv->hw_decrypted = %d\n", ++ __func__, ++ __LINE__, ++ prxattrib->bdecrypted, ++ prxattrib->encrypt, ++ psecuritypriv->hw_decrypted); ++ #endif ++ } ++ ++ if (res == _FAIL) ++ { ++ rtw_free_recvframe(return_packet,&padapter->recvpriv.free_recv_queue); ++ return_packet = NULL; ++ } ++ else ++ { ++ prxattrib->bdecrypted = true; ++ } ++ ++ return return_packet; ++} ++ ++/* set the security information in the recv_frame */ ++union recv_frame * portctrl(struct adapter *adapter, union recv_frame * precv_frame); ++union recv_frame * portctrl(struct adapter *adapter, union recv_frame * precv_frame) ++{ ++ u8 *psta_addr = NULL; ++ u8 *ptr; ++ uint auth_alg; ++ struct recv_frame_hdr *pfhdr; ++ struct sta_info *psta; ++ struct sta_priv *pstapriv ; ++ union recv_frame *prtnframe; ++ u16 ether_type = 0; ++ u16 eapol_type = 0x888e;/* for Funia BD's WPA issue */ ++ struct rx_pkt_attrib *pattrib; ++ ++ pstapriv = &adapter->stapriv; ++ ++ auth_alg = adapter->securitypriv.dot11AuthAlgrthm; ++ ++ ptr = get_recvframe_data(precv_frame); ++ pfhdr = &precv_frame->u.hdr; ++ pattrib = &pfhdr->attrib; ++ psta_addr = pattrib->ta; ++ ++ prtnframe = NULL; ++ ++ psta = rtw_get_stainfo(pstapriv, psta_addr); ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:adapter->securitypriv.dot11AuthAlgrthm =%d\n", adapter->securitypriv.dot11AuthAlgrthm)); ++ ++ if (auth_alg ==2) ++ { ++ if ((psta!= NULL) && (psta->ieee8021x_blocked)) ++ { ++ __be16 be_tmp; ++ ++ /* blocked */ ++ /* only accept EAPOL frame */ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:psta->ieee8021x_blocked == 1\n")); ++ ++ prtnframe =precv_frame; ++ ++ /* get ether_type */ ++ ptr =ptr+pfhdr->attrib.hdrlen+pfhdr->attrib.iv_len+LLC_HEADER_SIZE; ++ memcpy(&be_tmp, ptr, 2); ++ ether_type = ntohs(be_tmp); ++ ++ if (ether_type == eapol_type) { ++ prtnframe =precv_frame; ++ } ++ else { ++ /* free this frame */ ++ rtw_free_recvframe(precv_frame, &adapter->recvpriv.free_recv_queue); ++ prtnframe = NULL; ++ } ++ } ++ else ++ { ++ /* allowed */ ++ /* check decryption status, and decrypt the frame if needed */ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:psta->ieee8021x_blocked == 0\n")); ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("portctrl:precv_frame->hdr.attrib.privacy =%x\n", precv_frame->u.hdr.attrib.privacy)); ++ ++ if (pattrib->bdecrypted == 0) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("portctrl:prxstat->decrypted =%x\n", pattrib->bdecrypted)); ++ } ++ ++ prtnframe =precv_frame; ++ /* check is the EAPOL frame or not (Rekey) */ ++ /* if (ether_type == eapol_type) { */ ++ /* RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("########portctrl:ether_type == 0x888e\n")); */ ++ /* check Rekey */ ++ ++ /* prtnframe =precv_frame; */ ++ /* */ ++ /* else { */ ++ /* RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:ether_type = 0x%04x\n", ether_type)); */ ++ /* */ ++ } ++ } ++ else ++ { ++ prtnframe =precv_frame; ++ } ++ return prtnframe; ++} ++ ++sint recv_decache(union recv_frame *precv_frame, u8 bretry, struct stainfo_rxcache *prxcache); ++sint recv_decache(union recv_frame *precv_frame, u8 bretry, struct stainfo_rxcache *prxcache) ++{ ++ sint tid = precv_frame->u.hdr.attrib.priority; ++ ++ u16 seq_ctrl = ((precv_frame->u.hdr.attrib.seq_num&0xffff) << 4) | ++ (precv_frame->u.hdr.attrib.frag_num & 0xf); ++ ++ if (tid>15) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, (tid>15)! seq_ctrl = 0x%x, tid = 0x%x\n", seq_ctrl, tid)); ++ ++ return _FAIL; ++ } ++ ++ if (1)/* if (bretry) */ ++ { ++ if (seq_ctrl == prxcache->tid_rxseq[tid]) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, seq_ctrl = 0x%x, tid = 0x%x, tid_rxseq = 0x%x\n", seq_ctrl, tid, prxcache->tid_rxseq[tid])); ++ ++ return _FAIL; ++ } ++ } ++ ++ prxcache->tid_rxseq[tid] = seq_ctrl; ++ ++ return _SUCCESS; ++ ++} ++ ++void process_pwrbit_data(struct adapter *padapter, union recv_frame *precv_frame); ++void process_pwrbit_data(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ unsigned char pwrbit; ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *psta = NULL; ++ ++ psta = rtw_get_stainfo(pstapriv, pattrib->src); ++ ++ pwrbit = GetPwrMgt(ptr); ++ ++ if (psta) ++ { ++ if (pwrbit) ++ { ++ if (!(psta->state & WIFI_SLEEP_STATE)) ++ { ++ /* psta->state |= WIFI_SLEEP_STATE; */ ++ /* pstapriv->sta_dz_bitmap |= BIT(psta->aid); */ ++ ++ stop_sta_xmit(padapter, psta); ++ ++ /* DBG_871X("to sleep, sta_dz_bitmap =%x\n", pstapriv->sta_dz_bitmap); */ ++ } ++ } ++ else ++ { ++ if (psta->state & WIFI_SLEEP_STATE) ++ { ++ /* psta->state ^= WIFI_SLEEP_STATE; */ ++ /* pstapriv->sta_dz_bitmap &= ~BIT(psta->aid); */ ++ ++ wakeup_sta_to_xmit(padapter, psta); ++ ++ /* DBG_871X("to wakeup, sta_dz_bitmap =%x\n", pstapriv->sta_dz_bitmap); */ ++ } ++ } ++ ++ } ++} ++ ++void process_wmmps_data(struct adapter *padapter, union recv_frame *precv_frame); ++void process_wmmps_data(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *psta = NULL; ++ ++ psta = rtw_get_stainfo(pstapriv, pattrib->src); ++ ++ if (!psta) return; ++ ++ if (!psta->qos_option) ++ return; ++ ++ if (!(psta->qos_info&0xf)) ++ return; ++ ++ if (psta->state&WIFI_SLEEP_STATE) ++ { ++ u8 wmmps_ac = 0; ++ ++ switch (pattrib->priority) ++ { ++ case 1: ++ case 2: ++ wmmps_ac = psta->uapsd_bk&BIT(1); ++ break; ++ case 4: ++ case 5: ++ wmmps_ac = psta->uapsd_vi&BIT(1); ++ break; ++ case 6: ++ case 7: ++ wmmps_ac = psta->uapsd_vo&BIT(1); ++ break; ++ case 0: ++ case 3: ++ default: ++ wmmps_ac = psta->uapsd_be&BIT(1); ++ break; ++ } ++ ++ if (wmmps_ac) ++ { ++ if (psta->sleepq_ac_len>0) ++ { ++ /* process received triggered frame */ ++ xmit_delivery_enabled_frames(padapter, psta); ++ } ++ else ++ { ++ /* issue one qos null frame with More data bit = 0 and the EOSP bit set (= 1) */ ++ issue_qos_nulldata(padapter, psta->hwaddr, (u16)pattrib->priority, 0, 0); ++ } ++ } ++ } ++} ++ ++void count_rx_stats(struct adapter *padapter, union recv_frame *prframe, struct sta_info*sta); ++void count_rx_stats(struct adapter *padapter, union recv_frame *prframe, struct sta_info*sta) ++{ ++ int sz; ++ struct sta_info *psta = NULL; ++ struct stainfo_stats *pstats = NULL; ++ struct rx_pkt_attrib *pattrib = & prframe->u.hdr.attrib; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++ sz = get_recvframe_len(prframe); ++ precvpriv->rx_bytes += sz; ++ ++ padapter->mlmepriv.LinkDetectInfo.NumRxOkInPeriod++; ++ ++ if ((!MacAddr_isBcst(pattrib->dst)) && (!IS_MCAST(pattrib->dst))) { ++ padapter->mlmepriv.LinkDetectInfo.NumRxUnicastOkInPeriod++; ++ } ++ ++ if (sta) ++ psta = sta; ++ else ++ psta = prframe->u.hdr.psta; ++ ++ if (psta) ++ { ++ pstats = &psta->sta_stats; ++ ++ pstats->rx_data_pkts++; ++ pstats->rx_bytes += sz; ++ } ++ ++ traffic_check_for_leave_lps(padapter, false, 0); ++} ++ ++sint sta2sta_data_frame( ++ struct adapter *adapter, ++ union recv_frame *precv_frame, ++ struct sta_info**psta ++); ++sint sta2sta_data_frame( ++ struct adapter *adapter, ++ union recv_frame *precv_frame, ++ struct sta_info**psta ++) ++{ ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ sint ret = _SUCCESS; ++ struct rx_pkt_attrib *pattrib = & precv_frame->u.hdr.attrib; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ u8 *mybssid = get_bssid(pmlmepriv); ++ u8 *myhwaddr = myid(&adapter->eeprompriv); ++ u8 * sta_addr = NULL; ++ sint bmcast = IS_MCAST(pattrib->dst); ++ ++ /* DBG_871X("[%s] %d, seqnum:%d\n", __func__, __LINE__, pattrib->seq_num); */ ++ ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) ++ { ++ ++ /* filter packets that SA is myself or multicast or broadcast */ ++ if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" SA ==myself\n")); ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || ++ !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || ++ (memcmp(pattrib->bssid, mybssid, ETH_ALEN))) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ sta_addr = pattrib->src; ++ ++ } ++ else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) ++ { ++ { ++ /* For Station mode, sa and bssid should always be BSSID, and DA is my mac-address */ ++ if (memcmp(pattrib->bssid, pattrib->src, ETH_ALEN)) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("bssid != TA under STATION_MODE; drop pkt\n")); ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ sta_addr = pattrib->bssid; ++ } ++ ++ } ++ else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ++ { ++ if (bmcast) ++ { ++ /* For AP mode, if DA == MCAST, then BSSID should be also MCAST */ ++ if (!IS_MCAST(pattrib->bssid)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ } ++ else /* not mc-frame */ ++ { ++ /* For AP mode, if DA is non-MCAST, then it must be BSSID, and bssid == BSSID */ ++ if (memcmp(pattrib->bssid, pattrib->dst, ETH_ALEN)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ sta_addr = pattrib->src; ++ } ++ ++ } ++ else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) ++ { ++ memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); ++ memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); ++ memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); ++ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); ++ memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ ++ sta_addr = mybssid; ++ } ++ else ++ { ++ ret = _FAIL; ++ } ++ ++ ++ ++ if (bmcast) ++ *psta = rtw_get_bcmc_stainfo(adapter); ++ else ++ *psta = rtw_get_stainfo(pstapriv, sta_addr); /* get ap_info */ ++ ++ if (*psta == NULL) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under sta2sta_data_frame ; drop pkt\n")); ++ ret = _FAIL; ++ goto exit; ++ } ++ ++exit: ++ return ret; ++} ++ ++sint ap2sta_data_frame( ++ struct adapter *adapter, ++ union recv_frame *precv_frame, ++ struct sta_info**psta); ++sint ap2sta_data_frame( ++ struct adapter *adapter, ++ union recv_frame *precv_frame, ++ struct sta_info**psta) ++{ ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ struct rx_pkt_attrib *pattrib = & precv_frame->u.hdr.attrib; ++ sint ret = _SUCCESS; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ u8 *mybssid = get_bssid(pmlmepriv); ++ u8 *myhwaddr = myid(&adapter->eeprompriv); ++ sint bmcast = IS_MCAST(pattrib->dst); ++ ++ if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) ++ && (check_fwstate(pmlmepriv, _FW_LINKED) == true ++ || check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true ) ++ ) ++ { ++ ++ /* filter packets that SA is myself or multicast or broadcast */ ++ if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" SA ==myself\n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s SA ="MAC_FMT", myhwaddr ="MAC_FMT"\n", ++ __func__, MAC_ARG(pattrib->src), MAC_ARG(myhwaddr)); ++ #endif ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ /* da should be for me */ ++ if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ++ (" ap2sta_data_frame: compare DA fail; DA ="MAC_FMT"\n", MAC_ARG(pattrib->dst))); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s DA ="MAC_FMT"\n", __func__, MAC_ARG(pattrib->dst)); ++ #endif ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ ++ /* check BSSID */ ++ if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || ++ !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || ++ (memcmp(pattrib->bssid, mybssid, ETH_ALEN))) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ++ (" ap2sta_data_frame: compare BSSID fail ; BSSID ="MAC_FMT"\n", MAC_ARG(pattrib->bssid))); ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("mybssid ="MAC_FMT"\n", MAC_ARG(mybssid))); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s BSSID ="MAC_FMT", mybssid ="MAC_FMT"\n", ++ __func__, MAC_ARG(pattrib->bssid), MAC_ARG(mybssid)); ++ DBG_871X("this adapter = %d, buddy adapter = %d\n", adapter->adapter_type, adapter->pbuddystruct adapter->adapter_type); ++ #endif ++ ++ if (!bmcast) ++ { ++ DBG_871X("issue_deauth to the nonassociated ap =" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->bssid)); ++ issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ++ } ++ ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ if (bmcast) ++ *psta = rtw_get_bcmc_stainfo(adapter); ++ else ++ *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get ap_info */ ++ ++ if (*psta == NULL) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("ap2sta: can't get psta under STATION_MODE ; drop pkt\n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s can't get psta under STATION_MODE ; drop pkt\n", __func__); ++ #endif ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) { ++ } ++ ++ if (GetFrameSubType(ptr) & BIT(6)) { ++ /* No data, will not indicate to upper layer, temporily count it here */ ++ count_rx_stats(adapter, precv_frame, *psta); ++ ret = RTW_RX_HANDLED; ++ goto exit; ++ } ++ ++ } ++ else if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) && ++ (check_fwstate(pmlmepriv, _FW_LINKED) == true)) ++ { ++ memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); ++ memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); ++ memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); ++ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); ++ memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ ++ /* */ ++ memcpy(pattrib->bssid, mybssid, ETH_ALEN); ++ ++ ++ *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */ ++ if (*psta == NULL) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under MP_MODE ; drop pkt\n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s can't get psta under WIFI_MP_STATE ; drop pkt\n", __func__); ++ #endif ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ ++ } ++ else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ++ { ++ /* Special case */ ++ ret = RTW_RX_HANDLED; ++ goto exit; ++ } ++ else ++ { ++ if (!memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && (!bmcast)) ++ { ++ *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */ ++ if (*psta == NULL) ++ { ++ ++ /* for AP multicast issue , modify by yiwei */ ++ static unsigned long send_issue_deauth_time = 0; ++ ++ /* DBG_871X("After send deauth , %u ms has elapsed.\n", jiffies_to_msecs(jiffies - send_issue_deauth_time)); */ ++ ++ if (jiffies_to_msecs(jiffies - send_issue_deauth_time) > 10000 || send_issue_deauth_time == 0) ++ { ++ send_issue_deauth_time = jiffies; ++ ++ DBG_871X("issue_deauth to the ap =" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->bssid)); ++ ++ issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ++ } ++ } ++ } ++ ++ ret = _FAIL; ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s fw_state:0x%x\n", __func__, get_fwstate(pmlmepriv)); ++ #endif ++ } ++ ++exit: ++ return ret; ++} ++ ++sint sta2ap_data_frame( ++ struct adapter *adapter, ++ union recv_frame *precv_frame, ++ struct sta_info**psta); ++sint sta2ap_data_frame( ++ struct adapter *adapter, ++ union recv_frame *precv_frame, ++ struct sta_info**psta) ++{ ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ struct rx_pkt_attrib *pattrib = & precv_frame->u.hdr.attrib; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ unsigned char *mybssid = get_bssid(pmlmepriv); ++ sint ret = _SUCCESS; ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ++ { ++ /* For AP mode, RA =BSSID, TX =STA(SRC_ADDR), A3 =DST_ADDR */ ++ if (memcmp(pattrib->bssid, mybssid, ETH_ALEN)) ++ { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ *psta = rtw_get_stainfo(pstapriv, pattrib->src); ++ if (*psta == NULL) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under AP_MODE; drop pkt\n")); ++ DBG_871X("issue_deauth to sta =" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->src)); ++ ++ issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ++ ++ ret = RTW_RX_HANDLED; ++ goto exit; ++ } ++ ++ process_pwrbit_data(adapter, precv_frame); ++ ++ if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) { ++ process_wmmps_data(adapter, precv_frame); ++ } ++ ++ if (GetFrameSubType(ptr) & BIT(6)) { ++ /* No data, will not indicate to upper layer, temporily count it here */ ++ count_rx_stats(adapter, precv_frame, *psta); ++ ret = RTW_RX_HANDLED; ++ goto exit; ++ } ++ } ++ else { ++ u8 *myhwaddr = myid(&adapter->eeprompriv); ++ if (memcmp(pattrib->ra, myhwaddr, ETH_ALEN)) { ++ ret = RTW_RX_HANDLED; ++ goto exit; ++ } ++ DBG_871X("issue_deauth to sta =" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->src)); ++ issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ++ ret = RTW_RX_HANDLED; ++ goto exit; ++ } ++ ++exit: ++ return ret; ++} ++ ++sint validate_recv_ctrl_frame(struct adapter *padapter, union recv_frame *precv_frame); ++sint validate_recv_ctrl_frame(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 *pframe = precv_frame->u.hdr.rx_data; ++ struct sta_info *psta = NULL; ++ /* uint len = precv_frame->u.hdr.len; */ ++ ++ /* DBG_871X("+validate_recv_ctrl_frame\n"); */ ++ ++ if (GetFrameType(pframe) != WIFI_CTRL_TYPE) ++ { ++ return _FAIL; ++ } ++ ++ /* receive the frames that ra(a1) is my address */ ++ if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN)) ++ { ++ return _FAIL; ++ } ++ ++ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); ++ if (psta == NULL) ++ { ++ return _FAIL; ++ } ++ ++ /* for rx pkt statistics */ ++ psta->sta_stats.rx_ctrl_pkts++; ++ ++ /* only handle ps-poll */ ++ if (GetFrameSubType(pframe) == WIFI_PSPOLL) ++ { ++ u16 aid; ++ u8 wmmps_ac = 0; ++ ++ aid = GetAid(pframe); ++ if (psta->aid!=aid) ++ { ++ return _FAIL; ++ } ++ ++ switch (pattrib->priority) ++ { ++ case 1: ++ case 2: ++ wmmps_ac = psta->uapsd_bk&BIT(0); ++ break; ++ case 4: ++ case 5: ++ wmmps_ac = psta->uapsd_vi&BIT(0); ++ break; ++ case 6: ++ case 7: ++ wmmps_ac = psta->uapsd_vo&BIT(0); ++ break; ++ case 0: ++ case 3: ++ default: ++ wmmps_ac = psta->uapsd_be&BIT(0); ++ break; ++ } ++ ++ if (wmmps_ac) ++ return _FAIL; ++ ++ if (psta->state & WIFI_STA_ALIVE_CHK_STATE) ++ { ++ DBG_871X("%s alive check-rx ps-poll\n", __func__); ++ psta->expire_to = pstapriv->expire_to; ++ psta->state ^= WIFI_STA_ALIVE_CHK_STATE; ++ } ++ ++ if ((psta->state&WIFI_SLEEP_STATE) && (pstapriv->sta_dz_bitmap&BIT(psta->aid))) ++ { ++ struct list_head *xmitframe_plist, *xmitframe_phead; ++ struct xmit_frame *pxmitframe = NULL; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ /* spin_lock_bh(&psta->sleep_q.lock); */ ++ spin_lock_bh(&pxmitpriv->lock); ++ ++ xmitframe_phead = get_list_head(&psta->sleep_q); ++ xmitframe_plist = get_next(xmitframe_phead); ++ ++ if (xmitframe_phead != xmitframe_plist) ++ { ++ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); ++ ++ xmitframe_plist = get_next(xmitframe_plist); ++ ++ list_del_init(&pxmitframe->list); ++ ++ psta->sleepq_len--; ++ ++ if (psta->sleepq_len>0) ++ pxmitframe->attrib.mdata = 1; ++ else ++ pxmitframe->attrib.mdata = 0; ++ ++ pxmitframe->attrib.triggered = 1; ++ ++ /* DBG_871X("handling ps-poll, q_len =%d, tim =%x\n", psta->sleepq_len, pstapriv->tim_bitmap); */ ++ ++ rtw_hal_xmitframe_enqueue(padapter, pxmitframe); ++ ++ if (psta->sleepq_len == 0) ++ { ++ pstapriv->tim_bitmap &= ~BIT(psta->aid); ++ ++ /* DBG_871X("after handling ps-poll, tim =%x\n", pstapriv->tim_bitmap); */ ++ ++ /* upate BCN for TIM IE */ ++ /* update_BCNTIM(padapter); */ ++ update_beacon(padapter, _TIM_IE_, NULL, true); ++ } ++ ++ /* spin_unlock_bh(&psta->sleep_q.lock); */ ++ spin_unlock_bh(&pxmitpriv->lock); ++ ++ } ++ else ++ { ++ /* spin_unlock_bh(&psta->sleep_q.lock); */ ++ spin_unlock_bh(&pxmitpriv->lock); ++ ++ /* DBG_871X("no buffered packets to xmit\n"); */ ++ if (pstapriv->tim_bitmap&BIT(psta->aid)) ++ { ++ if (psta->sleepq_len == 0) ++ { ++ DBG_871X("no buffered packets to xmit\n"); ++ ++ /* issue nulldata with More data bit = 0 to indicate we have no buffered packets */ ++ issue_nulldata_in_interrupt(padapter, psta->hwaddr); ++ } ++ else ++ { ++ DBG_871X("error!psta->sleepq_len =%d\n", psta->sleepq_len); ++ psta->sleepq_len = 0; ++ } ++ ++ pstapriv->tim_bitmap &= ~BIT(psta->aid); ++ ++ /* upate BCN for TIM IE */ ++ /* update_BCNTIM(padapter); */ ++ update_beacon(padapter, _TIM_IE_, NULL, true); ++ } ++ } ++ } ++ } ++ ++ return _FAIL; ++ ++} ++ ++union recv_frame* recvframe_chk_defrag(struct adapter *padapter, union recv_frame *precv_frame); ++sint validate_recv_mgnt_frame(struct adapter *padapter, union recv_frame *precv_frame); ++sint validate_recv_mgnt_frame(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ /* struct mlme_priv *pmlmepriv = &adapter->mlmepriv; */ ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("+validate_recv_mgnt_frame\n")); ++ ++ precv_frame = recvframe_chk_defrag(padapter, precv_frame); ++ if (precv_frame == NULL) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("%s: fragment packet\n", __func__)); ++ return _SUCCESS; ++ } ++ ++ { ++ /* for rx pkt statistics */ ++ struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(precv_frame->u.hdr.rx_data)); ++ if (psta) { ++ psta->sta_stats.rx_mgnt_pkts++; ++ if (GetFrameSubType(precv_frame->u.hdr.rx_data) == WIFI_BEACON) ++ psta->sta_stats.rx_beacon_pkts++; ++ else if (GetFrameSubType(precv_frame->u.hdr.rx_data) == WIFI_PROBEREQ) ++ psta->sta_stats.rx_probereq_pkts++; ++ else if (GetFrameSubType(precv_frame->u.hdr.rx_data) == WIFI_PROBERSP) { ++ if (!memcmp(padapter->eeprompriv.mac_addr, GetAddr1Ptr(precv_frame->u.hdr.rx_data), ETH_ALEN)) ++ psta->sta_stats.rx_probersp_pkts++; ++ else if (is_broadcast_mac_addr(GetAddr1Ptr(precv_frame->u.hdr.rx_data)) ++ || is_multicast_mac_addr(GetAddr1Ptr(precv_frame->u.hdr.rx_data))) ++ psta->sta_stats.rx_probersp_bm_pkts++; ++ else ++ psta->sta_stats.rx_probersp_uo_pkts++; ++ } ++ } ++ } ++ ++ mgt_dispatcher(padapter, precv_frame); ++ ++ return _SUCCESS; ++ ++} ++ ++sint validate_recv_data_frame(struct adapter *adapter, union recv_frame *precv_frame); ++sint validate_recv_data_frame(struct adapter *adapter, union recv_frame *precv_frame) ++{ ++ u8 bretry; ++ u8 *psa, *pda, *pbssid; ++ struct sta_info *psta = NULL; ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ struct rx_pkt_attrib *pattrib = & precv_frame->u.hdr.attrib; ++ struct security_priv *psecuritypriv = &adapter->securitypriv; ++ sint ret = _SUCCESS; ++ ++ bretry = GetRetry(ptr); ++ pda = get_da(ptr); ++ psa = get_sa(ptr); ++ pbssid = get_hdr_bssid(ptr); ++ ++ if (pbssid == NULL) { ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s pbssid == NULL\n", __func__); ++ #endif ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ memcpy(pattrib->dst, pda, ETH_ALEN); ++ memcpy(pattrib->src, psa, ETH_ALEN); ++ ++ memcpy(pattrib->bssid, pbssid, ETH_ALEN); ++ ++ switch (pattrib->to_fr_ds) ++ { ++ case 0: ++ memcpy(pattrib->ra, pda, ETH_ALEN); ++ memcpy(pattrib->ta, psa, ETH_ALEN); ++ ret = sta2sta_data_frame(adapter, precv_frame, &psta); ++ break; ++ ++ case 1: ++ memcpy(pattrib->ra, pda, ETH_ALEN); ++ memcpy(pattrib->ta, pbssid, ETH_ALEN); ++ ret = ap2sta_data_frame(adapter, precv_frame, &psta); ++ break; ++ ++ case 2: ++ memcpy(pattrib->ra, pbssid, ETH_ALEN); ++ memcpy(pattrib->ta, psa, ETH_ALEN); ++ ret = sta2ap_data_frame(adapter, precv_frame, &psta); ++ break; ++ ++ case 3: ++ memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN); ++ memcpy(pattrib->ta, GetAddr2Ptr(ptr), ETH_ALEN); ++ ret = _FAIL; ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" case 3\n")); ++ break; ++ ++ default: ++ ret = _FAIL; ++ break; ++ ++ } ++ ++ if (ret == _FAIL) { ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s case:%d, res:%d\n", __func__, pattrib->to_fr_ds, ret); ++ #endif ++ goto exit; ++ } else if (ret == RTW_RX_HANDLED) { ++ goto exit; ++ } ++ ++ ++ if (psta == NULL) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" after to_fr_ds_chk; psta == NULL\n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s psta == NULL\n", __func__); ++ #endif ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ /* psta->rssi = prxcmd->rssi; */ ++ /* psta->signal_quality = prxcmd->sq; */ ++ precv_frame->u.hdr.psta = psta; ++ ++ ++ pattrib->amsdu = 0; ++ pattrib->ack_policy = 0; ++ /* parsing QC field */ ++ if (pattrib->qos == 1) ++ { ++ pattrib->priority = GetPriority((ptr + 24)); ++ pattrib->ack_policy = GetAckpolicy((ptr + 24)); ++ pattrib->amsdu = GetAMsdu((ptr + 24)); ++ pattrib->hdrlen = pattrib->to_fr_ds ==3 ? 32 : 26; ++ ++ if (pattrib->priority!= 0 && pattrib->priority!=3) ++ { ++ adapter->recvpriv.bIsAnyNonBEPkts = true; ++ } ++ } ++ else ++ { ++ pattrib->priority = 0; ++ pattrib->hdrlen = pattrib->to_fr_ds ==3 ? 30 : 24; ++ } ++ ++ ++ if (pattrib->order)/* HT-CTRL 11n */ ++ { ++ pattrib->hdrlen += 4; ++ } ++ ++ precv_frame->u.hdr.preorder_ctrl = &psta->recvreorder_ctrl[pattrib->priority]; ++ ++ /* decache, drop duplicate recv packets */ ++ if (recv_decache(precv_frame, bretry, &psta->sta_recvpriv.rxcache) == _FAIL) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("decache : drop pkt\n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s recv_decache return _FAIL\n", __func__); ++ #endif ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ if (pattrib->privacy) { ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("validate_recv_data_frame:pattrib->privacy =%x\n", pattrib->privacy)); ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n ^^^^^^^^^^^IS_MCAST(pattrib->ra(0x%02x)) =%d^^^^^^^^^^^^^^^6\n", pattrib->ra[0], IS_MCAST(pattrib->ra))); ++ ++ GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, IS_MCAST(pattrib->ra)); ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n pattrib->encrypt =%d\n", pattrib->encrypt)); ++ ++ SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len, pattrib->encrypt); ++ } ++ else ++ { ++ pattrib->encrypt = 0; ++ pattrib->iv_len = pattrib->icv_len = 0; ++ } ++ ++exit: ++ return ret; ++} ++ ++static sint validate_80211w_mgmt(struct adapter *adapter, union recv_frame *precv_frame) ++{ ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ struct rx_pkt_attrib *pattrib = & precv_frame->u.hdr.attrib; ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ u8 type; ++ u8 subtype; ++ ++ type = GetFrameType(ptr); ++ subtype = GetFrameSubType(ptr); /* bit(7)~bit(2) */ ++ ++ /* only support station mode */ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED) ++ && adapter->securitypriv.binstallBIPkey == true) ++ { ++ /* unicast management frame decrypt */ ++ if (pattrib->privacy && !(IS_MCAST(GetAddr1Ptr(ptr))) && ++ (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC || subtype == WIFI_ACTION)) ++ { ++ u8 *ppp, *mgmt_DATA; ++ u32 data_len = 0; ++ ppp = GetAddr2Ptr(ptr); ++ ++ pattrib->bdecrypted = 0; ++ pattrib->encrypt = _AES_; ++ pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr); ++ /* set iv and icv length */ ++ SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len, pattrib->encrypt); ++ memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN); ++ memcpy(pattrib->ta, GetAddr2Ptr(ptr), ETH_ALEN); ++ /* actual management data frame body */ ++ data_len = pattrib->pkt_len - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len; ++ mgmt_DATA = rtw_zmalloc(data_len); ++ if (mgmt_DATA == NULL) ++ { ++ DBG_871X("%s mgmt allocate fail !!!!!!!!!\n", __func__); ++ goto validate_80211w_fail; ++ } ++ precv_frame = decryptor(adapter, precv_frame); ++ /* save actual management data frame body */ ++ memcpy(mgmt_DATA, ptr+pattrib->hdrlen+pattrib->iv_len, data_len); ++ /* overwrite the iv field */ ++ memcpy(ptr+pattrib->hdrlen, mgmt_DATA, data_len); ++ /* remove the iv and icv length */ ++ pattrib->pkt_len = pattrib->pkt_len - pattrib->iv_len - pattrib->icv_len; ++ kfree(mgmt_DATA); ++ if (!precv_frame) ++ { ++ DBG_871X("%s mgmt descrypt fail !!!!!!!!!\n", __func__); ++ goto validate_80211w_fail; ++ } ++ } ++ else if (IS_MCAST(GetAddr1Ptr(ptr)) && ++ (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC)) ++ { ++ sint BIP_ret = _SUCCESS; ++ /* verify BIP MME IE of broadcast/multicast de-auth/disassoc packet */ ++ BIP_ret = rtw_BIP_verify(adapter, (u8 *)precv_frame); ++ if (BIP_ret == _FAIL) ++ { ++ /* DBG_871X("802.11w BIP verify fail\n"); */ ++ goto validate_80211w_fail; ++ } ++ else if (BIP_ret == RTW_RX_HANDLED) ++ { ++ /* DBG_871X("802.11w recv none protected packet\n"); */ ++ /* issue sa query request */ ++ issue_action_SA_Query(adapter, NULL, 0, 0); ++ goto validate_80211w_fail; ++ } ++ }/* 802.11w protect */ ++ else ++ { ++ if (subtype == WIFI_ACTION) ++ { ++ /* according 802.11-2012 standard, these five types are not robust types */ ++ if (ptr[WLAN_HDR_A3_LEN] != RTW_WLAN_CATEGORY_PUBLIC && ++ ptr[WLAN_HDR_A3_LEN] != RTW_WLAN_CATEGORY_HT && ++ ptr[WLAN_HDR_A3_LEN] != RTW_WLAN_CATEGORY_UNPROTECTED_WNM && ++ ptr[WLAN_HDR_A3_LEN] != RTW_WLAN_CATEGORY_SELF_PROTECTED && ++ ptr[WLAN_HDR_A3_LEN] != RTW_WLAN_CATEGORY_P2P) ++ { ++ DBG_871X("action frame category =%d should robust\n", ptr[WLAN_HDR_A3_LEN]); ++ goto validate_80211w_fail; ++ } ++ } ++ else if (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC) ++ { ++ DBG_871X("802.11w recv none protected packet\n"); ++ /* issue sa query request */ ++ issue_action_SA_Query(adapter, NULL, 0, 0); ++ goto validate_80211w_fail; ++ } ++ } ++ } ++ return _SUCCESS; ++ ++validate_80211w_fail: ++ return _FAIL; ++ ++} ++ ++static inline void dump_rx_packet(u8 *ptr) ++{ ++ int i; ++ ++ DBG_871X("#############################\n"); ++ for (i = 0; i<64;i =i+8) ++ DBG_871X("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr+i), ++ *(ptr+i+1), *(ptr+i+2) ,*(ptr+i+3) ,*(ptr+i+4),*(ptr+i+5), *(ptr+i+6), *(ptr+i+7)); ++ DBG_871X("#############################\n"); ++} ++ ++sint validate_recv_frame(struct adapter *adapter, union recv_frame *precv_frame); ++sint validate_recv_frame(struct adapter *adapter, union recv_frame *precv_frame) ++{ ++ /* shall check frame subtype, to / from ds, da, bssid */ ++ ++ /* then call check if rx seq/frag. duplicated. */ ++ ++ u8 type; ++ u8 subtype; ++ sint retval = _SUCCESS; ++ ++ struct rx_pkt_attrib *pattrib = & precv_frame->u.hdr.attrib; ++ ++ u8 *ptr = precv_frame->u.hdr.rx_data; ++ u8 ver =(unsigned char) (*ptr)&0x3 ; ++ ++ /* add version chk */ ++ if (ver!= 0) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_data_frame fail! (ver!= 0)\n")); ++ retval = _FAIL; ++ DBG_COUNTER(adapter->rx_logs.core_rx_pre_ver_err); ++ goto exit; ++ } ++ ++ type = GetFrameType(ptr); ++ subtype = GetFrameSubType(ptr); /* bit(7)~bit(2) */ ++ ++ pattrib->to_fr_ds = get_tofr_ds(ptr); ++ ++ pattrib->frag_num = GetFragNum(ptr); ++ pattrib->seq_num = GetSequence(ptr); ++ ++ pattrib->pw_save = GetPwrMgt(ptr); ++ pattrib->mfrag = GetMFrag(ptr); ++ pattrib->mdata = GetMData(ptr); ++ pattrib->privacy = GetPrivacy(ptr); ++ pattrib->order = GetOrder(ptr); ++{ ++ u8 bDumpRxPkt; ++ rtw_hal_get_def_var(adapter, HAL_DEF_DBG_DUMP_RXPKT, &(bDumpRxPkt)); ++ if (bDumpRxPkt == 1) /* dump all rx packets */ ++ dump_rx_packet(ptr); ++ else if ((bDumpRxPkt == 2) && (type == WIFI_MGT_TYPE)) ++ dump_rx_packet(ptr); ++ else if ((bDumpRxPkt == 3) && (type == WIFI_DATA_TYPE)) ++ dump_rx_packet(ptr); ++} ++ ++ switch (type) ++ { ++ case WIFI_MGT_TYPE: /* mgnt */ ++ DBG_COUNTER(adapter->rx_logs.core_rx_pre_mgmt); ++ if (validate_80211w_mgmt(adapter, precv_frame) == _FAIL) ++ { ++ retval = _FAIL; ++ DBG_COUNTER(padapter->rx_logs.core_rx_pre_mgmt_err_80211w); ++ break; ++ } ++ ++ retval = validate_recv_mgnt_frame(adapter, precv_frame); ++ if (retval == _FAIL) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_mgnt_frame fail\n")); ++ DBG_COUNTER(adapter->rx_logs.core_rx_pre_mgmt_err); ++ } ++ retval = _FAIL; /* only data frame return _SUCCESS */ ++ break; ++ case WIFI_CTRL_TYPE: /* ctrl */ ++ DBG_COUNTER(adapter->rx_logs.core_rx_pre_ctrl); ++ retval = validate_recv_ctrl_frame(adapter, precv_frame); ++ if (retval == _FAIL) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_ctrl_frame fail\n")); ++ DBG_COUNTER(adapter->rx_logs.core_rx_pre_ctrl_err); ++ } ++ retval = _FAIL; /* only data frame return _SUCCESS */ ++ break; ++ case WIFI_DATA_TYPE: /* data */ ++ DBG_COUNTER(adapter->rx_logs.core_rx_pre_data); ++ ++ pattrib->qos = (subtype & BIT(7))? 1:0; ++ retval = validate_recv_data_frame(adapter, precv_frame); ++ if (retval == _FAIL) ++ { ++ struct recv_priv *precvpriv = &adapter->recvpriv; ++ /* RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_data_frame fail\n")); */ ++ precvpriv->rx_drop++; ++ DBG_COUNTER(adapter->rx_logs.core_rx_pre_data_err); ++ } ++ else if (retval == _SUCCESS) ++ { ++#ifdef DBG_RX_DUMP_EAP ++ u8 bDumpRxPkt; ++ u16 eth_type; ++ ++ /* dump eapol */ ++ rtw_hal_get_def_var(adapter, HAL_DEF_DBG_DUMP_RXPKT, &(bDumpRxPkt)); ++ /* get ether_type */ ++ memcpy(ð_type, ptr + pattrib->hdrlen + pattrib->iv_len + LLC_HEADER_SIZE, 2); ++ eth_type = ntohs((unsigned short) eth_type); ++ if ((bDumpRxPkt == 4) && (eth_type == 0x888e)) ++ dump_rx_packet(ptr); ++#endif ++ } ++ else ++ { ++ DBG_COUNTER(adapter->rx_logs.core_rx_pre_data_handled); ++ } ++ break; ++ default: ++ DBG_COUNTER(adapter->rx_logs.core_rx_pre_unknown); ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_data_frame fail! type = 0x%x\n", type)); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME validate_recv_data_frame fail! type = 0x%x\n", type); ++ #endif ++ retval = _FAIL; ++ break; ++ } ++ ++exit: ++ return retval; ++} ++ ++ ++/* remove the wlanhdr and add the eth_hdr */ ++sint wlanhdr_to_ethhdr (union recv_frame *precvframe); ++sint wlanhdr_to_ethhdr (union recv_frame *precvframe) ++{ ++ sint rmv_len; ++ u16 eth_type, len; ++ u8 bsnaphdr; ++ u8 *psnap_type; ++ struct ieee80211_snap_hdr *psnap; ++ __be16 be_tmp; ++ sint ret = _SUCCESS; ++ struct adapter *adapter =precvframe->u.hdr.adapter; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ u8 *ptr = get_recvframe_data(precvframe) ; /* point to frame_ctrl field */ ++ struct rx_pkt_attrib *pattrib = & precvframe->u.hdr.attrib; ++ ++ if (pattrib->encrypt) { ++ recvframe_pull_tail(precvframe, pattrib->icv_len); ++ } ++ ++ psnap =(struct ieee80211_snap_hdr *)(ptr+pattrib->hdrlen + pattrib->iv_len); ++ psnap_type =ptr+pattrib->hdrlen + pattrib->iv_len+SNAP_SIZE; ++ /* convert hdr + possible LLC headers into Ethernet header */ ++ /* eth_type = (psnap_type[0] << 8) | psnap_type[1]; */ ++ if ((!memcmp(psnap, rtw_rfc1042_header, SNAP_SIZE) && ++ (memcmp(psnap_type, SNAP_ETH_TYPE_IPX, 2)) && ++ (memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_AARP, 2)))|| ++ /* eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || */ ++ !memcmp(psnap, rtw_bridge_tunnel_header, SNAP_SIZE)) { ++ /* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */ ++ bsnaphdr = true; ++ } ++ else { ++ /* Leave Ethernet header part of hdr and full payload */ ++ bsnaphdr = false; ++ } ++ ++ rmv_len = pattrib->hdrlen + pattrib->iv_len +(bsnaphdr?SNAP_SIZE:0); ++ len = precvframe->u.hdr.len - rmv_len; ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n ===pattrib->hdrlen: %x, pattrib->iv_len:%x ===\n\n", pattrib->hdrlen, pattrib->iv_len)); ++ ++ memcpy(&be_tmp, ptr+rmv_len, 2); ++ eth_type = ntohs(be_tmp); /* pattrib->ether_type */ ++ pattrib->eth_type = eth_type; ++ ++#ifdef CONFIG_AUTO_AP_MODE ++ if (0x8899 == pattrib->eth_type) ++ { ++ struct sta_info *psta = precvframe->u.hdr.psta; ++ ++ DBG_871X("wlan rx: got eth_type = 0x%x\n", pattrib->eth_type); ++ ++ if (psta && psta->isrc && psta->pid>0) ++ { ++ u16 rx_pid; ++ ++ rx_pid = *(u16*)(ptr+rmv_len+2); ++ ++ DBG_871X("wlan rx(pid = 0x%x): sta("MAC_FMT") pid = 0x%x\n", ++ rx_pid, MAC_ARG(psta->hwaddr), psta->pid); ++ ++ if (rx_pid == psta->pid) ++ { ++ int i; ++ u16 len = *(u16*)(ptr+rmv_len+4); ++ /* u16 ctrl_type = *(u16*)(ptr+rmv_len+6); */ ++ ++ /* DBG_871X("RC: len = 0x%x, ctrl_type = 0x%x\n", len, ctrl_type); */ ++ DBG_871X("RC: len = 0x%x\n", len); ++ ++ for (i = 0;idst, ETH_ALEN); ++ memcpy(ptr+ETH_ALEN, pattrib->src, ETH_ALEN); ++ ++ if (!bsnaphdr) { ++ be_tmp = htons(len); ++ memcpy(ptr+12, &be_tmp, 2); ++ } ++ ++ return ret; ++} ++ ++/* perform defrag */ ++union recv_frame * recvframe_defrag(struct adapter *adapter, struct __queue *defrag_q) ++{ ++ struct list_head *plist, *phead; ++ u8 *data, wlanhdr_offset; ++ u8 curfragnum; ++ struct recv_frame_hdr *pfhdr,*pnfhdr; ++ union recv_frame* prframe, *pnextrframe; ++ struct __queue *pfree_recv_queue; ++ ++ curfragnum = 0; ++ pfree_recv_queue =&adapter->recvpriv.free_recv_queue; ++ ++ phead = get_list_head(defrag_q); ++ plist = get_next(phead); ++ prframe = LIST_CONTAINOR(plist, union recv_frame, u); ++ pfhdr =&prframe->u.hdr; ++ list_del_init(&(prframe->u.list)); ++ ++ if (curfragnum!=pfhdr->attrib.frag_num) ++ { ++ /* the first fragment number must be 0 */ ++ /* free the whole queue */ ++ rtw_free_recvframe(prframe, pfree_recv_queue); ++ rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); ++ ++ return NULL; ++ } ++ ++ curfragnum++; ++ ++ plist = get_list_head(defrag_q); ++ ++ plist = get_next(plist); ++ ++ data =get_recvframe_data(prframe); ++ ++ while (phead != plist) ++ { ++ pnextrframe = LIST_CONTAINOR(plist, union recv_frame , u); ++ pnfhdr =&pnextrframe->u.hdr; ++ ++ ++ /* check the fragment sequence (2nd ~n fragment frame) */ ++ ++ if (curfragnum!=pnfhdr->attrib.frag_num) ++ { ++ /* the fragment number must be increasing (after decache) */ ++ /* release the defrag_q & prframe */ ++ rtw_free_recvframe(prframe, pfree_recv_queue); ++ rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); ++ return NULL; ++ } ++ ++ curfragnum++; ++ ++ /* copy the 2nd~n fragment frame's payload to the first fragment */ ++ /* get the 2nd~last fragment frame's payload */ ++ ++ wlanhdr_offset = pnfhdr->attrib.hdrlen + pnfhdr->attrib.iv_len; ++ ++ recvframe_pull(pnextrframe, wlanhdr_offset); ++ ++ /* append to first fragment frame's tail (if privacy frame, pull the ICV) */ ++ recvframe_pull_tail(prframe, pfhdr->attrib.icv_len); ++ ++ /* memcpy */ ++ memcpy(pfhdr->rx_tail, pnfhdr->rx_data, pnfhdr->len); ++ ++ recvframe_put(prframe, pnfhdr->len); ++ ++ pfhdr->attrib.icv_len =pnfhdr->attrib.icv_len; ++ plist = get_next(plist); ++ ++ }; ++ ++ /* free the defrag_q queue and return the prframe */ ++ rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("Performance defrag!!!!!\n")); ++ ++ return prframe; ++} ++ ++/* check if need to defrag, if needed queue the frame to defrag_q */ ++union recv_frame* recvframe_chk_defrag(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ u8 ismfrag; ++ u8 fragnum; ++ u8 *psta_addr; ++ struct recv_frame_hdr *pfhdr; ++ struct sta_info *psta; ++ struct sta_priv *pstapriv; ++ struct list_head *phead; ++ union recv_frame *prtnframe = NULL; ++ struct __queue *pfree_recv_queue, *pdefrag_q; ++ ++ pstapriv = &padapter->stapriv; ++ ++ pfhdr = &precv_frame->u.hdr; ++ ++ pfree_recv_queue = &padapter->recvpriv.free_recv_queue; ++ ++ /* need to define struct of wlan header frame ctrl */ ++ ismfrag = pfhdr->attrib.mfrag; ++ fragnum = pfhdr->attrib.frag_num; ++ ++ psta_addr = pfhdr->attrib.ta; ++ psta = rtw_get_stainfo(pstapriv, psta_addr); ++ if (psta == NULL) ++ { ++ u8 type = GetFrameType(pfhdr->rx_data); ++ if (type != WIFI_DATA_TYPE) { ++ psta = rtw_get_bcmc_stainfo(padapter); ++ pdefrag_q = &psta->sta_recvpriv.defrag_q; ++ } else ++ pdefrag_q = NULL; ++ } ++ else ++ pdefrag_q = &psta->sta_recvpriv.defrag_q; ++ ++ if ((ismfrag == 0) && (fragnum == 0)) ++ { ++ prtnframe = precv_frame;/* isn't a fragment frame */ ++ } ++ ++ if (ismfrag == 1) ++ { ++ /* 0~(n-1) fragment frame */ ++ /* enqueue to defraf_g */ ++ if (pdefrag_q != NULL) ++ { ++ if (fragnum == 0) ++ { ++ /* the first fragment */ ++ if (!list_empty(&pdefrag_q->queue)) ++ { ++ /* free current defrag_q */ ++ rtw_free_recvframe_queue(pdefrag_q, pfree_recv_queue); ++ } ++ } ++ ++ ++ /* Then enqueue the 0~(n-1) fragment into the defrag_q */ ++ ++ /* spin_lock(&pdefrag_q->lock); */ ++ phead = get_list_head(pdefrag_q); ++ list_add_tail(&pfhdr->list, phead); ++ /* spin_unlock(&pdefrag_q->lock); */ ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("Enqueuq: ismfrag = %d, fragnum = %d\n", ismfrag, fragnum)); ++ ++ prtnframe = NULL; ++ ++ } ++ else ++ { ++ /* can't find this ta's defrag_queue, so free this recv_frame */ ++ rtw_free_recvframe(precv_frame, pfree_recv_queue); ++ prtnframe = NULL; ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("Free because pdefrag_q == NULL: ismfrag = %d, fragnum = %d\n", ismfrag, fragnum)); ++ } ++ ++ } ++ ++ if ((ismfrag == 0) && (fragnum!= 0)) ++ { ++ /* the last fragment frame */ ++ /* enqueue the last fragment */ ++ if (pdefrag_q != NULL) ++ { ++ /* spin_lock(&pdefrag_q->lock); */ ++ phead = get_list_head(pdefrag_q); ++ list_add_tail(&pfhdr->list, phead); ++ /* spin_unlock(&pdefrag_q->lock); */ ++ ++ /* call recvframe_defrag to defrag */ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("defrag: ismfrag = %d, fragnum = %d\n", ismfrag, fragnum)); ++ precv_frame = recvframe_defrag(padapter, pdefrag_q); ++ prtnframe =precv_frame; ++ ++ } ++ else ++ { ++ /* can't find this ta's defrag_queue, so free this recv_frame */ ++ rtw_free_recvframe(precv_frame, pfree_recv_queue); ++ prtnframe = NULL; ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("Free because pdefrag_q == NULL: ismfrag = %d, fragnum = %d\n", ismfrag, fragnum)); ++ } ++ ++ } ++ ++ ++ if ((prtnframe!= NULL) && (prtnframe->u.hdr.attrib.privacy)) ++ { ++ /* after defrag we must check tkip mic code */ ++ if (recvframe_chkmic(padapter, prtnframe) == _FAIL) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chkmic(padapter, prtnframe) == _FAIL\n")); ++ rtw_free_recvframe(prtnframe, pfree_recv_queue); ++ prtnframe = NULL; ++ } ++ } ++ return prtnframe; ++} ++ ++static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe) ++{ ++ int a_len, padding_len; ++ u16 nSubframe_Length; ++ u8 nr_subframes, i; ++ u8 *pdata; ++ _pkt *sub_pkt,*subframes[MAX_SUBFRAME_COUNT]; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ struct __queue *pfree_recv_queue = &(precvpriv->free_recv_queue); ++ int ret = _SUCCESS; ++ ++ nr_subframes = 0; ++ ++ recvframe_pull(prframe, prframe->u.hdr.attrib.hdrlen); ++ ++ if (prframe->u.hdr.attrib.iv_len >0) ++ { ++ recvframe_pull(prframe, prframe->u.hdr.attrib.iv_len); ++ } ++ ++ a_len = prframe->u.hdr.len; ++ ++ pdata = prframe->u.hdr.rx_data; ++ ++ while (a_len > ETH_HLEN) { ++ ++ /* Offset 12 denote 2 mac address */ ++ nSubframe_Length = RTW_GET_BE16(pdata + 12); ++ ++ if (a_len < (ETHERNET_HEADER_SIZE + nSubframe_Length)) { ++ DBG_871X("nRemain_Length is %d and nSubframe_Length is : %d\n", a_len, nSubframe_Length); ++ break; ++ } ++ ++ sub_pkt = rtw_os_alloc_msdu_pkt(prframe, nSubframe_Length, pdata); ++ if (sub_pkt == NULL) { ++ DBG_871X("%s(): allocate sub packet fail !!!\n", __func__); ++ break; ++ } ++ ++ /* move the data point to data content */ ++ pdata += ETH_HLEN; ++ a_len -= ETH_HLEN; ++ ++ subframes[nr_subframes++] = sub_pkt; ++ ++ if (nr_subframes >= MAX_SUBFRAME_COUNT) { ++ DBG_871X("ParseSubframe(): Too many Subframes! Packets dropped!\n"); ++ break; ++ } ++ ++ pdata += nSubframe_Length; ++ a_len -= nSubframe_Length; ++ if (a_len != 0) { ++ padding_len = 4 - ((nSubframe_Length + ETH_HLEN) & (4-1)); ++ if (padding_len == 4) { ++ padding_len = 0; ++ } ++ ++ if (a_len < padding_len) { ++ DBG_871X("ParseSubframe(): a_len < padding_len !\n"); ++ break; ++ } ++ pdata += padding_len; ++ a_len -= padding_len; ++ } ++ } ++ ++ for (i = 0; iu.hdr.attrib); ++ } ++ } ++ ++ prframe->u.hdr.len = 0; ++ rtw_free_recvframe(prframe, pfree_recv_queue);/* free this recv_frame */ ++ ++ return ret; ++} ++ ++int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num); ++int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num) ++{ ++ struct adapter *padapter = preorder_ctrl->padapter; ++ struct dvobj_priv *psdpriv = padapter->dvobj; ++ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; ++ u8 wsize = preorder_ctrl->wsize_b; ++ u16 wend = (preorder_ctrl->indicate_seq + wsize -1) & 0xFFF;/* 4096; */ ++ ++ /* Rx Reorder initialize condition. */ ++ if (preorder_ctrl->indicate_seq == 0xFFFF) ++ { ++ preorder_ctrl->indicate_seq = seq_num; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d init IndicateSeq: %d, NewSeq: %d\n", __func__, __LINE__, ++ preorder_ctrl->indicate_seq, seq_num); ++ #endif ++ ++ /* DbgPrint("check_indicate_seq, 1st->indicate_seq =%d\n", precvpriv->indicate_seq); */ ++ } ++ ++ /* DbgPrint("enter->check_indicate_seq(): IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); */ ++ ++ /* Drop out the packet which SeqNum is smaller than WinStart */ ++ if (SN_LESS(seq_num, preorder_ctrl->indicate_seq)) ++ { ++ /* RT_TRACE(COMP_RX_REORDER, DBG_LOUD, ("CheckRxTsIndicateSeq(): Packet Drop! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, NewSeqNum)); */ ++ /* DbgPrint("CheckRxTsIndicateSeq(): Packet Drop! IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); */ ++ ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("%s IndicateSeq: %d > NewSeq: %d\n", __func__, ++ preorder_ctrl->indicate_seq, seq_num); ++ #endif ++ ++ ++ return false; ++ } ++ ++ /* */ ++ /* Sliding window manipulation. Conditions includes: */ ++ /* 1. Incoming SeqNum is equal to WinStart =>Window shift 1 */ ++ /* 2. Incoming SeqNum is larger than the WinEnd => Window shift N */ ++ /* */ ++ if (SN_EQUAL(seq_num, preorder_ctrl->indicate_seq)) ++ { ++ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF; ++ ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d SN_EQUAL IndicateSeq: %d, NewSeq: %d\n", __func__, __LINE__, ++ preorder_ctrl->indicate_seq, seq_num); ++ #endif ++ } ++ else if (SN_LESS(wend, seq_num)) ++ { ++ /* RT_TRACE(COMP_RX_REORDER, DBG_LOUD, ("CheckRxTsIndicateSeq(): Window Shift! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, NewSeqNum)); */ ++ /* DbgPrint("CheckRxTsIndicateSeq(): Window Shift! IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); */ ++ ++ /* boundary situation, when seq_num cross 0xFFF */ ++ if (seq_num >= (wsize - 1)) ++ preorder_ctrl->indicate_seq = seq_num + 1 -wsize; ++ else ++ preorder_ctrl->indicate_seq = 0xFFF - (wsize - (seq_num + 1)) + 1; ++ pdbgpriv->dbg_rx_ampdu_window_shift_cnt++; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d SN_LESS(wend, seq_num) IndicateSeq: %d, NewSeq: %d\n", __func__, __LINE__, ++ preorder_ctrl->indicate_seq, seq_num); ++ #endif ++ } ++ ++ /* DbgPrint("exit->check_indicate_seq(): IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); */ ++ ++ return true; ++} ++ ++int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, union recv_frame *prframe); ++int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, union recv_frame *prframe) ++{ ++ struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; ++ struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; ++ struct list_head *phead, *plist; ++ union recv_frame *pnextrframe; ++ struct rx_pkt_attrib *pnextattrib; ++ ++ /* DbgPrint("+enqueue_reorder_recvframe()\n"); */ ++ ++ /* spin_lock_irqsave(&ppending_recvframe_queue->lock, irql); */ ++ /* spin_lock(&ppending_recvframe_queue->lock); */ ++ ++ ++ phead = get_list_head(ppending_recvframe_queue); ++ plist = get_next(phead); ++ ++ while (phead != plist) ++ { ++ pnextrframe = LIST_CONTAINOR(plist, union recv_frame, u); ++ pnextattrib = &pnextrframe->u.hdr.attrib; ++ ++ if (SN_LESS(pnextattrib->seq_num, pattrib->seq_num)) ++ { ++ plist = get_next(plist); ++ } ++ else if (SN_EQUAL(pnextattrib->seq_num, pattrib->seq_num)) ++ { ++ /* Duplicate entry is found!! Do not insert current entry. */ ++ /* RT_TRACE(COMP_RX_REORDER, DBG_TRACE, ("InsertRxReorderList(): Duplicate packet is dropped!! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, SeqNum)); */ ++ ++ /* spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql); */ ++ ++ return false; ++ } ++ else ++ { ++ break; ++ } ++ ++ /* DbgPrint("enqueue_reorder_recvframe():while\n"); */ ++ ++ } ++ ++ ++ /* spin_lock_irqsave(&ppending_recvframe_queue->lock, irql); */ ++ /* spin_lock(&ppending_recvframe_queue->lock); */ ++ ++ list_del_init(&(prframe->u.hdr.list)); ++ ++ list_add_tail(&(prframe->u.hdr.list), plist); ++ ++ /* spin_unlock(&ppending_recvframe_queue->lock); */ ++ /* spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql); */ ++ ++ ++ /* RT_TRACE(COMP_RX_REORDER, DBG_TRACE, ("InsertRxReorderList(): Pkt insert into buffer!! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, SeqNum)); */ ++ return true; ++ ++} ++ ++void recv_indicatepkts_pkt_loss_cnt(struct debug_priv *pdbgpriv, u64 prev_seq, u64 current_seq); ++void recv_indicatepkts_pkt_loss_cnt(struct debug_priv *pdbgpriv, u64 prev_seq, u64 current_seq) ++{ ++ if (current_seq < prev_seq) ++ { ++ pdbgpriv->dbg_rx_ampdu_loss_count+= (4096 + current_seq - prev_seq); ++ ++ } ++ else ++ { ++ pdbgpriv->dbg_rx_ampdu_loss_count+= (current_seq - prev_seq); ++ } ++} ++int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reorder_ctrl *preorder_ctrl, int bforced); ++int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reorder_ctrl *preorder_ctrl, int bforced) ++{ ++ struct list_head *phead, *plist; ++ union recv_frame *prframe; ++ struct rx_pkt_attrib *pattrib; ++ /* u8 index = 0; */ ++ int bPktInBuf = false; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; ++ struct dvobj_priv *psdpriv = padapter->dvobj; ++ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; ++ ++ DBG_COUNTER(padapter->rx_logs.core_rx_post_indicate_in_oder); ++ ++ /* DbgPrint("+recv_indicatepkts_in_order\n"); */ ++ ++ /* spin_lock_irqsave(&ppending_recvframe_queue->lock, irql); */ ++ /* spin_lock(&ppending_recvframe_queue->lock); */ ++ ++ phead = get_list_head(ppending_recvframe_queue); ++ plist = get_next(phead); ++ ++ /* Handling some condition for forced indicate case. */ ++ if (bforced ==true) ++ { ++ pdbgpriv->dbg_rx_ampdu_forced_indicate_count++; ++ if (list_empty(phead)) ++ { ++ /* spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql); */ ++ /* spin_unlock(&ppending_recvframe_queue->lock); */ ++ return true; ++ } ++ ++ prframe = LIST_CONTAINOR(plist, union recv_frame, u); ++ pattrib = &prframe->u.hdr.attrib; ++ ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __func__, __LINE__, ++ preorder_ctrl->indicate_seq, pattrib->seq_num); ++ #endif ++ recv_indicatepkts_pkt_loss_cnt(pdbgpriv, preorder_ctrl->indicate_seq, pattrib->seq_num); ++ preorder_ctrl->indicate_seq = pattrib->seq_num; ++ ++ } ++ ++ /* Prepare indication list and indication. */ ++ /* Check if there is any packet need indicate. */ ++ while (!list_empty(phead)) ++ { ++ ++ prframe = LIST_CONTAINOR(plist, union recv_frame, u); ++ pattrib = &prframe->u.hdr.attrib; ++ ++ if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ++ ("recv_indicatepkts_in_order: indicate =%d seq =%d amsdu =%d\n", ++ preorder_ctrl->indicate_seq, pattrib->seq_num, pattrib->amsdu)); ++ ++ plist = get_next(plist); ++ list_del_init(&(prframe->u.hdr.list)); ++ ++ if (SN_EQUAL(preorder_ctrl->indicate_seq, pattrib->seq_num)) ++ { ++ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __func__, __LINE__, ++ preorder_ctrl->indicate_seq, pattrib->seq_num); ++ #endif ++ } ++ ++ /* Set this as a lock to make sure that only one thread is indicating packet. */ ++ /* pTS->RxIndicateState = RXTS_INDICATE_PROCESSING; */ ++ ++ /* Indicate packets */ ++ /* RT_ASSERT((index<=REORDER_WIN_SIZE), ("RxReorderIndicatePacket(): Rx Reorder buffer full!!\n")); */ ++ ++ ++ /* indicate this recv_frame */ ++ /* DbgPrint("recv_indicatepkts_in_order, indicate_seq =%d, seq_num =%d\n", precvpriv->indicate_seq, pattrib->seq_num); */ ++ if (!pattrib->amsdu) ++ { ++ /* DBG_871X("recv_indicatepkts_in_order, amsdu!= 1, indicate_seq =%d, seq_num =%d\n", preorder_ctrl->indicate_seq, pattrib->seq_num); */ ++ ++ if ((padapter->bDriverStopped == false) && ++ (padapter->bSurpriseRemoved == false)) ++ { ++ ++ rtw_recv_indicatepkt(padapter, prframe);/* indicate this recv_frame */ ++ ++ } ++ } ++ else if (pattrib->amsdu == 1) ++ { ++ if (amsdu_to_msdu(padapter, prframe)!= _SUCCESS) ++ { ++ rtw_free_recvframe(prframe, &precvpriv->free_recv_queue); ++ } ++ } ++ else ++ { ++ /* error condition; */ ++ } ++ ++ ++ /* Update local variables. */ ++ bPktInBuf = false; ++ ++ } ++ else ++ { ++ bPktInBuf = true; ++ break; ++ } ++ ++ /* DbgPrint("recv_indicatepkts_in_order():while\n"); */ ++ ++ } ++ ++ /* spin_unlock(&ppending_recvframe_queue->lock); */ ++ /* spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql); */ ++ ++ return bPktInBuf; ++} ++ ++int recv_indicatepkt_reorder(struct adapter *padapter, union recv_frame *prframe); ++int recv_indicatepkt_reorder(struct adapter *padapter, union recv_frame *prframe) ++{ ++ int retval = _SUCCESS; ++ struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; ++ struct recv_reorder_ctrl *preorder_ctrl = prframe->u.hdr.preorder_ctrl; ++ struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; ++ struct dvobj_priv *psdpriv = padapter->dvobj; ++ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; ++ ++ DBG_COUNTER(padapter->rx_logs.core_rx_post_indicate_reoder); ++ ++ if (!pattrib->amsdu) ++ { ++ /* s1. */ ++ wlanhdr_to_ethhdr(prframe); ++ ++ if (pattrib->qos!= 1) ++ { ++ if ((padapter->bDriverStopped == false) && ++ (padapter->bSurpriseRemoved == false)) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ recv_indicatepkt_reorder -recv_func recv_indicatepkt\n")); ++ ++ rtw_recv_indicatepkt(padapter, prframe); ++ return _SUCCESS; ++ ++ } ++ ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s pattrib->qos != 1\n", __func__); ++ #endif ++ ++ return _FAIL; ++ ++ } ++ ++ if (preorder_ctrl->enable == false) ++ { ++ /* indicate this recv_frame */ ++ preorder_ctrl->indicate_seq = pattrib->seq_num; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __func__, __LINE__, ++ preorder_ctrl->indicate_seq, pattrib->seq_num); ++ #endif ++ ++ rtw_recv_indicatepkt(padapter, prframe); ++ ++ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1)%4096; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __func__, __LINE__, ++ preorder_ctrl->indicate_seq, pattrib->seq_num); ++ #endif ++ ++ return _SUCCESS; ++ } ++ } ++ else if (pattrib->amsdu == 1) /* temp filter -> means didn't support A-MSDUs in a A-MPDU */ ++ { ++ if (preorder_ctrl->enable == false) ++ { ++ preorder_ctrl->indicate_seq = pattrib->seq_num; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __func__, __LINE__, ++ preorder_ctrl->indicate_seq, pattrib->seq_num); ++ #endif ++ ++ retval = amsdu_to_msdu(padapter, prframe); ++ ++ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1)%4096; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __func__, __LINE__, ++ preorder_ctrl->indicate_seq, pattrib->seq_num); ++ #endif ++ ++ if (retval != _SUCCESS) { ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s amsdu_to_msdu fail\n", __func__); ++ #endif ++ } ++ ++ return retval; ++ } ++ } ++ ++ spin_lock_bh(&ppending_recvframe_queue->lock); ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ++ ("recv_indicatepkt_reorder: indicate =%d seq =%d\n", ++ preorder_ctrl->indicate_seq, pattrib->seq_num)); ++ ++ /* s2. check if winstart_b(indicate_seq) needs to been updated */ ++ if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num)) ++ { ++ pdbgpriv->dbg_rx_ampdu_drop_count++; ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s check_indicate_seq fail\n", __func__); ++ #endif ++ goto _err_exit; ++ } ++ ++ ++ /* s3. Insert all packet into Reorder Queue to maintain its ordering. */ ++ if (!enqueue_reorder_recvframe(preorder_ctrl, prframe)) ++ { ++ /* DbgPrint("recv_indicatepkt_reorder, enqueue_reorder_recvframe fail!\n"); */ ++ /* spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql); */ ++ /* return _FAIL; */ ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s enqueue_reorder_recvframe fail\n", __func__); ++ #endif ++ goto _err_exit; ++ } ++ ++ ++ /* s4. */ ++ /* Indication process. */ ++ /* After Packet dropping and Sliding Window shifting as above, we can now just indicate the packets */ ++ /* with the SeqNum smaller than latest WinStart and buffer other packets. */ ++ /* */ ++ /* For Rx Reorder condition: */ ++ /* 1. All packets with SeqNum smaller than WinStart => Indicate */ ++ /* 2. All packets with SeqNum larger than or equal to WinStart => Buffer it. */ ++ /* */ ++ ++ /* recv_indicatepkts_in_order(padapter, preorder_ctrl, true); */ ++ if (recv_indicatepkts_in_order(padapter, preorder_ctrl, false) ==true) ++ { ++ _set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME); ++ spin_unlock_bh(&ppending_recvframe_queue->lock); ++ } ++ else ++ { ++ spin_unlock_bh(&ppending_recvframe_queue->lock); ++ del_timer_sync(&preorder_ctrl->reordering_ctrl_timer); ++ } ++ ++ return _SUCCESS; ++ ++_err_exit: ++ ++ spin_unlock_bh(&ppending_recvframe_queue->lock); ++ ++ return _FAIL; ++} ++ ++ ++void rtw_reordering_ctrl_timeout_handler(void *pcontext) ++{ ++ struct recv_reorder_ctrl *preorder_ctrl = (struct recv_reorder_ctrl *)pcontext; ++ struct adapter *padapter = preorder_ctrl->padapter; ++ struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; ++ ++ ++ if (padapter->bDriverStopped ||padapter->bSurpriseRemoved) ++ { ++ return; ++ } ++ ++ /* DBG_871X("+rtw_reordering_ctrl_timeout_handler() =>\n"); */ ++ ++ spin_lock_bh(&ppending_recvframe_queue->lock); ++ ++ if (recv_indicatepkts_in_order(padapter, preorder_ctrl, true) ==true) ++ { ++ _set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME); ++ } ++ ++ spin_unlock_bh(&ppending_recvframe_queue->lock); ++ ++} ++ ++int process_recv_indicatepkts(struct adapter *padapter, union recv_frame *prframe); ++int process_recv_indicatepkts(struct adapter *padapter, union recv_frame *prframe) ++{ ++ int retval = _SUCCESS; ++ /* struct recv_priv *precvpriv = &padapter->recvpriv; */ ++ /* struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; */ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ ++ DBG_COUNTER(padapter->rx_logs.core_rx_post_indicate); ++ ++ if (phtpriv->ht_option ==true) /* B/G/N Mode */ ++ { ++ /* prframe->u.hdr.preorder_ctrl = &precvpriv->recvreorder_ctrl[pattrib->priority]; */ ++ ++ if (recv_indicatepkt_reorder(padapter, prframe)!= _SUCCESS)/* including perform A-MPDU Rx Ordering Buffer Control */ ++ { ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s recv_indicatepkt_reorder error!\n", __func__); ++ #endif ++ ++ if ((padapter->bDriverStopped == false) && ++ (padapter->bSurpriseRemoved == false)) ++ { ++ retval = _FAIL; ++ return retval; ++ } ++ } ++ } ++ else /* B/G mode */ ++ { ++ retval =wlanhdr_to_ethhdr (prframe); ++ if (retval != _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("wlanhdr_to_ethhdr: drop pkt\n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s wlanhdr_to_ethhdr error!\n", __func__); ++ #endif ++ return retval; ++ } ++ ++ if ((padapter->bDriverStopped ==false) && (padapter->bSurpriseRemoved ==false)) ++ { ++ /* indicate this recv_frame */ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ process_recv_indicatepkts- recv_func recv_indicatepkt\n")); ++ rtw_recv_indicatepkt(padapter, prframe); ++ ++ ++ } ++ else ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ process_recv_indicatepkts- recv_func free_indicatepkt\n")); ++ ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_func:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved)); ++ retval = _FAIL; ++ return retval; ++ } ++ ++ } ++ ++ return retval; ++ ++} ++ ++static int recv_func_prehandle(struct adapter *padapter, union recv_frame *rframe) ++{ ++ int ret = _SUCCESS; ++ struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; ++ ++ DBG_COUNTER(padapter->rx_logs.core_rx_pre); ++ ++ /* check the frame crtl field and decache */ ++ ret = validate_recv_frame(padapter, rframe); ++ if (ret != _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("recv_func: validate_recv_frame fail! drop pkt\n")); ++ rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */ ++ goto exit; ++ } ++ ++exit: ++ return ret; ++} ++ ++static int recv_func_posthandle(struct adapter *padapter, union recv_frame *prframe) ++{ ++ int ret = _SUCCESS; ++ union recv_frame *orig_prframe = prframe; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; ++ ++ DBG_COUNTER(padapter->rx_logs.core_rx_post); ++ ++ prframe = decryptor(padapter, prframe); ++ if (prframe == NULL) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("decryptor: drop pkt\n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s decryptor: drop pkt\n", __func__); ++ #endif ++ ret = _FAIL; ++ DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_err); ++ goto _recv_data_drop; ++ } ++ ++ prframe = recvframe_chk_defrag(padapter, prframe); ++ if (prframe == NULL) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chk_defrag: drop pkt\n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s recvframe_chk_defrag: drop pkt\n", __func__); ++ #endif ++ DBG_COUNTER(padapter->rx_logs.core_rx_post_defrag_err); ++ goto _recv_data_drop; ++ } ++ ++ prframe =portctrl(padapter, prframe); ++ if (prframe == NULL) { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("portctrl: drop pkt\n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s portctrl: drop pkt\n", __func__); ++ #endif ++ ret = _FAIL; ++ DBG_COUNTER(padapter->rx_logs.core_rx_post_portctrl_err); ++ goto _recv_data_drop; ++ } ++ ++ count_rx_stats(padapter, prframe, NULL); ++ ++ ret = process_recv_indicatepkts(padapter, prframe); ++ if (ret != _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recv_func: process_recv_indicatepkts fail!\n")); ++ #ifdef DBG_RX_DROP_FRAME ++ DBG_871X("DBG_RX_DROP_FRAME %s process_recv_indicatepkts fail!\n", __func__); ++ #endif ++ rtw_free_recvframe(orig_prframe, pfree_recv_queue);/* free this recv_frame */ ++ DBG_COUNTER(padapter->rx_logs.core_rx_post_indicate_err); ++ goto _recv_data_drop; ++ } ++ ++_recv_data_drop: ++ precvpriv->rx_drop++; ++ return ret; ++} ++ ++ ++int recv_func(struct adapter *padapter, union recv_frame *rframe); ++int recv_func(struct adapter *padapter, union recv_frame *rframe) ++{ ++ int ret; ++ struct rx_pkt_attrib *prxattrib = &rframe->u.hdr.attrib; ++ struct recv_priv *recvpriv = &padapter->recvpriv; ++ struct security_priv *psecuritypriv =&padapter->securitypriv; ++ struct mlme_priv *mlmepriv = &padapter->mlmepriv; ++ ++ /* check if need to handle uc_swdec_pending_queue*/ ++ if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && psecuritypriv->busetkipkey) ++ { ++ union recv_frame *pending_frame; ++ int cnt = 0; ++ ++ while ((pending_frame =rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue))) { ++ cnt++; ++ DBG_COUNTER(padapter->rx_logs.core_rx_dequeue); ++ recv_func_posthandle(padapter, pending_frame); ++ } ++ ++ if (cnt) ++ DBG_871X(FUNC_ADPT_FMT" dequeue %d from uc_swdec_pending_queue\n", ++ FUNC_ADPT_ARG(padapter), cnt); ++ } ++ ++ DBG_COUNTER(padapter->rx_logs.core_rx); ++ ret = recv_func_prehandle(padapter, rframe); ++ ++ if (ret == _SUCCESS) { ++ ++ /* check if need to enqueue into uc_swdec_pending_queue*/ ++ if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && ++ !IS_MCAST(prxattrib->ra) && prxattrib->encrypt>0 && ++ (prxattrib->bdecrypted == 0 ||psecuritypriv->sw_decrypt == true) && ++ psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPAPSK && ++ !psecuritypriv->busetkipkey) ++ { ++ DBG_COUNTER(padapter->rx_logs.core_rx_enqueue); ++ rtw_enqueue_recvframe(rframe, &padapter->recvpriv.uc_swdec_pending_queue); ++ /* DBG_871X("%s: no key, enqueue uc_swdec_pending_queue\n", __func__); */ ++ ++ if (recvpriv->free_recvframe_cnt < NR_RECVFRAME/4) { ++ /* to prevent from recvframe starvation, get recvframe from uc_swdec_pending_queue to free_recvframe_cnt */ ++ rframe = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue); ++ if (rframe) ++ goto do_posthandle; ++ } ++ goto exit; ++ } ++ ++do_posthandle: ++ ret = recv_func_posthandle(padapter, rframe); ++ } ++ ++exit: ++ return ret; ++} ++ ++ ++s32 rtw_recv_entry(union recv_frame *precvframe) ++{ ++ struct adapter *padapter; ++ struct recv_priv *precvpriv; ++ s32 ret = _SUCCESS; ++ ++/* RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("+rtw_recv_entry\n")); */ ++ ++ padapter = precvframe->u.hdr.adapter; ++ ++ precvpriv = &padapter->recvpriv; ++ ++ ++ if ((ret = recv_func(padapter, precvframe)) == _FAIL) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("rtw_recv_entry: recv_func return fail!!!\n")); ++ goto _recv_entry_drop; ++ } ++ ++ ++ precvpriv->rx_pkts++; ++ ++ return ret; ++ ++_recv_entry_drop: ++ ++ /* RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("_recv_entry_drop\n")); */ ++ ++ return ret; ++} ++ ++void rtw_signal_stat_timer_hdl(RTW_TIMER_HDL_ARGS) { ++ struct adapter *adapter = (struct adapter *)FunctionContext; ++ struct recv_priv *recvpriv = &adapter->recvpriv; ++ ++ u32 tmp_s, tmp_q; ++ u8 avg_signal_strength = 0; ++ u8 avg_signal_qual = 0; ++ u32 num_signal_strength = 0; ++ u32 num_signal_qual = 0; ++ u8 _alpha = 5; /* this value is based on converging_constant = 5000 and sampling_interval = 1000 */ ++ ++ if (adapter->recvpriv.is_signal_dbg) { ++ /* update the user specific value, signal_strength_dbg, to signal_strength, rssi */ ++ adapter->recvpriv.signal_strength = adapter->recvpriv.signal_strength_dbg; ++ adapter->recvpriv.rssi =(s8)translate_percentage_to_dbm((u8)adapter->recvpriv.signal_strength_dbg); ++ } else { ++ ++ if (recvpriv->signal_strength_data.update_req == 0) {/* update_req is clear, means we got rx */ ++ avg_signal_strength = recvpriv->signal_strength_data.avg_val; ++ num_signal_strength = recvpriv->signal_strength_data.total_num; ++ /* after avg_vals are accquired, we can re-stat the signal values */ ++ recvpriv->signal_strength_data.update_req = 1; ++ } ++ ++ if (recvpriv->signal_qual_data.update_req == 0) {/* update_req is clear, means we got rx */ ++ avg_signal_qual = recvpriv->signal_qual_data.avg_val; ++ num_signal_qual = recvpriv->signal_qual_data.total_num; ++ /* after avg_vals are accquired, we can re-stat the signal values */ ++ recvpriv->signal_qual_data.update_req = 1; ++ } ++ ++ if (num_signal_strength == 0) { ++ if (rtw_get_on_cur_ch_time(adapter) == 0 ++ || jiffies_to_msecs(jiffies - rtw_get_on_cur_ch_time(adapter)) < 2 * adapter->mlmeextpriv.mlmext_info.bcn_interval ++ ) { ++ goto set_timer; ++ } ++ } ++ ++ if (check_fwstate(&adapter->mlmepriv, _FW_UNDER_SURVEY) == true ++ || check_fwstate(&adapter->mlmepriv, _FW_LINKED) == false ++ ) { ++ goto set_timer; ++ } ++ ++ /* update value of signal_strength, rssi, signal_qual */ ++ tmp_s = (avg_signal_strength+(_alpha-1)*recvpriv->signal_strength); ++ if (tmp_s %_alpha) ++ tmp_s = tmp_s/_alpha + 1; ++ else ++ tmp_s = tmp_s/_alpha; ++ if (tmp_s>100) ++ tmp_s = 100; ++ ++ tmp_q = (avg_signal_qual+(_alpha-1)*recvpriv->signal_qual); ++ if (tmp_q %_alpha) ++ tmp_q = tmp_q/_alpha + 1; ++ else ++ tmp_q = tmp_q/_alpha; ++ if (tmp_q>100) ++ tmp_q = 100; ++ ++ recvpriv->signal_strength = tmp_s; ++ recvpriv->rssi = (s8)translate_percentage_to_dbm(tmp_s); ++ recvpriv->signal_qual = tmp_q; ++ ++ #if defined(DBG_RX_SIGNAL_DISPLAY_PROCESSING) && 1 ++ DBG_871X(FUNC_ADPT_FMT" signal_strength:%3u, rssi:%3d, signal_qual:%3u" ++ ", num_signal_strength:%u, num_signal_qual:%u" ++ ", on_cur_ch_ms:%d" ++ "\n" ++ , FUNC_ADPT_ARG(adapter) ++ , recvpriv->signal_strength ++ , recvpriv->rssi ++ , recvpriv->signal_qual ++ , num_signal_strength, num_signal_qual ++ , rtw_get_on_cur_ch_time(adapter) ? jiffies_to_msecs(jiffies - rtw_get_on_cur_ch_time(adapter)) : 0 ++ ); ++ #endif ++ } ++ ++set_timer: ++ rtw_set_signal_stat_timer(recvpriv); ++ ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_rf.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_rf.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_rf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_rf.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,66 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTW_RF_C_ ++ ++#include ++ ++ ++struct ch_freq { ++ u32 channel; ++ u32 frequency; ++}; ++ ++static struct ch_freq ch_freq_map[] = { ++ {1, 2412}, {2, 2417}, {3, 2422}, {4, 2427}, {5, 2432}, ++ {6, 2437}, {7, 2442}, {8, 2447}, {9, 2452}, {10, 2457}, ++ {11, 2462}, {12, 2467}, {13, 2472}, {14, 2484}, ++ /* UNII */ ++ {36, 5180}, {40, 5200}, {44, 5220}, {48, 5240}, {52, 5260}, ++ {56, 5280}, {60, 5300}, {64, 5320}, {149, 5745}, {153, 5765}, ++ {157, 5785}, {161, 5805}, {165, 5825}, {167, 5835}, {169, 5845}, ++ {171, 5855}, {173, 5865}, ++ /* HiperLAN2 */ ++ {100, 5500}, {104, 5520}, {108, 5540}, {112, 5560}, {116, 5580}, ++ {120, 5600}, {124, 5620}, {128, 5640}, {132, 5660}, {136, 5680}, ++ {140, 5700}, ++ /* Japan MMAC */ ++ {34, 5170}, {38, 5190}, {42, 5210}, {46, 5230}, ++ /* Japan */ ++ {184, 4920}, {188, 4940}, {192, 4960}, {196, 4980}, ++ {208, 5040},/* Japan, means J08 */ ++ {212, 5060},/* Japan, means J12 */ ++ {216, 5080},/* Japan, means J16 */ ++}; ++ ++static int ch_freq_map_num = (sizeof(ch_freq_map) / sizeof(struct ch_freq)); ++ ++u32 rtw_ch2freq(u32 channel) ++{ ++ u8 i; ++ u32 freq = 0; ++ ++ for (i = 0; i < ch_freq_map_num; i++) ++ { ++ if (channel == ch_freq_map[i].channel) ++ { ++ freq = ch_freq_map[i].frequency; ++ break; ++ } ++ } ++ if (i == ch_freq_map_num) ++ freq = 2412; ++ ++ return freq; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_security.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_security.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_security.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_security.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,2486 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTW_SECURITY_C_ ++ ++#include ++#include ++ ++static const char *_security_type_str[] = { ++ "N/A", ++ "WEP40", ++ "TKIP", ++ "TKIP_WM", ++ "AES", ++ "WEP104", ++ "SMS4", ++ "WEP_WPA", ++ "BIP", ++}; ++ ++const char *security_type_str(u8 value) ++{ ++ if (value <= _BIP_) ++ return _security_type_str[value]; ++ return NULL; ++} ++ ++#ifdef DBG_SW_SEC_CNT ++#define WEP_SW_ENC_CNT_INC(sec, ra) \ ++ if (is_broadcast_mac_addr(ra)) \ ++ sec->wep_sw_enc_cnt_bc++; \ ++ else if (is_multicast_mac_addr(ra)) \ ++ sec->wep_sw_enc_cnt_mc++; \ ++ else \ ++ sec->wep_sw_enc_cnt_uc++; ++ ++#define WEP_SW_DEC_CNT_INC(sec, ra) \ ++ if (is_broadcast_mac_addr(ra)) \ ++ sec->wep_sw_dec_cnt_bc++; \ ++ else if (is_multicast_mac_addr(ra)) \ ++ sec->wep_sw_dec_cnt_mc++; \ ++ else \ ++ sec->wep_sw_dec_cnt_uc++; ++ ++#define TKIP_SW_ENC_CNT_INC(sec, ra) \ ++ if (is_broadcast_mac_addr(ra)) \ ++ sec->tkip_sw_enc_cnt_bc++; \ ++ else if (is_multicast_mac_addr(ra)) \ ++ sec->tkip_sw_enc_cnt_mc++; \ ++ else \ ++ sec->tkip_sw_enc_cnt_uc++; ++ ++#define TKIP_SW_DEC_CNT_INC(sec, ra) \ ++ if (is_broadcast_mac_addr(ra)) \ ++ sec->tkip_sw_dec_cnt_bc++; \ ++ else if (is_multicast_mac_addr(ra)) \ ++ sec->tkip_sw_dec_cnt_mc++; \ ++ else \ ++ sec->tkip_sw_dec_cnt_uc++; ++ ++#define AES_SW_ENC_CNT_INC(sec, ra) \ ++ if (is_broadcast_mac_addr(ra)) \ ++ sec->aes_sw_enc_cnt_bc++; \ ++ else if (is_multicast_mac_addr(ra)) \ ++ sec->aes_sw_enc_cnt_mc++; \ ++ else \ ++ sec->aes_sw_enc_cnt_uc++; ++ ++#define AES_SW_DEC_CNT_INC(sec, ra) \ ++ if (is_broadcast_mac_addr(ra)) \ ++ sec->aes_sw_dec_cnt_bc++; \ ++ else if (is_multicast_mac_addr(ra)) \ ++ sec->aes_sw_dec_cnt_mc++; \ ++ else \ ++ sec->aes_sw_dec_cnt_uc++; ++#else ++#define WEP_SW_ENC_CNT_INC(sec, ra) ++#define WEP_SW_DEC_CNT_INC(sec, ra) ++#define TKIP_SW_ENC_CNT_INC(sec, ra) ++#define TKIP_SW_DEC_CNT_INC(sec, ra) ++#define AES_SW_ENC_CNT_INC(sec, ra) ++#define AES_SW_DEC_CNT_INC(sec, ra) ++#endif /* DBG_SW_SEC_CNT */ ++ ++/* WEP related ===== */ ++ ++#define CRC32_POLY 0x04c11db7 ++ ++struct arc4context ++{ ++ u32 x; ++ u32 y; ++ u8 state[256]; ++}; ++ ++ ++static void arcfour_init(struct arc4context *parc4ctx, u8 * key, u32 key_len) ++{ ++ u32 t, u; ++ u32 keyindex; ++ u32 stateindex; ++ u8 * state; ++ u32 counter; ++ ++ state = parc4ctx->state; ++ parc4ctx->x = 0; ++ parc4ctx->y = 0; ++ for (counter = 0; counter < 256; counter++) ++ state[counter] = (u8)counter; ++ keyindex = 0; ++ stateindex = 0; ++ for (counter = 0; counter < 256; counter++) ++ { ++ t = state[counter]; ++ stateindex = (stateindex + key[keyindex] + t) & 0xff; ++ u = state[stateindex]; ++ state[stateindex] = (u8)t; ++ state[counter] = (u8)u; ++ if (++keyindex >= key_len) ++ keyindex = 0; ++ } ++} ++ ++static u32 arcfour_byte(struct arc4context *parc4ctx) ++{ ++ u32 x; ++ u32 y; ++ u32 sx, sy; ++ u8 * state; ++ ++ state = parc4ctx->state; ++ x = (parc4ctx->x + 1) & 0xff; ++ sx = state[x]; ++ y = (sx + parc4ctx->y) & 0xff; ++ sy = state[y]; ++ parc4ctx->x = x; ++ parc4ctx->y = y; ++ state[y] = (u8)sx; ++ state[x] = (u8)sy; ++ return state[(sx + sy) & 0xff]; ++} ++ ++static void arcfour_encrypt(struct arc4context *parc4ctx, ++ u8 * dest, ++ u8 * src, ++ u32 len) ++{ ++ u32 i; ++ ++ for (i = 0; i < len; i++) ++ dest[i] = src[i] ^ (unsigned char)arcfour_byte(parc4ctx); ++} ++ ++static sint bcrc32initialized = 0; ++static u32 crc32_table[256]; ++ ++ ++static u8 crc32_reverseBit(u8 data) ++{ ++ return((u8)((data<<7)&0x80) | ((data<<5)&0x40) | ((data<<3)&0x20) | ((data<<1)&0x10) | ((data>>1)&0x08) | ((data>>3)&0x04) | ((data>>5)&0x02) | ((data>>7)&0x01)); ++} ++ ++static void crc32_init(void) ++{ ++ if (bcrc32initialized == 1) ++ return; ++ else { ++ sint i, j; ++ u32 c; ++ u8 *p =(u8 *)&c, *p1; ++ u8 k; ++ ++ c = 0x12340000; ++ ++ for (i = 0; i < 256; ++i) ++ { ++ k = crc32_reverseBit((u8)i); ++ for (c = ((u32)k) << 24, j = 8; j > 0; --j) { ++ c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY : (c << 1); ++ } ++ p1 = (u8 *)&crc32_table[i]; ++ ++ p1[0] = crc32_reverseBit(p[3]); ++ p1[1] = crc32_reverseBit(p[2]); ++ p1[2] = crc32_reverseBit(p[1]); ++ p1[3] = crc32_reverseBit(p[0]); ++ } ++ bcrc32initialized = 1; ++ } ++} ++ ++static __le32 getcrc32(u8 *buf, sint len) ++{ ++ u8 *p; ++ u32 crc; ++ ++ if (bcrc32initialized == 0) crc32_init(); ++ ++ crc = 0xffffffff; /* preload shift register, per CRC-32 spec */ ++ ++ for (p = buf; len > 0; ++p, --len) ++ { ++ crc = crc32_table[ (crc ^ *p) & 0xff] ^ (crc >> 8); ++ } ++ return cpu_to_le32(~crc); /* transmit complement, per CRC-32 spec */ ++} ++ ++ ++/* ++ Need to consider the fragment situation ++*/ ++void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe) ++{ /* exclude ICV */ ++ ++ unsigned char crc[4]; ++ struct arc4context mycontext; ++ ++ sint curfragnum, length; ++ u32 keylength; ++ ++ u8 *pframe, *payload,*iv; /* wepkey */ ++ u8 wepkey[16]; ++ u8 hw_hdr_offset = 0; ++ struct pkt_attrib *pattrib = &((struct xmit_frame*)pxmitframe)->attrib; ++ struct security_priv *psecuritypriv =&padapter->securitypriv; ++ struct xmit_priv *pxmitpriv =&padapter->xmitpriv; ++ ++ if (((struct xmit_frame*)pxmitframe)->buf_addr == NULL) ++ return; ++ ++ hw_hdr_offset = TXDESC_OFFSET; ++ pframe = ((struct xmit_frame*)pxmitframe)->buf_addr + hw_hdr_offset; ++ ++ /* start to encrypt each fragment */ ++ if ((pattrib->encrypt == _WEP40_)||(pattrib->encrypt == _WEP104_)) ++ { ++ keylength =psecuritypriv->dot11DefKeylen[psecuritypriv->dot11PrivacyKeyIndex]; ++ ++ for (curfragnum = 0;curfragnumnr_frags;curfragnum++) ++ { ++ iv =pframe+pattrib->hdrlen; ++ memcpy(&wepkey[0], iv, 3); ++ memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[psecuritypriv->dot11PrivacyKeyIndex].skey[0], keylength); ++ payload =pframe+pattrib->iv_len+pattrib->hdrlen; ++ ++ if ((curfragnum+1) ==pattrib->nr_frags) ++ { /* the last fragment */ ++ ++ length =pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len- pattrib->icv_len; ++ ++ *((__le32 *)crc) = getcrc32(payload, length); ++ ++ arcfour_init(&mycontext, wepkey, 3+keylength); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ arcfour_encrypt(&mycontext, payload+length, crc, 4); ++ ++ } ++ else ++ { ++ length =pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len ; ++ *((__le32 *)crc) = getcrc32(payload, length); ++ arcfour_init(&mycontext, wepkey, 3+keylength); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ arcfour_encrypt(&mycontext, payload+length, crc, 4); ++ ++ pframe+=pxmitpriv->frag_len; ++ pframe =(u8 *)RND4((SIZE_PTR)(pframe)); ++ ++ } ++ ++ } ++ ++ WEP_SW_ENC_CNT_INC(psecuritypriv, pattrib->ra); ++ } ++} ++ ++void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe) ++{ ++ /* exclude ICV */ ++ u8 crc[4]; ++ struct arc4context mycontext; ++ sint length; ++ u32 keylength; ++ u8 *pframe, *payload,*iv, wepkey[16]; ++ u8 keyindex; ++ struct rx_pkt_attrib *prxattrib = &(((union recv_frame*)precvframe)->u.hdr.attrib); ++ struct security_priv *psecuritypriv =&padapter->securitypriv; ++ ++ pframe =(unsigned char *)((union recv_frame*)precvframe)->u.hdr.rx_data; ++ ++ /* start to decrypt recvframe */ ++ if ((prxattrib->encrypt == _WEP40_)||(prxattrib->encrypt == _WEP104_)) ++ { ++ iv =pframe+prxattrib->hdrlen; ++ /* keyindex =(iv[3]&0x3); */ ++ keyindex = prxattrib->key_index; ++ keylength =psecuritypriv->dot11DefKeylen[keyindex]; ++ memcpy(&wepkey[0], iv, 3); ++ /* memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[psecuritypriv->dot11PrivacyKeyIndex].skey[0], keylength); */ ++ memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[keyindex].skey[0], keylength); ++ length = ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len; ++ ++ payload =pframe+prxattrib->iv_len+prxattrib->hdrlen; ++ ++ /* decrypt payload include icv */ ++ arcfour_init(&mycontext, wepkey, 3+keylength); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ ++ /* calculate icv and compare the icv */ ++ *((u32 *)crc) =le32_to_cpu(getcrc32(payload, length-4)); ++ ++ if (crc[3]!=payload[length-1] || crc[2]!=payload[length-2] || crc[1]!=payload[length-3] || crc[0]!=payload[length-4]) ++ { ++ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_wep_decrypt:icv error crc[3](%x)!=payload[length-1](%x) || crc[2](%x)!=payload[length-2](%x) || crc[1](%x)!=payload[length-3](%x) || crc[0](%x)!=payload[length-4](%x)\n", ++ crc[3], payload[length-1], crc[2], payload[length-2], crc[1], payload[length-3], crc[0], payload[length-4])); ++ } ++ ++ WEP_SW_DEC_CNT_INC(psecuritypriv, prxattrib->ra); ++ } ++ return; ++} ++ ++/* 3 =====TKIP related ===== */ ++ ++static u32 secmicgetuint32(u8 * p) ++/* Convert from Byte[] to Us3232 in a portable way */ ++{ ++ s32 i; ++ u32 res = 0; ++ ++ for (i = 0; i<4; i++) ++ { ++ res |= ((u32)(*p++)) << (8*i); ++ } ++ return res; ++} ++ ++static void secmicputuint32(u8 * p, u32 val) ++/* Convert from Us3232 to Byte[] in a portable way */ ++{ ++ long i; ++ ++ for (i = 0; i<4; i++) ++ { ++ *p++ = (u8) (val & 0xff); ++ val >>= 8; ++ } ++} ++ ++static void secmicclear(struct mic_data *pmicdata) ++{ ++/* Reset the state to the empty message. */ ++ pmicdata->L = pmicdata->K0; ++ pmicdata->R = pmicdata->K1; ++ pmicdata->nBytesInM = 0; ++ pmicdata->M = 0; ++} ++ ++void rtw_secmicsetkey(struct mic_data *pmicdata, u8 * key) ++{ ++ /* Set the key */ ++ pmicdata->K0 = secmicgetuint32(key); ++ pmicdata->K1 = secmicgetuint32(key + 4); ++ /* and reset the message */ ++ secmicclear(pmicdata); ++} ++ ++void rtw_secmicappendbyte(struct mic_data *pmicdata, u8 b) ++{ ++ /* Append the byte to our word-sized buffer */ ++ pmicdata->M |= ((unsigned long)b) << (8*pmicdata->nBytesInM); ++ pmicdata->nBytesInM++; ++ /* Process the word if it is full. */ ++ if (pmicdata->nBytesInM >= 4) ++ { ++ pmicdata->L ^= pmicdata->M; ++ pmicdata->R ^= ROL32(pmicdata->L, 17); ++ pmicdata->L += pmicdata->R; ++ pmicdata->R ^= ((pmicdata->L & 0xff00ff00) >> 8) | ((pmicdata->L & 0x00ff00ff) << 8); ++ pmicdata->L += pmicdata->R; ++ pmicdata->R ^= ROL32(pmicdata->L, 3); ++ pmicdata->L += pmicdata->R; ++ pmicdata->R ^= ROR32(pmicdata->L, 2); ++ pmicdata->L += pmicdata->R; ++ /* Clear the buffer */ ++ pmicdata->M = 0; ++ pmicdata->nBytesInM = 0; ++ } ++} ++ ++void rtw_secmicappend(struct mic_data *pmicdata, u8 * src, u32 nbytes) ++{ ++ /* This is simple */ ++ while (nbytes > 0) ++ { ++ rtw_secmicappendbyte(pmicdata, *src++); ++ nbytes--; ++ } ++} ++ ++void rtw_secgetmic(struct mic_data *pmicdata, u8 * dst) ++{ ++ /* Append the minimum padding */ ++ rtw_secmicappendbyte(pmicdata, 0x5a); ++ rtw_secmicappendbyte(pmicdata, 0); ++ rtw_secmicappendbyte(pmicdata, 0); ++ rtw_secmicappendbyte(pmicdata, 0); ++ rtw_secmicappendbyte(pmicdata, 0); ++ /* and then zeroes until the length is a multiple of 4 */ ++ while (pmicdata->nBytesInM != 0) ++ { ++ rtw_secmicappendbyte(pmicdata, 0); ++ } ++ /* The appendByte function has already computed the result. */ ++ secmicputuint32(dst, pmicdata->L); ++ secmicputuint32(dst+4, pmicdata->R); ++ /* Reset to the empty message. */ ++ secmicclear(pmicdata); ++} ++ ++ ++void rtw_seccalctkipmic(u8 * key, u8 *header, u8 *data, u32 data_len, u8 *mic_code, u8 pri) ++{ ++ ++ struct mic_data micdata; ++ u8 priority[4]={0x0, 0x0, 0x0, 0x0}; ++ ++ rtw_secmicsetkey(&micdata, key); ++ priority[0]=pri; ++ ++ /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */ ++ if (header[1]&1) { /* ToDS == 1 */ ++ rtw_secmicappend(&micdata, &header[16], 6); /* DA */ ++ if (header[1]&2) /* From Ds == 1 */ ++ rtw_secmicappend(&micdata, &header[24], 6); ++ else ++ rtw_secmicappend(&micdata, &header[10], 6); ++ } ++ else { /* ToDS == 0 */ ++ rtw_secmicappend(&micdata, &header[4], 6); /* DA */ ++ if (header[1]&2) /* From Ds == 1 */ ++ rtw_secmicappend(&micdata, &header[16], 6); ++ else ++ rtw_secmicappend(&micdata, &header[10], 6); ++ ++ } ++ rtw_secmicappend(&micdata, &priority[0], 4); ++ ++ ++ rtw_secmicappend(&micdata, data, data_len); ++ ++ rtw_secgetmic(&micdata, mic_code); ++} ++ ++/* macros for extraction/creation of unsigned char/unsigned short values */ ++#define RotR1(v16) ((((v16) >> 1) & 0x7FFF) ^ (((v16) & 1) << 15)) ++#define Lo8(v16) ((u8)((v16) & 0x00FF)) ++#define Hi8(v16) ((u8)(((v16) >> 8) & 0x00FF)) ++#define Lo16(v32) ((u16)((v32) & 0xFFFF)) ++#define Hi16(v32) ((u16)(((v32) >>16) & 0xFFFF)) ++#define Mk16(hi, lo) ((lo) ^ (((u16)(hi)) << 8)) ++ ++/* select the Nth 16-bit word of the temporal key unsigned char array TK[] */ ++#define TK16(N) Mk16(tk[2*(N)+1], tk[2*(N)]) ++ ++/* S-box lookup: 16 bits --> 16 bits */ ++#define _S_(v16) (Sbox1[0][Lo8(v16)] ^ Sbox1[1][Hi8(v16)]) ++ ++/* fixed algorithm "parameters" */ ++#define PHASE1_LOOP_CNT 8 /* this needs to be "big enough" */ ++#define TA_SIZE 6 /* 48-bit transmitter address */ ++#define TK_SIZE 16 /* 128-bit temporal key */ ++#define P1K_SIZE 10 /* 80-bit Phase1 key */ ++#define RC4_KEY_SIZE 16 /* 128-bit RC4KEY (104 bits unknown) */ ++ ++ ++/* 2-unsigned char by 2-unsigned char subset of the full AES S-box table */ ++static const unsigned short Sbox1[2][256]= /* Sbox for hash (can be in ROM) */ ++{ { ++ 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, ++ }, ++ ++ ++ { /* second half of table is unsigned char-reversed version of first! */ ++ 0xA5C6, 0x84F8, 0x99EE, 0x8DF6, 0x0DFF, 0xBDD6, 0xB1DE, 0x5491, ++ 0x5060, 0x0302, 0xA9CE, 0x7D56, 0x19E7, 0x62B5, 0xE64D, 0x9AEC, ++ 0x458F, 0x9D1F, 0x4089, 0x87FA, 0x15EF, 0xEBB2, 0xC98E, 0x0BFB, ++ 0xEC41, 0x67B3, 0xFD5F, 0xEA45, 0xBF23, 0xF753, 0x96E4, 0x5B9B, ++ 0xC275, 0x1CE1, 0xAE3D, 0x6A4C, 0x5A6C, 0x417E, 0x02F5, 0x4F83, ++ 0x5C68, 0xF451, 0x34D1, 0x08F9, 0x93E2, 0x73AB, 0x5362, 0x3F2A, ++ 0x0C08, 0x5295, 0x6546, 0x5E9D, 0x2830, 0xA137, 0x0F0A, 0xB52F, ++ 0x090E, 0x3624, 0x9B1B, 0x3DDF, 0x26CD, 0x694E, 0xCD7F, 0x9FEA, ++ 0x1B12, 0x9E1D, 0x7458, 0x2E34, 0x2D36, 0xB2DC, 0xEEB4, 0xFB5B, ++ 0xF6A4, 0x4D76, 0x61B7, 0xCE7D, 0x7B52, 0x3EDD, 0x715E, 0x9713, ++ 0xF5A6, 0x68B9, 0x0000, 0x2CC1, 0x6040, 0x1FE3, 0xC879, 0xEDB6, ++ 0xBED4, 0x468D, 0xD967, 0x4B72, 0xDE94, 0xD498, 0xE8B0, 0x4A85, ++ 0x6BBB, 0x2AC5, 0xE54F, 0x16ED, 0xC586, 0xD79A, 0x5566, 0x9411, ++ 0xCF8A, 0x10E9, 0x0604, 0x81FE, 0xF0A0, 0x4478, 0xBA25, 0xE34B, ++ 0xF3A2, 0xFE5D, 0xC080, 0x8A05, 0xAD3F, 0xBC21, 0x4870, 0x04F1, ++ 0xDF63, 0xC177, 0x75AF, 0x6342, 0x3020, 0x1AE5, 0x0EFD, 0x6DBF, ++ 0x4C81, 0x1418, 0x3526, 0x2FC3, 0xE1BE, 0xA235, 0xCC88, 0x392E, ++ 0x5793, 0xF255, 0x82FC, 0x477A, 0xACC8, 0xE7BA, 0x2B32, 0x95E6, ++ 0xA0C0, 0x9819, 0xD19E, 0x7FA3, 0x6644, 0x7E54, 0xAB3B, 0x830B, ++ 0xCA8C, 0x29C7, 0xD36B, 0x3C28, 0x79A7, 0xE2BC, 0x1D16, 0x76AD, ++ 0x3BDB, 0x5664, 0x4E74, 0x1E14, 0xDB92, 0x0A0C, 0x6C48, 0xE4B8, ++ 0x5D9F, 0x6EBD, 0xEF43, 0xA6C4, 0xA839, 0xA431, 0x37D3, 0x8BF2, ++ 0x32D5, 0x438B, 0x596E, 0xB7DA, 0x8C01, 0x64B1, 0xD29C, 0xE049, ++ 0xB4D8, 0xFAAC, 0x07F3, 0x25CF, 0xAFCA, 0x8EF4, 0xE947, 0x1810, ++ 0xD56F, 0x88F0, 0x6F4A, 0x725C, 0x2438, 0xF157, 0xC773, 0x5197, ++ 0x23CB, 0x7CA1, 0x9CE8, 0x213E, 0xDD96, 0xDC61, 0x860D, 0x850F, ++ 0x90E0, 0x427C, 0xC471, 0xAACC, 0xD890, 0x0506, 0x01F7, 0x121C, ++ 0xA3C2, 0x5F6A, 0xF9AE, 0xD069, 0x9117, 0x5899, 0x273A, 0xB927, ++ 0x38D9, 0x13EB, 0xB32B, 0x3322, 0xBBD2, 0x70A9, 0x8907, 0xA733, ++ 0xB62D, 0x223C, 0x9215, 0x20C9, 0x4987, 0xFFAA, 0x7850, 0x7AA5, ++ 0x8F03, 0xF859, 0x8009, 0x171A, 0xDA65, 0x31D7, 0xC684, 0xB8D0, ++ 0xC382, 0xB029, 0x775A, 0x111E, 0xCB7B, 0xFCA8, 0xD66D, 0x3A2C, ++ } ++}; ++ ++ /* ++********************************************************************** ++* Routine: Phase 1 -- generate P1K, given TA, TK, IV32 ++* ++* Inputs: ++* tk[] = temporal key [128 bits] ++* ta[] = transmitter's MAC address [ 48 bits] ++* iv32 = upper 32 bits of IV [ 32 bits] ++* Output: ++* p1k[] = Phase 1 key [ 80 bits] ++* ++* Note: ++* This function only needs to be called every 2**16 packets, ++* although in theory it could be called every packet. ++* ++********************************************************************** ++*/ ++static void phase1(u16 *p1k, const u8 *tk, const u8 *ta, u32 iv32) ++{ ++ sint i; ++ ++ /* Initialize the 80 bits of P1K[] from IV32 and TA[0..5] */ ++ p1k[0] = Lo16(iv32); ++ p1k[1] = Hi16(iv32); ++ p1k[2] = Mk16(ta[1], ta[0]); /* use TA[] as little-endian */ ++ p1k[3] = Mk16(ta[3], ta[2]); ++ p1k[4] = Mk16(ta[5], ta[4]); ++ ++ /* Now compute an unbalanced Feistel cipher with 80-bit block */ ++ /* size on the 80-bit block P1K[], using the 128-bit key TK[] */ ++ for (i = 0; i < PHASE1_LOOP_CNT ;i++) ++ { /* Each add operation here is mod 2**16 */ ++ p1k[0] += _S_(p1k[4] ^ TK16((i&1)+0)); ++ p1k[1] += _S_(p1k[0] ^ TK16((i&1)+2)); ++ p1k[2] += _S_(p1k[1] ^ TK16((i&1)+4)); ++ p1k[3] += _S_(p1k[2] ^ TK16((i&1)+6)); ++ p1k[4] += _S_(p1k[3] ^ TK16((i&1)+0)); ++ p1k[4] += (unsigned short)i; /* avoid "slide attacks" */ ++ } ++} ++ ++ ++/* ++********************************************************************** ++* Routine: Phase 2 -- generate RC4KEY, given TK, P1K, IV16 ++* ++* Inputs: ++* tk[] = Temporal key [128 bits] ++* p1k[] = Phase 1 output key [ 80 bits] ++* iv16 = low 16 bits of IV counter [ 16 bits] ++* Output: ++* rc4key[] = the key used to encrypt the packet [128 bits] ++* ++* Note: ++* The value {TA, IV32, IV16} for Phase1/Phase2 must be unique ++* across all packets using the same key TK value. Then, for a ++* given value of TK[], this TKIP48 construction guarantees that ++* the final RC4KEY value is unique across all packets. ++* ++* Suggested implementation optimization: if PPK[] is "overlaid" ++* appropriately on RC4KEY[], there is no need for the final ++* for loop below that copies the PPK[] result into RC4KEY[]. ++* ++********************************************************************** ++*/ ++static void phase2(u8 *rc4key, const u8 *tk, const u16 *p1k, u16 iv16) ++{ ++ sint i; ++ u16 PPK[6]; /* temporary key for mixing */ ++ ++ /* Note: all adds in the PPK[] equations below are mod 2**16 */ ++ for (i = 0;i<5;i++) PPK[i]=p1k[i]; /* first, copy P1K to PPK */ ++ PPK[5] = p1k[4] +iv16; /* next, add in IV16 */ ++ ++ /* Bijective non-linear mixing of the 96 bits of PPK[0..5] */ ++ PPK[0] += _S_(PPK[5] ^ TK16(0)); /* Mix key in each "round" */ ++ PPK[1] += _S_(PPK[0] ^ TK16(1)); ++ PPK[2] += _S_(PPK[1] ^ TK16(2)); ++ PPK[3] += _S_(PPK[2] ^ TK16(3)); ++ PPK[4] += _S_(PPK[3] ^ TK16(4)); ++ PPK[5] += _S_(PPK[4] ^ TK16(5)); /* Total # S-box lookups == 6 */ ++ ++ /* Final sweep: bijective, "linear". Rotates kill LSB correlations */ ++ PPK[0] += RotR1(PPK[5] ^ TK16(6)); ++ PPK[1] += RotR1(PPK[0] ^ TK16(7)); /* Use all of TK[] in Phase2 */ ++ PPK[2] += RotR1(PPK[1]); ++ PPK[3] += RotR1(PPK[2]); ++ PPK[4] += RotR1(PPK[3]); ++ PPK[5] += RotR1(PPK[4]); ++ /* Note: At this point, for a given key TK[0..15], the 96-bit output */ ++ /* value PPK[0..5] is guaranteed to be unique, as a function */ ++ /* of the 96-bit "input" value {TA, IV32, IV16}. That is, P1K */ ++ /* is now a keyed permutation of {TA, IV32, IV16}. */ ++ ++ /* Set RC4KEY[0..3], which includes "cleartext" portion of RC4 key */ ++ rc4key[0] = Hi8(iv16); /* RC4KEY[0..2] is the WEP IV */ ++ rc4key[1] =(Hi8(iv16) | 0x20) & 0x7F; /* Help avoid weak (FMS) keys */ ++ rc4key[2] = Lo8(iv16); ++ rc4key[3] = Lo8((PPK[5] ^ TK16(0)) >> 1); ++ ++ ++ /* Copy 96 bits of PPK[0..5] to RC4KEY[4..15] (little-endian) */ ++ for (i = 0;i<6;i++) ++ { ++ rc4key[4+2*i] = Lo8(PPK[i]); ++ rc4key[5+2*i] = Hi8(PPK[i]); ++ } ++} ++ ++ ++/* The hlen isn't include the IV */ ++u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe) ++{ /* exclude ICV */ ++ u16 pnl; ++ u32 pnh; ++ u8 rc4key[16]; ++ u8 ttkey[16]; ++ u8 crc[4]; ++ u8 hw_hdr_offset = 0; ++ struct arc4context mycontext; ++ sint curfragnum, length; ++ u32 prwskeylen; ++ ++ u8 *pframe, *payload,*iv,*prwskey; ++ union pn48 dot11txpn; ++ /* struct sta_info *stainfo; */ ++ struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; ++ struct security_priv *psecuritypriv =&padapter->securitypriv; ++ struct xmit_priv *pxmitpriv =&padapter->xmitpriv; ++ u32 res = _SUCCESS; ++ ++ if (((struct xmit_frame*)pxmitframe)->buf_addr == NULL) ++ return _FAIL; ++ ++ hw_hdr_offset = TXDESC_OFFSET; ++ pframe = ((struct xmit_frame*)pxmitframe)->buf_addr + hw_hdr_offset; ++ ++ /* 4 start to encrypt each fragment */ ++ if (pattrib->encrypt == _TKIP_) { ++ ++/* ++ if (pattrib->psta) ++ { ++ stainfo = pattrib->psta; ++ } ++ else ++ { ++ DBG_871X("%s, call rtw_get_stainfo()\n", __func__); ++ stainfo =rtw_get_stainfo(&padapter->stapriv ,&pattrib->ra[0]); ++ } ++*/ ++ /* if (stainfo!= NULL) */ ++ { ++/* ++ if (!(stainfo->state &_FW_LINKED)) ++ { ++ DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, stainfo->state); ++ return _FAIL; ++ } ++*/ ++ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_encrypt: stainfo!= NULL!!!\n")); ++ ++ if (IS_MCAST(pattrib->ra)) ++ { ++ prwskey =psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; ++ } ++ else ++ { ++ /* prwskey =&stainfo->dot118021x_UncstKey.skey[0]; */ ++ prwskey =pattrib->dot118021x_UncstKey.skey; ++ } ++ ++ prwskeylen = 16; ++ ++ for (curfragnum = 0;curfragnumnr_frags;curfragnum++) { ++ iv =pframe+pattrib->hdrlen; ++ payload =pframe+pattrib->iv_len+pattrib->hdrlen; ++ ++ GET_TKIP_PN(iv, dot11txpn); ++ ++ pnl =(u16)(dot11txpn.val); ++ pnh =(u32)(dot11txpn.val>>16); ++ ++ phase1((u16 *)&ttkey[0], prwskey,&pattrib->ta[0], pnh); ++ ++ phase2(&rc4key[0], prwskey, (u16 *)&ttkey[0], pnl); ++ ++ if ((curfragnum+1) ==pattrib->nr_frags) { /* 4 the last fragment */ ++ length =pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len- pattrib->icv_len; ++ RT_TRACE(_module_rtl871x_security_c_, _drv_info_, ("pattrib->iv_len =%x, pattrib->icv_len =%x\n", pattrib->iv_len, pattrib->icv_len)); ++ *((__le32 *)crc) = getcrc32(payload, length);/* modified by Amy*/ ++ ++ arcfour_init(&mycontext, rc4key, 16); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ arcfour_encrypt(&mycontext, payload+length, crc, 4); ++ ++ } ++ else { ++ length =pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len ; ++ *((__le32 *)crc) = getcrc32(payload, length);/* modified by Amy*/ ++ arcfour_init(&mycontext, rc4key, 16); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ arcfour_encrypt(&mycontext, payload+length, crc, 4); ++ ++ pframe+=pxmitpriv->frag_len; ++ pframe =(u8 *)RND4((SIZE_PTR)(pframe)); ++ ++ } ++ } ++ ++ TKIP_SW_ENC_CNT_INC(psecuritypriv, pattrib->ra); ++ } ++/* ++ else { ++ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_encrypt: stainfo == NULL!!!\n")); ++ DBG_871X("%s, psta ==NUL\n", __func__); ++ res = _FAIL; ++ } ++*/ ++ ++ } ++ return res; ++} ++ ++ ++/* The hlen isn't include the IV */ ++u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe) ++{ /* exclude ICV */ ++ u16 pnl; ++ u32 pnh; ++ u8 rc4key[16]; ++ u8 ttkey[16]; ++ u8 crc[4]; ++ struct arc4context mycontext; ++ sint length; ++ u32 prwskeylen; ++ ++ u8 *pframe, *payload,*iv,*prwskey; ++ union pn48 dot11txpn; ++ struct sta_info *stainfo; ++ struct rx_pkt_attrib *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib; ++ struct security_priv *psecuritypriv =&padapter->securitypriv; ++/* struct recv_priv *precvpriv =&padapter->recvpriv; */ ++ u32 res = _SUCCESS; ++ ++ pframe =(unsigned char *)((union recv_frame*)precvframe)->u.hdr.rx_data; ++ ++ /* 4 start to decrypt recvframe */ ++ if (prxattrib->encrypt == _TKIP_) { ++ ++ stainfo =rtw_get_stainfo(&padapter->stapriv ,&prxattrib->ta[0]); ++ if (stainfo!= NULL) { ++ ++ if (IS_MCAST(prxattrib->ra)) ++ { ++ static unsigned long start = 0; ++ static u32 no_gkey_bc_cnt = 0; ++ static u32 no_gkey_mc_cnt = 0; ++ ++ if (psecuritypriv->binstallGrpkey ==false) ++ { ++ res = _FAIL; ++ ++ if (start == 0) ++ start = jiffies; ++ ++ if (is_broadcast_mac_addr(prxattrib->ra)) ++ no_gkey_bc_cnt++; ++ else ++ no_gkey_mc_cnt++; ++ ++ if (jiffies_to_msecs(jiffies - start) > 1000) { ++ if (no_gkey_bc_cnt || no_gkey_mc_cnt) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", ++ FUNC_ADPT_ARG(padapter), no_gkey_bc_cnt, no_gkey_mc_cnt); ++ } ++ start = jiffies; ++ no_gkey_bc_cnt = 0; ++ no_gkey_mc_cnt = 0; ++ } ++ goto exit; ++ } ++ ++ if (no_gkey_bc_cnt || no_gkey_mc_cnt) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" gkey installed. no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", ++ FUNC_ADPT_ARG(padapter), no_gkey_bc_cnt, no_gkey_mc_cnt); ++ } ++ start = 0; ++ no_gkey_bc_cnt = 0; ++ no_gkey_mc_cnt = 0; ++ ++ /* DBG_871X("rx bc/mc packets, to perform sw rtw_tkip_decrypt\n"); */ ++ /* prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; */ ++ prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey; ++ prwskeylen = 16; ++ } ++ else ++ { ++ prwskey =&stainfo->dot118021x_UncstKey.skey[0]; ++ prwskeylen = 16; ++ } ++ ++ iv =pframe+prxattrib->hdrlen; ++ payload =pframe+prxattrib->iv_len+prxattrib->hdrlen; ++ length = ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len; ++ ++ GET_TKIP_PN(iv, dot11txpn); ++ ++ pnl =(u16)(dot11txpn.val); ++ pnh =(u32)(dot11txpn.val>>16); ++ ++ phase1((u16 *)&ttkey[0], prwskey,&prxattrib->ta[0], pnh); ++ phase2(&rc4key[0], prwskey, (unsigned short *)&ttkey[0], pnl); ++ ++ /* 4 decrypt payload include icv */ ++ ++ arcfour_init(&mycontext, rc4key, 16); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ ++ *((u32 *)crc) =le32_to_cpu(getcrc32(payload, length-4)); ++ ++ if (crc[3]!=payload[length-1] || crc[2]!=payload[length-2] || crc[1]!=payload[length-3] || crc[0]!=payload[length-4]) ++ { ++ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_wep_decrypt:icv error crc[3](%x)!=payload[length-1](%x) || crc[2](%x)!=payload[length-2](%x) || crc[1](%x)!=payload[length-3](%x) || crc[0](%x)!=payload[length-4](%x)\n", ++ crc[3], payload[length-1], crc[2], payload[length-2], crc[1], payload[length-3], crc[0], payload[length-4])); ++ res = _FAIL; ++ } ++ ++ TKIP_SW_DEC_CNT_INC(psecuritypriv, prxattrib->ra); ++ } ++ else { ++ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_decrypt: stainfo == NULL!!!\n")); ++ res = _FAIL; ++ } ++ ++ } ++exit: ++ return res; ++ ++} ++ ++ ++/* 3 =====AES related ===== */ ++ ++ ++ ++#define MAX_MSG_SIZE 2048 ++/*****************************/ ++/******** SBOX Table *********/ ++/*****************************/ ++ ++ static u8 sbox_table[256] = ++ { ++ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, ++ 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, ++ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, ++ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, ++ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, ++ 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, ++ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, ++ 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, ++ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, ++ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, ++ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, ++ 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, ++ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, ++ 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, ++ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, ++ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, ++ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, ++ 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, ++ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, ++ 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, ++ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, ++ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, ++ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, ++ 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, ++ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, ++ 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, ++ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, ++ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, ++ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, ++ 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, ++ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, ++ 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ++ }; ++ ++/*****************************/ ++/**** Function Prototypes ****/ ++/*****************************/ ++ ++static void bitwise_xor(u8 *ina, u8 *inb, u8 *out); ++static void construct_mic_iv( ++ u8 *mic_header1, ++ sint qc_exists, ++ sint a4_exists, ++ u8 *mpdu, ++ uint payload_length, ++ u8 * pn_vector, ++ uint frtype);/* add for CONFIG_IEEE80211W, none 11w also can use */ ++static void construct_mic_header1( ++ u8 *mic_header1, ++ sint header_length, ++ u8 *mpdu, ++ uint frtype);/* add for CONFIG_IEEE80211W, none 11w also can use */ ++static void construct_mic_header2( ++ u8 *mic_header2, ++ u8 *mpdu, ++ sint a4_exists, ++ sint qc_exists); ++static void construct_ctr_preload( ++ u8 *ctr_preload, ++ sint a4_exists, ++ sint qc_exists, ++ u8 *mpdu, ++ u8 *pn_vector, ++ sint c, ++ uint frtype);/* add for CONFIG_IEEE80211W, none 11w also can use */ ++static void xor_128(u8 *a, u8 *b, u8 *out); ++static void xor_32(u8 *a, u8 *b, u8 *out); ++static u8 sbox(u8 a); ++static void next_key(u8 *key, sint round); ++static void byte_sub(u8 *in, u8 *out); ++static void shift_row(u8 *in, u8 *out); ++static void mix_column(u8 *in, u8 *out); ++static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext); ++ ++ ++/****************************************/ ++/* aes128k128d() */ ++/* Performs a 128 bit AES encrypt with */ ++/* 128 bit data. */ ++/****************************************/ ++static void xor_128(u8 *a, u8 *b, u8 *out) ++{ ++ sint i; ++ ++ for (i = 0;i<16; i++) ++ { ++ out[i] = a[i] ^ b[i]; ++ } ++} ++ ++ ++static void xor_32(u8 *a, u8 *b, u8 *out) ++{ ++ sint i; ++ ++ for (i = 0;i<4; i++) ++ { ++ out[i] = a[i] ^ b[i]; ++ } ++} ++ ++ ++static u8 sbox(u8 a) ++{ ++ return sbox_table[(sint)a]; ++} ++ ++ ++static void next_key(u8 *key, sint round) ++{ ++ u8 rcon; ++ u8 sbox_key[4]; ++ u8 rcon_table[12] = ++ { ++ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, ++ 0x1b, 0x36, 0x36, 0x36 ++ }; ++ sbox_key[0] = sbox(key[13]); ++ sbox_key[1] = sbox(key[14]); ++ sbox_key[2] = sbox(key[15]); ++ sbox_key[3] = sbox(key[12]); ++ ++ rcon = rcon_table[round]; ++ ++ xor_32(&key[0], sbox_key, &key[0]); ++ key[0] = key[0] ^ rcon; ++ ++ xor_32(&key[4], &key[0], &key[4]); ++ xor_32(&key[8], &key[4], &key[8]); ++ xor_32(&key[12], &key[8], &key[12]); ++} ++ ++ ++static void byte_sub(u8 *in, u8 *out) ++{ ++ sint i; ++ ++ for (i = 0; i< 16; i++) ++ { ++ out[i] = sbox(in[i]); ++ } ++} ++ ++ ++static void shift_row(u8 *in, u8 *out) ++{ ++ out[0] = in[0]; ++ out[1] = in[5]; ++ out[2] = in[10]; ++ out[3] = in[15]; ++ out[4] = in[4]; ++ out[5] = in[9]; ++ out[6] = in[14]; ++ out[7] = in[3]; ++ out[8] = in[8]; ++ out[9] = in[13]; ++ out[10] = in[2]; ++ out[11] = in[7]; ++ out[12] = in[12]; ++ out[13] = in[1]; ++ out[14] = in[6]; ++ out[15] = in[11]; ++} ++ ++ ++static void mix_column(u8 *in, u8 *out) ++{ ++ sint i; ++ u8 add1b[4]; ++ u8 add1bf7[4]; ++ u8 rotl[4]; ++ u8 swap_halfs[4]; ++ u8 andf7[4]; ++ u8 rotr[4]; ++ u8 temp[4]; ++ u8 tempb[4]; ++ ++ for (i = 0 ; i<4; i++) ++ { ++ if ((in[i] & 0x80) == 0x80) ++ add1b[i] = 0x1b; ++ else ++ add1b[i] = 0x00; ++ } ++ ++ swap_halfs[0] = in[2]; /* Swap halfs */ ++ swap_halfs[1] = in[3]; ++ swap_halfs[2] = in[0]; ++ swap_halfs[3] = in[1]; ++ ++ rotl[0] = in[3]; /* Rotate left 8 bits */ ++ rotl[1] = in[0]; ++ rotl[2] = in[1]; ++ rotl[3] = in[2]; ++ ++ andf7[0] = in[0] & 0x7f; ++ andf7[1] = in[1] & 0x7f; ++ andf7[2] = in[2] & 0x7f; ++ andf7[3] = in[3] & 0x7f; ++ ++ for (i = 3; i>0; i--) /* logical shift left 1 bit */ ++ { ++ andf7[i] = andf7[i] << 1; ++ if ((andf7[i-1] & 0x80) == 0x80) ++ { ++ andf7[i] = (andf7[i] | 0x01); ++ } ++ } ++ andf7[0] = andf7[0] << 1; ++ andf7[0] = andf7[0] & 0xfe; ++ ++ xor_32(add1b, andf7, add1bf7); ++ ++ xor_32(in, add1bf7, rotr); ++ ++ temp[0] = rotr[0]; /* Rotate right 8 bits */ ++ rotr[0] = rotr[1]; ++ rotr[1] = rotr[2]; ++ rotr[2] = rotr[3]; ++ rotr[3] = temp[0]; ++ ++ xor_32(add1bf7, rotr, temp); ++ xor_32(swap_halfs, rotl, tempb); ++ xor_32(temp, tempb, out); ++} ++ ++static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext) ++{ ++ sint round; ++ sint i; ++ u8 intermediatea[16]; ++ u8 intermediateb[16]; ++ u8 round_key[16]; ++ ++ for (i = 0; i<16; i++) round_key[i] = key[i]; ++ ++ for (round = 0; round < 11; round++) ++ { ++ if (round == 0) ++ { ++ xor_128(round_key, data, ciphertext); ++ next_key(round_key, round); ++ } ++ else if (round == 10) ++ { ++ byte_sub(ciphertext, intermediatea); ++ shift_row(intermediatea, intermediateb); ++ xor_128(intermediateb, round_key, ciphertext); ++ } ++ else /* 1 - 9 */ ++ { ++ byte_sub(ciphertext, intermediatea); ++ shift_row(intermediatea, intermediateb); ++ mix_column(&intermediateb[0], &intermediatea[0]); ++ mix_column(&intermediateb[4], &intermediatea[4]); ++ mix_column(&intermediateb[8], &intermediatea[8]); ++ mix_column(&intermediateb[12], &intermediatea[12]); ++ xor_128(intermediatea, round_key, ciphertext); ++ next_key(round_key, round); ++ } ++ } ++} ++ ++ ++/************************************************/ ++/* construct_mic_iv() */ ++/* Builds the MIC IV from header fields and PN */ ++/* Baron think the function is construct CCM */ ++/* nonce */ ++/************************************************/ ++static void construct_mic_iv( ++ u8 *mic_iv, ++ sint qc_exists, ++ sint a4_exists, ++ u8 *mpdu, ++ uint payload_length, ++ u8 *pn_vector, ++ uint frtype/* add for CONFIG_IEEE80211W, none 11w also can use */ ++ ) ++{ ++ sint i; ++ ++ mic_iv[0] = 0x59; ++ if (qc_exists && a4_exists) mic_iv[1] = mpdu[30] & 0x0f; /* QoS_TC */ ++ if (qc_exists && !a4_exists) mic_iv[1] = mpdu[24] & 0x0f; /* mute bits 7-4 */ ++ if (!qc_exists) mic_iv[1] = 0x00; ++ /* 802.11w management frame should set management bit(4) */ ++ if (frtype == WIFI_MGT_TYPE) ++ mic_iv[1] |= BIT(4); ++ for (i = 2; i < 8; i++) ++ mic_iv[i] = mpdu[i + 8]; /* mic_iv[2:7] = A2[0:5] = mpdu[10:15] */ ++ #ifdef CONSISTENT_PN_ORDER ++ for (i = 8; i < 14; i++) ++ mic_iv[i] = pn_vector[i - 8]; /* mic_iv[8:13] = PN[0:5] */ ++ #else ++ for (i = 8; i < 14; i++) ++ mic_iv[i] = pn_vector[13 - i]; /* mic_iv[8:13] = PN[5:0] */ ++ #endif ++ mic_iv[14] = (unsigned char) (payload_length / 256); ++ mic_iv[15] = (unsigned char) (payload_length % 256); ++} ++ ++ ++/************************************************/ ++/* construct_mic_header1() */ ++/* Builds the first MIC header block from */ ++/* header fields. */ ++/* Build AAD SC, A1, A2 */ ++/************************************************/ ++static void construct_mic_header1( ++ u8 *mic_header1, ++ sint header_length, ++ u8 *mpdu, ++ uint frtype/* add for CONFIG_IEEE80211W, none 11w also can use */ ++ ) ++{ ++ mic_header1[0] = (u8)((header_length - 2) / 256); ++ mic_header1[1] = (u8)((header_length - 2) % 256); ++ ++ /* 802.11w management frame don't AND subtype bits 4, 5, 6 of frame control field */ ++ if (frtype == WIFI_MGT_TYPE) ++ mic_header1[2] = mpdu[0]; ++ else ++ mic_header1[2] = mpdu[0] & 0xcf; /* Mute CF poll & CF ack bits */ ++ ++ mic_header1[3] = mpdu[1] & 0xc7; /* Mute retry, more data and pwr mgt bits */ ++ mic_header1[4] = mpdu[4]; /* A1 */ ++ mic_header1[5] = mpdu[5]; ++ mic_header1[6] = mpdu[6]; ++ mic_header1[7] = mpdu[7]; ++ mic_header1[8] = mpdu[8]; ++ mic_header1[9] = mpdu[9]; ++ mic_header1[10] = mpdu[10]; /* A2 */ ++ mic_header1[11] = mpdu[11]; ++ mic_header1[12] = mpdu[12]; ++ mic_header1[13] = mpdu[13]; ++ mic_header1[14] = mpdu[14]; ++ mic_header1[15] = mpdu[15]; ++} ++ ++ ++/************************************************/ ++/* construct_mic_header2() */ ++/* Builds the last MIC header block from */ ++/* header fields. */ ++/************************************************/ ++static void construct_mic_header2( ++ u8 *mic_header2, ++ u8 *mpdu, ++ sint a4_exists, ++ sint qc_exists ++ ) ++{ ++ sint i; ++ ++ for (i = 0; i<16; i++) mic_header2[i]= 0x00; ++ ++ mic_header2[0] = mpdu[16]; /* A3 */ ++ mic_header2[1] = mpdu[17]; ++ mic_header2[2] = mpdu[18]; ++ mic_header2[3] = mpdu[19]; ++ mic_header2[4] = mpdu[20]; ++ mic_header2[5] = mpdu[21]; ++ ++ mic_header2[6] = 0x00; ++ mic_header2[7] = 0x00; /* mpdu[23]; */ ++ ++ ++ if (!qc_exists && a4_exists) ++ { ++ for (i = 0;i<6;i++) mic_header2[8+i] = mpdu[24+i]; /* A4 */ ++ ++ } ++ ++ if (qc_exists && !a4_exists) ++ { ++ mic_header2[8] = mpdu[24] & 0x0f; /* mute bits 15 - 4 */ ++ mic_header2[9] = mpdu[25] & 0x00; ++ } ++ ++ if (qc_exists && a4_exists) ++ { ++ for (i = 0;i<6;i++) mic_header2[8+i] = mpdu[24+i]; /* A4 */ ++ ++ mic_header2[14] = mpdu[30] & 0x0f; ++ mic_header2[15] = mpdu[31] & 0x00; ++ } ++ ++} ++ ++/************************************************/ ++/* construct_mic_header2() */ ++/* Builds the last MIC header block from */ ++/* header fields. */ ++/* Baron think the function is construct CCM */ ++/* nonce */ ++/************************************************/ ++static void construct_ctr_preload( ++ u8 *ctr_preload, ++ sint a4_exists, ++ sint qc_exists, ++ u8 *mpdu, ++ u8 *pn_vector, ++ sint c, ++ uint frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ ++ ) ++{ ++ sint i = 0; ++ ++ for (i = 0; i<16; i++) ctr_preload[i] = 0x00; ++ i = 0; ++ ++ ctr_preload[0] = 0x01; /* flag */ ++ if (qc_exists && a4_exists) ++ ctr_preload[1] = mpdu[30] & 0x0f; /* QoC_Control */ ++ if (qc_exists && !a4_exists) ++ ctr_preload[1] = mpdu[24] & 0x0f; ++ /* 802.11w management frame should set management bit(4) */ ++ if (frtype == WIFI_MGT_TYPE) ++ ctr_preload[1] |= BIT(4); ++ for (i = 2; i < 8; i++) ++ ctr_preload[i] = mpdu[i + 8]; /* ctr_preload[2:7] = A2[0:5] = mpdu[10:15] */ ++ #ifdef CONSISTENT_PN_ORDER ++ for (i = 8; i < 14; i++) ++ ctr_preload[i] = pn_vector[i - 8]; /* ctr_preload[8:13] = PN[0:5] */ ++ #else ++ for (i = 8; i < 14; i++) ++ ctr_preload[i] = pn_vector[13 - i]; /* ctr_preload[8:13] = PN[5:0] */ ++ #endif ++ ctr_preload[14] = (unsigned char) (c / 256); /* Ctr */ ++ ctr_preload[15] = (unsigned char) (c % 256); ++} ++ ++ ++/************************************/ ++/* bitwise_xor() */ ++/* A 128 bit, bitwise exclusive or */ ++/************************************/ ++static void bitwise_xor(u8 *ina, u8 *inb, u8 *out) ++{ ++ sint i; ++ ++ for (i = 0; i<16; i++) ++ { ++ out[i] = ina[i] ^ inb[i]; ++ } ++} ++ ++ ++static sint aes_cipher(u8 *key, uint hdrlen, ++ u8 *pframe, uint plen) ++{ ++ uint qc_exists, a4_exists, i, j, payload_remainder, ++ num_blocks, payload_index; ++ ++ u8 pn_vector[6]; ++ u8 mic_iv[16]; ++ u8 mic_header1[16]; ++ u8 mic_header2[16]; ++ u8 ctr_preload[16]; ++ ++ /* Intermediate Buffers */ ++ u8 chain_buffer[16]; ++ u8 aes_out[16]; ++ u8 padded_buffer[16]; ++ u8 mic[8]; ++ uint frtype = GetFrameType(pframe); ++ uint frsubtype = GetFrameSubType(pframe); ++ ++ frsubtype =frsubtype>>4; ++ ++ ++ memset((void *)mic_iv, 0, 16); ++ memset((void *)mic_header1, 0, 16); ++ memset((void *)mic_header2, 0, 16); ++ memset((void *)ctr_preload, 0, 16); ++ memset((void *)chain_buffer, 0, 16); ++ memset((void *)aes_out, 0, 16); ++ memset((void *)padded_buffer, 0, 16); ++ ++ if ((hdrlen == WLAN_HDR_A3_LEN)||(hdrlen == WLAN_HDR_A3_QOS_LEN)) ++ a4_exists = 0; ++ else ++ a4_exists = 1; ++ ++ if ( ++ ((frtype|frsubtype) == WIFI_DATA_CFACK) || ++ ((frtype|frsubtype) == WIFI_DATA_CFPOLL)|| ++ ((frtype|frsubtype) == WIFI_DATA_CFACKPOLL)) ++ { ++ qc_exists = 1; ++ if (hdrlen != WLAN_HDR_A3_QOS_LEN) { ++ ++ hdrlen += 2; ++ } ++ } ++ /* add for CONFIG_IEEE80211W, none 11w also can use */ ++ else if ((frtype == WIFI_DATA) && ++ ((frsubtype == 0x08) || ++ (frsubtype == 0x09)|| ++ (frsubtype == 0x0a)|| ++ (frsubtype == 0x0b))) ++ { ++ if (hdrlen != WLAN_HDR_A3_QOS_LEN) { ++ ++ hdrlen += 2; ++ } ++ qc_exists = 1; ++ } ++ else ++ qc_exists = 0; ++ ++ pn_vector[0]=pframe[hdrlen]; ++ pn_vector[1]=pframe[hdrlen+1]; ++ pn_vector[2]=pframe[hdrlen+4]; ++ pn_vector[3]=pframe[hdrlen+5]; ++ pn_vector[4]=pframe[hdrlen+6]; ++ pn_vector[5]=pframe[hdrlen+7]; ++ ++ construct_mic_iv( ++ mic_iv, ++ qc_exists, ++ a4_exists, ++ pframe, /* message, */ ++ plen, ++ pn_vector, ++ frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ ++ ); ++ ++ construct_mic_header1( ++ mic_header1, ++ hdrlen, ++ pframe, /* message */ ++ frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ ++ ); ++ construct_mic_header2( ++ mic_header2, ++ pframe, /* message, */ ++ a4_exists, ++ qc_exists ++ ); ++ ++ ++ payload_remainder = plen % 16; ++ num_blocks = plen / 16; ++ ++ /* Find start of payload */ ++ payload_index = (hdrlen + 8); ++ ++ /* Calculate MIC */ ++ aes128k128d(key, mic_iv, aes_out); ++ bitwise_xor(aes_out, mic_header1, chain_buffer); ++ aes128k128d(key, chain_buffer, aes_out); ++ bitwise_xor(aes_out, mic_header2, chain_buffer); ++ aes128k128d(key, chain_buffer, aes_out); ++ ++ for (i = 0; i < num_blocks; i++) ++ { ++ bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);/* bitwise_xor(aes_out, &message[payload_index], chain_buffer); */ ++ ++ payload_index += 16; ++ aes128k128d(key, chain_buffer, aes_out); ++ } ++ ++ /* Add on the final payload block if it needs padding */ ++ if (payload_remainder > 0) ++ { ++ for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; ++ for (j = 0; j < payload_remainder; j++) ++ { ++ padded_buffer[j] = pframe[payload_index++];/* padded_buffer[j] = message[payload_index++]; */ ++ } ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ aes128k128d(key, chain_buffer, aes_out); ++ ++ } ++ ++ for (j = 0 ; j < 8; j++) mic[j] = aes_out[j]; ++ ++ /* Insert MIC into payload */ ++ for (j = 0; j < 8; j++) ++ pframe[payload_index+j] = mic[j]; /* message[payload_index+j] = mic[j]; */ ++ ++ payload_index = hdrlen + 8; ++ for (i = 0; i< num_blocks; i++) ++ { ++ construct_ctr_preload( ++ ctr_preload, ++ a4_exists, ++ qc_exists, ++ pframe, /* message, */ ++ pn_vector, ++ i+1, ++ frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);/* bitwise_xor(aes_out, &message[payload_index], chain_buffer); */ ++ for (j = 0; j<16;j++) pframe[payload_index++] = chain_buffer[j];/* for (j = 0; j<16;j++) message[payload_index++] = chain_buffer[j]; */ ++ } ++ ++ if (payload_remainder > 0) /* If there is a short final block, then pad it,*/ ++ { /* encrypt it and copy the unpadded part back */ ++ construct_ctr_preload( ++ ctr_preload, ++ a4_exists, ++ qc_exists, ++ pframe, /* message, */ ++ pn_vector, ++ num_blocks+1, ++ frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ ++ ++ for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; ++ for (j = 0; j < payload_remainder; j++) ++ { ++ padded_buffer[j] = pframe[payload_index+j];/* padded_buffer[j] = message[payload_index+j]; */ ++ } ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ for (j = 0; jattrib; ++ struct security_priv *psecuritypriv =&padapter->securitypriv; ++ struct xmit_priv *pxmitpriv =&padapter->xmitpriv; ++ ++/* uint offset = 0; */ ++ u32 res = _SUCCESS; ++ ++ if (((struct xmit_frame*)pxmitframe)->buf_addr == NULL) ++ return _FAIL; ++ ++ hw_hdr_offset = TXDESC_OFFSET; ++ pframe = ((struct xmit_frame*)pxmitframe)->buf_addr + hw_hdr_offset; ++ ++ /* 4 start to encrypt each fragment */ ++ if ((pattrib->encrypt == _AES_)) { ++ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo!= NULL!!!\n")); ++ ++ if (IS_MCAST(pattrib->ra)) ++ { ++ prwskey =psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; ++ } ++ else ++ { ++ /* prwskey =&stainfo->dot118021x_UncstKey.skey[0]; */ ++ prwskey =pattrib->dot118021x_UncstKey.skey; ++ } ++ ++ prwskeylen = 16; ++ ++ for (curfragnum = 0;curfragnumnr_frags;curfragnum++) { ++ ++ if ((curfragnum+1) ==pattrib->nr_frags) { /* 4 the last fragment */ ++ length =pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len- pattrib->icv_len; ++ ++ aes_cipher(prwskey, pattrib->hdrlen, pframe, length); ++ } ++ else { ++ length =pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len ; ++ ++ aes_cipher(prwskey, pattrib->hdrlen, pframe, length); ++ pframe+=pxmitpriv->frag_len; ++ pframe =(u8 *)RND4((SIZE_PTR)(pframe)); ++ ++ } ++ } ++ ++ AES_SW_ENC_CNT_INC(psecuritypriv, pattrib->ra); ++ } ++ return res; ++} ++ ++static sint aes_decipher(u8 *key, uint hdrlen, ++ u8 *pframe, uint plen) ++{ ++ static u8 message[MAX_MSG_SIZE]; ++ uint qc_exists, a4_exists, i, j, payload_remainder, ++ num_blocks, payload_index; ++ sint res = _SUCCESS; ++ u8 pn_vector[6]; ++ u8 mic_iv[16]; ++ u8 mic_header1[16]; ++ u8 mic_header2[16]; ++ u8 ctr_preload[16]; ++ ++ /* Intermediate Buffers */ ++ u8 chain_buffer[16]; ++ u8 aes_out[16]; ++ u8 padded_buffer[16]; ++ u8 mic[8]; ++ ++ ++/* uint offset = 0; */ ++ uint frtype = GetFrameType(pframe); ++ uint frsubtype = GetFrameSubType(pframe); ++ ++ frsubtype =frsubtype>>4; ++ ++ ++ memset((void *)mic_iv, 0, 16); ++ memset((void *)mic_header1, 0, 16); ++ memset((void *)mic_header2, 0, 16); ++ memset((void *)ctr_preload, 0, 16); ++ memset((void *)chain_buffer, 0, 16); ++ memset((void *)aes_out, 0, 16); ++ memset((void *)padded_buffer, 0, 16); ++ ++ /* start to decrypt the payload */ ++ ++ num_blocks = (plen-8) / 16; /* plen including LLC, payload_length and mic) */ ++ ++ payload_remainder = (plen-8) % 16; ++ ++ pn_vector[0] = pframe[hdrlen]; ++ pn_vector[1] = pframe[hdrlen+1]; ++ pn_vector[2] = pframe[hdrlen+4]; ++ pn_vector[3] = pframe[hdrlen+5]; ++ pn_vector[4] = pframe[hdrlen+6]; ++ pn_vector[5] = pframe[hdrlen+7]; ++ ++ if ((hdrlen == WLAN_HDR_A3_LEN)||(hdrlen == WLAN_HDR_A3_QOS_LEN)) ++ a4_exists = 0; ++ else ++ a4_exists = 1; ++ ++ if ( ++ ((frtype|frsubtype) == WIFI_DATA_CFACK) || ++ ((frtype|frsubtype) == WIFI_DATA_CFPOLL)|| ++ ((frtype|frsubtype) == WIFI_DATA_CFACKPOLL)) ++ { ++ qc_exists = 1; ++ if (hdrlen != WLAN_HDR_A3_QOS_LEN) { ++ ++ hdrlen += 2; ++ } ++ }/* only for data packet . add for CONFIG_IEEE80211W, none 11w also can use */ ++ else if ((frtype == WIFI_DATA) && ++ ((frsubtype == 0x08) || ++ (frsubtype == 0x09)|| ++ (frsubtype == 0x0a)|| ++ (frsubtype == 0x0b))) ++ { ++ if (hdrlen != WLAN_HDR_A3_QOS_LEN) { ++ ++ hdrlen += 2; ++ } ++ qc_exists = 1; ++ } ++ else ++ qc_exists = 0; ++ ++ ++ /* now, decrypt pframe with hdrlen offset and plen long */ ++ ++ payload_index = hdrlen + 8; /* 8 is for extiv */ ++ ++ for (i = 0; i< num_blocks; i++) ++ { ++ construct_ctr_preload( ++ ctr_preload, ++ a4_exists, ++ qc_exists, ++ pframe, ++ pn_vector, ++ i+1, ++ frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ ++ ); ++ ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); ++ ++ for (j = 0; j<16;j++) pframe[payload_index++] = chain_buffer[j]; ++ } ++ ++ if (payload_remainder > 0) /* If there is a short final block, then pad it,*/ ++ { /* encrypt it and copy the unpadded part back */ ++ construct_ctr_preload( ++ ctr_preload, ++ a4_exists, ++ qc_exists, ++ pframe, ++ pn_vector, ++ num_blocks+1, ++ frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ ++ ); ++ ++ for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; ++ for (j = 0; j < payload_remainder; j++) ++ { ++ padded_buffer[j] = pframe[payload_index+j]; ++ } ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ for (j = 0; j 0) ++ { ++ for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; ++ for (j = 0; j < payload_remainder; j++) ++ { ++ padded_buffer[j] = message[payload_index++]; ++ } ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ aes128k128d(key, chain_buffer, aes_out); ++ ++ } ++ ++ for (j = 0 ; j < 8; j++) mic[j] = aes_out[j]; ++ ++ /* Insert MIC into payload */ ++ for (j = 0; j < 8; j++) ++ message[payload_index+j] = mic[j]; ++ ++ payload_index = hdrlen + 8; ++ for (i = 0; i< num_blocks; i++) ++ { ++ construct_ctr_preload( ++ ctr_preload, ++ a4_exists, ++ qc_exists, ++ message, ++ pn_vector, ++ i+1, ++ frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, &message[payload_index], chain_buffer); ++ for (j = 0; j<16;j++) message[payload_index++] = chain_buffer[j]; ++ } ++ ++ if (payload_remainder > 0) /* If there is a short final block, then pad it,*/ ++ { /* encrypt it and copy the unpadded part back */ ++ construct_ctr_preload( ++ ctr_preload, ++ a4_exists, ++ qc_exists, ++ message, ++ pn_vector, ++ num_blocks+1, ++ frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ ++ ++ for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; ++ for (j = 0; j < payload_remainder; j++) ++ { ++ padded_buffer[j] = message[payload_index+j]; ++ } ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ for (j = 0; ju.hdr.attrib; ++ struct security_priv *psecuritypriv =&padapter->securitypriv; ++/* struct recv_priv *precvpriv =&padapter->recvpriv; */ ++ u32 res = _SUCCESS; ++ ++ pframe =(unsigned char *)((union recv_frame*)precvframe)->u.hdr.rx_data; ++ /* 4 start to encrypt each fragment */ ++ if ((prxattrib->encrypt == _AES_)) { ++ ++ stainfo =rtw_get_stainfo(&padapter->stapriv ,&prxattrib->ta[0]); ++ if (stainfo!= NULL) { ++ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_decrypt: stainfo!= NULL!!!\n")); ++ ++ if (IS_MCAST(prxattrib->ra)) ++ { ++ static unsigned long start = 0; ++ static u32 no_gkey_bc_cnt = 0; ++ static u32 no_gkey_mc_cnt = 0; ++ ++ /* DBG_871X("rx bc/mc packets, to perform sw rtw_aes_decrypt\n"); */ ++ /* prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; */ ++ if (psecuritypriv->binstallGrpkey ==false) ++ { ++ res = _FAIL; ++ ++ if (start == 0) ++ start = jiffies; ++ ++ if (is_broadcast_mac_addr(prxattrib->ra)) ++ no_gkey_bc_cnt++; ++ else ++ no_gkey_mc_cnt++; ++ ++ if (jiffies_to_msecs(jiffies - start) > 1000) { ++ if (no_gkey_bc_cnt || no_gkey_mc_cnt) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", ++ FUNC_ADPT_ARG(padapter), no_gkey_bc_cnt, no_gkey_mc_cnt); ++ } ++ start = jiffies; ++ no_gkey_bc_cnt = 0; ++ no_gkey_mc_cnt = 0; ++ } ++ ++ goto exit; ++ } ++ ++ if (no_gkey_bc_cnt || no_gkey_mc_cnt) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" gkey installed. no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", ++ FUNC_ADPT_ARG(padapter), no_gkey_bc_cnt, no_gkey_mc_cnt); ++ } ++ start = 0; ++ no_gkey_bc_cnt = 0; ++ no_gkey_mc_cnt = 0; ++ ++ prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey; ++ if (psecuritypriv->dot118021XGrpKeyid != prxattrib->key_index) ++ { ++ DBG_871X("not match packet_index =%d, install_index =%d\n" ++ , prxattrib->key_index, psecuritypriv->dot118021XGrpKeyid); ++ res = _FAIL; ++ goto exit; ++ } ++ } ++ else ++ { ++ prwskey =&stainfo->dot118021x_UncstKey.skey[0]; ++ } ++ ++ length = ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len; ++ ++ res = aes_decipher(prwskey, prxattrib->hdrlen, pframe, length); ++ ++ AES_SW_DEC_CNT_INC(psecuritypriv, prxattrib->ra); ++ } else { ++ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_decrypt: stainfo == NULL!!!\n")); ++ res = _FAIL; ++ } ++ } ++exit: ++ return res; ++} ++ ++u32 rtw_BIP_verify(struct adapter *padapter, u8 *precvframe) ++{ ++ struct rx_pkt_attrib *pattrib = &((union recv_frame *)precvframe)->u.hdr.attrib; ++ u8 *pframe; ++ u8 *BIP_AAD, *p; ++ u32 res = _FAIL; ++ uint len, ori_len; ++ struct ieee80211_hdr *pwlanhdr; ++ u8 mic[16]; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ __le16 le_tmp; ++ __le64 le_tmp64; ++ ++ ori_len = pattrib->pkt_len-WLAN_HDR_A3_LEN+BIP_AAD_SIZE; ++ BIP_AAD = rtw_zmalloc(ori_len); ++ ++ if (BIP_AAD == NULL) ++ { ++ DBG_871X("BIP AAD allocate fail\n"); ++ return _FAIL; ++ } ++ /* PKT start */ ++ pframe =(unsigned char *)((union recv_frame*)precvframe)->u.hdr.rx_data; ++ /* mapping to wlan header */ ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ /* save the frame body + MME */ ++ memcpy(BIP_AAD+BIP_AAD_SIZE, pframe+WLAN_HDR_A3_LEN, pattrib->pkt_len-WLAN_HDR_A3_LEN); ++ /* find MME IE pointer */ ++ p = rtw_get_ie(BIP_AAD+BIP_AAD_SIZE, _MME_IE_, &len, pattrib->pkt_len-WLAN_HDR_A3_LEN); ++ /* Baron */ ++ if (p) ++ { ++ u16 keyid = 0; ++ u64 temp_ipn = 0; ++ /* save packet number */ ++ memcpy(&le_tmp64, p+4, 6); ++ temp_ipn = le64_to_cpu(le_tmp64); ++ /* BIP packet number should bigger than previous BIP packet */ ++ if (temp_ipn <= pmlmeext->mgnt_80211w_IPN_rx) ++ { ++ DBG_871X("replay BIP packet\n"); ++ goto BIP_exit; ++ } ++ /* copy key index */ ++ memcpy(&le_tmp, p+2, 2); ++ keyid = le16_to_cpu(le_tmp); ++ if (keyid != padapter->securitypriv.dot11wBIPKeyid) ++ { ++ DBG_871X("BIP key index error!\n"); ++ goto BIP_exit; ++ } ++ /* clear the MIC field of MME to zero */ ++ memset(p+2+len-8, 0, 8); ++ ++ /* conscruct AAD, copy frame control field */ ++ memcpy(BIP_AAD, &pwlanhdr->frame_control, 2); ++ ClearRetry(BIP_AAD); ++ ClearPwrMgt(BIP_AAD); ++ ClearMData(BIP_AAD); ++ /* conscruct AAD, copy address 1 to address 3 */ ++ memcpy(BIP_AAD+2, pwlanhdr->addr1, 18); ++ ++ if (omac1_aes_128(padapter->securitypriv.dot11wBIPKey[padapter->securitypriv.dot11wBIPKeyid].skey ++ , BIP_AAD, ori_len, mic)) ++ goto BIP_exit; ++ ++ /* MIC field should be last 8 bytes of packet (packet without FCS) */ ++ if (!memcmp(mic, pframe+pattrib->pkt_len-8, 8)) ++ { ++ pmlmeext->mgnt_80211w_IPN_rx = temp_ipn; ++ res = _SUCCESS; ++ } ++ else ++ DBG_871X("BIP MIC error!\n"); ++ ++ } ++ else ++ res = RTW_RX_HANDLED; ++BIP_exit: ++ ++ kfree(BIP_AAD); ++ return res; ++} ++ ++/* AES tables*/ ++const u32 Te0[256] = { ++ 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, ++ 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, ++ 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, ++ 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, ++ 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, ++ 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, ++ 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, ++ 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, ++ 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, ++ 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, ++ 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, ++ 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, ++ 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, ++ 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, ++ 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, ++ 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, ++ 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, ++ 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, ++ 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, ++ 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, ++ 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, ++ 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, ++ 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, ++ 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, ++ 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, ++ 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, ++ 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, ++ 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, ++ 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, ++ 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, ++ 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, ++ 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, ++ 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, ++ 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, ++ 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, ++ 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, ++ 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, ++ 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, ++ 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, ++ 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, ++ 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, ++ 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, ++ 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, ++ 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, ++ 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, ++ 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, ++ 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, ++ 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, ++ 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, ++ 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, ++ 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, ++ 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, ++ 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, ++ 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, ++ 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, ++ 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, ++ 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, ++ 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, ++ 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, ++ 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, ++ 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, ++ 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, ++ 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, ++ 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, ++}; ++const u32 Td0[256] = { ++ 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, ++ 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, ++ 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, ++ 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, ++ 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, ++ 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, ++ 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, ++ 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, ++ 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, ++ 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, ++ 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, ++ 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, ++ 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, ++ 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, ++ 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, ++ 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, ++ 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, ++ 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, ++ 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, ++ 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, ++ 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, ++ 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, ++ 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, ++ 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, ++ 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, ++ 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, ++ 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, ++ 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, ++ 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, ++ 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, ++ 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, ++ 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, ++ 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, ++ 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, ++ 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, ++ 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, ++ 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, ++ 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, ++ 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, ++ 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, ++ 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, ++ 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, ++ 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, ++ 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, ++ 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, ++ 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, ++ 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, ++ 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, ++ 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, ++ 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, ++ 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, ++ 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, ++ 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, ++ 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, ++ 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, ++ 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, ++ 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, ++ 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, ++ 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, ++ 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, ++ 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, ++ 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, ++ 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, ++ 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, ++}; ++const u8 Td4s[256] = { ++ 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, ++ 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, ++ 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, ++ 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, ++ 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, ++ 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, ++ 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, ++ 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, ++ 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, ++ 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, ++ 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, ++ 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, ++ 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, ++ 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, ++ 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, ++ 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, ++ 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, ++ 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, ++ 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, ++ 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, ++ 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, ++ 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, ++ 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, ++ 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, ++ 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, ++ 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, ++ 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, ++ 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU, ++ 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, ++ 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, ++ 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, ++ 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU, ++}; ++const u8 rcons[] = { ++ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 ++ /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ ++}; ++ ++/** ++ * Expand the cipher key into the encryption key schedule. ++ * ++ * @return the number of rounds for the given cipher key size. ++ */ ++static void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[]) ++{ ++ int i; ++ u32 temp; ++ ++ rk[0] = GETU32(cipherKey ); ++ rk[1] = GETU32(cipherKey + 4); ++ rk[2] = GETU32(cipherKey + 8); ++ rk[3] = GETU32(cipherKey + 12); ++ for (i = 0; i < 10; i++) { ++ temp = rk[3]; ++ rk[4] = rk[0] ^ ++ TE421(temp) ^ TE432(temp) ^ TE443(temp) ^ TE414(temp) ^ ++ RCON(i); ++ rk[5] = rk[1] ^ rk[4]; ++ rk[6] = rk[2] ^ rk[5]; ++ rk[7] = rk[3] ^ rk[6]; ++ rk += 4; ++ } ++} ++ ++static void rijndaelEncrypt(u32 rk[/*44*/], u8 pt[16], u8 ct[16]) ++{ ++ u32 s0, s1, s2, s3, t0, t1, t2, t3; ++ int Nr = 10; ++ int r; ++ ++ /* ++ * map byte array block to cipher state ++ * and add initial round key: ++ */ ++ s0 = GETU32(pt ) ^ rk[0]; ++ s1 = GETU32(pt + 4) ^ rk[1]; ++ s2 = GETU32(pt + 8) ^ rk[2]; ++ s3 = GETU32(pt + 12) ^ rk[3]; ++ ++#define ROUND(i, d, s) \ ++d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \ ++d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \ ++d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \ ++d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3] ++ ++ /* Nr - 1 full rounds: */ ++ r = Nr >> 1; ++ for (;;) { ++ ROUND(1, t, s); ++ rk += 8; ++ if (--r == 0) ++ break; ++ ROUND(0, s, t); ++ } ++ ++#undef ROUND ++ ++ /* ++ * apply last round and ++ * map cipher state to byte array block: ++ */ ++ s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0]; ++ PUTU32(ct , s0); ++ s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1]; ++ PUTU32(ct + 4, s1); ++ s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2]; ++ PUTU32(ct + 8, s2); ++ s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3]; ++ PUTU32(ct + 12, s3); ++} ++ ++static void *aes_encrypt_init(u8 *key, size_t len) ++{ ++ u32 *rk; ++ if (len != 16) ++ return NULL; ++ rk = (u32*)rtw_malloc(AES_PRIV_SIZE); ++ if (rk == NULL) ++ return NULL; ++ rijndaelKeySetupEnc(rk, key); ++ return rk; ++} ++ ++static void aes_128_encrypt(void *ctx, u8 *plain, u8 *crypt) ++{ ++ rijndaelEncrypt(ctx, plain, crypt); ++} ++ ++ ++static void gf_mulx(u8 *pad) ++{ ++ int i, carry; ++ ++ carry = pad[0] & 0x80; ++ for (i = 0; i < AES_BLOCK_SIZE - 1; i++) ++ pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7); ++ pad[AES_BLOCK_SIZE - 1] <<= 1; ++ if (carry) ++ pad[AES_BLOCK_SIZE - 1] ^= 0x87; ++} ++ ++static void aes_encrypt_deinit(void *ctx) ++{ ++ memset(ctx, 0, AES_PRIV_SIZE); ++ kfree(ctx); ++} ++ ++ ++/** ++ * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128 ++ * @key: 128-bit key for the hash operation ++ * @num_elem: Number of elements in the data vector ++ * @addr: Pointers to the data areas ++ * @len: Lengths of the data blocks ++ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) ++ * Returns: 0 on success, -1 on failure ++ * ++ * This is a mode for using block cipher (AES in this case) for authentication. ++ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication ++ * (SP) 800-38B. ++ */ ++static int omac1_aes_128_vector(u8 *key, size_t num_elem, ++ u8 *addr[], size_t *len, u8 *mac) ++{ ++ void *ctx; ++ u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; ++ u8 *pos, *end; ++ size_t i, e, left, total_len; ++ ++ ctx = aes_encrypt_init(key, 16); ++ if (ctx == NULL) ++ return -1; ++ memset(cbc, 0, AES_BLOCK_SIZE); ++ ++ total_len = 0; ++ for (e = 0; e < num_elem; e++) ++ total_len += len[e]; ++ left = total_len; ++ ++ e = 0; ++ pos = addr[0]; ++ end = pos + len[0]; ++ ++ while (left >= AES_BLOCK_SIZE) { ++ for (i = 0; i < AES_BLOCK_SIZE; i++) { ++ cbc[i] ^= *pos++; ++ if (pos >= end) { ++ e++; ++ pos = addr[e]; ++ end = pos + len[e]; ++ } ++ } ++ if (left > AES_BLOCK_SIZE) ++ aes_128_encrypt(ctx, cbc, cbc); ++ left -= AES_BLOCK_SIZE; ++ } ++ ++ memset(pad, 0, AES_BLOCK_SIZE); ++ aes_128_encrypt(ctx, pad, pad); ++ gf_mulx(pad); ++ ++ if (left || total_len == 0) { ++ for (i = 0; i < left; i++) { ++ cbc[i] ^= *pos++; ++ if (pos >= end) { ++ e++; ++ pos = addr[e]; ++ end = pos + len[e]; ++ } ++ } ++ cbc[left] ^= 0x80; ++ gf_mulx(pad); ++ } ++ ++ for (i = 0; i < AES_BLOCK_SIZE; i++) ++ pad[i] ^= cbc[i]; ++ aes_128_encrypt(ctx, pad, mac); ++ aes_encrypt_deinit(ctx); ++ return 0; ++} ++ ++ ++/** ++ * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC) ++ * @key: 128-bit key for the hash operation ++ * @data: Data buffer for which a MAC is determined ++ * @data_len: Length of data buffer in bytes ++ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) ++ * Returns: 0 on success, -1 on failure ++ * ++ * This is a mode for using block cipher (AES in this case) for authentication. ++ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication ++ * (SP) 800-38B. ++ * modify for CONFIG_IEEE80211W */ ++int omac1_aes_128(u8 *key, u8 *data, size_t data_len, u8 *mac) ++{ ++ return omac1_aes_128_vector(key, 1, &data, &data_len, mac); ++} ++ ++/* Restore HW wep key setting according to key_mask */ ++void rtw_sec_restore_wep_key(struct adapter *adapter) ++{ ++ struct security_priv* securitypriv =&(adapter->securitypriv); ++ sint keyid; ++ ++ if ((_WEP40_ == securitypriv->dot11PrivacyAlgrthm) ||(_WEP104_ == securitypriv->dot11PrivacyAlgrthm)) { ++ for (keyid = 0;keyid<4;keyid++) { ++ if (securitypriv->key_mask & BIT(keyid)) { ++ if (keyid == securitypriv->dot11PrivacyKeyIndex) ++ rtw_set_key(adapter, securitypriv, keyid, 1, false); ++ else ++ rtw_set_key(adapter, securitypriv, keyid, 0, false); ++ } ++ } ++ } ++} ++ ++u8 rtw_handle_tkip_countermeasure(struct adapter * adapter, const char *caller) ++{ ++ struct security_priv* securitypriv =&(adapter->securitypriv); ++ u8 status = _SUCCESS; ++ ++ if (securitypriv->btkip_countermeasure == true) { ++ unsigned long passing_ms = jiffies_to_msecs(jiffies - securitypriv->btkip_countermeasure_time); ++ if (passing_ms > 60*1000) { ++ DBG_871X_LEVEL(_drv_always_, "%s("ADPT_FMT") countermeasure time:%lus > 60s\n", ++ caller, ADPT_ARG(adapter), passing_ms/1000); ++ securitypriv->btkip_countermeasure = false; ++ securitypriv->btkip_countermeasure_time = 0; ++ } else { ++ DBG_871X_LEVEL(_drv_always_, "%s("ADPT_FMT") countermeasure time:%lus < 60s\n", ++ caller, ADPT_ARG(adapter), passing_ms/1000); ++ status = _FAIL; ++ } ++ } ++ ++ return status; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_sta_mgt.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_sta_mgt.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_sta_mgt.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_sta_mgt.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,646 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTW_STA_MGT_C_ ++ ++#include ++#include ++ ++void _rtw_init_stainfo(struct sta_info *psta); ++void _rtw_init_stainfo(struct sta_info *psta) ++{ ++ memset((u8 *)psta, 0, sizeof (struct sta_info)); ++ ++ spin_lock_init(&psta->lock); ++ INIT_LIST_HEAD(&psta->list); ++ INIT_LIST_HEAD(&psta->hash_list); ++ /* INIT_LIST_HEAD(&psta->asoc_list); */ ++ /* INIT_LIST_HEAD(&psta->sleep_list); */ ++ /* INIT_LIST_HEAD(&psta->wakeup_list); */ ++ ++ _rtw_init_queue(&psta->sleep_q); ++ psta->sleepq_len = 0; ++ ++ _rtw_init_sta_xmit_priv(&psta->sta_xmitpriv); ++ _rtw_init_sta_recv_priv(&psta->sta_recvpriv); ++ ++ INIT_LIST_HEAD(&psta->asoc_list); ++ ++ INIT_LIST_HEAD(&psta->auth_list); ++ ++ psta->expire_to = 0; ++ ++ psta->flags = 0; ++ ++ psta->capability = 0; ++ ++ psta->bpairwise_key_installed = false; ++ ++ psta->nonerp_set = 0; ++ psta->no_short_slot_time_set = 0; ++ psta->no_short_preamble_set = 0; ++ psta->no_ht_gf_set = 0; ++ psta->no_ht_set = 0; ++ psta->ht_20mhz_set = 0; ++ ++ psta->under_exist_checking = 0; ++ ++ psta->keep_alive_trycnt = 0; ++} ++ ++u32 _rtw_init_sta_priv(struct sta_priv *pstapriv) ++{ ++ struct sta_info *psta; ++ s32 i; ++ ++ pstapriv->pallocated_stainfo_buf = vzalloc (sizeof(struct sta_info) * NUM_STA+ 4); ++ ++ if (!pstapriv->pallocated_stainfo_buf) ++ return _FAIL; ++ ++ pstapriv->pstainfo_buf = pstapriv->pallocated_stainfo_buf + 4 - ++ ((SIZE_PTR)(pstapriv->pallocated_stainfo_buf) & 3); ++ ++ _rtw_init_queue(&pstapriv->free_sta_queue); ++ ++ spin_lock_init(&pstapriv->sta_hash_lock); ++ ++ /* _rtw_init_queue(&pstapriv->asoc_q); */ ++ pstapriv->asoc_sta_count = 0; ++ _rtw_init_queue(&pstapriv->sleep_q); ++ _rtw_init_queue(&pstapriv->wakeup_q); ++ ++ psta = (struct sta_info *)(pstapriv->pstainfo_buf); ++ ++ ++ for (i = 0; i < NUM_STA; i++) ++ { ++ _rtw_init_stainfo(psta); ++ ++ INIT_LIST_HEAD(&(pstapriv->sta_hash[i])); ++ ++ list_add_tail(&psta->list, get_list_head(&pstapriv->free_sta_queue)); ++ ++ psta++; ++ } ++ ++ pstapriv->sta_dz_bitmap = 0; ++ pstapriv->tim_bitmap = 0; ++ ++ INIT_LIST_HEAD(&pstapriv->asoc_list); ++ INIT_LIST_HEAD(&pstapriv->auth_list); ++ spin_lock_init(&pstapriv->asoc_list_lock); ++ spin_lock_init(&pstapriv->auth_list_lock); ++ pstapriv->asoc_list_cnt = 0; ++ pstapriv->auth_list_cnt = 0; ++ ++ pstapriv->auth_to = 3; /* 3*2 = 6 sec */ ++ pstapriv->assoc_to = 3; ++ pstapriv->expire_to = 3; /* 3*2 = 6 sec */ ++ pstapriv->max_num_sta = NUM_STA; ++ return _SUCCESS; ++} ++ ++inline int rtw_stainfo_offset(struct sta_priv *stapriv, struct sta_info *sta) ++{ ++ int offset = (((u8 *)sta) - stapriv->pstainfo_buf)/sizeof(struct sta_info); ++ ++ if (!stainfo_offset_valid(offset)) ++ DBG_871X("%s invalid offset(%d), out of range!!!", __func__, offset); ++ ++ return offset; ++} ++ ++inline struct sta_info *rtw_get_stainfo_by_offset(struct sta_priv *stapriv, int offset) ++{ ++ if (!stainfo_offset_valid(offset)) ++ DBG_871X("%s invalid offset(%d), out of range!!!", __func__, offset); ++ ++ return (struct sta_info *)(stapriv->pstainfo_buf + offset * sizeof(struct sta_info)); ++} ++ ++/* this function is used to free the memory of lock || sema for all stainfos */ ++void kfree_all_stainfo(struct sta_priv *pstapriv); ++void kfree_all_stainfo(struct sta_priv *pstapriv) ++{ ++ struct list_head *plist, *phead; ++ struct sta_info *psta = NULL; ++ ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ ++ phead = get_list_head(&pstapriv->free_sta_queue); ++ plist = get_next(phead); ++ ++ while (phead != plist) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info , list); ++ plist = get_next(plist); ++ } ++ ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++} ++ ++void kfree_sta_priv_lock(struct sta_priv *pstapriv); ++void kfree_sta_priv_lock(struct sta_priv *pstapriv) ++{ ++ kfree_all_stainfo(pstapriv); /* be done before free sta_hash_lock */ ++} ++ ++u32 _rtw_free_sta_priv(struct sta_priv *pstapriv) ++{ ++ struct list_head *phead, *plist; ++ struct sta_info *psta = NULL; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ int index; ++ ++ if (pstapriv) { ++ ++ /*delete all reordering_ctrl_timer */ ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ for (index = 0; index < NUM_STA; index++) ++ { ++ phead = &(pstapriv->sta_hash[index]); ++ plist = get_next(phead); ++ ++ while (phead != plist) ++ { ++ int i; ++ psta = LIST_CONTAINOR(plist, struct sta_info , hash_list); ++ plist = get_next(plist); ++ ++ for (i = 0; i < 16 ; i++) ++ { ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ del_timer_sync(&preorder_ctrl->reordering_ctrl_timer); ++ } ++ } ++ } ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++ /*===============================*/ ++ ++ kfree_sta_priv_lock(pstapriv); ++ ++ if (pstapriv->pallocated_stainfo_buf) { ++ vfree(pstapriv->pallocated_stainfo_buf); ++ } ++ } ++ return _SUCCESS; ++} ++ ++/* struct sta_info *rtw_alloc_stainfo(_queue *pfree_sta_queue, unsigned char *hwaddr) */ ++struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) ++{ ++ uint tmp_aid; ++ s32 index; ++ struct list_head *phash_list; ++ struct sta_info *psta; ++ struct __queue *pfree_sta_queue; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ int i = 0; ++ u16 wRxSeqInitialValue = 0xffff; ++ ++ pfree_sta_queue = &pstapriv->free_sta_queue; ++ ++ /* spin_lock_bh(&(pfree_sta_queue->lock)); */ ++ spin_lock_bh(&(pstapriv->sta_hash_lock)); ++ if (list_empty(&pfree_sta_queue->queue)) ++ { ++ /* spin_unlock_bh(&(pfree_sta_queue->lock)); */ ++ spin_unlock_bh(&(pstapriv->sta_hash_lock)); ++ psta = NULL; ++ return psta; ++ } ++ else ++ { ++ psta = LIST_CONTAINOR(get_next(&pfree_sta_queue->queue), struct sta_info, list); ++ ++ list_del_init(&(psta->list)); ++ ++ /* spin_unlock_bh(&(pfree_sta_queue->lock)); */ ++ ++ tmp_aid = psta->aid; ++ ++ _rtw_init_stainfo(psta); ++ ++ psta->padapter = pstapriv->padapter; ++ ++ memcpy(psta->hwaddr, hwaddr, ETH_ALEN); ++ ++ index = wifi_mac_hash(hwaddr); ++ ++ RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, ("rtw_alloc_stainfo: index = %x", index)); ++ ++ if (index >= NUM_STA) { ++ RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("ERROR => rtw_alloc_stainfo: index >= NUM_STA")); ++ spin_unlock_bh(&(pstapriv->sta_hash_lock)); ++ psta = NULL; ++ goto exit; ++ } ++ phash_list = &(pstapriv->sta_hash[index]); ++ ++ /* spin_lock_bh(&(pstapriv->sta_hash_lock)); */ ++ ++ list_add_tail(&psta->hash_list, phash_list); ++ ++ pstapriv->asoc_sta_count ++ ; ++ ++ /* spin_unlock_bh(&(pstapriv->sta_hash_lock)); */ ++ ++/* Commented by Albert 2009/08/13 */ ++/* For the SMC router, the sequence number of first packet of WPS handshake will be 0. */ ++/* In this case, this packet will be dropped by recv_decache function if we use the 0x00 as the default value for tid_rxseq variable. */ ++/* So, we initialize the tid_rxseq variable as the 0xffff. */ ++ ++ for (i = 0; i < 16; i++) ++ { ++ memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[ i ], &wRxSeqInitialValue, 2); ++ } ++ ++ RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, ("alloc number_%d stainfo with hwaddr = %x %x %x %x %x %x \n", ++ pstapriv->asoc_sta_count , hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5])); ++ ++ init_addba_retry_timer(pstapriv->padapter, psta); ++ ++ /* for A-MPDU Rx reordering buffer control */ ++ for (i = 0; i < 16 ; i++) ++ { ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ ++ preorder_ctrl->padapter = pstapriv->padapter; ++ ++ preorder_ctrl->enable = false; ++ ++ preorder_ctrl->indicate_seq = 0xffff; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d\n", __func__, __LINE__, ++ preorder_ctrl->indicate_seq); ++ #endif ++ preorder_ctrl->wend_b = 0xffff; ++ /* preorder_ctrl->wsize_b = (NR_RECVBUFF-2); */ ++ preorder_ctrl->wsize_b = 64;/* 64; */ ++ ++ _rtw_init_queue(&preorder_ctrl->pending_recvframe_queue); ++ ++ rtw_init_recv_timer(preorder_ctrl); ++ } ++ ++ ++ /* init for DM */ ++ psta->rssi_stat.UndecoratedSmoothedPWDB = (-1); ++ psta->rssi_stat.UndecoratedSmoothedCCK = (-1); ++ ++ /* init for the sequence number of received management frame */ ++ psta->RxMgmtFrameSeqNum = 0xffff; ++ spin_unlock_bh(&(pstapriv->sta_hash_lock)); ++ /* alloc mac id for non-bc/mc station, */ ++ rtw_alloc_macid(pstapriv->padapter, psta); ++ ++ } ++ ++exit: ++ ++ ++ return psta; ++} ++ ++/* using pstapriv->sta_hash_lock to protect */ ++u32 rtw_free_stainfo(struct adapter *padapter , struct sta_info *psta) ++{ ++ int i; ++ struct __queue *pfree_sta_queue; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ struct sta_xmit_priv *pstaxmitpriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct hw_xmit *phwxmit; ++ ++ if (psta == NULL) ++ goto exit; ++ ++ ++ spin_lock_bh(&psta->lock); ++ psta->state &= ~_FW_LINKED; ++ spin_unlock_bh(&psta->lock); ++ ++ pfree_sta_queue = &pstapriv->free_sta_queue; ++ ++ ++ pstaxmitpriv = &psta->sta_xmitpriv; ++ ++ /* list_del_init(&psta->sleep_list); */ ++ ++ /* list_del_init(&psta->wakeup_list); */ ++ ++ spin_lock_bh(&pxmitpriv->lock); ++ ++ rtw_free_xmitframe_queue(pxmitpriv, &psta->sleep_q); ++ psta->sleepq_len = 0; ++ ++ /* vo */ ++ /* spin_lock_bh(&(pxmitpriv->vo_pending.lock)); */ ++ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vo_q.sta_pending); ++ list_del_init(&(pstaxmitpriv->vo_q.tx_pending)); ++ phwxmit = pxmitpriv->hwxmits; ++ phwxmit->accnt -= pstaxmitpriv->vo_q.qcnt; ++ pstaxmitpriv->vo_q.qcnt = 0; ++ /* spin_unlock_bh(&(pxmitpriv->vo_pending.lock)); */ ++ ++ /* vi */ ++ /* spin_lock_bh(&(pxmitpriv->vi_pending.lock)); */ ++ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vi_q.sta_pending); ++ list_del_init(&(pstaxmitpriv->vi_q.tx_pending)); ++ phwxmit = pxmitpriv->hwxmits+1; ++ phwxmit->accnt -= pstaxmitpriv->vi_q.qcnt; ++ pstaxmitpriv->vi_q.qcnt = 0; ++ /* spin_unlock_bh(&(pxmitpriv->vi_pending.lock)); */ ++ ++ /* be */ ++ /* spin_lock_bh(&(pxmitpriv->be_pending.lock)); */ ++ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->be_q.sta_pending); ++ list_del_init(&(pstaxmitpriv->be_q.tx_pending)); ++ phwxmit = pxmitpriv->hwxmits+2; ++ phwxmit->accnt -= pstaxmitpriv->be_q.qcnt; ++ pstaxmitpriv->be_q.qcnt = 0; ++ /* spin_unlock_bh(&(pxmitpriv->be_pending.lock)); */ ++ ++ /* bk */ ++ /* spin_lock_bh(&(pxmitpriv->bk_pending.lock)); */ ++ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->bk_q.sta_pending); ++ list_del_init(&(pstaxmitpriv->bk_q.tx_pending)); ++ phwxmit = pxmitpriv->hwxmits+3; ++ phwxmit->accnt -= pstaxmitpriv->bk_q.qcnt; ++ pstaxmitpriv->bk_q.qcnt = 0; ++ /* spin_unlock_bh(&(pxmitpriv->bk_pending.lock)); */ ++ ++ spin_unlock_bh(&pxmitpriv->lock); ++ ++ list_del_init(&psta->hash_list); ++ RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("\n free number_%d stainfo with hwaddr = 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x \n", pstapriv->asoc_sta_count , psta->hwaddr[0], psta->hwaddr[1], psta->hwaddr[2], psta->hwaddr[3], psta->hwaddr[4], psta->hwaddr[5])); ++ pstapriv->asoc_sta_count --; ++ ++ ++ /* re-init sta_info; 20061114 will be init in alloc_stainfo */ ++ /* _rtw_init_sta_xmit_priv(&psta->sta_xmitpriv); */ ++ /* _rtw_init_sta_recv_priv(&psta->sta_recvpriv); */ ++ ++ del_timer_sync(&psta->addba_retry_timer); ++ ++ /* for A-MPDU Rx reordering buffer control, cancel reordering_ctrl_timer */ ++ for (i = 0; i < 16 ; i++) ++ { ++ struct list_head *phead, *plist; ++ union recv_frame *prframe; ++ struct __queue *ppending_recvframe_queue; ++ struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; ++ ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ ++ del_timer_sync(&preorder_ctrl->reordering_ctrl_timer); ++ ++ ++ ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; ++ ++ spin_lock_bh(&ppending_recvframe_queue->lock); ++ ++ phead = get_list_head(ppending_recvframe_queue); ++ plist = get_next(phead); ++ ++ while (!list_empty(phead)) ++ { ++ prframe = LIST_CONTAINOR(plist, union recv_frame, u); ++ ++ plist = get_next(plist); ++ ++ list_del_init(&(prframe->u.hdr.list)); ++ ++ rtw_free_recvframe(prframe, pfree_recv_queue); ++ } ++ ++ spin_unlock_bh(&ppending_recvframe_queue->lock); ++ ++ } ++ ++ if (!(psta->state & WIFI_AP_STATE)) ++ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, false); ++ ++ ++ /* release mac id for non-bc/mc station, */ ++ rtw_release_macid(pstapriv->padapter, psta); ++ ++/* ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ list_del_init(&psta->asoc_list); ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++*/ ++ spin_lock_bh(&pstapriv->auth_list_lock); ++ if (!list_empty(&psta->auth_list)) { ++ list_del_init(&psta->auth_list); ++ pstapriv->auth_list_cnt--; ++ } ++ spin_unlock_bh(&pstapriv->auth_list_lock); ++ ++ psta->expire_to = 0; ++ psta->sleepq_ac_len = 0; ++ psta->qos_info = 0; ++ ++ psta->max_sp_len = 0; ++ psta->uapsd_bk = 0; ++ psta->uapsd_be = 0; ++ psta->uapsd_vi = 0; ++ psta->uapsd_vo = 0; ++ ++ psta->has_legacy_ac = 0; ++ ++ pstapriv->sta_dz_bitmap &=~BIT(psta->aid); ++ pstapriv->tim_bitmap &=~BIT(psta->aid); ++ ++ if ((psta->aid >0) && (pstapriv->sta_aid[psta->aid - 1] == psta)) ++ { ++ pstapriv->sta_aid[psta->aid - 1] = NULL; ++ psta->aid = 0; ++ } ++ ++ psta->under_exist_checking = 0; ++ ++ /* spin_lock_bh(&(pfree_sta_queue->lock)); */ ++ list_add_tail(&psta->list, get_list_head(pfree_sta_queue)); ++ /* spin_unlock_bh(&(pfree_sta_queue->lock)); */ ++ ++exit: ++ return _SUCCESS; ++} ++ ++/* free all stainfo which in sta_hash[all] */ ++void rtw_free_all_stainfo(struct adapter *padapter) ++{ ++ struct list_head *plist, *phead; ++ s32 index; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info* pbcmc_stainfo =rtw_get_bcmc_stainfo(padapter); ++ ++ if (pstapriv->asoc_sta_count == 1) ++ return; ++ ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ ++ for (index = 0; index< NUM_STA; index++) ++ { ++ phead = &(pstapriv->sta_hash[index]); ++ plist = get_next(phead); ++ ++ while (phead != plist) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info , hash_list); ++ ++ plist = get_next(plist); ++ ++ if (pbcmc_stainfo!=psta) ++ rtw_free_stainfo(padapter , psta); ++ ++ } ++ } ++ ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++} ++ ++/* any station allocated can be searched by hash list */ ++struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) ++{ ++ struct list_head *plist, *phead; ++ struct sta_info *psta = NULL; ++ u32 index; ++ u8 *addr; ++ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ if (hwaddr == NULL) ++ return NULL; ++ ++ if (IS_MCAST(hwaddr)) ++ { ++ addr = bc_addr; ++ } ++ else ++ { ++ addr = hwaddr; ++ } ++ ++ index = wifi_mac_hash(addr); ++ ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ ++ phead = &(pstapriv->sta_hash[index]); ++ plist = get_next(phead); ++ ++ ++ while (phead != plist) ++ { ++ ++ psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); ++ ++ if ((!memcmp(psta->hwaddr, addr, ETH_ALEN))) ++ { /* if found the matched address */ ++ break; ++ } ++ psta = NULL; ++ plist = get_next(plist); ++ } ++ ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++ return psta; ++} ++ ++u32 rtw_init_bcmc_stainfo(struct adapter *padapter) ++{ ++ ++ struct sta_info *psta; ++ struct tx_servq *ptxservq; ++ u32 res = _SUCCESS; ++ NDIS_802_11_MAC_ADDRESS bcast_addr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ /* struct __queue *pstapending = &padapter->xmitpriv.bm_pending; */ ++ ++ psta = rtw_alloc_stainfo(pstapriv, bcast_addr); ++ ++ if (psta == NULL) { ++ res = _FAIL; ++ RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("rtw_alloc_stainfo fail")); ++ goto exit; ++ } ++ ++ /* default broadcast & multicast use macid 1 */ ++ psta->mac_id = 1; ++ ++ ptxservq = &(psta->sta_xmitpriv.be_q); ++exit: ++ return _SUCCESS; ++} ++ ++ ++struct sta_info* rtw_get_bcmc_stainfo(struct adapter *padapter) ++{ ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ psta = rtw_get_stainfo(pstapriv, bc_addr); ++ return psta; ++} ++ ++u8 rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr) ++{ ++ u8 res = true; ++ struct list_head *plist, *phead; ++ struct rtw_wlan_acl_node *paclnode; ++ u8 match = false; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ struct __queue *pacl_node_q =&pacl_list->acl_node_q; ++ ++ spin_lock_bh(&(pacl_node_q->lock)); ++ phead = get_list_head(pacl_node_q); ++ plist = get_next(phead); ++ while (phead != plist) ++ { ++ paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list); ++ plist = get_next(plist); ++ ++ if (!memcmp(paclnode->addr, mac_addr, ETH_ALEN)) ++ { ++ if (paclnode->valid == true) ++ { ++ match = true; ++ break; ++ } ++ } ++ } ++ spin_unlock_bh(&(pacl_node_q->lock)); ++ ++ ++ if (pacl_list->mode == 1)/* accept unless in deny list */ ++ { ++ res = (match == true) ? false:true; ++ } ++ else if (pacl_list->mode == 2)/* deny unless in accept list */ ++ { ++ res = (match == true) ? true:false; ++ } ++ else ++ { ++ res = true; ++ } ++ ++ return res; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_wlan_util.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_wlan_util.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_wlan_util.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_wlan_util.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,2542 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTW_WLAN_UTIL_C_ ++ ++#include ++#include ++#include ++ ++#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) ++#include ++#endif ++ ++static unsigned char ARTHEROS_OUI1[] = {0x00, 0x03, 0x7f}; ++static unsigned char ARTHEROS_OUI2[] = {0x00, 0x13, 0x74}; ++ ++static unsigned char BROADCOM_OUI1[] = {0x00, 0x10, 0x18}; ++static unsigned char BROADCOM_OUI2[] = {0x00, 0x0a, 0xf7}; ++static unsigned char BROADCOM_OUI3[] = {0x00, 0x05, 0xb5}; ++ ++static unsigned char CISCO_OUI[] = {0x00, 0x40, 0x96}; ++static unsigned char MARVELL_OUI[] = {0x00, 0x50, 0x43}; ++static unsigned char RALINK_OUI[] = {0x00, 0x0c, 0x43}; ++static unsigned char REALTEK_OUI[] = {0x00, 0xe0, 0x4c}; ++static unsigned char AIRGOCAP_OUI[] = {0x00, 0x0a, 0xf5}; ++static unsigned char RSN_TKIP_CIPHER[4] = {0x00, 0x0f, 0xac, 0x02}; ++static unsigned char WPA_TKIP_CIPHER[4] = {0x00, 0x50, 0xf2, 0x02}; ++ ++extern unsigned char RTW_WPA_OUI[]; ++extern unsigned char WPA_TKIP_CIPHER[4]; ++ ++#define R2T_PHY_DELAY (0) ++ ++/* define WAIT_FOR_BCN_TO_MIN (3000) */ ++#define WAIT_FOR_BCN_TO_MIN (6000) ++#define WAIT_FOR_BCN_TO_MAX (20000) ++ ++#define DISCONNECT_BY_CHK_BCN_FAIL_OBSERV_PERIOD_IN_MS 1000 ++#define DISCONNECT_BY_CHK_BCN_FAIL_THRESHOLD 3 ++ ++static u8 rtw_basic_rate_cck[4] = { ++ IEEE80211_CCK_RATE_1MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_2MB|IEEE80211_BASIC_RATE_MASK, ++ IEEE80211_CCK_RATE_5MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_11MB|IEEE80211_BASIC_RATE_MASK ++}; ++ ++static u8 rtw_basic_rate_ofdm[3] = { ++ IEEE80211_OFDM_RATE_6MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_OFDM_RATE_12MB|IEEE80211_BASIC_RATE_MASK, ++ IEEE80211_OFDM_RATE_24MB|IEEE80211_BASIC_RATE_MASK ++}; ++ ++int cckrates_included(unsigned char *rate, int ratelen) ++{ ++ int i; ++ ++ for (i = 0; i < ratelen; i++) ++ { ++ if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) || ++ (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22)) ++ return true; ++ } ++ ++ return false; ++ ++} ++ ++int cckratesonly_included(unsigned char *rate, int ratelen) ++{ ++ int i; ++ ++ for (i = 0; i < ratelen; i++) ++ { ++ if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && ++ (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22)) ++ return false; ++ } ++ ++ return true; ++} ++ ++u8 networktype_to_raid_ex(struct adapter *adapter, struct sta_info *psta) ++{ ++ u8 raid, cur_rf_type, rf_type = RF_1T1R; ++ ++ rtw_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, (u8 *)(&cur_rf_type)); ++ ++ if (cur_rf_type == RF_1T1R) { ++ rf_type = RF_1T1R; ++ } ++ else if (IsSupportedVHT(psta->wireless_mode)) { ++ if (psta->ra_mask & 0xffc00000) ++ rf_type = RF_2T2R; ++ } ++ else if (IsSupportedHT(psta->wireless_mode)) { ++ if (psta->ra_mask & 0xfff00000) ++ rf_type = RF_2T2R; ++ } ++ ++ switch (psta->wireless_mode) ++ { ++ case WIRELESS_11B: ++ raid = RATEID_IDX_B; ++ break; ++ case WIRELESS_11A: ++ case WIRELESS_11G: ++ raid = RATEID_IDX_G; ++ break; ++ case WIRELESS_11BG: ++ raid = RATEID_IDX_BG; ++ break; ++ case WIRELESS_11_24N: ++ case WIRELESS_11_5N: ++ case WIRELESS_11A_5N: ++ case WIRELESS_11G_24N: ++ if (rf_type == RF_2T2R) ++ raid = RATEID_IDX_GN_N2SS; ++ else ++ raid = RATEID_IDX_GN_N1SS; ++ break; ++ case WIRELESS_11B_24N: ++ case WIRELESS_11BG_24N: ++ if (psta->bw_mode == CHANNEL_WIDTH_20) { ++ if (rf_type == RF_2T2R) ++ raid = RATEID_IDX_BGN_20M_2SS_BN; ++ else ++ raid = RATEID_IDX_BGN_20M_1SS_BN; ++ } else { ++ if (rf_type == RF_2T2R) ++ raid = RATEID_IDX_BGN_40M_2SS; ++ else ++ raid = RATEID_IDX_BGN_40M_1SS; ++ } ++ break; ++ default: ++ raid = RATEID_IDX_BGN_40M_2SS; ++ break; ++ ++ } ++ return raid; ++ ++} ++ ++unsigned char ratetbl_val_2wifirate(unsigned char rate); ++unsigned char ratetbl_val_2wifirate(unsigned char rate) ++{ ++ unsigned char val = 0; ++ ++ switch (rate & 0x7f) ++ { ++ case 0: ++ val = IEEE80211_CCK_RATE_1MB; ++ break; ++ ++ case 1: ++ val = IEEE80211_CCK_RATE_2MB; ++ break; ++ ++ case 2: ++ val = IEEE80211_CCK_RATE_5MB; ++ break; ++ ++ case 3: ++ val = IEEE80211_CCK_RATE_11MB; ++ break; ++ ++ case 4: ++ val = IEEE80211_OFDM_RATE_6MB; ++ break; ++ ++ case 5: ++ val = IEEE80211_OFDM_RATE_9MB; ++ break; ++ ++ case 6: ++ val = IEEE80211_OFDM_RATE_12MB; ++ break; ++ ++ case 7: ++ val = IEEE80211_OFDM_RATE_18MB; ++ break; ++ ++ case 8: ++ val = IEEE80211_OFDM_RATE_24MB; ++ break; ++ ++ case 9: ++ val = IEEE80211_OFDM_RATE_36MB; ++ break; ++ ++ case 10: ++ val = IEEE80211_OFDM_RATE_48MB; ++ break; ++ ++ case 11: ++ val = IEEE80211_OFDM_RATE_54MB; ++ break; ++ ++ } ++ ++ return val; ++ ++} ++ ++int is_basicrate(struct adapter *padapter, unsigned char rate); ++int is_basicrate(struct adapter *padapter, unsigned char rate) ++{ ++ int i; ++ unsigned char val; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ for (i = 0; i < NumRates; i++) ++ { ++ val = pmlmeext->basicrate[i]; ++ ++ if ((val != 0xff) && (val != 0xfe)) ++ { ++ if (rate == ratetbl_val_2wifirate(val)) ++ { ++ return true; ++ } ++ } ++ } ++ ++ return false; ++} ++ ++unsigned int ratetbl2rateset(struct adapter *padapter, unsigned char *rateset); ++unsigned int ratetbl2rateset(struct adapter *padapter, unsigned char *rateset) ++{ ++ int i; ++ unsigned char rate; ++ unsigned int len = 0; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ for (i = 0; i < NumRates; i++) ++ { ++ rate = pmlmeext->datarate[i]; ++ ++ switch (rate) ++ { ++ case 0xff: ++ return len; ++ ++ case 0xfe: ++ continue; ++ ++ default: ++ rate = ratetbl_val_2wifirate(rate); ++ ++ if (is_basicrate(padapter, rate) == true) ++ { ++ rate |= IEEE80211_BASIC_RATE_MASK; ++ } ++ ++ rateset[len] = rate; ++ len++; ++ break; ++ } ++ } ++ return len; ++} ++ ++void get_rate_set(struct adapter *padapter, unsigned char *pbssrate, int *bssrate_len) ++{ ++ unsigned char supportedrates[NumRates]; ++ ++ memset(supportedrates, 0, NumRates); ++ *bssrate_len = ratetbl2rateset(padapter, supportedrates); ++ memcpy(pbssrate, supportedrates, *bssrate_len); ++} ++ ++void set_mcs_rate_by_mask(u8 *mcs_set, u32 mask) ++{ ++ u8 mcs_rate_1r = (u8)(mask&0xff); ++ u8 mcs_rate_2r = (u8)((mask>>8)&0xff); ++ u8 mcs_rate_3r = (u8)((mask>>16)&0xff); ++ u8 mcs_rate_4r = (u8)((mask>>24)&0xff); ++ ++ mcs_set[0] &= mcs_rate_1r; ++ mcs_set[1] &= mcs_rate_2r; ++ mcs_set[2] &= mcs_rate_3r; ++ mcs_set[3] &= mcs_rate_4r; ++} ++ ++void UpdateBrateTbl( ++ struct adapter * Adapter, ++ u8 *mBratesOS ++) ++{ ++ u8 i; ++ u8 rate; ++ ++ /* 1M, 2M, 5.5M, 11M, 6M, 12M, 24M are mandatory. */ ++ for (i = 0;ioper_channel; ++} ++ ++inline void rtw_set_oper_ch(struct adapter *adapter, u8 ch) ++{ ++#ifdef DBG_CH_SWITCH ++ const int len = 128; ++ char msg[128] = {0}; ++ int cnt = 0; ++ int i = 0; ++#endif /* DBG_CH_SWITCH */ ++ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); ++ ++ if (dvobj->oper_channel != ch) { ++ dvobj->on_oper_ch_time = jiffies; ++ ++#ifdef DBG_CH_SWITCH ++ cnt += snprintf(msg+cnt, len-cnt, "switch to ch %3u", ch); ++ ++ for (i = 0; i < dvobj->iface_nums; i++) { ++ struct adapter *iface = dvobj->padapters[i]; ++ cnt += snprintf(msg+cnt, len-cnt, " ["ADPT_FMT":", ADPT_ARG(iface)); ++ if (iface->mlmeextpriv.cur_channel == ch) ++ cnt += snprintf(msg+cnt, len-cnt, "C"); ++ else ++ cnt += snprintf(msg+cnt, len-cnt, "_"); ++ if (iface->wdinfo.listen_channel == ch && !rtw_p2p_chk_state(&iface->wdinfo, P2P_STATE_NONE)) ++ cnt += snprintf(msg+cnt, len-cnt, "L"); ++ else ++ cnt += snprintf(msg+cnt, len-cnt, "_"); ++ cnt += snprintf(msg+cnt, len-cnt, "]"); ++ } ++ ++ DBG_871X(FUNC_ADPT_FMT" %s\n", FUNC_ADPT_ARG(adapter), msg); ++#endif /* DBG_CH_SWITCH */ ++ } ++ ++ dvobj->oper_channel = ch; ++} ++ ++inline u8 rtw_get_oper_bw(struct adapter *adapter) ++{ ++ return adapter_to_dvobj(adapter)->oper_bwmode; ++} ++ ++inline void rtw_set_oper_bw(struct adapter *adapter, u8 bw) ++{ ++ adapter_to_dvobj(adapter)->oper_bwmode = bw; ++} ++ ++inline u8 rtw_get_oper_choffset(struct adapter *adapter) ++{ ++ return adapter_to_dvobj(adapter)->oper_ch_offset; ++} ++ ++inline void rtw_set_oper_choffset(struct adapter *adapter, u8 offset) ++{ ++ adapter_to_dvobj(adapter)->oper_ch_offset = offset; ++} ++ ++u8 rtw_get_center_ch(u8 channel, u8 chnl_bw, u8 chnl_offset) ++{ ++ u8 center_ch = channel; ++ ++ if (chnl_bw == CHANNEL_WIDTH_80) ++ { ++ if ((channel == 36) || (channel == 40) || (channel == 44) || (channel == 48)) ++ center_ch = 42; ++ if ((channel == 52) || (channel == 56) || (channel == 60) || (channel == 64)) ++ center_ch = 58; ++ if ((channel == 100) || (channel == 104) || (channel == 108) || (channel == 112)) ++ center_ch = 106; ++ if ((channel == 116) || (channel == 120) || (channel == 124) || (channel == 128)) ++ center_ch = 122; ++ if ((channel == 132) || (channel == 136) || (channel == 140) || (channel == 144)) ++ center_ch = 138; ++ if ((channel == 149) || (channel == 153) || (channel == 157) || (channel == 161)) ++ center_ch = 155; ++ else if (channel <= 14) ++ center_ch = 7; ++ } ++ else if (chnl_bw == CHANNEL_WIDTH_40) ++ { ++ if (chnl_offset == HAL_PRIME_CHNL_OFFSET_LOWER) ++ center_ch = channel + 2; ++ else ++ center_ch = channel - 2; ++ } ++ ++ return center_ch; ++} ++ ++inline unsigned long rtw_get_on_cur_ch_time(struct adapter *adapter) ++{ ++ if (adapter->mlmeextpriv.cur_channel == adapter_to_dvobj(adapter)->oper_channel) ++ return adapter_to_dvobj(adapter)->on_oper_ch_time; ++ else ++ return 0; ++} ++ ++void SelectChannel(struct adapter *padapter, unsigned char channel) ++{ ++ if (mutex_lock_interruptible(&(adapter_to_dvobj(padapter)->setch_mutex))) ++ return; ++ ++ /* saved channel info */ ++ rtw_set_oper_ch(padapter, channel); ++ ++ rtw_hal_set_chan(padapter, channel); ++ ++ mutex_unlock(&(adapter_to_dvobj(padapter)->setch_mutex)); ++} ++ ++void set_channel_bwmode(struct adapter *padapter, unsigned char channel, unsigned char channel_offset, unsigned short bwmode) ++{ ++ u8 center_ch, chnl_offset80 = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ if (padapter->bNotifyChannelChange) ++ { ++ DBG_871X("[%s] ch = %d, offset = %d, bwmode = %d\n", __func__, channel, channel_offset, bwmode); ++ } ++ ++ center_ch = rtw_get_center_ch(channel, bwmode, channel_offset); ++ ++ if (bwmode == CHANNEL_WIDTH_80) ++ { ++ if (center_ch > channel) ++ chnl_offset80 = HAL_PRIME_CHNL_OFFSET_LOWER; ++ else if (center_ch < channel) ++ chnl_offset80 = HAL_PRIME_CHNL_OFFSET_UPPER; ++ else ++ chnl_offset80 = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ } ++ ++ /* set Channel */ ++ if (mutex_lock_interruptible(&(adapter_to_dvobj(padapter)->setch_mutex))) ++ return; ++ ++ /* saved channel/bw info */ ++ rtw_set_oper_ch(padapter, channel); ++ rtw_set_oper_bw(padapter, bwmode); ++ rtw_set_oper_choffset(padapter, channel_offset); ++ ++ rtw_hal_set_chnl_bw(padapter, center_ch, bwmode, channel_offset, chnl_offset80); /* set center channel */ ++ ++ mutex_unlock(&(adapter_to_dvobj(padapter)->setch_mutex)); ++} ++ ++__inline u8 *get_my_bssid(struct wlan_bssid_ex *pnetwork) ++{ ++ return (pnetwork->MacAddress); ++} ++ ++u16 get_beacon_interval(struct wlan_bssid_ex *bss) ++{ ++ __le16 val; ++ memcpy((unsigned char *)&val, rtw_get_beacon_interval_from_ie(bss->IEs), 2); ++ ++ return le16_to_cpu(val); ++ ++} ++ ++int is_client_associated_to_ap(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext; ++ struct mlme_ext_info *pmlmeinfo; ++ ++ if (!padapter) ++ return _FAIL; ++ ++ pmlmeext = &padapter->mlmeextpriv; ++ pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE)) ++ { ++ return true; ++ } ++ else ++ { ++ return _FAIL; ++ } ++} ++ ++int is_client_associated_to_ibss(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE)) ++ { ++ return true; ++ } ++ else ++ { ++ return _FAIL; ++ } ++} ++ ++int is_IBSS_empty(struct adapter *padapter) ++{ ++ unsigned int i; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) ++ { ++ if (pmlmeinfo->FW_sta_info[i].status == 1) ++ { ++ return _FAIL; ++ } ++ } ++ ++ return true; ++ ++} ++ ++unsigned int decide_wait_for_beacon_timeout(unsigned int bcn_interval) ++{ ++ if ((bcn_interval << 2) < WAIT_FOR_BCN_TO_MIN) ++ { ++ return WAIT_FOR_BCN_TO_MIN; ++ } ++ else if ((bcn_interval << 2) > WAIT_FOR_BCN_TO_MAX) ++ { ++ return WAIT_FOR_BCN_TO_MAX; ++ } ++ else ++ { ++ return ((bcn_interval << 2)); ++ } ++} ++ ++void invalidate_cam_all(struct adapter *padapter) ++{ ++ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); ++ struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_CAM_INVALID_ALL, NULL); ++ ++ spin_lock_bh(&cam_ctl->lock); ++ cam_ctl->bitmap = 0; ++ memset(dvobj->cam_cache, 0, sizeof(struct cam_entry_cache)*TOTAL_CAM_ENTRY); ++ spin_unlock_bh(&cam_ctl->lock); ++} ++ ++static u32 _ReadCAM(struct adapter *padapter , u32 addr) ++{ ++ u32 count = 0, cmd; ++ cmd = CAM_POLLINIG |addr ; ++ rtw_write32(padapter, RWCAM, cmd); ++ ++ do{ ++ if (0 == (rtw_read32(padapter, REG_CAMCMD) & CAM_POLLINIG)) { ++ break; ++ } ++ }while (count++ < 100); ++ ++ return rtw_read32(padapter, REG_CAMREAD); ++} ++void read_cam(struct adapter *padapter , u8 entry, u8 *get_key) ++{ ++ u32 j, addr, cmd; ++ addr = entry << 3; ++ ++ /* DBG_8192C("********* DUMP CAM Entry_#%02d***************\n", entry); */ ++ for (j = 0; j < 6; j++) ++ { ++ cmd = _ReadCAM(padapter , addr+j); ++ /* DBG_8192C("offset:0x%02x => 0x%08x\n", addr+j, cmd); */ ++ if (j>1) /* get key from cam */ ++ memcpy(get_key+(j-2)*4, &cmd, 4); ++ } ++ /* DBG_8192C("*********************************\n"); */ ++} ++ ++void _write_cam(struct adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key) ++{ ++ unsigned int i, val, addr; ++ int j; ++ u32 cam_val[2]; ++ ++ addr = entry << 3; ++ ++ for (j = 5; j >= 0; j--) { ++ switch (j) { ++ case 0: ++ val = (ctrl | (mac[0] << 16) | (mac[1] << 24)); ++ break; ++ case 1: ++ val = (mac[2] | (mac[3] << 8) | (mac[4] << 16) | (mac[5] << 24)); ++ break; ++ default: ++ i = (j - 2) << 2; ++ val = (key[i] | (key[i+1] << 8) | (key[i+2] << 16) | (key[i+3] << 24)); ++ break; ++ } ++ ++ cam_val[0] = val; ++ cam_val[1] = addr + (unsigned int)j; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_CAM_WRITE, (u8 *)cam_val); ++ } ++} ++ ++void _clear_cam_entry(struct adapter *padapter, u8 entry) ++{ ++ unsigned char null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ++ unsigned char null_key[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ++ ++ _write_cam(padapter, entry, 0, null_sta, null_key); ++} ++ ++inline void write_cam(struct adapter *adapter, u8 id, u16 ctrl, u8 *mac, u8 *key) ++{ ++ _write_cam(adapter, id, ctrl, mac, key); ++ write_cam_cache(adapter, id , ctrl, mac, key); ++} ++ ++inline void clear_cam_entry(struct adapter *adapter, u8 id) ++{ ++ _clear_cam_entry(adapter, id); ++ clear_cam_cache(adapter, id); ++} ++ ++inline void write_cam_from_cache(struct adapter *adapter, u8 id) ++{ ++ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); ++ struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; ++ struct cam_entry_cache cache; ++ ++ spin_lock_bh(&cam_ctl->lock); ++ memcpy(&cache, &dvobj->cam_cache[id], sizeof(struct cam_entry_cache)); ++ spin_unlock_bh(&cam_ctl->lock); ++ ++ _write_cam(adapter, id, cache.ctrl, cache.mac, cache.key); ++} ++ ++void write_cam_cache(struct adapter *adapter, u8 id, u16 ctrl, u8 *mac, u8 *key) ++{ ++ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); ++ struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; ++ ++ spin_lock_bh(&cam_ctl->lock); ++ ++ dvobj->cam_cache[id].ctrl = ctrl; ++ memcpy(dvobj->cam_cache[id].mac, mac, ETH_ALEN); ++ memcpy(dvobj->cam_cache[id].key, key, 16); ++ ++ spin_unlock_bh(&cam_ctl->lock); ++} ++ ++void clear_cam_cache(struct adapter *adapter, u8 id) ++{ ++ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); ++ struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; ++ ++ spin_lock_bh(&cam_ctl->lock); ++ ++ memset(&(dvobj->cam_cache[id]), 0, sizeof(struct cam_entry_cache)); ++ ++ spin_unlock_bh(&cam_ctl->lock); ++} ++ ++static bool _rtw_camid_is_gk(struct adapter *adapter, u8 cam_id) ++{ ++ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); ++ struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; ++ bool ret = false; ++ ++ if (cam_id >= TOTAL_CAM_ENTRY) ++ goto exit; ++ ++ if (!(cam_ctl->bitmap & BIT(cam_id))) ++ goto exit; ++ ++ ret = (dvobj->cam_cache[cam_id].ctrl&BIT6)?true:false; ++ ++exit: ++ return ret; ++} ++ ++static s16 _rtw_camid_search(struct adapter *adapter, u8 *addr, s16 kid) ++{ ++ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); ++ int i; ++ s16 cam_id = -1; ++ ++ for (i = 0;icam_cache[i].mac, addr, ETH_ALEN)) ++ continue; ++ if (kid >= 0 && kid != (dvobj->cam_cache[i].ctrl&0x03)) ++ continue; ++ ++ cam_id = i; ++ break; ++ } ++ ++ if (addr) ++ DBG_871X(FUNC_ADPT_FMT" addr:"MAC_FMT" kid:%d, return cam_id:%d\n" ++ , FUNC_ADPT_ARG(adapter), MAC_ARG(addr), kid, cam_id); ++ else ++ DBG_871X(FUNC_ADPT_FMT" addr:%p kid:%d, return cam_id:%d\n" ++ , FUNC_ADPT_ARG(adapter), addr, kid, cam_id); ++ ++ return cam_id; ++} ++ ++s16 rtw_camid_search(struct adapter *adapter, u8 *addr, s16 kid) ++{ ++ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); ++ struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; ++ s16 cam_id = -1; ++ ++ spin_lock_bh(&cam_ctl->lock); ++ cam_id = _rtw_camid_search(adapter, addr, kid); ++ spin_unlock_bh(&cam_ctl->lock); ++ ++ return cam_id; ++} ++ ++s16 rtw_camid_alloc(struct adapter *adapter, struct sta_info *sta, u8 kid) ++{ ++ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); ++ struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; ++ s16 cam_id = -1; ++ struct mlme_ext_info *mlmeinfo; ++ ++ spin_lock_bh(&cam_ctl->lock); ++ ++ mlmeinfo = &adapter->mlmeextpriv.mlmext_info; ++ ++ if ((((mlmeinfo->state&0x03) == WIFI_FW_AP_STATE) || ((mlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE)) ++ && !sta) { ++ /* AP/Ad-hoc mode group key: static alloction to default key by key ID */ ++ if (kid > 3) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" group key with invalid key id:%u\n" ++ , FUNC_ADPT_ARG(adapter), kid); ++ rtw_warn_on(1); ++ goto bitmap_handle; ++ } ++ ++ cam_id = kid; ++ } ++ else { ++ int i; ++ u8 *addr = sta?sta->hwaddr:NULL; ++ ++ if (!sta) { ++ if (!(mlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) { ++ /* bypass STA mode group key setting before connected(ex:WEP) because bssid is not ready */ ++ goto bitmap_handle; ++ } ++ ++ addr = get_bssid(&adapter->mlmepriv); ++ } ++ ++ if ((i = _rtw_camid_search(adapter, addr, kid)) >= 0) { ++ /* Fix issue that pairwise and group key have same key id. Pairwise key first, group key can overwirte group only(ex: rekey) */ ++ if (sta || _rtw_camid_is_gk(adapter, i) == true) ++ cam_id = i; ++ else ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" group key id:%u the same key id as pairwise key\n" ++ , FUNC_ADPT_ARG(adapter), kid); ++ goto bitmap_handle; ++ } ++ ++ for (i =4;ibitmap & BIT(i))) ++ break; ++ ++ if (i == TOTAL_CAM_ENTRY) { ++ if (sta) ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" pairwise key with "MAC_FMT" id:%u no room\n" ++ , FUNC_ADPT_ARG(adapter), MAC_ARG(sta->hwaddr), kid); ++ else ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" group key id:%u no room\n" ++ , FUNC_ADPT_ARG(adapter), kid); ++ rtw_warn_on(1); ++ goto bitmap_handle; ++ } ++ ++ cam_id = i; ++ } ++ ++bitmap_handle: ++ if (cam_id >= 0) ++ cam_ctl->bitmap |= BIT(cam_id); ++ ++ spin_unlock_bh(&cam_ctl->lock); ++ ++ return cam_id; ++} ++ ++void rtw_camid_free(struct adapter *adapter, u8 cam_id) ++{ ++ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); ++ struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; ++ ++ spin_lock_bh(&cam_ctl->lock); ++ ++ if (cam_id < TOTAL_CAM_ENTRY) ++ cam_ctl->bitmap &= ~(BIT(cam_id)); ++ ++ spin_unlock_bh(&cam_ctl->lock); ++} ++ ++int allocate_fw_sta_entry(struct adapter *padapter) ++{ ++ unsigned int mac_id; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ for (mac_id = IBSS_START_MAC_ID; mac_id < NUM_STA; mac_id++) ++ { ++ if (pmlmeinfo->FW_sta_info[mac_id].status == 0) ++ { ++ pmlmeinfo->FW_sta_info[mac_id].status = 1; ++ pmlmeinfo->FW_sta_info[mac_id].retry = 0; ++ break; ++ } ++ } ++ ++ return mac_id; ++} ++ ++void flush_all_cam_entry(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ invalidate_cam_all(padapter); ++ /* clear default key related key search setting */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_DK_CFG, (u8 *)false); ++ ++ memset((u8 *)(pmlmeinfo->FW_sta_info), 0, sizeof(pmlmeinfo->FW_sta_info)); ++ ++} ++ ++int WMM_param_handler(struct adapter *padapter, struct ndis_80211_var_ie * pIE) ++{ ++ /* struct registry_priv *pregpriv = &padapter->registrypriv; */ ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if (pmlmepriv->qospriv.qos_option == 0) ++ { ++ pmlmeinfo->WMM_enable = 0; ++ return false; ++ } ++ ++ if (!memcmp(&(pmlmeinfo->WMM_param), (pIE->data + 6), sizeof(struct WMM_para_element))) ++ { ++ return false; ++ } ++ else ++ { ++ memcpy(&(pmlmeinfo->WMM_param), (pIE->data + 6), sizeof(struct WMM_para_element)); ++ } ++ pmlmeinfo->WMM_enable = 1; ++ return true; ++} ++ ++void WMMOnAssocRsp(struct adapter *padapter) ++{ ++ u8 ACI, ACM, AIFS, ECWMin, ECWMax, aSifsTime; ++ u8 acm_mask; ++ u16 TXOP; ++ u32 acParm, i; ++ u32 edca[4], inx[4]; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ ++ acm_mask = 0; ++ ++ if (pmlmeext->cur_wireless_mode & WIRELESS_11_24N) ++ aSifsTime = 16; ++ else ++ aSifsTime = 10; ++ ++ if (pmlmeinfo->WMM_enable == 0) ++ { ++ padapter->mlmepriv.acm_mask = 0; ++ ++ AIFS = aSifsTime + (2 * pmlmeinfo->slotTime); ++ ++ if (pmlmeext->cur_wireless_mode & (WIRELESS_11G |WIRELESS_11A)) { ++ ECWMin = 4; ++ ECWMax = 10; ++ } else if (pmlmeext->cur_wireless_mode & WIRELESS_11B) { ++ ECWMin = 5; ++ ECWMax = 10; ++ } else { ++ ECWMin = 4; ++ ECWMax = 10; ++ } ++ ++ TXOP = 0; ++ acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16); ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm)); ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm)); ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm)); ++ ++ ECWMin = 2; ++ ECWMax = 3; ++ TXOP = 0x2f; ++ acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16); ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm)); ++ } ++ else ++ { ++ edca[0] = edca[1] = edca[2] = edca[3] = 0; ++ ++ for (i = 0; i < 4; i++) ++ { ++ ACI = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 5) & 0x03; ++ ACM = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 4) & 0x01; ++ ++ /* AIFS = AIFSN * slot time + SIFS - r2t phy delay */ ++ AIFS = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN & 0x0f) * pmlmeinfo->slotTime + aSifsTime; ++ ++ ECWMin = (pmlmeinfo->WMM_param.ac_param[i].CW & 0x0f); ++ ECWMax = (pmlmeinfo->WMM_param.ac_param[i].CW & 0xf0) >> 4; ++ TXOP = le16_to_cpu(pmlmeinfo->WMM_param.ac_param[i].TXOP_limit); ++ ++ acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16); ++ ++ switch (ACI) ++ { ++ case 0x0: ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm)); ++ acm_mask |= (ACM? BIT(1):0); ++ edca[XMIT_BE_QUEUE] = acParm; ++ break; ++ ++ case 0x1: ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm)); ++ /* acm_mask |= (ACM? BIT(0):0); */ ++ edca[XMIT_BK_QUEUE] = acParm; ++ break; ++ ++ case 0x2: ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm)); ++ acm_mask |= (ACM? BIT(2):0); ++ edca[XMIT_VI_QUEUE] = acParm; ++ break; ++ ++ case 0x3: ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm)); ++ acm_mask |= (ACM? BIT(3):0); ++ edca[XMIT_VO_QUEUE] = acParm; ++ break; ++ } ++ ++ DBG_871X("WMM(%x): %x, %x\n", ACI, ACM, acParm); ++ } ++ ++ if (padapter->registrypriv.acm_method == 1) ++ rtw_hal_set_hwreg(padapter, HW_VAR_ACM_CTRL, (u8 *)(&acm_mask)); ++ else ++ padapter->mlmepriv.acm_mask = acm_mask; ++ ++ inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3; ++ ++ if (pregpriv->wifi_spec == 1) ++ { ++ u32 j, tmp, change_inx =false; ++ ++ /* entry indx: 0->vo, 1->vi, 2->be, 3->bk. */ ++ for (i = 0; i<4; i++) ++ { ++ for (j =i+1; j<4; j++) ++ { ++ /* compare CW and AIFS */ ++ if ((edca[j] & 0xFFFF) < (edca[i] & 0xFFFF)) ++ { ++ change_inx = true; ++ } ++ else if ((edca[j] & 0xFFFF) == (edca[i] & 0xFFFF)) ++ { ++ /* compare TXOP */ ++ if ((edca[j] >> 16) > (edca[i] >> 16)) ++ change_inx = true; ++ } ++ ++ if (change_inx) ++ { ++ tmp = edca[i]; ++ edca[i] = edca[j]; ++ edca[j] = tmp; ++ ++ tmp = inx[i]; ++ inx[i] = inx[j]; ++ inx[j] = tmp; ++ ++ change_inx = false; ++ } ++ } ++ } ++ } ++ ++ for (i = 0; i<4; i++) { ++ pxmitpriv->wmm_para_seq[i] = inx[i]; ++ DBG_871X("wmm_para_seq(%d): %d\n", i, pxmitpriv->wmm_para_seq[i]); ++ } ++ } ++} ++ ++static void bwmode_update_check(struct adapter *padapter, struct ndis_80211_var_ie * pIE) ++{ ++ unsigned char new_bwmode; ++ unsigned char new_ch_offset; ++ struct HT_info_element *pHT_info; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ u8 cbw40_enable = 0; ++ ++ if (!pIE) ++ return; ++ ++ if (phtpriv->ht_option == false) return; ++ ++ if (pmlmeext->cur_bwmode >= CHANNEL_WIDTH_80) return; ++ ++ if (pIE->Length > sizeof(struct HT_info_element)) ++ return; ++ ++ pHT_info = (struct HT_info_element *)pIE->data; ++ ++ if (pmlmeext->cur_channel > 14) { ++ if ((pregistrypriv->bw_mode & 0xf0) > 0) ++ cbw40_enable = 1; ++ } else { ++ if ((pregistrypriv->bw_mode & 0x0f) > 0) ++ cbw40_enable = 1; ++ } ++ ++ if ((pHT_info->infos[0] & BIT(2)) && cbw40_enable) ++ { ++ new_bwmode = CHANNEL_WIDTH_40; ++ ++ switch (pHT_info->infos[0] & 0x3) ++ { ++ case 1: ++ new_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ break; ++ ++ case 3: ++ new_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ break; ++ ++ default: ++ new_bwmode = CHANNEL_WIDTH_20; ++ new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ break; ++ } ++ } ++ else ++ { ++ new_bwmode = CHANNEL_WIDTH_20; ++ new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ } ++ ++ ++ if ((new_bwmode!= pmlmeext->cur_bwmode) || (new_ch_offset!=pmlmeext->cur_ch_offset)) ++ { ++ pmlmeinfo->bwmode_updated = true; ++ ++ pmlmeext->cur_bwmode = new_bwmode; ++ pmlmeext->cur_ch_offset = new_ch_offset; ++ ++ /* update HT info also */ ++ HT_info_handler(padapter, pIE); ++ } ++ else ++ { ++ pmlmeinfo->bwmode_updated = false; ++ } ++ ++ ++ if (true == pmlmeinfo->bwmode_updated) ++ { ++ struct sta_info *psta; ++ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ /* set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */ ++ ++ ++ /* update ap's stainfo */ ++ psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress); ++ if (psta) ++ { ++ struct ht_priv *phtpriv_sta = &psta->htpriv; ++ ++ if (phtpriv_sta->ht_option) ++ { ++ /* bwmode */ ++ psta->bw_mode = pmlmeext->cur_bwmode; ++ phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset; ++ } ++ else ++ { ++ psta->bw_mode = CHANNEL_WIDTH_20; ++ phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ } ++ ++ rtw_dm_ra_mask_wk_cmd(padapter, (u8 *)psta); ++ } ++ } ++} ++ ++void HT_caps_handler(struct adapter *padapter, struct ndis_80211_var_ie * pIE) ++{ ++ unsigned int i; ++ u8 rf_type; ++ u8 max_AMPDU_len, min_MPDU_spacing; ++ u8 cur_ldpc_cap = 0, cur_stbc_cap = 0; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ ++ if (pIE == NULL) return; ++ ++ if (phtpriv->ht_option == false) return; ++ ++ pmlmeinfo->HT_caps_enable = 1; ++ ++ for (i = 0; i < (pIE->Length); i++) ++ { ++ if (i != 2) ++ { ++ /* Commented by Albert 2010/07/12 */ ++ /* Got the endian issue here. */ ++ pmlmeinfo->HT_caps.u.HT_cap[i] &= (pIE->data[i]); ++ } ++ else ++ { ++ /* modify from fw by Thomas 2010/11/17 */ ++ if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3) > (pIE->data[i] & 0x3)) ++ { ++ max_AMPDU_len = (pIE->data[i] & 0x3); ++ } ++ else ++ { ++ max_AMPDU_len = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3); ++ } ++ ++ if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) > (pIE->data[i] & 0x1c)) ++ { ++ min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c); ++ } ++ else ++ { ++ min_MPDU_spacing = (pIE->data[i] & 0x1c); ++ } ++ ++ pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para = max_AMPDU_len | min_MPDU_spacing; ++ } ++ } ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ ++ /* update the MCS set */ ++ for (i = 0; i < 16; i++) ++ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= pmlmeext->default_supported_mcs_set[i]; ++ ++ /* update the MCS rates */ ++ switch (rf_type) ++ { ++ case RF_1T1R: ++ case RF_1T2R: ++ set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_1R); ++ break; ++ case RF_2T2R: ++ default: ++#ifdef CONFIG_DISABLE_MCS13TO15 ++ if (pmlmeext->cur_bwmode == CHANNEL_WIDTH_40 && pregistrypriv->wifi_spec != 1) ++ set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R_13TO15_OFF); ++ else ++ set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R); ++#else /* CONFIG_DISABLE_MCS13TO15 */ ++ set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R); ++#endif /* CONFIG_DISABLE_MCS13TO15 */ ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ /* Config STBC setting */ ++ if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX) && GET_HT_CAPABILITY_ELE_TX_STBC(pIE->data)) ++ { ++ SET_FLAG(cur_stbc_cap, STBC_HT_ENABLE_TX); ++ DBG_871X("Enable HT Tx STBC !\n"); ++ } ++ phtpriv->stbc_cap = cur_stbc_cap; ++ } else { ++ /* Config LDPC Coding Capability */ ++ if (TEST_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_TX) && GET_HT_CAPABILITY_ELE_LDPC_CAP(pIE->data)) ++ { ++ SET_FLAG(cur_ldpc_cap, (LDPC_HT_ENABLE_TX | LDPC_HT_CAP_TX)); ++ DBG_871X("Enable HT Tx LDPC!\n"); ++ } ++ phtpriv->ldpc_cap = cur_ldpc_cap; ++ ++ /* Config STBC setting */ ++ if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX) && GET_HT_CAPABILITY_ELE_RX_STBC(pIE->data)) ++ { ++ SET_FLAG(cur_stbc_cap, (STBC_HT_ENABLE_TX | STBC_HT_CAP_TX)); ++ DBG_871X("Enable HT Tx STBC!\n"); ++ } ++ phtpriv->stbc_cap = cur_stbc_cap; ++ } ++} ++ ++void HT_info_handler(struct adapter *padapter, struct ndis_80211_var_ie * pIE) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ ++ if (pIE == NULL) return; ++ ++ if (phtpriv->ht_option == false) return; ++ ++ ++ if (pIE->Length > sizeof(struct HT_info_element)) ++ return; ++ ++ pmlmeinfo->HT_info_enable = 1; ++ memcpy(&(pmlmeinfo->HT_info), pIE->data, pIE->Length); ++ ++ return; ++} ++ ++void HTOnAssocRsp(struct adapter *padapter) ++{ ++ unsigned char max_AMPDU_len; ++ unsigned char min_MPDU_spacing; ++ /* struct registry_priv *pregpriv = &padapter->registrypriv; */ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ DBG_871X("%s\n", __func__); ++ ++ if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) ++ { ++ pmlmeinfo->HT_enable = 1; ++ } ++ else ++ { ++ pmlmeinfo->HT_enable = 0; ++ /* set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */ ++ return; ++ } ++ ++ /* handle A-MPDU parameter field */ ++ /* ++ AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k ++ AMPDU_para [4:2]:Min MPDU Start Spacing ++ */ ++ max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; ++ ++ min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing)); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len)); ++} ++ ++void ERP_IE_handler(struct adapter *padapter, struct ndis_80211_var_ie * pIE) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if (pIE->Length>1) ++ return; ++ ++ pmlmeinfo->ERP_enable = 1; ++ memcpy(&(pmlmeinfo->ERP_IE), pIE->data, pIE->Length); ++} ++ ++void VCS_update(struct adapter *padapter, struct sta_info *psta) ++{ ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ switch (pregpriv->vrtl_carrier_sense)/* 0:off 1:on 2:auto */ ++ { ++ case 0: /* off */ ++ psta->rtsen = 0; ++ psta->cts2self = 0; ++ break; ++ ++ case 1: /* on */ ++ if (pregpriv->vcs_type == 1) /* 1:RTS/CTS 2:CTS to self */ ++ { ++ psta->rtsen = 1; ++ psta->cts2self = 0; ++ } ++ else ++ { ++ psta->rtsen = 0; ++ psta->cts2self = 1; ++ } ++ break; ++ ++ case 2: /* auto */ ++ default: ++ if ((pmlmeinfo->ERP_enable) && (pmlmeinfo->ERP_IE & BIT(1))) ++ { ++ if (pregpriv->vcs_type == 1) ++ { ++ psta->rtsen = 1; ++ psta->cts2self = 0; ++ } ++ else ++ { ++ psta->rtsen = 0; ++ psta->cts2self = 1; ++ } ++ } ++ else ++ { ++ psta->rtsen = 0; ++ psta->cts2self = 0; ++ } ++ break; ++ } ++} ++ ++void update_ldpc_stbc_cap(struct sta_info *psta) ++{ ++ if (psta->htpriv.ht_option) { ++ if (TEST_FLAG(psta->htpriv.ldpc_cap, LDPC_HT_ENABLE_TX)) ++ psta->ldpc = 1; ++ ++ if (TEST_FLAG(psta->htpriv.stbc_cap, STBC_HT_ENABLE_TX)) ++ psta->stbc = 1; ++ } else { ++ psta->ldpc = 0; ++ psta->stbc = 0; ++ } ++} ++ ++int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) ++{ ++ unsigned int len; ++ unsigned char *p; ++ unsigned short val16, subtype; ++ struct wlan_network *cur_network = &(Adapter->mlmepriv.cur_network); ++ /* u8 wpa_ie[255], rsn_ie[255]; */ ++ u16 wpa_len = 0, rsn_len = 0; ++ u8 encryp_protocol = 0; ++ struct wlan_bssid_ex *bssid; ++ int group_cipher = 0, pairwise_cipher = 0, is_8021x = 0; ++ unsigned char *pbuf; ++ u32 wpa_ielen = 0; ++ u8 *pbssid = GetAddr3Ptr(pframe); ++ u32 hidden_ssid = 0; ++ struct HT_info_element *pht_info = NULL; ++ struct rtw_ieee80211_ht_cap *pht_cap = NULL; ++ u32 bcn_channel; ++ unsigned short ht_cap_info; ++ unsigned char ht_info_infos_0; ++ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; ++ ++ if (is_client_associated_to_ap(Adapter) == false) ++ return true; ++ ++ len = packet_len - sizeof(struct ieee80211_hdr_3addr); ++ ++ if (len > MAX_IE_SZ) { ++ DBG_871X("%s IE too long for survey event\n", __func__); ++ return _FAIL; ++ } ++ ++ if (memcmp(cur_network->network.MacAddress, pbssid, 6)) { ++ DBG_871X("Oops: rtw_check_network_encrypt linked but recv other bssid bcn\n" MAC_FMT MAC_FMT, ++ MAC_ARG(pbssid), MAC_ARG(cur_network->network.MacAddress)); ++ return true; ++ } ++ ++ bssid = (struct wlan_bssid_ex *)rtw_zmalloc(sizeof(struct wlan_bssid_ex)); ++ if (bssid == NULL) { ++ DBG_871X("%s rtw_zmalloc fail !!!\n", __func__); ++ return true; ++ } ++ ++ if ((pmlmepriv->timeBcnInfoChkStart != 0) && (jiffies_to_msecs(jiffies - pmlmepriv->timeBcnInfoChkStart) > DISCONNECT_BY_CHK_BCN_FAIL_OBSERV_PERIOD_IN_MS)) ++ { ++ pmlmepriv->timeBcnInfoChkStart = 0; ++ pmlmepriv->NumOfBcnInfoChkFail = 0; ++ } ++ ++ subtype = GetFrameSubType(pframe) >> 4; ++ ++ if (subtype ==WIFI_BEACON) ++ bssid->Reserved[0] = 1; ++ ++ bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len; ++ ++ /* below is to copy the information element */ ++ bssid->IELength = len; ++ memcpy(bssid->IEs, (pframe + sizeof(struct ieee80211_hdr_3addr)), bssid->IELength); ++ ++ /* check bw and channel offset */ ++ /* parsing HT_CAP_IE */ ++ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); ++ if (p && len>0) { ++ pht_cap = (struct rtw_ieee80211_ht_cap *)(p + 2); ++ ht_cap_info = le16_to_cpu(pht_cap->cap_info); ++ } else { ++ ht_cap_info = 0; ++ } ++ /* parsing HT_INFO_IE */ ++ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); ++ if (p && len>0) { ++ pht_info = (struct HT_info_element *)(p + 2); ++ ht_info_infos_0 = pht_info->infos[0]; ++ } else { ++ ht_info_infos_0 = 0; ++ } ++ if (ht_cap_info != cur_network->BcnInfo.ht_cap_info || ++ ((ht_info_infos_0&0x03) != (cur_network->BcnInfo.ht_info_infos_0&0x03))) { ++ DBG_871X("%s bcn now: ht_cap_info:%x ht_info_infos_0:%x\n", __func__, ++ ht_cap_info, ht_info_infos_0); ++ DBG_871X("%s bcn link: ht_cap_info:%x ht_info_infos_0:%x\n", __func__, ++ cur_network->BcnInfo.ht_cap_info, cur_network->BcnInfo.ht_info_infos_0); ++ DBG_871X("%s bw mode change\n", __func__); ++ { ++ /* bcn_info_update */ ++ cur_network->BcnInfo.ht_cap_info = ht_cap_info; ++ cur_network->BcnInfo.ht_info_infos_0 = ht_info_infos_0; ++ /* to do : need to check that whether modify related register of BB or not */ ++ } ++ /* goto _mismatch; */ ++ } ++ ++ /* Checking for channel */ ++ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _DSSET_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); ++ if (p) { ++ bcn_channel = *(p + 2); ++ } else {/* In 5G, some ap do not have DSSET IE checking HT info for channel */ ++ rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); ++ if (pht_info) { ++ bcn_channel = pht_info->primary_channel; ++ } else { /* we don't find channel IE, so don't check it */ ++ /* DBG_871X("Oops: %s we don't find channel IE, so don't check it\n", __func__); */ ++ bcn_channel = Adapter->mlmeextpriv.cur_channel; ++ } ++ } ++ if (bcn_channel != Adapter->mlmeextpriv.cur_channel) { ++ DBG_871X("%s beacon channel:%d cur channel:%d disconnect\n", __func__, ++ bcn_channel, Adapter->mlmeextpriv.cur_channel); ++ goto _mismatch; ++ } ++ ++ /* checking SSID */ ++ if ((p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _SSID_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_)) == NULL) { ++ DBG_871X("%s marc: cannot find SSID for survey event\n", __func__); ++ hidden_ssid = true; ++ } else { ++ hidden_ssid = false; ++ } ++ ++ if ((NULL != p) && (false == hidden_ssid && (*(p + 1)))) { ++ memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1)); ++ bssid->Ssid.SsidLength = *(p + 1); ++ } else { ++ bssid->Ssid.SsidLength = 0; ++ bssid->Ssid.Ssid[0] = '\0'; ++ } ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s bssid.Ssid.Ssid:%s bssid.Ssid.SsidLength:%d " ++ "cur_network->network.Ssid.Ssid:%s len:%d\n", __func__, bssid->Ssid.Ssid, ++ bssid->Ssid.SsidLength, cur_network->network.Ssid.Ssid, ++ cur_network->network.Ssid.SsidLength)); ++ ++ if (memcmp(bssid->Ssid.Ssid, cur_network->network.Ssid.Ssid, 32) || ++ bssid->Ssid.SsidLength != cur_network->network.Ssid.SsidLength) { ++ if (bssid->Ssid.Ssid[0] != '\0' && bssid->Ssid.SsidLength != 0) { /* not hidden ssid */ ++ DBG_871X("%s(), SSID is not match\n", __func__); ++ goto _mismatch; ++ } ++ } ++ ++ /* check encryption info */ ++ val16 = rtw_get_capability((struct wlan_bssid_ex *)bssid); ++ ++ if (val16 & BIT(4)) ++ bssid->Privacy = 1; ++ else ++ bssid->Privacy = 0; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ++ ("%s(): cur_network->network.Privacy is %d, bssid.Privacy is %d\n", ++ __func__, cur_network->network.Privacy, bssid->Privacy)); ++ if (cur_network->network.Privacy != bssid->Privacy) { ++ DBG_871X("%s(), privacy is not match\n", __func__); ++ goto _mismatch; ++ } ++ ++ rtw_get_sec_ie(bssid->IEs, bssid->IELength, NULL,&rsn_len, NULL,&wpa_len); ++ ++ if (rsn_len > 0) { ++ encryp_protocol = ENCRYP_PROTOCOL_WPA2; ++ } else if (wpa_len > 0) { ++ encryp_protocol = ENCRYP_PROTOCOL_WPA; ++ } else { ++ if (bssid->Privacy) ++ encryp_protocol = ENCRYP_PROTOCOL_WEP; ++ } ++ ++ if (cur_network->BcnInfo.encryp_protocol != encryp_protocol) { ++ DBG_871X("%s(): enctyp is not match\n", __func__); ++ goto _mismatch; ++ } ++ ++ if (encryp_protocol == ENCRYP_PROTOCOL_WPA || encryp_protocol == ENCRYP_PROTOCOL_WPA2) { ++ pbuf = rtw_get_wpa_ie(&bssid->IEs[12], &wpa_ielen, bssid->IELength-12); ++ if (pbuf && (wpa_ielen>0)) { ++ if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is_8021x)) { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ++ ("%s pnetwork->pairwise_cipher: %d, group_cipher is %d, is_8021x is %d\n", __func__, ++ pairwise_cipher, group_cipher, is_8021x)); ++ } ++ } else { ++ pbuf = rtw_get_wpa2_ie(&bssid->IEs[12], &wpa_ielen, bssid->IELength-12); ++ ++ if (pbuf && (wpa_ielen>0)) { ++ if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is_8021x)) { ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ++ ("%s pnetwork->pairwise_cipher: %d, pnetwork->group_cipher is %d, is_802x is %d\n", ++ __func__, pairwise_cipher, group_cipher, is_8021x)); ++ } ++ } ++ } ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ++ ("%s cur_network->group_cipher is %d: %d\n", __func__, cur_network->BcnInfo.group_cipher, group_cipher)); ++ if (pairwise_cipher != cur_network->BcnInfo.pairwise_cipher || group_cipher != cur_network->BcnInfo.group_cipher) { ++ DBG_871X("%s pairwise_cipher(%x:%x) or group_cipher(%x:%x) is not match\n", __func__, ++ pairwise_cipher, cur_network->BcnInfo.pairwise_cipher, ++ group_cipher, cur_network->BcnInfo.group_cipher); ++ goto _mismatch; ++ } ++ ++ if (is_8021x != cur_network->BcnInfo.is_8021x) { ++ DBG_871X("%s authentication is not match\n", __func__); ++ goto _mismatch; ++ } ++ } ++ ++ kfree((u8 *)bssid); ++ return _SUCCESS; ++ ++_mismatch: ++ kfree((u8 *)bssid); ++ ++ if (pmlmepriv->NumOfBcnInfoChkFail == 0) ++ { ++ pmlmepriv->timeBcnInfoChkStart = jiffies; ++ } ++ ++ pmlmepriv->NumOfBcnInfoChkFail++; ++ DBG_871X("%s by "ADPT_FMT" - NumOfChkFail = %d (SeqNum of this Beacon frame = %d).\n", __func__, ADPT_ARG(Adapter), pmlmepriv->NumOfBcnInfoChkFail, GetSequence(pframe)); ++ ++ if ((pmlmepriv->timeBcnInfoChkStart != 0) && (jiffies_to_msecs(jiffies - pmlmepriv->timeBcnInfoChkStart) <= DISCONNECT_BY_CHK_BCN_FAIL_OBSERV_PERIOD_IN_MS) ++ && (pmlmepriv->NumOfBcnInfoChkFail >= DISCONNECT_BY_CHK_BCN_FAIL_THRESHOLD)) ++ { ++ DBG_871X("%s by "ADPT_FMT" - NumOfChkFail = %d >= threshold : %d (in %d ms), return FAIL.\n", __func__, ADPT_ARG(Adapter), pmlmepriv->NumOfBcnInfoChkFail, ++ DISCONNECT_BY_CHK_BCN_FAIL_THRESHOLD, jiffies_to_msecs(jiffies - pmlmepriv->timeBcnInfoChkStart)); ++ pmlmepriv->timeBcnInfoChkStart = 0; ++ pmlmepriv->NumOfBcnInfoChkFail = 0; ++ return _FAIL; ++ } ++ ++ return _SUCCESS; ++} ++ ++void update_beacon_info(struct adapter *padapter, u8 *pframe, uint pkt_len, struct sta_info *psta) ++{ ++ unsigned int i; ++ unsigned int len; ++ struct ndis_80211_var_ie * pIE; ++ ++ len = pkt_len - (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN); ++ ++ for (i = 0; i < len;) ++ { ++ pIE = (struct ndis_80211_var_ie *)(pframe + (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN) + i); ++ ++ switch (pIE->ElementID) ++ { ++ case _VENDOR_SPECIFIC_IE_: ++ /* to update WMM paramter set while receiving beacon */ ++ if (!memcmp(pIE->data, WMM_PARA_OUI, 6) && pIE->Length == WLAN_WMM_LEN) /* WMM */ ++ { ++ if (WMM_param_handler(padapter, pIE)) ++ report_wmm_edca_update(padapter); ++ } ++ ++ break; ++ ++ case _HT_EXTRA_INFO_IE_: /* HT info */ ++ /* HT_info_handler(padapter, pIE); */ ++ bwmode_update_check(padapter, pIE); ++ break; ++ ++ case _ERPINFO_IE_: ++ ERP_IE_handler(padapter, pIE); ++ VCS_update(padapter, psta); ++ break; ++ ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++} ++ ++unsigned int is_ap_in_tkip(struct adapter *padapter) ++{ ++ u32 i; ++ struct ndis_80211_var_ie * pIE; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); ++ ++ if (rtw_get_capability((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) ++ { ++ for (i = sizeof(struct ndis_802_11_fix_ie); i < pmlmeinfo->network.IELength;) ++ { ++ pIE = (struct ndis_80211_var_ie *)(pmlmeinfo->network.IEs + i); ++ ++ switch (pIE->ElementID) ++ { ++ case _VENDOR_SPECIFIC_IE_: ++ if ((!memcmp(pIE->data, RTW_WPA_OUI, 4)) && (!memcmp((pIE->data + 12), WPA_TKIP_CIPHER, 4))) ++ { ++ return true; ++ } ++ break; ++ ++ case _RSN_IE_2_: ++ if (!memcmp((pIE->data + 8), RSN_TKIP_CIPHER, 4)) ++ { ++ return true; ++ } ++ ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++ ++ return false; ++ } ++ else ++ { ++ return false; ++ } ++ ++} ++ ++int support_short_GI(struct adapter *padapter, struct HT_caps_element *pHT_caps, u8 bwmode) ++{ ++ unsigned char bit_offset; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if (!(pmlmeinfo->HT_enable)) ++ return _FAIL; ++ ++ bit_offset = (bwmode & CHANNEL_WIDTH_40)? 6: 5; ++ ++ if (le16_to_cpu(pHT_caps->u.HT_cap_element.HT_caps_info) & (0x1 << bit_offset)) ++ { ++ return _SUCCESS; ++ } ++ else ++ { ++ return _FAIL; ++ } ++} ++ ++unsigned char get_highest_rate_idx(u32 mask) ++{ ++ int i; ++ unsigned char rate_idx = 0; ++ ++ for (i =31; i>= 0; i--) ++ { ++ if (mask & BIT(i)) ++ { ++ rate_idx = i; ++ break; ++ } ++ } ++ ++ return rate_idx; ++} ++ ++void Update_RA_Entry(struct adapter *padapter, struct sta_info *psta) ++{ ++ rtw_hal_update_ra_mask(psta, 0); ++} ++ ++void enable_rate_adaptive(struct adapter *padapter, struct sta_info *psta); ++void enable_rate_adaptive(struct adapter *padapter, struct sta_info *psta) ++{ ++ Update_RA_Entry(padapter, psta); ++} ++ ++void set_sta_rate(struct adapter *padapter, struct sta_info *psta) ++{ ++ /* rate adaptive */ ++ enable_rate_adaptive(padapter, psta); ++} ++ ++unsigned char check_assoc_AP(u8 *pframe, uint len) ++{ ++ unsigned int i; ++ struct ndis_80211_var_ie * pIE; ++ ++ for (i = sizeof(struct ndis_802_11_fix_ie); i < len;) ++ { ++ pIE = (struct ndis_80211_var_ie *)(pframe + i); ++ ++ switch (pIE->ElementID) ++ { ++ case _VENDOR_SPECIFIC_IE_: ++ if ((!memcmp(pIE->data, ARTHEROS_OUI1, 3)) || (!memcmp(pIE->data, ARTHEROS_OUI2, 3))) ++ { ++ DBG_871X("link to Artheros AP\n"); ++ return HT_IOT_PEER_ATHEROS; ++ } ++ else if ((!memcmp(pIE->data, BROADCOM_OUI1, 3)) ++ || (!memcmp(pIE->data, BROADCOM_OUI2, 3)) ++ || (!memcmp(pIE->data, BROADCOM_OUI3, 3))) ++ { ++ DBG_871X("link to Broadcom AP\n"); ++ return HT_IOT_PEER_BROADCOM; ++ } ++ else if (!memcmp(pIE->data, MARVELL_OUI, 3)) ++ { ++ DBG_871X("link to Marvell AP\n"); ++ return HT_IOT_PEER_MARVELL; ++ } ++ else if (!memcmp(pIE->data, RALINK_OUI, 3)) ++ { ++ DBG_871X("link to Ralink AP\n"); ++ return HT_IOT_PEER_RALINK; ++ } ++ else if (!memcmp(pIE->data, CISCO_OUI, 3)) ++ { ++ DBG_871X("link to Cisco AP\n"); ++ return HT_IOT_PEER_CISCO; ++ } ++ else if (!memcmp(pIE->data, REALTEK_OUI, 3)) ++ { ++ u32 Vender = HT_IOT_PEER_REALTEK; ++ ++ if (pIE->Length >= 5) { ++ if (pIE->data[4]== 1) ++ { ++ /* if (pIE->data[5] & RT_HT_CAP_USE_LONG_PREAMBLE) */ ++ /* bssDesc->BssHT.RT2RT_HT_Mode |= RT_HT_CAP_USE_LONG_PREAMBLE; */ ++ ++ if (pIE->data[5] & RT_HT_CAP_USE_92SE) ++ { ++ /* bssDesc->BssHT.RT2RT_HT_Mode |= RT_HT_CAP_USE_92SE; */ ++ Vender = HT_IOT_PEER_REALTEK_92SE; ++ } ++ } ++ ++ if (pIE->data[5] & RT_HT_CAP_USE_SOFTAP) ++ Vender = HT_IOT_PEER_REALTEK_SOFTAP; ++ ++ if (pIE->data[4] == 2) ++ { ++ if (pIE->data[6] & RT_HT_CAP_USE_JAGUAR_BCUT) { ++ Vender = HT_IOT_PEER_REALTEK_JAGUAR_BCUTAP; ++ DBG_871X("link to Realtek JAGUAR_BCUTAP\n"); ++ } ++ if (pIE->data[6] & RT_HT_CAP_USE_JAGUAR_CCUT) { ++ Vender = HT_IOT_PEER_REALTEK_JAGUAR_CCUTAP; ++ DBG_871X("link to Realtek JAGUAR_CCUTAP\n"); ++ } ++ } ++ } ++ ++ DBG_871X("link to Realtek AP\n"); ++ return Vender; ++ } ++ else if (!memcmp(pIE->data, AIRGOCAP_OUI, 3)) ++ { ++ DBG_871X("link to Airgo Cap\n"); ++ return HT_IOT_PEER_AIRGO; ++ } ++ else ++ { ++ break; ++ } ++ ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++ ++ DBG_871X("link to new AP\n"); ++ return HT_IOT_PEER_UNKNOWN; ++} ++ ++void update_IOT_info(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ switch (pmlmeinfo->assoc_AP_vendor) ++ { ++ case HT_IOT_PEER_MARVELL: ++ pmlmeinfo->turboMode_cts2self = 1; ++ pmlmeinfo->turboMode_rtsen = 0; ++ break; ++ ++ case HT_IOT_PEER_RALINK: ++ pmlmeinfo->turboMode_cts2self = 0; ++ pmlmeinfo->turboMode_rtsen = 1; ++ /* disable high power */ ++ Switch_DM_Func(padapter, (~DYNAMIC_BB_DYNAMIC_TXPWR), false); ++ break; ++ case HT_IOT_PEER_REALTEK: ++ /* rtw_write16(padapter, 0x4cc, 0xffff); */ ++ /* rtw_write16(padapter, 0x546, 0x01c0); */ ++ /* disable high power */ ++ Switch_DM_Func(padapter, (~DYNAMIC_BB_DYNAMIC_TXPWR), false); ++ break; ++ default: ++ pmlmeinfo->turboMode_cts2self = 0; ++ pmlmeinfo->turboMode_rtsen = 1; ++ break; ++ } ++ ++} ++ ++void update_capinfo(struct adapter * Adapter, u16 updateCap) ++{ ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ bool ShortPreamble; ++ ++ /* Check preamble mode, 2005.01.06, by rcnjko. */ ++ /* Mark to update preamble value forever, 2008.03.18 by lanhsin */ ++ /* if (pMgntInfo->RegPreambleMode == PREAMBLE_AUTO) */ ++ { ++ ++ if (updateCap & cShortPreamble) ++ { /* Short Preamble */ ++ if (pmlmeinfo->preamble_mode != PREAMBLE_SHORT) /* PREAMBLE_LONG or PREAMBLE_AUTO */ ++ { ++ ShortPreamble = true; ++ pmlmeinfo->preamble_mode = PREAMBLE_SHORT; ++ rtw_hal_set_hwreg(Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble); ++ } ++ } ++ else ++ { /* Long Preamble */ ++ if (pmlmeinfo->preamble_mode != PREAMBLE_LONG) /* PREAMBLE_SHORT or PREAMBLE_AUTO */ ++ { ++ ShortPreamble = false; ++ pmlmeinfo->preamble_mode = PREAMBLE_LONG; ++ rtw_hal_set_hwreg(Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble); ++ } ++ } ++ } ++ ++ if (updateCap & cIBSS) { ++ /* Filen: See 802.11-2007 p.91 */ ++ pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; ++ } ++ else ++ { ++ /* Filen: See 802.11-2007 p.90 */ ++ if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N | WIRELESS_11A | WIRELESS_11_5N | WIRELESS_11AC)) ++ { ++ pmlmeinfo->slotTime = SHORT_SLOT_TIME; ++ } ++ else if (pmlmeext->cur_wireless_mode & (WIRELESS_11G)) ++ { ++ if ((updateCap & cShortSlotTime) /* && (!(pMgntInfo->pHTInfo->RT2RT_HT_Mode & RT_HT_CAP_USE_LONG_PREAMBLE)) */) ++ { /* Short Slot Time */ ++ pmlmeinfo->slotTime = SHORT_SLOT_TIME; ++ } ++ else ++ { /* Long Slot Time */ ++ pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; ++ } ++ } ++ else ++ { ++ /* B Mode */ ++ pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; ++ } ++ } ++ ++ rtw_hal_set_hwreg(Adapter, HW_VAR_SLOT_TIME, &pmlmeinfo->slotTime); ++ ++} ++ ++void update_wireless_mode(struct adapter *padapter) ++{ ++ int ratelen, network_type = 0; ++ u32 SIFS_Timer; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); ++ unsigned char *rate = cur_network->SupportedRates; ++ ++ ratelen = rtw_get_rateset_len(cur_network->SupportedRates); ++ ++ if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) ++ { ++ pmlmeinfo->HT_enable = 1; ++ } ++ ++ if (pmlmeext->cur_channel > 14) ++ { ++ if (pmlmeinfo->VHT_enable) ++ network_type = WIRELESS_11AC; ++ else if (pmlmeinfo->HT_enable) ++ network_type = WIRELESS_11_5N; ++ ++ network_type |= WIRELESS_11A; ++ } ++ else ++ { ++ if (pmlmeinfo->VHT_enable) ++ network_type = WIRELESS_11AC; ++ else if (pmlmeinfo->HT_enable) ++ network_type = WIRELESS_11_24N; ++ ++ if ((cckratesonly_included(rate, ratelen)) == true) ++ { ++ network_type |= WIRELESS_11B; ++ } ++ else if ((cckrates_included(rate, ratelen)) == true) ++ { ++ network_type |= WIRELESS_11BG; ++ } ++ else ++ { ++ network_type |= WIRELESS_11G; ++ } ++ } ++ ++ pmlmeext->cur_wireless_mode = network_type & padapter->registrypriv.wireless_mode; ++ ++ SIFS_Timer = 0x0a0a0808; /* 0x0808 -> for CCK, 0x0a0a -> for OFDM */ ++ /* change this value if having IOT issues. */ ++ ++ padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_RESP_SIFS, (u8 *)&SIFS_Timer); ++ ++ padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_WIRELESS_MODE, (u8 *)&(pmlmeext->cur_wireless_mode)); ++ ++ if (pmlmeext->cur_wireless_mode & WIRELESS_11B) ++ update_mgnt_tx_rate(padapter, IEEE80211_CCK_RATE_1MB); ++ else ++ update_mgnt_tx_rate(padapter, IEEE80211_OFDM_RATE_6MB); ++} ++ ++void update_sta_basic_rate(struct sta_info *psta, u8 wireless_mode) ++{ ++ if (IsSupportedTxCCK(wireless_mode)) ++ { ++ /* Only B, B/G, and B/G/N AP could use CCK rate */ ++ memcpy(psta->bssrateset, rtw_basic_rate_cck, 4); ++ psta->bssratelen = 4; ++ } ++ else ++ { ++ memcpy(psta->bssrateset, rtw_basic_rate_ofdm, 3); ++ psta->bssratelen = 3; ++ } ++} ++ ++int update_sta_support_rate(struct adapter *padapter, u8 *pvar_ie, uint var_ie_len, int cam_idx) ++{ ++ unsigned int ie_len; ++ struct ndis_80211_var_ie * pIE; ++ int supportRateNum = 0; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ pIE = (struct ndis_80211_var_ie *)rtw_get_ie(pvar_ie, _SUPPORTEDRATES_IE_, &ie_len, var_ie_len); ++ if (pIE == NULL) ++ { ++ return _FAIL; ++ } ++ ++ memcpy(pmlmeinfo->FW_sta_info[cam_idx].SupportedRates, pIE->data, ie_len); ++ supportRateNum = ie_len; ++ ++ pIE = (struct ndis_80211_var_ie *)rtw_get_ie(pvar_ie, _EXT_SUPPORTEDRATES_IE_, &ie_len, var_ie_len); ++ if (pIE) ++ { ++ memcpy((pmlmeinfo->FW_sta_info[cam_idx].SupportedRates + supportRateNum), pIE->data, ie_len); ++ } ++ ++ return _SUCCESS; ++ ++} ++ ++void process_addba_req(struct adapter *padapter, u8 *paddba_req, u8 *addr) ++{ ++ struct sta_info *psta; ++ u16 tid, start_seq, param; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct ADDBA_request *preq = (struct ADDBA_request*)paddba_req; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ psta = rtw_get_stainfo(pstapriv, addr); ++ ++ if (psta) ++ { ++ start_seq = le16_to_cpu(preq->BA_starting_seqctrl) >> 4; ++ ++ param = le16_to_cpu(preq->BA_para_set); ++ tid = (param>>2)&0x0f; ++ ++ preorder_ctrl = &psta->recvreorder_ctrl[tid]; ++ ++ #ifdef CONFIG_UPDATE_INDICATE_SEQ_WHILE_PROCESS_ADDBA_REQ ++ preorder_ctrl->indicate_seq = start_seq; ++ #ifdef DBG_RX_SEQ ++ DBG_871X("DBG_RX_SEQ %s:%d IndicateSeq: %d, start_seq: %d\n", __func__, __LINE__, ++ preorder_ctrl->indicate_seq, start_seq); ++ #endif ++ #else ++ preorder_ctrl->indicate_seq = 0xffff; ++ #endif ++ ++ preorder_ctrl->enable =(pmlmeinfo->bAcceptAddbaReq == true)? true :false; ++ } ++ ++} ++ ++void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len) ++{ ++ u8 *pIE; ++ __le32 *pbuf; ++ ++ pIE = pframe + sizeof(struct ieee80211_hdr_3addr); ++ pbuf = (__le32 *)pIE; ++ ++ pmlmeext->TSFValue = le32_to_cpu(*(pbuf+1)); ++ ++ pmlmeext->TSFValue = pmlmeext->TSFValue << 32; ++ ++ pmlmeext->TSFValue |= le32_to_cpu(*pbuf); ++} ++ ++void correct_TSF(struct adapter *padapter, struct mlme_ext_priv *pmlmeext) ++{ ++ rtw_hal_set_hwreg(padapter, HW_VAR_CORRECT_TSF, NULL); ++} ++ ++void adaptive_early_32k(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len) ++{ ++ int i; ++ u8 *pIE; ++ __le32 *pbuf; ++ u64 tsf = 0; ++ u32 delay_ms; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ ++ pmlmeext->bcn_cnt++; ++ ++ pIE = pframe + sizeof(struct ieee80211_hdr_3addr); ++ pbuf = (__le32 *)pIE; ++ ++ tsf = le32_to_cpu(*(pbuf+1)); ++ tsf = tsf << 32; ++ tsf |= le32_to_cpu(*pbuf); ++ ++ /* DBG_871X("%s(): tsf_upper = 0x%08x, tsf_lower = 0x%08x\n", __func__, (u32)(tsf>>32), (u32)tsf); */ ++ ++ /* delay = (timestamp mod 1024*100)/1000 (unit: ms) */ ++ /* delay_ms = do_div(tsf, (pmlmeinfo->bcn_interval*1024))/1000; */ ++ delay_ms = rtw_modular64(tsf, (pmlmeinfo->bcn_interval*1024)); ++ delay_ms = delay_ms/1000; ++ ++ if (delay_ms >= 8) ++ { ++ pmlmeext->bcn_delay_cnt[8]++; ++ /* pmlmeext->bcn_delay_ratio[8] = (pmlmeext->bcn_delay_cnt[8] * 100) /pmlmeext->bcn_cnt; */ ++ } ++ else ++ { ++ pmlmeext->bcn_delay_cnt[delay_ms]++; ++ /* pmlmeext->bcn_delay_ratio[delay_ms] = (pmlmeext->bcn_delay_cnt[delay_ms] * 100) /pmlmeext->bcn_cnt; */ ++ } ++ ++/* ++ DBG_871X("%s(): (a)bcn_cnt = %d\n", __func__, pmlmeext->bcn_cnt); ++ ++ ++ for (i = 0; i<9; i++) ++ { ++ DBG_871X("%s():bcn_delay_cnt[%d]=%d, bcn_delay_ratio[%d]=%d\n", __func__, i, ++ pmlmeext->bcn_delay_cnt[i] , i, pmlmeext->bcn_delay_ratio[i]); ++ } ++*/ ++ ++ /* dump for adaptive_early_32k */ ++ if (pmlmeext->bcn_cnt > 100 && (pmlmeext->adaptive_tsf_done ==true)) ++ { ++ u8 ratio_20_delay, ratio_80_delay; ++ u8 DrvBcnEarly, DrvBcnTimeOut; ++ ++ ratio_20_delay = 0; ++ ratio_80_delay = 0; ++ DrvBcnEarly = 0xff; ++ DrvBcnTimeOut = 0xff; ++ ++ DBG_871X("%s(): bcn_cnt = %d\n", __func__, pmlmeext->bcn_cnt); ++ ++ for (i = 0; i<9; i++) ++ { ++ pmlmeext->bcn_delay_ratio[i] = (pmlmeext->bcn_delay_cnt[i] * 100) /pmlmeext->bcn_cnt; ++ ++ ++ DBG_871X("%s():bcn_delay_cnt[%d]=%d, bcn_delay_ratio[%d]=%d\n", __func__, i, ++ pmlmeext->bcn_delay_cnt[i] , i, pmlmeext->bcn_delay_ratio[i]); ++ ++ ratio_20_delay += pmlmeext->bcn_delay_ratio[i]; ++ ratio_80_delay += pmlmeext->bcn_delay_ratio[i]; ++ ++ if (ratio_20_delay > 20 && DrvBcnEarly == 0xff) ++ { ++ DrvBcnEarly = i; ++ DBG_871X("%s(): DrvBcnEarly = %d\n", __func__, DrvBcnEarly); ++ } ++ ++ if (ratio_80_delay > 80 && DrvBcnTimeOut == 0xff) ++ { ++ DrvBcnTimeOut = i; ++ DBG_871X("%s(): DrvBcnTimeOut = %d\n", __func__, DrvBcnTimeOut); ++ } ++ ++ /* reset adaptive_early_32k cnt */ ++ pmlmeext->bcn_delay_cnt[i] = 0; ++ pmlmeext->bcn_delay_ratio[i] = 0; ++ } ++ ++ pmlmeext->DrvBcnEarly = DrvBcnEarly; ++ pmlmeext->DrvBcnTimeOut = DrvBcnTimeOut; ++ ++ pmlmeext->bcn_cnt = 0; ++ } ++ ++} ++ ++ ++void beacon_timing_control(struct adapter *padapter) ++{ ++ rtw_hal_bcn_related_reg_setting(padapter); ++} ++ ++void rtw_alloc_macid(struct adapter *padapter, struct sta_info *psta) ++{ ++ int i; ++ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); ++ ++ ++ if (!memcmp(psta->hwaddr, bc_addr, ETH_ALEN)) ++ return; ++ ++ if (!memcmp(psta->hwaddr, myid(&padapter->eeprompriv), ETH_ALEN)) ++ { ++ psta->mac_id = NUM_STA; ++ return; ++ } ++ ++ spin_lock_bh(&pdvobj->lock); ++ for (i = 0; imacid[i] == false) ++ { ++ pdvobj->macid[i] = true; ++ break; ++ } ++ } ++ spin_unlock_bh(&pdvobj->lock); ++ ++ if (i > (NUM_STA-1)) ++ { ++ psta->mac_id = NUM_STA; ++ DBG_871X(" no room for more MACIDs\n"); ++ } ++ else ++ { ++ psta->mac_id = i; ++ DBG_871X("%s = %d\n", __func__, psta->mac_id); ++ } ++ ++} ++ ++void rtw_release_macid(struct adapter *padapter, struct sta_info *psta) ++{ ++ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); ++ ++ ++ if (!memcmp(psta->hwaddr, bc_addr, ETH_ALEN)) ++ return; ++ ++ if (!memcmp(psta->hwaddr, myid(&padapter->eeprompriv), ETH_ALEN)) ++ { ++ return; ++ } ++ ++ spin_lock_bh(&pdvobj->lock); ++ if (psta->mac_idmac_id != 1) ++ { ++ if (pdvobj->macid[psta->mac_id] == true) ++ { ++ DBG_871X("%s = %d\n", __func__, psta->mac_id); ++ pdvobj->macid[psta->mac_id] = false; ++ psta->mac_id = NUM_STA; ++ } ++ ++ } ++ spin_unlock_bh(&pdvobj->lock); ++ ++} ++/* For 8188E RA */ ++u8 rtw_search_max_mac_id(struct adapter *padapter) ++{ ++ u8 max_mac_id = 0; ++ struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); ++ int i; ++ spin_lock_bh(&pdvobj->lock); ++ for (i =(NUM_STA-1); i>= 0 ; i--) ++ { ++ if (pdvobj->macid[i] == true) ++ { ++ break; ++ } ++ } ++ max_mac_id = i; ++ spin_unlock_bh(&pdvobj->lock); ++ ++ return max_mac_id; ++ ++} ++ ++struct adapter *dvobj_get_port0_adapter(struct dvobj_priv *dvobj) ++{ ++ if (get_iface_type(dvobj->padapters[i]) != IFACE_PORT0) ++ return NULL; ++ ++ return dvobj->padapters; ++} ++ ++#ifdef CONFIG_GPIO_API ++int rtw_get_gpio(struct net_device *netdev, int gpio_num) ++{ ++ u8 value; ++ u8 direction; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(netdev); ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); ++ ++ rtw_ps_deny(adapter, PS_DENY_IOCTL); ++ ++ DBG_871X("rf_pwrstate = 0x%02x\n", pwrpriv->rf_pwrstate); ++ LeaveAllPowerSaveModeDirect(adapter); ++ ++ /* Read GPIO Direction */ ++ direction = (rtw_read8(adapter, REG_GPIO_PIN_CTRL + 2) & BIT(gpio_num)) >> gpio_num; ++ ++ /* According the direction to read register value */ ++ if (direction) ++ value = (rtw_read8(adapter, REG_GPIO_PIN_CTRL + 1)& BIT(gpio_num)) >> gpio_num; ++ else ++ value = (rtw_read8(adapter, REG_GPIO_PIN_CTRL)& BIT(gpio_num)) >> gpio_num; ++ ++ rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL); ++ DBG_871X("%s direction =%d value =%d\n", __func__, direction, value); ++ ++ return value; ++} ++EXPORT_SYMBOL(rtw_get_gpio); ++ ++int rtw_set_gpio_output_value(struct net_device *netdev, int gpio_num, bool isHigh) ++{ ++ u8 direction = 0; ++ u8 res = -1; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(netdev); ++ ++ /* Check GPIO is 4~7 */ ++ if (gpio_num > 7 || gpio_num < 4) ++ { ++ DBG_871X("%s The gpio number does not included 4~7.\n", __func__); ++ return -1; ++ } ++ ++ rtw_ps_deny(adapter, PS_DENY_IOCTL); ++ ++ LeaveAllPowerSaveModeDirect(adapter); ++ ++ /* Read GPIO direction */ ++ direction = (rtw_read8(adapter, REG_GPIO_PIN_CTRL + 2) & BIT(gpio_num)) >> gpio_num; ++ ++ /* If GPIO is output direction, setting value. */ ++ if (direction) ++ { ++ if (isHigh) ++ rtw_write8(adapter, REG_GPIO_PIN_CTRL + 1, rtw_read8(adapter, REG_GPIO_PIN_CTRL + 1) | BIT(gpio_num)); ++ else ++ rtw_write8(adapter, REG_GPIO_PIN_CTRL + 1, rtw_read8(adapter, REG_GPIO_PIN_CTRL + 1) & ~BIT(gpio_num)); ++ ++ DBG_871X("%s Set gpio %x[%d]=%d\n", __func__, REG_GPIO_PIN_CTRL+1, gpio_num, isHigh); ++ res = 0; ++ } ++ else ++ { ++ DBG_871X("%s The gpio is input, not be set!\n", __func__); ++ res = -1; ++ } ++ ++ rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL); ++ return res; ++} ++EXPORT_SYMBOL(rtw_set_gpio_output_value); ++ ++int rtw_config_gpio(struct net_device *netdev, int gpio_num, bool isOutput) ++{ ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(netdev); ++ ++ if (gpio_num > 7 || gpio_num < 4) ++ { ++ DBG_871X("%s The gpio number does not included 4~7.\n", __func__); ++ return -1; ++ } ++ ++ DBG_871X("%s gpio_num =%d direction =%d\n", __func__, gpio_num, isOutput); ++ ++ rtw_ps_deny(adapter, PS_DENY_IOCTL); ++ ++ LeaveAllPowerSaveModeDirect(adapter); ++ ++ if (isOutput) ++ { ++ rtw_write8(adapter, REG_GPIO_PIN_CTRL + 2, rtw_read8(adapter, REG_GPIO_PIN_CTRL + 2) | BIT(gpio_num)); ++ } ++ else ++ { ++ rtw_write8(adapter, REG_GPIO_PIN_CTRL + 2, rtw_read8(adapter, REG_GPIO_PIN_CTRL + 2) & ~BIT(gpio_num)); ++ } ++ ++ rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL); ++ ++ return 0; ++} ++EXPORT_SYMBOL(rtw_config_gpio); ++#endif ++ ++#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) ++void rtw_get_current_ip_address(struct adapter *padapter, u8 *pcurrentip) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct in_device *my_ip_ptr = padapter->pnetdev->ip_ptr; ++ u8 ipaddress[4]; ++ ++ if ((pmlmeinfo->state & WIFI_FW_LINKING_STATE) || ++ pmlmeinfo->state & WIFI_FW_AP_STATE) { ++ if (my_ip_ptr != NULL) { ++ struct in_ifaddr *my_ifa_list = my_ip_ptr->ifa_list ; ++ if (my_ifa_list != NULL) { ++ ipaddress[0] = my_ifa_list->ifa_address & 0xFF; ++ ipaddress[1] = (my_ifa_list->ifa_address >> 8) & 0xFF; ++ ipaddress[2] = (my_ifa_list->ifa_address >> 16) & 0xFF; ++ ipaddress[3] = my_ifa_list->ifa_address >> 24; ++ DBG_871X("%s: %d.%d.%d.%d ==========\n", __func__, ++ ipaddress[0], ipaddress[1], ipaddress[2], ipaddress[3]); ++ memcpy(pcurrentip, ipaddress, 4); ++ } ++ } ++ } ++} ++#endif ++#ifdef CONFIG_WOWLAN ++void rtw_get_sec_iv(struct adapter *padapter, u8*pcur_dot11txpn, u8 *StaAddr) ++{ ++ struct sta_info *psta; ++ struct security_priv *psecpriv = &padapter->securitypriv; ++ ++ memset(pcur_dot11txpn, 0, 8); ++ if (NULL == StaAddr) ++ return; ++ psta = rtw_get_stainfo(&padapter->stapriv, StaAddr); ++ DBG_871X("%s(): StaAddr: %02x %02x %02x %02x %02x %02x\n", ++ __func__, StaAddr[0], StaAddr[1], StaAddr[2], ++ StaAddr[3], StaAddr[4], StaAddr[5]); ++ ++ if (psta) ++ { ++ if (psecpriv->dot11PrivacyAlgrthm != _NO_PRIVACY_ && psta->dot11txpn.val > 0) ++ psta->dot11txpn.val--; ++ AES_IV(pcur_dot11txpn, psta->dot11txpn, 0); ++ ++ DBG_871X("%s(): CurrentIV: %02x %02x %02x %02x %02x %02x %02x %02x\n" ++ , __func__, pcur_dot11txpn[0], pcur_dot11txpn[1], ++ pcur_dot11txpn[2], pcur_dot11txpn[3], pcur_dot11txpn[4], ++ pcur_dot11txpn[5], pcur_dot11txpn[6], pcur_dot11txpn[7]); ++ } ++} ++void rtw_set_sec_pn(struct adapter *padapter) ++{ ++ struct sta_info *psta; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct security_priv *psecpriv = &padapter->securitypriv; ++ ++ psta = rtw_get_stainfo(&padapter->stapriv, ++ get_my_bssid(&pmlmeinfo->network)); ++ ++ if (psta) ++ { ++ if (pwrpriv->wowlan_fw_iv > psta->dot11txpn.val) ++ { ++ if (psecpriv->dot11PrivacyAlgrthm != _NO_PRIVACY_) ++ psta->dot11txpn.val = pwrpriv->wowlan_fw_iv + 2; ++ } else { ++ DBG_871X("%s(): FW IV is smaller than driver\n", __func__); ++ psta->dot11txpn.val += 2; ++ } ++ DBG_871X("%s: dot11txpn: 0x%016llx\n", __func__ , psta->dot11txpn.val); ++ } ++} ++#endif /* CONFIG_WOWLAN */ ++ ++#ifdef CONFIG_PNO_SUPPORT ++#define CSCAN_TLV_TYPE_SSID_IE 'S' ++#define CIPHER_IE "key_mgmt =" ++#define CIPHER_NONE "NONE" ++#define CIPHER_WPA_PSK "WPA-PSK" ++#define CIPHER_WPA_EAP "WPA-EAP IEEE8021X" ++ ++#endif /* CONFIG_PNO_SUPPORT */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/core/rtw_xmit.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_xmit.c +--- linux-4.3/3rdparty/rtl8723bs/core/rtw_xmit.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/core/rtw_xmit.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,3263 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTW_XMIT_C_ ++ ++#include ++#include ++ ++static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; ++static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; ++ ++static void _init_txservq(struct tx_servq *ptxservq) ++{ ++ INIT_LIST_HEAD(&ptxservq->tx_pending); ++ _rtw_init_queue(&ptxservq->sta_pending); ++ ptxservq->qcnt = 0; ++} ++ ++void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv) ++{ ++ memset((unsigned char *)psta_xmitpriv, 0, sizeof (struct sta_xmit_priv)); ++ ++ spin_lock_init(&psta_xmitpriv->lock); ++ ++ /* for (i = 0 ; i < MAX_NUMBLKS; i++) */ ++ /* _init_txservq(&(psta_xmitpriv->blk_q[i])); */ ++ ++ _init_txservq(&psta_xmitpriv->be_q); ++ _init_txservq(&psta_xmitpriv->bk_q); ++ _init_txservq(&psta_xmitpriv->vi_q); ++ _init_txservq(&psta_xmitpriv->vo_q); ++ INIT_LIST_HEAD(&psta_xmitpriv->legacy_dz); ++ INIT_LIST_HEAD(&psta_xmitpriv->apsd); ++} ++ ++s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) ++{ ++ int i; ++ struct xmit_buf *pxmitbuf; ++ struct xmit_frame *pxframe; ++ sint res = _SUCCESS; ++ ++ /* We don't need to memset padapter->XXX to zero, because adapter is allocated by vzalloc(). */ ++ /* memset((unsigned char *)pxmitpriv, 0, sizeof(struct xmit_priv)); */ ++ ++ spin_lock_init(&pxmitpriv->lock); ++ spin_lock_init(&pxmitpriv->lock_sctx); ++ sema_init(&pxmitpriv->xmit_sema, 0); ++ sema_init(&pxmitpriv->terminate_xmitthread_sema, 0); ++ ++ /* ++ Please insert all the queue initializaiton using _rtw_init_queue below ++ */ ++ ++ pxmitpriv->adapter = padapter; ++ ++ /* for (i = 0 ; i < MAX_NUMBLKS; i++) */ ++ /* _rtw_init_queue(&pxmitpriv->blk_strms[i]); */ ++ ++ _rtw_init_queue(&pxmitpriv->be_pending); ++ _rtw_init_queue(&pxmitpriv->bk_pending); ++ _rtw_init_queue(&pxmitpriv->vi_pending); ++ _rtw_init_queue(&pxmitpriv->vo_pending); ++ _rtw_init_queue(&pxmitpriv->bm_pending); ++ ++ /* _rtw_init_queue(&pxmitpriv->legacy_dz_queue); */ ++ /* _rtw_init_queue(&pxmitpriv->apsd_queue); */ ++ ++ _rtw_init_queue(&pxmitpriv->free_xmit_queue); ++ ++ /* ++ Please allocate memory with the sz = (struct xmit_frame) * NR_XMITFRAME, ++ and initialize free_xmit_frame below. ++ Please also apply free_txobj to link_up all the xmit_frames... ++ */ ++ ++ pxmitpriv->pallocated_frame_buf = vzalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4); ++ ++ if (pxmitpriv->pallocated_frame_buf == NULL) { ++ pxmitpriv->pxmit_frame_buf = NULL; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_frame fail!\n")); ++ res = _FAIL; ++ goto exit; ++ } ++ pxmitpriv->pxmit_frame_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitpriv->pallocated_frame_buf), 4); ++ /* pxmitpriv->pxmit_frame_buf = pxmitpriv->pallocated_frame_buf + 4 - */ ++ /* ((SIZE_PTR) (pxmitpriv->pallocated_frame_buf) &3); */ ++ ++ pxframe = (struct xmit_frame*) pxmitpriv->pxmit_frame_buf; ++ ++ for (i = 0; i < NR_XMITFRAME; i++) ++ { ++ INIT_LIST_HEAD(&(pxframe->list)); ++ ++ pxframe->padapter = padapter; ++ pxframe->frame_tag = NULL_FRAMETAG; ++ ++ pxframe->pkt = NULL; ++ ++ pxframe->buf_addr = NULL; ++ pxframe->pxmitbuf = NULL; ++ ++ list_add_tail(&(pxframe->list), &(pxmitpriv->free_xmit_queue.queue)); ++ ++ pxframe++; ++ } ++ ++ pxmitpriv->free_xmitframe_cnt = NR_XMITFRAME; ++ ++ pxmitpriv->frag_len = MAX_FRAG_THRESHOLD; ++ ++ ++ /* init xmit_buf */ ++ _rtw_init_queue(&pxmitpriv->free_xmitbuf_queue); ++ _rtw_init_queue(&pxmitpriv->pending_xmitbuf_queue); ++ ++ pxmitpriv->pallocated_xmitbuf = vzalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4); ++ ++ if (pxmitpriv->pallocated_xmitbuf == NULL) { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_buf fail!\n")); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pxmitpriv->pxmitbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitpriv->pallocated_xmitbuf), 4); ++ /* pxmitpriv->pxmitbuf = pxmitpriv->pallocated_xmitbuf + 4 - */ ++ /* ((SIZE_PTR) (pxmitpriv->pallocated_xmitbuf) &3); */ ++ ++ pxmitbuf = (struct xmit_buf*)pxmitpriv->pxmitbuf; ++ ++ for (i = 0; i < NR_XMITBUFF; i++) ++ { ++ INIT_LIST_HEAD(&pxmitbuf->list); ++ ++ pxmitbuf->priv_data = NULL; ++ pxmitbuf->padapter = padapter; ++ pxmitbuf->buf_tag = XMITBUF_DATA; ++ ++ /* Tx buf allocation may fail sometimes, so sleep and retry. */ ++ if ((res =rtw_os_xmit_resource_alloc(padapter, pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ), true)) == _FAIL) { ++ msleep(10); ++ res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ), true); ++ if (res == _FAIL) { ++ goto exit; ++ } ++ } ++ ++ pxmitbuf->phead = pxmitbuf->pbuf; ++ pxmitbuf->pend = pxmitbuf->pbuf + MAX_XMITBUF_SZ; ++ pxmitbuf->len = 0; ++ pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; ++ ++ pxmitbuf->flags = XMIT_VO_QUEUE; ++ ++ list_add_tail(&pxmitbuf->list, &(pxmitpriv->free_xmitbuf_queue.queue)); ++ #ifdef DBG_XMIT_BUF ++ pxmitbuf->no =i; ++ #endif ++ ++ pxmitbuf++; ++ ++ } ++ ++ pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF; ++ ++ /* init xframe_ext queue, the same count as extbuf */ ++ _rtw_init_queue(&pxmitpriv->free_xframe_ext_queue); ++ ++ pxmitpriv->xframe_ext_alloc_addr = vzalloc(NR_XMIT_EXTBUFF * sizeof(struct xmit_frame) + 4); ++ ++ if (pxmitpriv->xframe_ext_alloc_addr == NULL) { ++ pxmitpriv->xframe_ext = NULL; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xframe_ext fail!\n")); ++ res = _FAIL; ++ goto exit; ++ } ++ pxmitpriv->xframe_ext = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitpriv->xframe_ext_alloc_addr), 4); ++ pxframe = (struct xmit_frame*)pxmitpriv->xframe_ext; ++ ++ for (i = 0; i < NR_XMIT_EXTBUFF; i++) { ++ INIT_LIST_HEAD(&(pxframe->list)); ++ ++ pxframe->padapter = padapter; ++ pxframe->frame_tag = NULL_FRAMETAG; ++ ++ pxframe->pkt = NULL; ++ ++ pxframe->buf_addr = NULL; ++ pxframe->pxmitbuf = NULL; ++ ++ pxframe->ext_tag = 1; ++ ++ list_add_tail(&(pxframe->list), &(pxmitpriv->free_xframe_ext_queue.queue)); ++ ++ pxframe++; ++ } ++ pxmitpriv->free_xframe_ext_cnt = NR_XMIT_EXTBUFF; ++ ++ /* Init xmit extension buff */ ++ _rtw_init_queue(&pxmitpriv->free_xmit_extbuf_queue); ++ ++ pxmitpriv->pallocated_xmit_extbuf = vzalloc(NR_XMIT_EXTBUFF * sizeof(struct xmit_buf) + 4); ++ ++ if (pxmitpriv->pallocated_xmit_extbuf == NULL) { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_extbuf fail!\n")); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pxmitpriv->pxmit_extbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitpriv->pallocated_xmit_extbuf), 4); ++ ++ pxmitbuf = (struct xmit_buf*)pxmitpriv->pxmit_extbuf; ++ ++ for (i = 0; i < NR_XMIT_EXTBUFF; i++) ++ { ++ INIT_LIST_HEAD(&pxmitbuf->list); ++ ++ pxmitbuf->priv_data = NULL; ++ pxmitbuf->padapter = padapter; ++ pxmitbuf->buf_tag = XMITBUF_MGNT; ++ ++ if ((res =rtw_os_xmit_resource_alloc(padapter, pxmitbuf, MAX_XMIT_EXTBUF_SZ + XMITBUF_ALIGN_SZ, true)) == _FAIL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pxmitbuf->phead = pxmitbuf->pbuf; ++ pxmitbuf->pend = pxmitbuf->pbuf + MAX_XMIT_EXTBUF_SZ; ++ pxmitbuf->len = 0; ++ pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; ++ ++ list_add_tail(&pxmitbuf->list, &(pxmitpriv->free_xmit_extbuf_queue.queue)); ++ #ifdef DBG_XMIT_BUF_EXT ++ pxmitbuf->no =i; ++ #endif ++ pxmitbuf++; ++ ++ } ++ ++ pxmitpriv->free_xmit_extbuf_cnt = NR_XMIT_EXTBUFF; ++ ++ for (i = 0; ipcmd_xmitbuf[i]; ++ if (pxmitbuf) { ++ INIT_LIST_HEAD(&pxmitbuf->list); ++ ++ pxmitbuf->priv_data = NULL; ++ pxmitbuf->padapter = padapter; ++ pxmitbuf->buf_tag = XMITBUF_CMD; ++ ++ if ((res =rtw_os_xmit_resource_alloc(padapter, pxmitbuf, MAX_CMDBUF_SZ+XMITBUF_ALIGN_SZ, true)) == _FAIL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pxmitbuf->phead = pxmitbuf->pbuf; ++ pxmitbuf->pend = pxmitbuf->pbuf + MAX_CMDBUF_SZ; ++ pxmitbuf->len = 0; ++ pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; ++ pxmitbuf->alloc_sz = MAX_CMDBUF_SZ+XMITBUF_ALIGN_SZ; ++ } ++ } ++ ++ rtw_alloc_hwxmits(padapter); ++ rtw_init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); ++ ++ for (i = 0; i < 4; i ++) ++ { ++ pxmitpriv->wmm_para_seq[i] = i; ++ } ++ ++ pxmitpriv->ack_tx = false; ++ mutex_init(&pxmitpriv->ack_tx_mutex); ++ rtw_sctx_init(&pxmitpriv->ack_tx_ops, 0); ++ ++ rtw_hal_init_xmit_priv(padapter); ++ ++exit: ++ return res; ++} ++ ++void _rtw_free_xmit_priv (struct xmit_priv *pxmitpriv) ++{ ++ int i; ++ struct adapter *padapter = pxmitpriv->adapter; ++ struct xmit_frame *pxmitframe = (struct xmit_frame*) pxmitpriv->pxmit_frame_buf; ++ struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; ++ ++ rtw_hal_free_xmit_priv(padapter); ++ ++ if (pxmitpriv->pxmit_frame_buf == NULL) ++ return; ++ ++ for (i = 0; ipallocated_frame_buf) { ++ vfree(pxmitpriv->pallocated_frame_buf); ++ } ++ ++ ++ if (pxmitpriv->pallocated_xmitbuf) { ++ vfree(pxmitpriv->pallocated_xmitbuf); ++ } ++ ++ /* free xframe_ext queue, the same count as extbuf */ ++ if ((pxmitframe = (struct xmit_frame*)pxmitpriv->xframe_ext)) { ++ for (i = 0; ixframe_ext_alloc_addr) ++ vfree(pxmitpriv->xframe_ext_alloc_addr); ++ ++ /* free xmit extension buff */ ++ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; ++ for (i = 0; ipallocated_xmit_extbuf) { ++ vfree(pxmitpriv->pallocated_xmit_extbuf); ++ } ++ ++ for (i = 0; ipcmd_xmitbuf[i]; ++ if (pxmitbuf!= NULL) ++ rtw_os_xmit_resource_free(padapter, pxmitbuf, MAX_CMDBUF_SZ+XMITBUF_ALIGN_SZ , true); ++ } ++ ++ rtw_free_hwxmits(padapter); ++ ++ mutex_destroy(&pxmitpriv->ack_tx_mutex); ++} ++ ++u8 query_ra_short_GI(struct sta_info *psta) ++{ ++ u8 sgi = false, sgi_20m = false, sgi_40m = false, sgi_80m = false; ++ ++ sgi_20m = psta->htpriv.sgi_20m; ++ sgi_40m = psta->htpriv.sgi_40m; ++ ++ switch (psta->bw_mode) { ++ case CHANNEL_WIDTH_80: ++ sgi = sgi_80m; ++ break; ++ case CHANNEL_WIDTH_40: ++ sgi = sgi_40m; ++ break; ++ case CHANNEL_WIDTH_20: ++ default: ++ sgi = sgi_20m; ++ break; ++ } ++ ++ return sgi; ++} ++ ++static void update_attrib_vcs_info(struct adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ u32 sz; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ /* struct sta_info *psta = pattrib->psta; */ ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ if (pattrib->nr_frags != 1) ++ { ++ sz = padapter->xmitpriv.frag_len; ++ } ++ else /* no frag */ ++ { ++ sz = pattrib->last_txcmdsz; ++ } ++ ++ /* (1) RTS_Threshold is compared to the MPDU, not MSDU. */ ++ /* (2) If there are more than one frag in this MSDU, only the first frag uses protection frame. */ ++ /* Other fragments are protected by previous fragment. */ ++ /* So we only need to check the length of first fragment. */ ++ if (pmlmeext->cur_wireless_mode < WIRELESS_11_24N || padapter->registrypriv.wifi_spec) ++ { ++ if (sz > padapter->registrypriv.rts_thresh) ++ { ++ pattrib->vcs_mode = RTS_CTS; ++ } ++ else ++ { ++ if (pattrib->rtsen) ++ pattrib->vcs_mode = RTS_CTS; ++ else if (pattrib->cts2self) ++ pattrib->vcs_mode = CTS_TO_SELF; ++ else ++ pattrib->vcs_mode = NONE_VCS; ++ } ++ } ++ else ++ { ++ while (true) ++ { ++ /* IOT action */ ++ if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS) && (pattrib->ampdu_en ==true) && ++ (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) ++ { ++ pattrib->vcs_mode = CTS_TO_SELF; ++ break; ++ } ++ ++ ++ /* check ERP protection */ ++ if (pattrib->rtsen || pattrib->cts2self) ++ { ++ if (pattrib->rtsen) ++ pattrib->vcs_mode = RTS_CTS; ++ else if (pattrib->cts2self) ++ pattrib->vcs_mode = CTS_TO_SELF; ++ ++ break; ++ } ++ ++ /* check HT op mode */ ++ if (pattrib->ht_en) ++ { ++ u8 HTOpMode = pmlmeinfo->HT_protection; ++ if ((pmlmeext->cur_bwmode && (HTOpMode == 2 || HTOpMode == 3)) || ++ (!pmlmeext->cur_bwmode && HTOpMode == 3)) ++ { ++ pattrib->vcs_mode = RTS_CTS; ++ break; ++ } ++ } ++ ++ /* check rts */ ++ if (sz > padapter->registrypriv.rts_thresh) ++ { ++ pattrib->vcs_mode = RTS_CTS; ++ break; ++ } ++ ++ /* to do list: check MIMO power save condition. */ ++ ++ /* check AMPDU aggregation for TXOP */ ++ if (pattrib->ampdu_en ==true) ++ { ++ pattrib->vcs_mode = RTS_CTS; ++ break; ++ } ++ ++ pattrib->vcs_mode = NONE_VCS; ++ break; ++ } ++ } ++ ++ /* for debug : force driver control vrtl_carrier_sense. */ ++ if (padapter->driver_vcs_en == 1) ++ pattrib->vcs_mode = padapter->driver_vcs_type; ++} ++ ++static void update_attrib_phy_info(struct adapter *padapter, struct pkt_attrib *pattrib, struct sta_info *psta) ++{ ++ struct mlme_ext_priv *mlmeext = &padapter->mlmeextpriv; ++ ++ pattrib->rtsen = psta->rtsen; ++ pattrib->cts2self = psta->cts2self; ++ ++ pattrib->mdata = 0; ++ pattrib->eosp = 0; ++ pattrib->triggered = 0; ++ pattrib->ampdu_spacing = 0; ++ ++ /* qos_en, ht_en, init rate, , bw, ch_offset, sgi */ ++ pattrib->qos_en = psta->qos_option; ++ ++ pattrib->raid = psta->raid; ++ ++ if (mlmeext->cur_bwmode < psta->bw_mode) ++ pattrib->bwmode = mlmeext->cur_bwmode; ++ else ++ pattrib->bwmode = psta->bw_mode; ++ ++ pattrib->sgi = query_ra_short_GI(psta); ++ ++ pattrib->ldpc = psta->ldpc; ++ pattrib->stbc = psta->stbc; ++ ++ pattrib->ht_en = psta->htpriv.ht_option; ++ pattrib->ch_offset = psta->htpriv.ch_offset; ++ pattrib->ampdu_en = false; ++ ++ if (padapter->driver_ampdu_spacing != 0xFF) /* driver control AMPDU Density for peer sta's rx */ ++ pattrib->ampdu_spacing = padapter->driver_ampdu_spacing; ++ else ++ pattrib->ampdu_spacing = psta->htpriv.rx_ampdu_min_spacing; ++ ++ /* if (pattrib->ht_en && psta->htpriv.ampdu_enable) */ ++ /* */ ++ /* if (psta->htpriv.agg_enable_bitmap & BIT(pattrib->priority)) */ ++ /* pattrib->ampdu_en = true; */ ++ /* */ ++ ++ ++ pattrib->retry_ctrl = false; ++ ++#ifdef CONFIG_AUTO_AP_MODE ++ if (psta->isrc && psta->pid>0) ++ pattrib->pctrl = true; ++#endif ++ ++} ++ ++static s32 update_attrib_sec_info(struct adapter *padapter, struct pkt_attrib *pattrib, struct sta_info *psta) ++{ ++ sint res = _SUCCESS; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ sint bmcast = IS_MCAST(pattrib->ra); ++ ++ memset(pattrib->dot118021x_UncstKey.skey, 0, 16); ++ memset(pattrib->dot11tkiptxmickey.skey, 0, 16); ++ pattrib->mac_id = psta->mac_id; ++ ++ if (psta->ieee8021x_blocked == true) ++ { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("\n psta->ieee8021x_blocked == true\n")); ++ ++ pattrib->encrypt = 0; ++ ++ if ((pattrib->ether_type != 0x888e) && (check_fwstate(pmlmepriv, WIFI_MP_STATE) == false)) ++ { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("\npsta->ieee8021x_blocked == true, pattrib->ether_type(%.4x) != 0x888e\n", pattrib->ether_type)); ++ #ifdef DBG_TX_DROP_FRAME ++ DBG_871X("DBG_TX_DROP_FRAME %s psta->ieee8021x_blocked == true, pattrib->ether_type(%04x) != 0x888e\n", __func__, pattrib->ether_type); ++ #endif ++ res = _FAIL; ++ goto exit; ++ } ++ } ++ else ++ { ++ GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast); ++ ++ switch (psecuritypriv->dot11AuthAlgrthm) ++ { ++ case dot11AuthAlgrthm_Open: ++ case dot11AuthAlgrthm_Shared: ++ case dot11AuthAlgrthm_Auto: ++ pattrib->key_idx = (u8)psecuritypriv->dot11PrivacyKeyIndex; ++ break; ++ case dot11AuthAlgrthm_8021X: ++ if (bmcast) ++ pattrib->key_idx = (u8)psecuritypriv->dot118021XGrpKeyid; ++ else ++ pattrib->key_idx = 0; ++ break; ++ default: ++ pattrib->key_idx = 0; ++ break; ++ } ++ ++ /* For WPS 1.0 WEP, driver should not encrypt EAPOL Packet for WPS handshake. */ ++ if (((pattrib->encrypt == _WEP40_)||(pattrib->encrypt == _WEP104_)) && (pattrib->ether_type == 0x888e)) ++ pattrib->encrypt = _NO_PRIVACY_; ++ ++ } ++ ++ switch (pattrib->encrypt) ++ { ++ case _WEP40_: ++ case _WEP104_: ++ pattrib->iv_len = 4; ++ pattrib->icv_len = 4; ++ WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); ++ break; ++ ++ case _TKIP_: ++ pattrib->iv_len = 8; ++ pattrib->icv_len = 4; ++ ++ if (psecuritypriv->busetkipkey == _FAIL) ++ { ++ #ifdef DBG_TX_DROP_FRAME ++ DBG_871X("DBG_TX_DROP_FRAME %s psecuritypriv->busetkipkey(%d) == _FAIL drop packet\n", __func__, psecuritypriv->busetkipkey); ++ #endif ++ res = _FAIL; ++ goto exit; ++ } ++ ++ if (bmcast) ++ TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); ++ else ++ TKIP_IV(pattrib->iv, psta->dot11txpn, 0); ++ ++ ++ memcpy(pattrib->dot11tkiptxmickey.skey, psta->dot11tkiptxmickey.skey, 16); ++ ++ break; ++ ++ case _AES_: ++ ++ pattrib->iv_len = 8; ++ pattrib->icv_len = 8; ++ ++ if (bmcast) ++ AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); ++ else ++ AES_IV(pattrib->iv, psta->dot11txpn, 0); ++ ++ break; ++ ++ default: ++ pattrib->iv_len = 0; ++ pattrib->icv_len = 0; ++ break; ++ } ++ ++ if (pattrib->encrypt>0) ++ memcpy(pattrib->dot118021x_UncstKey.skey, psta->dot118021x_UncstKey.skey, 16); ++ ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ++ ("update_attrib: encrypt =%d securitypriv.sw_encrypt =%d\n", ++ pattrib->encrypt, padapter->securitypriv.sw_encrypt)); ++ ++ if (pattrib->encrypt && ++ ((padapter->securitypriv.sw_encrypt == true) || (psecuritypriv->hw_decrypted == false))) ++ { ++ pattrib->bswenc = true; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ++ ("update_attrib: encrypt =%d securitypriv.hw_decrypted =%d bswenc =true\n", ++ pattrib->encrypt, padapter->securitypriv.sw_encrypt)); ++ } else { ++ pattrib->bswenc = false; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("update_attrib: bswenc =false\n")); ++ } ++ ++exit: ++ ++ return res; ++ ++} ++ ++u8 qos_acm(u8 acm_mask, u8 priority) ++{ ++ u8 change_priority = priority; ++ ++ switch (priority) ++ { ++ case 0: ++ case 3: ++ if (acm_mask & BIT(1)) ++ change_priority = 1; ++ break; ++ case 1: ++ case 2: ++ break; ++ case 4: ++ case 5: ++ if (acm_mask & BIT(2)) ++ change_priority = 0; ++ break; ++ case 6: ++ case 7: ++ if (acm_mask & BIT(3)) ++ change_priority = 5; ++ break; ++ default: ++ DBG_871X("qos_acm(): invalid pattrib->priority: %d!!!\n", priority); ++ break; ++ } ++ ++ return change_priority; ++} ++ ++static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib) ++{ ++ struct ethhdr etherhdr; ++ struct iphdr ip_hdr; ++ s32 UserPriority = 0; ++ ++ ++ _rtw_open_pktfile(ppktfile->pkt, ppktfile); ++ _rtw_pktfile_read(ppktfile, (unsigned char*)ðerhdr, ETH_HLEN); ++ ++ /* get UserPriority from IP hdr */ ++ if (pattrib->ether_type == 0x0800) { ++ _rtw_pktfile_read(ppktfile, (u8 *)&ip_hdr, sizeof(ip_hdr)); ++/* UserPriority = (ntohs(ip_hdr.tos) >> 5) & 0x3; */ ++ UserPriority = ip_hdr.tos >> 5; ++ } ++ pattrib->priority = UserPriority; ++ pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN; ++ pattrib->subtype = WIFI_QOS_DATA_TYPE; ++} ++ ++static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib *pattrib) ++{ ++ uint i; ++ struct pkt_file pktfile; ++ struct sta_info *psta = NULL; ++ struct ethhdr etherhdr; ++ ++ sint bmcast; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct qos_priv *pqospriv = &pmlmepriv->qospriv; ++ sint res = _SUCCESS; ++ ++ DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib); ++ ++ _rtw_open_pktfile(pkt, &pktfile); ++ i = _rtw_pktfile_read(&pktfile, (u8 *)ðerhdr, ETH_HLEN); ++ ++ pattrib->ether_type = ntohs(etherhdr.h_proto); ++ ++ ++ memcpy(pattrib->dst, ðerhdr.h_dest, ETH_ALEN); ++ memcpy(pattrib->src, ðerhdr.h_source, ETH_ALEN); ++ ++ ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { ++ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); ++ memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_adhoc); ++ } ++ else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { ++ memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); ++ memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_sta); ++ } ++ else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); ++ memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN); ++ DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_ap); ++ } ++ else ++ DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_unknown); ++ ++ pattrib->pktlen = pktfile.pkt_len; ++ ++ if (ETH_P_IP == pattrib->ether_type) ++ { ++ /* The following is for DHCP and ARP packet, we use cck1M to tx these packets and let LPS awake some time */ ++ /* to prevent DHCP protocol fail */ ++ ++ u8 tmp[24]; ++ ++ _rtw_pktfile_read(&pktfile, &tmp[0], 24); ++ ++ pattrib->dhcp_pkt = 0; ++ if (pktfile.pkt_len > 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */ ++ if (ETH_P_IP == pattrib->ether_type) {/* IP header */ ++ if (((tmp[21] == 68) && (tmp[23] == 67)) || ++ ((tmp[21] == 67) && (tmp[23] == 68))) { ++ /* 68 : UDP BOOTP client */ ++ /* 67 : UDP BOOTP server */ ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("======================update_attrib: get DHCP Packet\n")); ++ pattrib->dhcp_pkt = 1; ++ DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_dhcp); ++ } ++ } ++ } ++ ++ /* for parsing ICMP pakcets */ ++ { ++ struct iphdr *piphdr = (struct iphdr *)tmp; ++ ++ pattrib->icmp_pkt = 0; ++ if (piphdr->protocol == 0x1) /* protocol type in ip header 0x1 is ICMP */ ++ { ++ pattrib->icmp_pkt = 1; ++ DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_icmp); ++ } ++ } ++ ++ ++ } else if (0x888e == pattrib->ether_type) { ++ DBG_871X_LEVEL(_drv_always_, "send eapol packet\n"); ++ } ++ ++ if ((pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1)) ++ { ++ rtw_set_scan_deny(padapter, 3000); ++ } ++ ++ /* If EAPOL , ARP , OR DHCP packet, driver must be in active mode. */ ++ if (pattrib->icmp_pkt == 1) ++ { ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_LEAVE, 1); ++ } ++ else if (pattrib->dhcp_pkt == 1) ++ { ++ DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_active); ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SPECIAL_PACKET, 1); ++ } ++ ++ bmcast = IS_MCAST(pattrib->ra); ++ ++ /* get sta_info */ ++ if (bmcast) { ++ psta = rtw_get_bcmc_stainfo(padapter); ++ } else { ++ psta = rtw_get_stainfo(pstapriv, pattrib->ra); ++ if (psta == NULL) { /* if we cannot get psta => drop the pkt */ ++ DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_ucast_sta); ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:" MAC_FMT"\n", MAC_ARG(pattrib->ra))); ++ #ifdef DBG_TX_DROP_FRAME ++ DBG_871X("DBG_TX_DROP_FRAME %s get sta_info fail, ra:" MAC_FMT"\n", __func__, MAC_ARG(pattrib->ra)); ++ #endif ++ res = _FAIL; ++ goto exit; ++ } ++ else if ((check_fwstate(pmlmepriv, WIFI_AP_STATE) ==true) && (!(psta->state & _FW_LINKED))) ++ { ++ DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_ucast_ap_link); ++ res = _FAIL; ++ goto exit; ++ } ++ } ++ ++ if (psta == NULL) ++ { /* if we cannot get psta => drop the pkt */ ++ DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_sta); ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:" MAC_FMT "\n", MAC_ARG(pattrib->ra))); ++ #ifdef DBG_TX_DROP_FRAME ++ DBG_871X("DBG_TX_DROP_FRAME %s get sta_info fail, ra:" MAC_FMT"\n", __func__, MAC_ARG(pattrib->ra)); ++ #endif ++ res = _FAIL; ++ goto exit; ++ } ++ ++ if (!(psta->state &_FW_LINKED)) ++ { ++ DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_link); ++ DBG_871X("%s, psta("MAC_FMT")->state(0x%x) != _FW_LINKED\n", __func__, MAC_ARG(psta->hwaddr), psta->state); ++ return _FAIL; ++ } ++ ++ ++ ++ /* TODO:_lock */ ++ if (update_attrib_sec_info(padapter, pattrib, psta) == _FAIL) ++ { ++ DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_sec); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ update_attrib_phy_info(padapter, pattrib, psta); ++ ++ /* DBG_8192C("%s ==> mac_id(%d)\n", __func__, pattrib->mac_id); */ ++ ++ pattrib->psta = psta; ++ /* TODO:_unlock */ ++ ++ pattrib->pctrl = 0; ++ ++ pattrib->ack_policy = 0; ++ /* get ether_hdr_len */ ++ pattrib->pkt_hdrlen = ETH_HLEN;/* pattrib->ether_type == 0x8100) ? (14 + 4): 14; vlan tag */ ++ ++ pattrib->hdrlen = WLAN_HDR_A3_LEN; ++ pattrib->subtype = WIFI_DATA_TYPE; ++ pattrib->priority = 0; ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE|WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) ++ { ++ if (pattrib->qos_en) ++ set_qos(&pktfile, pattrib); ++ } ++ else ++ { ++ if (pqospriv->qos_option) ++ { ++ set_qos(&pktfile, pattrib); ++ ++ if (pmlmepriv->acm_mask != 0) ++ { ++ pattrib->priority = qos_acm(pmlmepriv->acm_mask, pattrib->priority); ++ } ++ } ++ } ++ ++ /* pattrib->priority = 5; force to used VI queue, for testing */ ++ ++ rtw_set_tx_chksum_offload(pkt, pattrib); ++ ++exit: ++ return res; ++} ++ ++static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitframe) { ++ sint curfragnum, length; ++ u8 *pframe, *payload, mic[8]; ++ struct mic_data micdata; ++ /* struct sta_info *stainfo; */ ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct security_priv *psecuritypriv =&padapter->securitypriv; ++ struct xmit_priv *pxmitpriv =&padapter->xmitpriv; ++ u8 priority[4]={0x0, 0x0, 0x0, 0x0}; ++ u8 hw_hdr_offset = 0; ++ sint bmcst = IS_MCAST(pattrib->ra); ++ ++/* ++ if (pattrib->psta) ++ { ++ stainfo = pattrib->psta; ++ } ++ else ++ { ++ DBG_871X("%s, call rtw_get_stainfo()\n", __func__); ++ stainfo =rtw_get_stainfo(&padapter->stapriv ,&pattrib->ra[0]); ++ } ++ ++ if (stainfo == NULL) ++ { ++ DBG_871X("%s, psta ==NUL\n", __func__); ++ return _FAIL; ++ } ++ ++ if (!(stainfo->state &_FW_LINKED)) ++ { ++ DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, stainfo->state); ++ return _FAIL; ++ } ++*/ ++ ++ hw_hdr_offset = TXDESC_OFFSET; ++ ++ if (pattrib->encrypt == _TKIP_)/* if (psecuritypriv->dot11PrivacyAlgrthm == _TKIP_PRIVACY_) */ ++ { ++ /* encode mic code */ ++ /* if (stainfo!= NULL) */ ++ { ++ u8 null_key[16]={0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; ++ ++ pframe = pxmitframe->buf_addr + hw_hdr_offset; ++ ++ if (bmcst) ++ { ++ if (!memcmp(psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey, null_key, 16)) { ++ /* DbgPrint("\nxmitframe_addmic:stainfo->dot11tkiptxmickey == 0\n"); */ ++ /* msleep(10); */ ++ return _FAIL; ++ } ++ /* start to calculate the mic code */ ++ rtw_secmicsetkey(&micdata, psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey); ++ } ++ else ++ { ++ if (!memcmp(&pattrib->dot11tkiptxmickey.skey[0], null_key, 16)) { ++ /* DbgPrint("\nxmitframe_addmic:stainfo->dot11tkiptxmickey == 0\n"); */ ++ /* msleep(10); */ ++ return _FAIL; ++ } ++ /* start to calculate the mic code */ ++ rtw_secmicsetkey(&micdata, &pattrib->dot11tkiptxmickey.skey[0]); ++ } ++ ++ if (pframe[1]&1) { /* ToDS == 1 */ ++ rtw_secmicappend(&micdata, &pframe[16], 6); /* DA */ ++ if (pframe[1]&2) /* From Ds == 1 */ ++ rtw_secmicappend(&micdata, &pframe[24], 6); ++ else ++ rtw_secmicappend(&micdata, &pframe[10], 6); ++ } ++ else { /* ToDS == 0 */ ++ rtw_secmicappend(&micdata, &pframe[4], 6); /* DA */ ++ if (pframe[1]&2) /* From Ds == 1 */ ++ rtw_secmicappend(&micdata, &pframe[16], 6); ++ else ++ rtw_secmicappend(&micdata, &pframe[10], 6); ++ ++ } ++ ++ /* if (pqospriv->qos_option == 1) */ ++ if (pattrib->qos_en) ++ priority[0]=(u8)pxmitframe->attrib.priority; ++ ++ ++ rtw_secmicappend(&micdata, &priority[0], 4); ++ ++ payload =pframe; ++ ++ for (curfragnum = 0;curfragnumnr_frags;curfragnum++) { ++ payload =(u8 *)RND4((SIZE_PTR)(payload)); ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("===curfragnum =%d, pframe = 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x,!!!\n", ++ curfragnum,*payload, *(payload+1),*(payload+2),*(payload+3),*(payload+4),*(payload+5),*(payload+6),*(payload+7))); ++ ++ payload =payload+pattrib->hdrlen+pattrib->iv_len; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("curfragnum =%d pattrib->hdrlen =%d pattrib->iv_len =%d", curfragnum, pattrib->hdrlen, pattrib->iv_len)); ++ if ((curfragnum+1) ==pattrib->nr_frags) { ++ length =pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-((pattrib->bswenc) ? pattrib->icv_len : 0); ++ rtw_secmicappend(&micdata, payload, length); ++ payload =payload+length; ++ } ++ else { ++ length =pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-((pattrib->bswenc) ? pattrib->icv_len : 0); ++ rtw_secmicappend(&micdata, payload, length); ++ payload =payload+length+pattrib->icv_len; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("curfragnum =%d length =%d pattrib->icv_len =%d", curfragnum, length, pattrib->icv_len)); ++ } ++ } ++ rtw_secgetmic(&micdata,&(mic[0])); ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: before add mic code!!!\n")); ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: pattrib->last_txcmdsz =%d!!!\n", pattrib->last_txcmdsz)); ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: mic[0]= 0x%.2x , mic[1]= 0x%.2x , mic[2]= 0x%.2x , mic[3]= 0x%.2x\n\ ++ mic[4]= 0x%.2x , mic[5]= 0x%.2x , mic[6]= 0x%.2x , mic[7]= 0x%.2x !!!!\n", ++ mic[0], mic[1], mic[2], mic[3], mic[4], mic[5], mic[6], mic[7])); ++ /* add mic code and add the mic code length in last_txcmdsz */ ++ ++ memcpy(payload, &(mic[0]), 8); ++ pattrib->last_txcmdsz+=8; ++ ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("\n ========last pkt ========\n")); ++ payload =payload-pattrib->last_txcmdsz+8; ++ for (curfragnum = 0;curfragnumlast_txcmdsz;curfragnum =curfragnum+8) ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, (" %.2x, %.2x, %.2x, %.2x, %.2x, %.2x, %.2x, %.2x ", ++ *(payload+curfragnum), *(payload+curfragnum+1), *(payload+curfragnum+2),*(payload+curfragnum+3), ++ *(payload+curfragnum+4),*(payload+curfragnum+5),*(payload+curfragnum+6),*(payload+curfragnum+7))); ++ } ++/* ++ else { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: rtw_get_stainfo == NULL!!!\n")); ++ } ++*/ ++ } ++ return _SUCCESS; ++} ++ ++static s32 xmitframe_swencrypt(struct adapter *padapter, struct xmit_frame *pxmitframe) { ++ ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ /* struct security_priv *psecuritypriv =&padapter->securitypriv; */ ++ ++ /* if ((psecuritypriv->sw_encrypt)||(pattrib->bswenc)) */ ++ if (pattrib->bswenc) ++ { ++ /* DBG_871X("start xmitframe_swencrypt\n"); */ ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("### xmitframe_swencrypt\n")); ++ switch (pattrib->encrypt) { ++ case _WEP40_: ++ case _WEP104_: ++ rtw_wep_encrypt(padapter, (u8 *)pxmitframe); ++ break; ++ case _TKIP_: ++ rtw_tkip_encrypt(padapter, (u8 *)pxmitframe); ++ break; ++ case _AES_: ++ rtw_aes_encrypt(padapter, (u8 *)pxmitframe); ++ break; ++ default: ++ break; ++ } ++ ++ } else { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_, ("### xmitframe_hwencrypt\n")); ++ } ++ return _SUCCESS; ++} ++ ++s32 rtw_make_wlanhdr (struct adapter *padapter , u8 *hdr, struct pkt_attrib *pattrib) ++{ ++ u16 *qc; ++ ++ struct ieee80211_hdr *pwlanhdr = (struct ieee80211_hdr *)hdr; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct qos_priv *pqospriv = &pmlmepriv->qospriv; ++ u8 qos_option = false; ++ sint res = _SUCCESS; ++ __le16 *fctrl = &pwlanhdr->frame_control; ++ ++ memset(hdr, 0, WLANHDR_OFFSET); ++ ++ SetFrameSubType(fctrl, pattrib->subtype); ++ ++ if (pattrib->subtype & WIFI_DATA_TYPE) ++ { ++ if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true)) { ++ /* to_ds = 1, fr_ds = 0; */ ++ ++ { ++ /* 1.Data transfer to AP */ ++ /* 2.Arp pkt will relayed by AP */ ++ SetToDs(fctrl); ++ memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN); ++ } ++ ++ if (pqospriv->qos_option) ++ qos_option = true; ++ ++ } ++ else if ((check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)) { ++ /* to_ds = 0, fr_ds = 1; */ ++ SetFrDs(fctrl); ++ memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN); ++ ++ if (pattrib->qos_en) ++ qos_option = true; ++ } ++ else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { ++ memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN); ++ ++ if (pattrib->qos_en) ++ qos_option = true; ++ } ++ else { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("fw_state:%x is not allowed to xmit frame\n", get_fwstate(pmlmepriv))); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ if (pattrib->mdata) ++ SetMData(fctrl); ++ ++ if (pattrib->encrypt) ++ SetPrivacy(fctrl); ++ ++ if (qos_option) ++ { ++ qc = (unsigned short *)(hdr + pattrib->hdrlen - 2); ++ ++ if (pattrib->priority) ++ SetPriority(qc, pattrib->priority); ++ ++ SetEOSP(qc, pattrib->eosp); ++ ++ SetAckpolicy(qc, pattrib->ack_policy); ++ } ++ ++ /* TODO: fill HT Control Field */ ++ ++ /* Update Seq Num will be handled by f/w */ ++ { ++ struct sta_info *psta; ++ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); ++ if (pattrib->psta != psta) ++ { ++ DBG_871X("%s, pattrib->psta(%p) != psta(%p)\n", __func__, pattrib->psta, psta); ++ return _FAIL; ++ } ++ ++ if (psta == NULL) ++ { ++ DBG_871X("%s, psta ==NUL\n", __func__); ++ return _FAIL; ++ } ++ ++ if (!(psta->state &_FW_LINKED)) ++ { ++ DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); ++ return _FAIL; ++ } ++ ++ ++ if (psta) ++ { ++ psta->sta_xmitpriv.txseq_tid[pattrib->priority]++; ++ psta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF; ++ pattrib->seqnum = psta->sta_xmitpriv.txseq_tid[pattrib->priority]; ++ ++ SetSeqNum(hdr, pattrib->seqnum); ++ ++ /* check if enable ampdu */ ++ if (pattrib->ht_en && psta->htpriv.ampdu_enable) ++ { ++ if (psta->htpriv.agg_enable_bitmap & BIT(pattrib->priority)) ++ pattrib->ampdu_en = true; ++ } ++ ++ /* re-check if enable ampdu by BA_starting_seqctrl */ ++ if (pattrib->ampdu_en == true) ++ { ++ u16 tx_seq; ++ ++ tx_seq = psta->BA_starting_seqctrl[pattrib->priority & 0x0f]; ++ ++ /* check BA_starting_seqctrl */ ++ if (SN_LESS(pattrib->seqnum, tx_seq)) ++ { ++ /* DBG_871X("tx ampdu seqnum(%d) < tx_seq(%d)\n", pattrib->seqnum, tx_seq); */ ++ pattrib->ampdu_en = false;/* AGG BK */ ++ } ++ else if (SN_EQUAL(pattrib->seqnum, tx_seq)) ++ { ++ psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (tx_seq+1)&0xfff; ++ ++ pattrib->ampdu_en = true;/* AGG EN */ ++ } ++ else ++ { ++ /* DBG_871X("tx ampdu over run\n"); */ ++ psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (pattrib->seqnum+1)&0xfff; ++ pattrib->ampdu_en = true;/* AGG EN */ ++ } ++ ++ } ++ } ++ } ++ ++ } ++ else ++ { ++ ++ } ++ ++exit: ++ return res; ++} ++ ++s32 rtw_txframes_pending(struct adapter *padapter) ++{ ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ return ((!list_empty(&pxmitpriv->be_pending.queue)) || ++ (!list_empty(&pxmitpriv->bk_pending.queue)) || ++ (!list_empty(&pxmitpriv->vi_pending.queue)) || ++ (!list_empty(&pxmitpriv->vo_pending.queue))); ++} ++ ++/* ++ * Calculate wlan 802.11 packet MAX size from pkt_attrib ++ * This function doesn't consider fragment case ++ */ ++u32 rtw_calculate_wlan_pkt_size_by_attribue(struct pkt_attrib *pattrib) ++{ ++ u32 len = 0; ++ ++ len = pattrib->hdrlen + pattrib->iv_len; /* WLAN Header and IV */ ++ len += SNAP_SIZE + sizeof(u16); /* LLC */ ++ len += pattrib->pktlen; ++ if (pattrib->encrypt == _TKIP_) len += 8; /* MIC */ ++ len += ((pattrib->bswenc) ? pattrib->icv_len : 0); /* ICV */ ++ ++ return len; ++} ++ ++/* ++ ++This sub-routine will perform all the following: ++ ++1. remove 802.3 header. ++2. create wlan_header, based on the info in pxmitframe ++3. append sta's iv/ext-iv ++4. append LLC ++5. move frag chunk from pframe to pxmitframe->mem ++6. apply sw-encrypt, if necessary. ++ ++*/ ++s32 rtw_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_frame *pxmitframe) ++{ ++ struct pkt_file pktfile; ++ ++ s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz; ++ ++ SIZE_PTR addr; ++ ++ u8 *pframe, *mem_start; ++ u8 hw_hdr_offset; ++ ++ /* struct sta_info *psta; */ ++ /* struct sta_priv *pstapriv = &padapter->stapriv; */ ++ /* struct mlme_priv *pmlmepriv = &padapter->mlmepriv; */ ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ ++ u8 *pbuf_start; ++ ++ s32 bmcst = IS_MCAST(pattrib->ra); ++ s32 res = _SUCCESS; ++ ++/* ++ if (pattrib->psta) ++ { ++ psta = pattrib->psta; ++ } else ++ { ++ DBG_871X("%s, call rtw_get_stainfo()\n", __func__); ++ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); ++ } ++ ++ if (psta == NULL) ++ { ++ ++ DBG_871X("%s, psta ==NUL\n", __func__); ++ return _FAIL; ++ } ++ ++ ++ if (!(psta->state &_FW_LINKED)) ++ { ++ DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); ++ return _FAIL; ++ } ++*/ ++ if (pxmitframe->buf_addr == NULL) { ++ DBG_8192C("==> %s buf_addr == NULL\n", __func__); ++ return _FAIL; ++ } ++ ++ pbuf_start = pxmitframe->buf_addr; ++ ++ hw_hdr_offset = TXDESC_OFFSET; ++ mem_start = pbuf_start + hw_hdr_offset; ++ ++ if (rtw_make_wlanhdr(padapter, mem_start, pattrib) == _FAIL) { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n")); ++ DBG_8192C("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n"); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ _rtw_open_pktfile(pkt, &pktfile); ++ _rtw_pktfile_read(&pktfile, NULL, pattrib->pkt_hdrlen); ++ ++ frg_inx = 0; ++ frg_len = pxmitpriv->frag_len - 4;/* 2346-4 = 2342 */ ++ ++ while (1) ++ { ++ llc_sz = 0; ++ ++ mpdu_len = frg_len; ++ ++ pframe = mem_start; ++ ++ SetMFrag(mem_start); ++ ++ pframe += pattrib->hdrlen; ++ mpdu_len -= pattrib->hdrlen; ++ ++ /* adding icv, if necessary... */ ++ if (pattrib->iv_len) ++ { ++ memcpy(pframe, pattrib->iv, pattrib->iv_len); ++ ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_, ++ ("rtw_xmitframe_coalesce: keyid =%d pattrib->iv[3]=%.2x pframe =%.2x %.2x %.2x %.2x\n", ++ padapter->securitypriv.dot11PrivacyKeyIndex, pattrib->iv[3], *pframe, *(pframe+1), *(pframe+2), *(pframe+3))); ++ ++ pframe += pattrib->iv_len; ++ ++ mpdu_len -= pattrib->iv_len; ++ } ++ ++ if (frg_inx == 0) { ++ llc_sz = rtw_put_snap(pframe, pattrib->ether_type); ++ pframe += llc_sz; ++ mpdu_len -= llc_sz; ++ } ++ ++ if ((pattrib->icv_len >0) && (pattrib->bswenc)) { ++ mpdu_len -= pattrib->icv_len; ++ } ++ ++ ++ if (bmcst) { ++ /* don't do fragment to broadcat/multicast packets */ ++ mem_sz = _rtw_pktfile_read(&pktfile, pframe, pattrib->pktlen); ++ } else { ++ mem_sz = _rtw_pktfile_read(&pktfile, pframe, mpdu_len); ++ } ++ ++ pframe += mem_sz; ++ ++ if ((pattrib->icv_len >0) && (pattrib->bswenc)) { ++ memcpy(pframe, pattrib->icv, pattrib->icv_len); ++ pframe += pattrib->icv_len; ++ } ++ ++ frg_inx++; ++ ++ if (bmcst || (rtw_endofpktfile(&pktfile) == true)) ++ { ++ pattrib->nr_frags = frg_inx; ++ ++ pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->iv_len + ((pattrib->nr_frags == 1)? llc_sz:0) + ++ ((pattrib->bswenc) ? pattrib->icv_len : 0) + mem_sz; ++ ++ ClearMFrag(mem_start); ++ ++ break; ++ } else { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: There're still something in packet!\n", __func__)); ++ } ++ ++ addr = (SIZE_PTR)(pframe); ++ ++ mem_start = (unsigned char *)RND4(addr) + hw_hdr_offset; ++ memcpy(mem_start, pbuf_start + hw_hdr_offset, pattrib->hdrlen); ++ ++ } ++ ++ if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) ++ { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n")); ++ DBG_8192C("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n"); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ xmitframe_swencrypt(padapter, pxmitframe); ++ ++ if (bmcst == false) ++ update_attrib_vcs_info(padapter, pxmitframe); ++ else ++ pattrib->vcs_mode = NONE_VCS; ++ ++exit: ++ return res; ++} ++ ++/* broadcast or multicast management pkt use BIP, unicast management pkt use CCMP encryption */ ++s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_frame *pxmitframe) ++{ ++ u8 *pframe, *mem_start = NULL, *tmp_buf = NULL; ++ u8 subtype ; ++ struct sta_info *psta = NULL; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ s32 bmcst = IS_MCAST(pattrib->ra); ++ u8 *BIP_AAD = NULL; ++ u8 *MGMT_body = NULL; ++ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ieee80211_hdr *pwlanhdr; ++ u8 MME[_MME_IE_LENGTH_]; ++ u32 ori_len; ++ mem_start = pframe = (u8 *)(pxmitframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ ++ ori_len = BIP_AAD_SIZE+pattrib->pktlen; ++ tmp_buf = BIP_AAD = rtw_zmalloc(ori_len); ++ subtype = GetFrameSubType(pframe); /* bit(7)~bit(2) */ ++ ++ if (BIP_AAD == NULL) ++ return _FAIL; ++ ++ spin_lock_bh(&padapter->security_key_mutex); ++ ++ /* only support station mode */ ++ if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE) || !check_fwstate(pmlmepriv, _FW_LINKED)) ++ goto xmitframe_coalesce_success; ++ ++ /* IGTK key is not install, it may not support 802.11w */ ++ if (padapter->securitypriv.binstallBIPkey != true) ++ { ++ DBG_871X("no instll BIP key\n"); ++ goto xmitframe_coalesce_success; ++ } ++ /* station mode doesn't need TX BIP, just ready the code */ ++ if (bmcst) ++ { ++ int frame_body_len; ++ u8 mic[16]; ++ ++ memset(MME, 0, 18); ++ ++ /* other types doesn't need the BIP */ ++ if (GetFrameSubType(pframe) != WIFI_DEAUTH && GetFrameSubType(pframe) != WIFI_DISASSOC) ++ goto xmitframe_coalesce_fail; ++ ++ MGMT_body = pframe + sizeof(struct ieee80211_hdr_3addr); ++ pframe += pattrib->pktlen; ++ ++ /* octent 0 and 1 is key index , BIP keyid is 4 or 5, LSB only need octent 0 */ ++ MME[0]=padapter->securitypriv.dot11wBIPKeyid; ++ /* copy packet number */ ++ memcpy(&MME[2], &pmlmeext->mgnt_80211w_IPN, 6); ++ /* increase the packet number */ ++ pmlmeext->mgnt_80211w_IPN++; ++ ++ /* add MME IE with MIC all zero, MME string doesn't include element id and length */ ++ pframe = rtw_set_ie(pframe, _MME_IE_ , 16 , MME, &(pattrib->pktlen)); ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ /* total frame length - header length */ ++ frame_body_len = pattrib->pktlen - sizeof(struct ieee80211_hdr_3addr); ++ ++ /* conscruct AAD, copy frame control field */ ++ memcpy(BIP_AAD, &pwlanhdr->frame_control, 2); ++ ClearRetry(BIP_AAD); ++ ClearPwrMgt(BIP_AAD); ++ ClearMData(BIP_AAD); ++ /* conscruct AAD, copy address 1 to address 3 */ ++ memcpy(BIP_AAD+2, pwlanhdr->addr1, 18); ++ /* copy management fram body */ ++ memcpy(BIP_AAD+BIP_AAD_SIZE, MGMT_body, frame_body_len); ++ /* calculate mic */ ++ if (omac1_aes_128(padapter->securitypriv.dot11wBIPKey[padapter->securitypriv.dot11wBIPKeyid].skey ++ , BIP_AAD, BIP_AAD_SIZE+frame_body_len, mic)) ++ goto xmitframe_coalesce_fail; ++ ++ /* copy right BIP mic value, total is 128bits, we use the 0~63 bits */ ++ memcpy(pframe-8, mic, 8); ++ } ++ else /* unicast mgmt frame TX */ ++ { ++ /* start to encrypt mgmt frame */ ++ if (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC || ++ subtype == WIFI_REASSOCREQ || subtype == WIFI_ACTION) ++ { ++ if (pattrib->psta) ++ psta = pattrib->psta; ++ else ++ { ++ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); ++ } ++ ++ if (psta == NULL) ++ { ++ ++ DBG_871X("%s, psta ==NUL\n", __func__); ++ goto xmitframe_coalesce_fail; ++ } ++ ++ if (!(psta->state & _FW_LINKED) || pxmitframe->buf_addr == NULL) ++ { ++ DBG_871X("%s, not _FW_LINKED or addr null\n", __func__); ++ goto xmitframe_coalesce_fail; ++ } ++ ++ /* DBG_871X("%s, action frame category =%d\n", __func__, pframe[WLAN_HDR_A3_LEN]); */ ++ /* according 802.11-2012 standard, these five types are not robust types */ ++ if (subtype == WIFI_ACTION && ++ (pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_PUBLIC || ++ pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_HT || ++ pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_UNPROTECTED_WNM || ++ pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_SELF_PROTECTED || ++ pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_P2P)) ++ goto xmitframe_coalesce_fail; ++ /* before encrypt dump the management packet content */ ++ if (pattrib->encrypt>0) ++ memcpy(pattrib->dot118021x_UncstKey.skey, psta->dot118021x_UncstKey.skey, 16); ++ /* bakeup original management packet */ ++ memcpy(tmp_buf, pframe, pattrib->pktlen); ++ /* move to data portion */ ++ pframe += pattrib->hdrlen; ++ ++ /* 802.11w unicast management packet must be _AES_ */ ++ pattrib->iv_len = 8; ++ /* it's MIC of AES */ ++ pattrib->icv_len = 8; ++ ++ switch (pattrib->encrypt) ++ { ++ case _AES_: ++ /* set AES IV header */ ++ AES_IV(pattrib->iv, psta->dot11wtxpn, 0); ++ break; ++ default: ++ goto xmitframe_coalesce_fail; ++ } ++ /* insert iv header into management frame */ ++ memcpy(pframe, pattrib->iv, pattrib->iv_len); ++ pframe += pattrib->iv_len; ++ /* copy mgmt data portion after CCMP header */ ++ memcpy(pframe, tmp_buf+pattrib->hdrlen, pattrib->pktlen-pattrib->hdrlen); ++ /* move pframe to end of mgmt pkt */ ++ pframe += pattrib->pktlen-pattrib->hdrlen; ++ /* add 8 bytes CCMP IV header to length */ ++ pattrib->pktlen += pattrib->iv_len; ++ if ((pattrib->icv_len >0) && (pattrib->bswenc)) { ++ memcpy(pframe, pattrib->icv, pattrib->icv_len); ++ pframe += pattrib->icv_len; ++ } ++ /* add 8 bytes MIC */ ++ pattrib->pktlen += pattrib->icv_len; ++ /* set final tx command size */ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ /* set protected bit must be beofre SW encrypt */ ++ SetPrivacy(mem_start); ++ /* software encrypt */ ++ xmitframe_swencrypt(padapter, pxmitframe); ++ } ++ } ++ ++xmitframe_coalesce_success: ++ spin_unlock_bh(&padapter->security_key_mutex); ++ kfree(BIP_AAD); ++ return _SUCCESS; ++ ++xmitframe_coalesce_fail: ++ spin_unlock_bh(&padapter->security_key_mutex); ++ kfree(BIP_AAD); ++ return _FAIL; ++} ++ ++/* Logical Link Control(LLC) SubNetwork Attachment Point(SNAP) header ++ * IEEE LLC/SNAP header contains 8 octets ++ * First 3 octets comprise the LLC portion ++ * SNAP portion, 5 octets, is divided into two fields: ++ *Organizationally Unique Identifier(OUI), 3 octets, ++ *type, defined by that organization, 2 octets. ++ */ ++s32 rtw_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]; ++ ++ *(__be16 *)(data + SNAP_SIZE) = htons(h_proto); ++ ++ return SNAP_SIZE + sizeof(u16); ++} ++ ++void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len) ++{ ++ ++ uint protection; ++ u8 *perp; ++ sint erp_len; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ ++ switch (pxmitpriv->vcs_setting) ++ { ++ case DISABLE_VCS: ++ pxmitpriv->vcs = NONE_VCS; ++ break; ++ ++ case ENABLE_VCS: ++ break; ++ ++ case AUTO_VCS: ++ default: ++ perp = rtw_get_ie(ie, _ERPINFO_IE_, &erp_len, ie_len); ++ if (perp == NULL) ++ { ++ pxmitpriv->vcs = NONE_VCS; ++ } ++ else ++ { ++ protection = (*(perp + 2)) & BIT(1); ++ if (protection) ++ { ++ if (pregistrypriv->vcs_type == RTS_CTS) ++ pxmitpriv->vcs = RTS_CTS; ++ else ++ pxmitpriv->vcs = CTS_TO_SELF; ++ } ++ else ++ pxmitpriv->vcs = NONE_VCS; ++ } ++ ++ break; ++ ++ } ++} ++ ++void rtw_count_tx_stats(struct adapter *padapter, struct xmit_frame *pxmitframe, int sz) ++{ ++ struct sta_info *psta = NULL; ++ struct stainfo_stats *pstats = NULL; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u8 pkt_num = 1; ++ ++ if ((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) ++ { ++ pkt_num = pxmitframe->agg_num; ++ ++ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod += pkt_num; ++ ++ pxmitpriv->tx_pkts += pkt_num; ++ ++ pxmitpriv->tx_bytes += sz; ++ ++ psta = pxmitframe->attrib.psta; ++ if (psta) ++ { ++ pstats = &psta->sta_stats; ++ ++ pstats->tx_pkts += pkt_num; ++ ++ pstats->tx_bytes += sz; ++ } ++ } ++} ++ ++static struct xmit_buf *__rtw_alloc_cmd_xmitbuf(struct xmit_priv *pxmitpriv, ++ enum cmdbuf_type buf_type) ++{ ++ struct xmit_buf *pxmitbuf = NULL; ++ ++ pxmitbuf = &pxmitpriv->pcmd_xmitbuf[buf_type]; ++ if (pxmitbuf != NULL) { ++ pxmitbuf->priv_data = NULL; ++ ++ pxmitbuf->len = 0; ++ pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; ++ pxmitbuf->agg_num = 0; ++ pxmitbuf->pg_num = 0; ++ ++ if (pxmitbuf->sctx) { ++ DBG_871X("%s pxmitbuf->sctx is not NULL\n", __func__); ++ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); ++ } ++ } else { ++ DBG_871X("%s fail, no xmitbuf available !!!\n", __func__); ++ } ++ return pxmitbuf; ++} ++ ++struct xmit_frame *__rtw_alloc_cmdxmitframe(struct xmit_priv *pxmitpriv, ++ enum cmdbuf_type buf_type) ++{ ++ struct xmit_frame *pcmdframe; ++ struct xmit_buf *pxmitbuf; ++ ++ if ((pcmdframe = rtw_alloc_xmitframe(pxmitpriv)) == NULL) ++ { ++ DBG_871X("%s, alloc xmitframe fail\n", __func__); ++ return NULL; ++ } ++ ++ if ((pxmitbuf = __rtw_alloc_cmd_xmitbuf(pxmitpriv, buf_type)) == NULL) { ++ DBG_871X("%s, alloc xmitbuf fail\n", __func__); ++ rtw_free_xmitframe(pxmitpriv, pcmdframe); ++ return NULL; ++ } ++ ++ pcmdframe->frame_tag = MGNT_FRAMETAG; ++ ++ pcmdframe->pxmitbuf = pxmitbuf; ++ ++ pcmdframe->buf_addr = pxmitbuf->pbuf; ++ ++ pxmitbuf->priv_data = pcmdframe; ++ ++ return pcmdframe; ++ ++} ++ ++struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv) ++{ ++ _irqL irqL; ++ struct xmit_buf *pxmitbuf = NULL; ++ struct list_head *plist, *phead; ++ struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; ++ ++ spin_lock_irqsave(&pfree_queue->lock, irqL); ++ ++ if (list_empty(&pfree_queue->queue)) { ++ pxmitbuf = NULL; ++ } else { ++ ++ phead = get_list_head(pfree_queue); ++ ++ plist = get_next(phead); ++ ++ pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); ++ ++ list_del_init(&(pxmitbuf->list)); ++ } ++ ++ if (pxmitbuf != NULL) ++ { ++ pxmitpriv->free_xmit_extbuf_cnt--; ++ #ifdef DBG_XMIT_BUF_EXT ++ DBG_871X("DBG_XMIT_BUF_EXT ALLOC no =%d, free_xmit_extbuf_cnt =%d\n", pxmitbuf->no, pxmitpriv->free_xmit_extbuf_cnt); ++ #endif ++ ++ ++ pxmitbuf->priv_data = NULL; ++ ++ pxmitbuf->len = 0; ++ pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; ++ pxmitbuf->agg_num = 1; ++ ++ if (pxmitbuf->sctx) { ++ DBG_871X("%s pxmitbuf->sctx is not NULL\n", __func__); ++ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); ++ } ++ ++ } ++ ++ spin_unlock_irqrestore(&pfree_queue->lock, irqL); ++ ++ return pxmitbuf; ++} ++ ++s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) ++{ ++ _irqL irqL; ++ struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; ++ ++ if (pxmitbuf == NULL) ++ { ++ return _FAIL; ++ } ++ ++ spin_lock_irqsave(&pfree_queue->lock, irqL); ++ ++ list_del_init(&pxmitbuf->list); ++ ++ list_add_tail(&(pxmitbuf->list), get_list_head(pfree_queue)); ++ pxmitpriv->free_xmit_extbuf_cnt++; ++ #ifdef DBG_XMIT_BUF_EXT ++ DBG_871X("DBG_XMIT_BUF_EXT FREE no =%d, free_xmit_extbuf_cnt =%d\n", pxmitbuf->no , pxmitpriv->free_xmit_extbuf_cnt); ++ #endif ++ ++ spin_unlock_irqrestore(&pfree_queue->lock, irqL); ++ ++ return _SUCCESS; ++} ++ ++struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv) ++{ ++ _irqL irqL; ++ struct xmit_buf *pxmitbuf = NULL; ++ struct list_head *plist, *phead; ++ struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; ++ ++ /* DBG_871X("+rtw_alloc_xmitbuf\n"); */ ++ ++ spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL); ++ ++ if (list_empty(&pfree_xmitbuf_queue->queue)) { ++ pxmitbuf = NULL; ++ } else { ++ ++ phead = get_list_head(pfree_xmitbuf_queue); ++ ++ plist = get_next(phead); ++ ++ pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); ++ ++ list_del_init(&(pxmitbuf->list)); ++ } ++ ++ if (pxmitbuf != NULL) ++ { ++ pxmitpriv->free_xmitbuf_cnt--; ++ #ifdef DBG_XMIT_BUF ++ DBG_871X("DBG_XMIT_BUF ALLOC no =%d, free_xmitbuf_cnt =%d\n", pxmitbuf->no, pxmitpriv->free_xmitbuf_cnt); ++ #endif ++ /* DBG_871X("alloc, free_xmitbuf_cnt =%d\n", pxmitpriv->free_xmitbuf_cnt); */ ++ ++ pxmitbuf->priv_data = NULL; ++ ++ pxmitbuf->len = 0; ++ pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; ++ pxmitbuf->agg_num = 0; ++ pxmitbuf->pg_num = 0; ++ ++ if (pxmitbuf->sctx) { ++ DBG_871X("%s pxmitbuf->sctx is not NULL\n", __func__); ++ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); ++ } ++ } ++ #ifdef DBG_XMIT_BUF ++ else ++ { ++ DBG_871X("DBG_XMIT_BUF rtw_alloc_xmitbuf return NULL\n"); ++ } ++ #endif ++ ++ spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL); ++ ++ return pxmitbuf; ++} ++ ++s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) ++{ ++ _irqL irqL; ++ struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; ++ ++ /* DBG_871X("+rtw_free_xmitbuf\n"); */ ++ ++ if (pxmitbuf == NULL) ++ { ++ return _FAIL; ++ } ++ ++ if (pxmitbuf->sctx) { ++ DBG_871X("%s pxmitbuf->sctx is not NULL\n", __func__); ++ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_FREE); ++ } ++ ++ if (pxmitbuf->buf_tag == XMITBUF_CMD) { ++ } ++ else if (pxmitbuf->buf_tag == XMITBUF_MGNT) { ++ rtw_free_xmitbuf_ext(pxmitpriv, pxmitbuf); ++ } ++ else ++ { ++ spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL); ++ ++ list_del_init(&pxmitbuf->list); ++ ++ list_add_tail(&(pxmitbuf->list), get_list_head(pfree_xmitbuf_queue)); ++ ++ pxmitpriv->free_xmitbuf_cnt++; ++ /* DBG_871X("FREE, free_xmitbuf_cnt =%d\n", pxmitpriv->free_xmitbuf_cnt); */ ++ #ifdef DBG_XMIT_BUF ++ DBG_871X("DBG_XMIT_BUF FREE no =%d, free_xmitbuf_cnt =%d\n", pxmitbuf->no , pxmitpriv->free_xmitbuf_cnt); ++ #endif ++ spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL); ++ } ++ return _SUCCESS; ++} ++ ++static void rtw_init_xmitframe(struct xmit_frame *pxframe) ++{ ++ if (pxframe != NULL)/* default value setting */ ++ { ++ pxframe->buf_addr = NULL; ++ pxframe->pxmitbuf = NULL; ++ ++ memset(&pxframe->attrib, 0, sizeof(struct pkt_attrib)); ++ /* pxframe->attrib.psta = NULL; */ ++ ++ pxframe->frame_tag = DATA_FRAMETAG; ++ ++ pxframe->pg_num = 1; ++ pxframe->agg_num = 1; ++ pxframe->ack_report = 0; ++ } ++} ++ ++/* ++Calling context: ++1. OS_TXENTRY ++2. RXENTRY (rx_thread or RX_ISR/RX_CallBack) ++ ++If we turn on USE_RXTHREAD, then, no need for critical section. ++Otherwise, we must use _enter/_exit critical to protect free_xmit_queue... ++ ++Must be very very cautious... ++ ++*/ ++struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv)/* _queue *pfree_xmit_queue) */ ++{ ++ /* ++ Please remember to use all the osdep_service api, ++ and lock/unlock or _enter/_exit critical to protect ++ pfree_xmit_queue ++ */ ++ ++ struct xmit_frame *pxframe = NULL; ++ struct list_head *plist, *phead; ++ struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; ++ ++ spin_lock_bh(&pfree_xmit_queue->lock); ++ ++ if (list_empty(&pfree_xmit_queue->queue)) { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe:%d\n", pxmitpriv->free_xmitframe_cnt)); ++ pxframe = NULL; ++ } else { ++ phead = get_list_head(pfree_xmit_queue); ++ ++ plist = get_next(phead); ++ ++ pxframe = LIST_CONTAINOR(plist, struct xmit_frame, list); ++ ++ list_del_init(&(pxframe->list)); ++ pxmitpriv->free_xmitframe_cnt--; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe():free_xmitframe_cnt =%d\n", pxmitpriv->free_xmitframe_cnt)); ++ } ++ ++ spin_unlock_bh(&pfree_xmit_queue->lock); ++ ++ rtw_init_xmitframe(pxframe); ++ return pxframe; ++} ++ ++struct xmit_frame *rtw_alloc_xmitframe_ext(struct xmit_priv *pxmitpriv) ++{ ++ struct xmit_frame *pxframe = NULL; ++ struct list_head *plist, *phead; ++ struct __queue *queue = &pxmitpriv->free_xframe_ext_queue; ++ ++ spin_lock_bh(&queue->lock); ++ ++ if (list_empty(&queue->queue)) { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe_ext:%d\n", pxmitpriv->free_xframe_ext_cnt)); ++ pxframe = NULL; ++ } else { ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ pxframe = LIST_CONTAINOR(plist, struct xmit_frame, list); ++ ++ list_del_init(&(pxframe->list)); ++ pxmitpriv->free_xframe_ext_cnt--; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe_ext():free_xmitframe_cnt =%d\n", pxmitpriv->free_xframe_ext_cnt)); ++ } ++ ++ spin_unlock_bh(&queue->lock); ++ ++ rtw_init_xmitframe(pxframe); ++ ++ return pxframe; ++} ++ ++struct xmit_frame *rtw_alloc_xmitframe_once(struct xmit_priv *pxmitpriv) ++{ ++ struct xmit_frame *pxframe = NULL; ++ u8 *alloc_addr; ++ ++ alloc_addr = rtw_zmalloc(sizeof(struct xmit_frame) + 4); ++ ++ if (alloc_addr == NULL) ++ goto exit; ++ ++ pxframe = (struct xmit_frame *)N_BYTE_ALIGMENT((SIZE_PTR)(alloc_addr), 4); ++ pxframe->alloc_addr = alloc_addr; ++ ++ pxframe->padapter = pxmitpriv->adapter; ++ pxframe->frame_tag = NULL_FRAMETAG; ++ ++ pxframe->pkt = NULL; ++ ++ pxframe->buf_addr = NULL; ++ pxframe->pxmitbuf = NULL; ++ ++ rtw_init_xmitframe(pxframe); ++ ++ DBG_871X("################## %s ##################\n", __func__); ++ ++exit: ++ return pxframe; ++} ++ ++s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitframe) ++{ ++ struct __queue *queue = NULL; ++ struct adapter *padapter = pxmitpriv->adapter; ++ _pkt *pndis_pkt = NULL; ++ ++ if (pxmitframe == NULL) { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("======rtw_free_xmitframe():pxmitframe == NULL!!!!!!!!!!\n")); ++ goto exit; ++ } ++ ++ if (pxmitframe->pkt) { ++ pndis_pkt = pxmitframe->pkt; ++ pxmitframe->pkt = NULL; ++ } ++ ++ if (pxmitframe->alloc_addr) { ++ DBG_871X("################## %s with alloc_addr ##################\n", __func__); ++ kfree(pxmitframe->alloc_addr); ++ goto check_pkt_complete; ++ } ++ ++ if (pxmitframe->ext_tag == 0) ++ queue = &pxmitpriv->free_xmit_queue; ++ else if (pxmitframe->ext_tag == 1) ++ queue = &pxmitpriv->free_xframe_ext_queue; ++ else ++ {} ++ ++ spin_lock_bh(&queue->lock); ++ ++ list_del_init(&pxmitframe->list); ++ list_add_tail(&pxmitframe->list, get_list_head(queue)); ++ if (pxmitframe->ext_tag == 0) { ++ pxmitpriv->free_xmitframe_cnt++; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("rtw_free_xmitframe():free_xmitframe_cnt =%d\n", pxmitpriv->free_xmitframe_cnt)); ++ } else if (pxmitframe->ext_tag == 1) { ++ pxmitpriv->free_xframe_ext_cnt++; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("rtw_free_xmitframe():free_xframe_ext_cnt =%d\n", pxmitpriv->free_xframe_ext_cnt)); ++ } else { ++ } ++ ++ spin_unlock_bh(&queue->lock); ++ ++check_pkt_complete: ++ ++ if (pndis_pkt) ++ rtw_os_pkt_complete(padapter, pndis_pkt); ++ ++exit: ++ return _SUCCESS; ++} ++ ++void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, struct __queue *pframequeue) ++{ ++ struct list_head *plist, *phead; ++ struct xmit_frame *pxmitframe; ++ ++ spin_lock_bh(&(pframequeue->lock)); ++ ++ phead = get_list_head(pframequeue); ++ plist = get_next(phead); ++ ++ while (phead != plist) ++ { ++ ++ pxmitframe = LIST_CONTAINOR(plist, struct xmit_frame, list); ++ ++ plist = get_next(plist); ++ ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ ++ } ++ spin_unlock_bh(&(pframequeue->lock)); ++} ++ ++s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ DBG_COUNTER(padapter->tx_logs.core_tx_enqueue); ++ if (rtw_xmit_classifier(padapter, pxmitframe) == _FAIL) ++ { ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ++ ("rtw_xmitframe_enqueue: drop xmit pkt for classifier fail\n")); ++/* pxmitframe->pkt = NULL; */ ++ return _FAIL; ++ } ++ ++ return _SUCCESS; ++} ++ ++struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info *psta, sint up, u8 *ac) ++{ ++ struct tx_servq *ptxservq = NULL; ++ ++ switch (up) ++ { ++ case 1: ++ case 2: ++ ptxservq = &(psta->sta_xmitpriv.bk_q); ++ *(ac) = 3; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : BK\n")); ++ break; ++ ++ case 4: ++ case 5: ++ ptxservq = &(psta->sta_xmitpriv.vi_q); ++ *(ac) = 1; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : VI\n")); ++ break; ++ ++ case 6: ++ case 7: ++ ptxservq = &(psta->sta_xmitpriv.vo_q); ++ *(ac) = 0; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : VO\n")); ++ break; ++ ++ case 0: ++ case 3: ++ default: ++ ptxservq = &(psta->sta_xmitpriv.be_q); ++ *(ac) = 2; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : BE\n")); ++ break; ++ ++ } ++ ++ return ptxservq; ++} ++ ++/* ++ * Will enqueue pxmitframe to the proper queue, ++ * and indicate it to xx_pending list..... ++ */ ++s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ /* _irqL irqL0; */ ++ u8 ac_index; ++ struct sta_info *psta; ++ struct tx_servq *ptxservq; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; ++ sint res = _SUCCESS; ++ ++ DBG_COUNTER(padapter->tx_logs.core_tx_enqueue_class); ++ ++/* ++ if (pattrib->psta) { ++ psta = pattrib->psta; ++ } else { ++ DBG_871X("%s, call rtw_get_stainfo()\n", __func__); ++ psta = rtw_get_stainfo(pstapriv, pattrib->ra); ++ } ++*/ ++ ++ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); ++ if (pattrib->psta != psta) ++ { ++ DBG_COUNTER(padapter->tx_logs.core_tx_enqueue_class_err_sta); ++ DBG_871X("%s, pattrib->psta(%p) != psta(%p)\n", __func__, pattrib->psta, psta); ++ return _FAIL; ++ } ++ ++ if (psta == NULL) { ++ DBG_COUNTER(padapter->tx_logs.core_tx_enqueue_class_err_nosta); ++ res = _FAIL; ++ DBG_8192C("rtw_xmit_classifier: psta == NULL\n"); ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("rtw_xmit_classifier: psta == NULL\n")); ++ goto exit; ++ } ++ ++ if (!(psta->state &_FW_LINKED)) ++ { ++ DBG_COUNTER(padapter->tx_logs.core_tx_enqueue_class_err_fwlink); ++ DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); ++ return _FAIL; ++ } ++ ++ ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index)); ++ ++ /* spin_lock_irqsave(&pstapending->lock, irqL0); */ ++ ++ if (list_empty(&ptxservq->tx_pending)) { ++ list_add_tail(&ptxservq->tx_pending, get_list_head(phwxmits[ac_index].sta_queue)); ++ } ++ ++ /* spin_lock_irqsave(&ptxservq->sta_pending.lock, irqL1); */ ++ ++ list_add_tail(&pxmitframe->list, get_list_head(&ptxservq->sta_pending)); ++ ptxservq->qcnt++; ++ phwxmits[ac_index].accnt++; ++ ++ /* spin_unlock_irqrestore(&ptxservq->sta_pending.lock, irqL1); */ ++ ++ /* spin_unlock_irqrestore(&pstapending->lock, irqL0); */ ++ ++exit: ++ ++ return res; ++} ++ ++void rtw_alloc_hwxmits(struct adapter *padapter) ++{ ++ struct hw_xmit *hwxmits; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ pxmitpriv->hwxmit_entry = HWXMIT_ENTRY; ++ ++ pxmitpriv->hwxmits = NULL; ++ ++ pxmitpriv->hwxmits = (struct hw_xmit *)rtw_zmalloc(sizeof (struct hw_xmit) * pxmitpriv->hwxmit_entry); ++ ++ if (pxmitpriv->hwxmits == NULL) ++ { ++ DBG_871X("alloc hwxmits fail!...\n"); ++ return; ++ } ++ ++ hwxmits = pxmitpriv->hwxmits; ++ ++ if (pxmitpriv->hwxmit_entry == 5) ++ { ++ /* pxmitpriv->bmc_txqueue.head = 0; */ ++ /* hwxmits[0] .phwtxqueue = &pxmitpriv->bmc_txqueue; */ ++ hwxmits[0] .sta_queue = &pxmitpriv->bm_pending; ++ ++ /* pxmitpriv->vo_txqueue.head = 0; */ ++ /* hwxmits[1] .phwtxqueue = &pxmitpriv->vo_txqueue; */ ++ hwxmits[1] .sta_queue = &pxmitpriv->vo_pending; ++ ++ /* pxmitpriv->vi_txqueue.head = 0; */ ++ /* hwxmits[2] .phwtxqueue = &pxmitpriv->vi_txqueue; */ ++ hwxmits[2] .sta_queue = &pxmitpriv->vi_pending; ++ ++ /* pxmitpriv->bk_txqueue.head = 0; */ ++ /* hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue; */ ++ hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; ++ ++ /* pxmitpriv->be_txqueue.head = 0; */ ++ /* hwxmits[4] .phwtxqueue = &pxmitpriv->be_txqueue; */ ++ hwxmits[4] .sta_queue = &pxmitpriv->be_pending; ++ ++ } ++ else if (pxmitpriv->hwxmit_entry == 4) ++ { ++ ++ /* pxmitpriv->vo_txqueue.head = 0; */ ++ /* hwxmits[0] .phwtxqueue = &pxmitpriv->vo_txqueue; */ ++ hwxmits[0] .sta_queue = &pxmitpriv->vo_pending; ++ ++ /* pxmitpriv->vi_txqueue.head = 0; */ ++ /* hwxmits[1] .phwtxqueue = &pxmitpriv->vi_txqueue; */ ++ hwxmits[1] .sta_queue = &pxmitpriv->vi_pending; ++ ++ /* pxmitpriv->be_txqueue.head = 0; */ ++ /* hwxmits[2] .phwtxqueue = &pxmitpriv->be_txqueue; */ ++ hwxmits[2] .sta_queue = &pxmitpriv->be_pending; ++ ++ /* pxmitpriv->bk_txqueue.head = 0; */ ++ /* hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue; */ ++ hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; ++ } ++ else ++ { ++ ++ ++ } ++ ++ ++} ++ ++void rtw_free_hwxmits(struct adapter *padapter) ++{ ++ struct hw_xmit *hwxmits; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ hwxmits = pxmitpriv->hwxmits; ++ if (hwxmits) ++ kfree((u8 *)hwxmits); ++} ++ ++void rtw_init_hwxmits(struct hw_xmit *phwxmit, sint entry) ++{ ++ sint i; ++ ++ for (i = 0; i < entry; i++, phwxmit++) ++ { ++ /* spin_lock_init(&phwxmit->xmit_lock); */ ++ /* INIT_LIST_HEAD(&phwxmit->pending); */ ++ /* phwxmit->txcmdcnt = 0; */ ++ phwxmit->accnt = 0; ++ } ++} ++ ++u32 rtw_get_ff_hwaddr(struct xmit_frame *pxmitframe) ++{ ++ u32 addr; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ ++ switch (pattrib->qsel) ++ { ++ case 0: ++ case 3: ++ addr = BE_QUEUE_INX; ++ break; ++ case 1: ++ case 2: ++ addr = BK_QUEUE_INX; ++ break; ++ case 4: ++ case 5: ++ addr = VI_QUEUE_INX; ++ break; ++ case 6: ++ case 7: ++ addr = VO_QUEUE_INX; ++ break; ++ case 0x10: ++ addr = BCN_QUEUE_INX; ++ break; ++ case 0x11:/* BC/MC in PS (HIQ) */ ++ addr = HIGH_QUEUE_INX; ++ break; ++ case 0x12: ++ default: ++ addr = MGT_QUEUE_INX; ++ break; ++ ++ } ++ ++ return addr; ++ ++} ++ ++static void do_queue_select(struct adapter *padapter, struct pkt_attrib *pattrib) ++{ ++ u8 qsel; ++ ++ qsel = pattrib->priority; ++ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("### do_queue_select priority =%d , qsel = %d\n", pattrib->priority , qsel)); ++ ++ pattrib->qsel = qsel; ++} ++ ++/* ++ * The main transmit(tx) entry ++ * ++ * Return ++ *1 enqueue ++ *0 success, hardware will handle this xmit frame(packet) ++ *<0 fail ++ */ ++s32 rtw_xmit(struct adapter *padapter, _pkt **ppkt) ++{ ++ static unsigned long start = 0; ++ static u32 drop_cnt = 0; ++ ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct xmit_frame *pxmitframe = NULL; ++ ++ s32 res; ++ ++ DBG_COUNTER(padapter->tx_logs.core_tx); ++ ++ if (start == 0) ++ start = jiffies; ++ ++ pxmitframe = rtw_alloc_xmitframe(pxmitpriv); ++ ++ if (jiffies_to_msecs(jiffies - start) > 2000) { ++ if (drop_cnt) ++ DBG_871X("DBG_TX_DROP_FRAME %s no more pxmitframe, drop_cnt:%u\n", __func__, drop_cnt); ++ start = jiffies; ++ drop_cnt = 0; ++ } ++ ++ if (pxmitframe == NULL) { ++ drop_cnt ++; ++ RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit: no more pxmitframe\n")); ++ DBG_COUNTER(padapter->tx_logs.core_tx_err_pxmitframe); ++ return -1; ++ } ++ ++ res = update_attrib(padapter, *ppkt, &pxmitframe->attrib); ++ ++ if (res == _FAIL) { ++ RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit: update attrib fail\n")); ++ #ifdef DBG_TX_DROP_FRAME ++ DBG_871X("DBG_TX_DROP_FRAME %s update attrib fail\n", __func__); ++ #endif ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ return -1; ++ } ++ pxmitframe->pkt = *ppkt; ++ ++ do_queue_select(padapter, &pxmitframe->attrib); ++ ++ spin_lock_bh(&pxmitpriv->lock); ++ if (xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe) == true) ++ { ++ spin_unlock_bh(&pxmitpriv->lock); ++ DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue); ++ return 1; ++ } ++ spin_unlock_bh(&pxmitpriv->lock); ++ ++ /* pre_xmitframe */ ++ if (rtw_hal_xmit(padapter, pxmitframe) == false) ++ return 1; ++ ++ return 0; ++} ++ ++#define RTW_HIQ_FILTER_ALLOW_ALL 0 ++#define RTW_HIQ_FILTER_ALLOW_SPECIAL 1 ++#define RTW_HIQ_FILTER_DENY_ALL 2 ++ ++inline bool xmitframe_hiq_filter(struct xmit_frame *xmitframe) ++{ ++ bool allow = false; ++ struct adapter *adapter = xmitframe->padapter; ++ struct registry_priv *registry = &adapter->registrypriv; ++ ++ if (registry->hiq_filter == RTW_HIQ_FILTER_ALLOW_SPECIAL) { ++ ++ struct pkt_attrib *attrib = &xmitframe->attrib; ++ ++ if (attrib->ether_type == 0x0806 ++ || attrib->ether_type == 0x888e ++ || attrib->dhcp_pkt ++ ) { ++ DBG_871X(FUNC_ADPT_FMT" ether_type:0x%04x%s\n", FUNC_ADPT_ARG(xmitframe->padapter) ++ , attrib->ether_type, attrib->dhcp_pkt?" DHCP":""); ++ allow = true; ++ } ++ } ++ else if (registry->hiq_filter == RTW_HIQ_FILTER_ALLOW_ALL) { ++ allow = true; ++ } ++ else if (registry->hiq_filter == RTW_HIQ_FILTER_DENY_ALL) { ++ } ++ else { ++ rtw_warn_on(1); ++ } ++ ++ return allow; ++} ++ ++sint xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ sint ret =false; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ sint bmcst = IS_MCAST(pattrib->ra); ++ bool update_tim = false; ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == false) ++ { ++ DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_warn_fwstate); ++ return ret; ++ } ++/* ++ if (pattrib->psta) ++ { ++ psta = pattrib->psta; ++ } ++ else ++ { ++ DBG_871X("%s, call rtw_get_stainfo()\n", __func__); ++ psta =rtw_get_stainfo(pstapriv, pattrib->ra); ++ } ++*/ ++ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); ++ if (pattrib->psta != psta) ++ { ++ DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_warn_sta); ++ DBG_871X("%s, pattrib->psta(%p) != psta(%p)\n", __func__, pattrib->psta, psta); ++ return false; ++ } ++ ++ if (psta == NULL) ++ { ++ DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_warn_nosta); ++ DBG_871X("%s, psta ==NUL\n", __func__); ++ return false; ++ } ++ ++ if (!(psta->state &_FW_LINKED)) ++ { ++ DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_warn_link); ++ DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); ++ return false; ++ } ++ ++ if (pattrib->triggered == 1) ++ { ++ DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_warn_trigger); ++ /* DBG_871X("directly xmit pspoll_triggered packet\n"); */ ++ ++ /* pattrib->triggered = 0; */ ++ if (bmcst && xmitframe_hiq_filter(pxmitframe) == true) ++ pattrib->qsel = 0x11;/* HIQ */ ++ ++ return ret; ++ } ++ ++ ++ if (bmcst) ++ { ++ spin_lock_bh(&psta->sleep_q.lock); ++ ++ if (pstapriv->sta_dz_bitmap)/* if anyone sta is in ps mode */ ++ { ++ /* pattrib->qsel = 0x11;HIQ */ ++ ++ list_del_init(&pxmitframe->list); ++ ++ /* spin_lock_bh(&psta->sleep_q.lock); */ ++ ++ list_add_tail(&pxmitframe->list, get_list_head(&psta->sleep_q)); ++ ++ psta->sleepq_len++; ++ ++ if (!(pstapriv->tim_bitmap & BIT(0))) ++ update_tim = true; ++ ++ pstapriv->tim_bitmap |= BIT(0);/* */ ++ pstapriv->sta_dz_bitmap |= BIT(0); ++ ++ /* DBG_871X("enqueue, sq_len =%d, tim =%x\n", psta->sleepq_len, pstapriv->tim_bitmap); */ ++ ++ if (update_tim == true) { ++ update_beacon(padapter, _TIM_IE_, NULL, true); ++ } else { ++ chk_bmc_sleepq_cmd(padapter); ++ } ++ ++ /* spin_unlock_bh(&psta->sleep_q.lock); */ ++ ++ ret = true; ++ ++ DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_mcast); ++ ++ } ++ ++ spin_unlock_bh(&psta->sleep_q.lock); ++ ++ return ret; ++ ++ } ++ ++ ++ spin_lock_bh(&psta->sleep_q.lock); ++ ++ if (psta->state&WIFI_SLEEP_STATE) ++ { ++ u8 wmmps_ac = 0; ++ ++ if (pstapriv->sta_dz_bitmap&BIT(psta->aid)) ++ { ++ list_del_init(&pxmitframe->list); ++ ++ /* spin_lock_bh(&psta->sleep_q.lock); */ ++ ++ list_add_tail(&pxmitframe->list, get_list_head(&psta->sleep_q)); ++ ++ psta->sleepq_len++; ++ ++ switch (pattrib->priority) ++ { ++ case 1: ++ case 2: ++ wmmps_ac = psta->uapsd_bk&BIT(0); ++ break; ++ case 4: ++ case 5: ++ wmmps_ac = psta->uapsd_vi&BIT(0); ++ break; ++ case 6: ++ case 7: ++ wmmps_ac = psta->uapsd_vo&BIT(0); ++ break; ++ case 0: ++ case 3: ++ default: ++ wmmps_ac = psta->uapsd_be&BIT(0); ++ break; ++ } ++ ++ if (wmmps_ac) ++ psta->sleepq_ac_len++; ++ ++ if (((psta->has_legacy_ac) && (!wmmps_ac)) ||((!psta->has_legacy_ac) && (wmmps_ac))) ++ { ++ if (!(pstapriv->tim_bitmap & BIT(psta->aid))) ++ update_tim = true; ++ ++ pstapriv->tim_bitmap |= BIT(psta->aid); ++ ++ /* DBG_871X("enqueue, sq_len =%d, tim =%x\n", psta->sleepq_len, pstapriv->tim_bitmap); */ ++ ++ if (update_tim == true) ++ { ++ /* DBG_871X("sleepq_len == 1, update BCNTIM\n"); */ ++ /* upate BCN for TIM IE */ ++ update_beacon(padapter, _TIM_IE_, NULL, true); ++ } ++ } ++ ++ /* spin_unlock_bh(&psta->sleep_q.lock); */ ++ ++ /* if (psta->sleepq_len > (NR_XMITFRAME>>3)) */ ++ /* */ ++ /* wakeup_sta_to_xmit(padapter, psta); */ ++ /* */ ++ ++ ret = true; ++ ++ DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_ucast); ++ } ++ ++ } ++ ++ spin_unlock_bh(&psta->sleep_q.lock); ++ ++ return ret; ++ ++} ++ ++static void dequeue_xmitframes_to_sleeping_queue(struct adapter *padapter, struct sta_info *psta, struct __queue *pframequeue) ++{ ++ sint ret; ++ struct list_head *plist, *phead; ++ u8 ac_index; ++ struct tx_servq *ptxservq; ++ struct pkt_attrib *pattrib; ++ struct xmit_frame *pxmitframe; ++ struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; ++ ++ phead = get_list_head(pframequeue); ++ plist = get_next(phead); ++ ++ while (phead != plist) ++ { ++ pxmitframe = LIST_CONTAINOR(plist, struct xmit_frame, list); ++ ++ plist = get_next(plist); ++ ++ pattrib = &pxmitframe->attrib; ++ ++ pattrib->triggered = 0; ++ ++ ret = xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe); ++ ++ if (true == ret) ++ { ++ ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index)); ++ ++ ptxservq->qcnt--; ++ phwxmits[ac_index].accnt--; ++ } ++ else ++ { ++ /* DBG_871X("xmitframe_enqueue_for_sleeping_sta return false\n"); */ ++ } ++ ++ } ++ ++} ++ ++void stop_sta_xmit(struct adapter *padapter, struct sta_info *psta) ++{ ++ struct sta_info *psta_bmc; ++ struct sta_xmit_priv *pstaxmitpriv; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ pstaxmitpriv = &psta->sta_xmitpriv; ++ ++ /* for BC/MC Frames */ ++ psta_bmc = rtw_get_bcmc_stainfo(padapter); ++ ++ ++ spin_lock_bh(&pxmitpriv->lock); ++ ++ psta->state |= WIFI_SLEEP_STATE; ++ ++ pstapriv->sta_dz_bitmap |= BIT(psta->aid); ++ ++ ++ ++ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vo_q.sta_pending); ++ list_del_init(&(pstaxmitpriv->vo_q.tx_pending)); ++ ++ ++ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vi_q.sta_pending); ++ list_del_init(&(pstaxmitpriv->vi_q.tx_pending)); ++ ++ ++ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->be_q.sta_pending); ++ list_del_init(&(pstaxmitpriv->be_q.tx_pending)); ++ ++ ++ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->bk_q.sta_pending); ++ list_del_init(&(pstaxmitpriv->bk_q.tx_pending)); ++ ++ /* for BC/MC Frames */ ++ pstaxmitpriv = &psta_bmc->sta_xmitpriv; ++ dequeue_xmitframes_to_sleeping_queue(padapter, psta_bmc, &pstaxmitpriv->be_q.sta_pending); ++ list_del_init(&(pstaxmitpriv->be_q.tx_pending)); ++ ++ spin_unlock_bh(&pxmitpriv->lock); ++} ++ ++void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta) ++{ ++ u8 update_mask = 0, wmmps_ac = 0; ++ struct sta_info *psta_bmc; ++ struct list_head *xmitframe_plist, *xmitframe_phead; ++ struct xmit_frame *pxmitframe = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ psta_bmc = rtw_get_bcmc_stainfo(padapter); ++ ++ ++ /* spin_lock_bh(&psta->sleep_q.lock); */ ++ spin_lock_bh(&pxmitpriv->lock); ++ ++ xmitframe_phead = get_list_head(&psta->sleep_q); ++ xmitframe_plist = get_next(xmitframe_phead); ++ ++ while (xmitframe_phead != xmitframe_plist) ++ { ++ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); ++ ++ xmitframe_plist = get_next(xmitframe_plist); ++ ++ list_del_init(&pxmitframe->list); ++ ++ switch (pxmitframe->attrib.priority) ++ { ++ case 1: ++ case 2: ++ wmmps_ac = psta->uapsd_bk&BIT(1); ++ break; ++ case 4: ++ case 5: ++ wmmps_ac = psta->uapsd_vi&BIT(1); ++ break; ++ case 6: ++ case 7: ++ wmmps_ac = psta->uapsd_vo&BIT(1); ++ break; ++ case 0: ++ case 3: ++ default: ++ wmmps_ac = psta->uapsd_be&BIT(1); ++ break; ++ } ++ ++ psta->sleepq_len--; ++ if (psta->sleepq_len>0) ++ pxmitframe->attrib.mdata = 1; ++ else ++ pxmitframe->attrib.mdata = 0; ++ ++ if (wmmps_ac) ++ { ++ psta->sleepq_ac_len--; ++ if (psta->sleepq_ac_len>0) ++ { ++ pxmitframe->attrib.mdata = 1; ++ pxmitframe->attrib.eosp = 0; ++ } ++ else ++ { ++ pxmitframe->attrib.mdata = 0; ++ pxmitframe->attrib.eosp = 1; ++ } ++ } ++ ++ pxmitframe->attrib.triggered = 1; ++ ++/* ++ spin_unlock_bh(&psta->sleep_q.lock); ++ if (rtw_hal_xmit(padapter, pxmitframe) == true) ++ { ++ rtw_os_xmit_complete(padapter, pxmitframe); ++ } ++ spin_lock_bh(&psta->sleep_q.lock); ++*/ ++ rtw_hal_xmitframe_enqueue(padapter, pxmitframe); ++ ++ ++ } ++ ++ if (psta->sleepq_len == 0) ++ { ++ if (pstapriv->tim_bitmap & BIT(psta->aid)) { ++ /* DBG_871X("wakeup to xmit, qlen == 0, update_BCNTIM, tim =%x\n", pstapriv->tim_bitmap); */ ++ /* upate BCN for TIM IE */ ++ /* update_BCNTIM(padapter); */ ++ update_mask = BIT(0); ++ } ++ ++ pstapriv->tim_bitmap &= ~BIT(psta->aid); ++ ++ if (psta->state&WIFI_SLEEP_STATE) ++ psta->state ^= WIFI_SLEEP_STATE; ++ ++ if (psta->state & WIFI_STA_ALIVE_CHK_STATE) ++ { ++ DBG_871X("%s alive check\n", __func__); ++ psta->expire_to = pstapriv->expire_to; ++ psta->state ^= WIFI_STA_ALIVE_CHK_STATE; ++ } ++ ++ pstapriv->sta_dz_bitmap &= ~BIT(psta->aid); ++ } ++ ++ /* for BC/MC Frames */ ++ if (!psta_bmc) ++ goto _exit; ++ ++ if ((pstapriv->sta_dz_bitmap&0xfffe) == 0x0)/* no any sta in ps mode */ ++ { ++ xmitframe_phead = get_list_head(&psta_bmc->sleep_q); ++ xmitframe_plist = get_next(xmitframe_phead); ++ ++ while (xmitframe_phead != xmitframe_plist) ++ { ++ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); ++ ++ xmitframe_plist = get_next(xmitframe_plist); ++ ++ list_del_init(&pxmitframe->list); ++ ++ psta_bmc->sleepq_len--; ++ if (psta_bmc->sleepq_len>0) ++ pxmitframe->attrib.mdata = 1; ++ else ++ pxmitframe->attrib.mdata = 0; ++ ++ ++ pxmitframe->attrib.triggered = 1; ++/* ++ spin_unlock_bh(&psta_bmc->sleep_q.lock); ++ if (rtw_hal_xmit(padapter, pxmitframe) == true) ++ { ++ rtw_os_xmit_complete(padapter, pxmitframe); ++ } ++ spin_lock_bh(&psta_bmc->sleep_q.lock); ++ ++*/ ++ rtw_hal_xmitframe_enqueue(padapter, pxmitframe); ++ ++ } ++ ++ if (psta_bmc->sleepq_len == 0) ++ { ++ if (pstapriv->tim_bitmap & BIT(0)) { ++ /* DBG_871X("wakeup to xmit, qlen == 0, update_BCNTIM, tim =%x\n", pstapriv->tim_bitmap); */ ++ /* upate BCN for TIM IE */ ++ /* update_BCNTIM(padapter); */ ++ update_mask |= BIT(1); ++ } ++ pstapriv->tim_bitmap &= ~BIT(0); ++ pstapriv->sta_dz_bitmap &= ~BIT(0); ++ } ++ ++ } ++ ++_exit: ++ ++ /* spin_unlock_bh(&psta_bmc->sleep_q.lock); */ ++ spin_unlock_bh(&pxmitpriv->lock); ++ ++ if (update_mask) ++ { ++ /* update_BCNTIM(padapter); */ ++ /* printk("%s => call update_beacon\n", __func__); */ ++ update_beacon(padapter, _TIM_IE_, NULL, true); ++ } ++ ++} ++ ++void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *psta) ++{ ++ u8 wmmps_ac = 0; ++ struct list_head *xmitframe_plist, *xmitframe_phead; ++ struct xmit_frame *pxmitframe = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ ++ /* spin_lock_bh(&psta->sleep_q.lock); */ ++ spin_lock_bh(&pxmitpriv->lock); ++ ++ xmitframe_phead = get_list_head(&psta->sleep_q); ++ xmitframe_plist = get_next(xmitframe_phead); ++ ++ while (xmitframe_phead != xmitframe_plist) ++ { ++ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); ++ ++ xmitframe_plist = get_next(xmitframe_plist); ++ ++ switch (pxmitframe->attrib.priority) ++ { ++ case 1: ++ case 2: ++ wmmps_ac = psta->uapsd_bk&BIT(1); ++ break; ++ case 4: ++ case 5: ++ wmmps_ac = psta->uapsd_vi&BIT(1); ++ break; ++ case 6: ++ case 7: ++ wmmps_ac = psta->uapsd_vo&BIT(1); ++ break; ++ case 0: ++ case 3: ++ default: ++ wmmps_ac = psta->uapsd_be&BIT(1); ++ break; ++ } ++ ++ if (!wmmps_ac) ++ continue; ++ ++ list_del_init(&pxmitframe->list); ++ ++ psta->sleepq_len--; ++ psta->sleepq_ac_len--; ++ ++ if (psta->sleepq_ac_len>0) ++ { ++ pxmitframe->attrib.mdata = 1; ++ pxmitframe->attrib.eosp = 0; ++ } ++ else ++ { ++ pxmitframe->attrib.mdata = 0; ++ pxmitframe->attrib.eosp = 1; ++ } ++ ++ pxmitframe->attrib.triggered = 1; ++ rtw_hal_xmitframe_enqueue(padapter, pxmitframe); ++ ++ if ((psta->sleepq_ac_len == 0) && (!psta->has_legacy_ac) && (wmmps_ac)) ++ { ++ pstapriv->tim_bitmap &= ~BIT(psta->aid); ++ ++ /* DBG_871X("wakeup to xmit, qlen == 0, update_BCNTIM, tim =%x\n", pstapriv->tim_bitmap); */ ++ /* upate BCN for TIM IE */ ++ /* update_BCNTIM(padapter); */ ++ update_beacon(padapter, _TIM_IE_, NULL, true); ++ /* update_mask = BIT(0); */ ++ } ++ ++ } ++ ++ /* spin_unlock_bh(&psta->sleep_q.lock); */ ++ spin_unlock_bh(&pxmitpriv->lock); ++ ++ return; ++} ++ ++void enqueue_pending_xmitbuf( ++ struct xmit_priv *pxmitpriv, ++ struct xmit_buf *pxmitbuf) ++{ ++ struct __queue *pqueue; ++ struct adapter *pri_adapter = pxmitpriv->adapter; ++ ++ pqueue = &pxmitpriv->pending_xmitbuf_queue; ++ ++ spin_lock_bh(&pqueue->lock); ++ list_del_init(&pxmitbuf->list); ++ list_add_tail(&pxmitbuf->list, get_list_head(pqueue)); ++ spin_unlock_bh(&pqueue->lock); ++ ++ up(&(pri_adapter->xmitpriv.xmit_sema)); ++} ++ ++void enqueue_pending_xmitbuf_to_head( ++ struct xmit_priv *pxmitpriv, ++ struct xmit_buf *pxmitbuf) ++{ ++ struct __queue *pqueue; ++ ++ pqueue = &pxmitpriv->pending_xmitbuf_queue; ++ ++ spin_lock_bh(&pqueue->lock); ++ list_del_init(&pxmitbuf->list); ++ list_add(&pxmitbuf->list, get_list_head(pqueue)); ++ spin_unlock_bh(&pqueue->lock); ++} ++ ++struct xmit_buf* dequeue_pending_xmitbuf( ++ struct xmit_priv *pxmitpriv) ++{ ++ struct xmit_buf *pxmitbuf; ++ struct __queue *pqueue; ++ ++ ++ pxmitbuf = NULL; ++ pqueue = &pxmitpriv->pending_xmitbuf_queue; ++ ++ spin_lock_bh(&pqueue->lock); ++ ++ if (!list_empty(&pqueue->queue)) ++ { ++ struct list_head *plist, *phead; ++ ++ phead = get_list_head(pqueue); ++ plist = get_next(phead); ++ pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); ++ list_del_init(&pxmitbuf->list); ++ } ++ ++ spin_unlock_bh(&pqueue->lock); ++ ++ return pxmitbuf; ++} ++ ++struct xmit_buf* dequeue_pending_xmitbuf_under_survey( ++ struct xmit_priv *pxmitpriv) ++{ ++ struct xmit_buf *pxmitbuf; ++ struct __queue *pqueue; ++ ++ ++ pxmitbuf = NULL; ++ pqueue = &pxmitpriv->pending_xmitbuf_queue; ++ ++ spin_lock_bh(&pqueue->lock); ++ ++ if (!list_empty(&pqueue->queue)) ++ { ++ struct list_head *plist, *phead; ++ u8 type; ++ ++ phead = get_list_head(pqueue); ++ plist = phead; ++ do { ++ plist = get_next(plist); ++ if (plist == phead) break; ++ ++ pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); ++ ++ type = GetFrameSubType(pxmitbuf->pbuf + TXDESC_OFFSET); ++ ++ if ((type == WIFI_PROBEREQ) || ++ (type == WIFI_DATA_NULL) || ++ (type == WIFI_QOS_DATA_NULL)) ++ { ++ list_del_init(&pxmitbuf->list); ++ break; ++ } ++ pxmitbuf = NULL; ++ } while (1); ++ } ++ ++ spin_unlock_bh(&pqueue->lock); ++ ++ return pxmitbuf; ++} ++ ++sint check_pending_xmitbuf( ++ struct xmit_priv *pxmitpriv) ++{ ++ struct __queue *pqueue; ++ sint ret = false; ++ ++ pqueue = &pxmitpriv->pending_xmitbuf_queue; ++ ++ spin_lock_bh(&pqueue->lock); ++ ++ if (!list_empty(&pqueue->queue)) ++ ret = true; ++ ++ spin_unlock_bh(&pqueue->lock); ++ ++ return ret; ++} ++ ++int rtw_xmit_thread(void *context) ++{ ++ s32 err; ++ struct adapter *padapter; ++ ++ ++ err = _SUCCESS; ++ padapter = (struct adapter *)context; ++ ++ thread_enter("RTW_XMIT_THREAD"); ++ ++ do { ++ err = rtw_hal_xmit_thread_handler(padapter); ++ flush_signals_thread(); ++ } while (_SUCCESS == err); ++ ++ up(&padapter->xmitpriv.terminate_xmitthread_sema); ++ ++ thread_exit(); ++} ++ ++void rtw_sctx_init(struct submit_ctx *sctx, int timeout_ms) ++{ ++ sctx->timeout_ms = timeout_ms; ++ sctx->submit_time = jiffies; ++ init_completion(&sctx->done); ++ sctx->status = RTW_SCTX_SUBMITTED; ++} ++ ++int rtw_sctx_wait(struct submit_ctx *sctx, const char *msg) ++{ ++ int ret = _FAIL; ++ unsigned long expire; ++ int status = 0; ++ ++ expire = sctx->timeout_ms ? msecs_to_jiffies(sctx->timeout_ms) : MAX_SCHEDULE_TIMEOUT; ++ if (!wait_for_completion_timeout(&sctx->done, expire)) { ++ /* timeout, do something?? */ ++ status = RTW_SCTX_DONE_TIMEOUT; ++ DBG_871X("%s timeout: %s\n", __func__, msg); ++ } else { ++ status = sctx->status; ++ } ++ ++ if (status == RTW_SCTX_DONE_SUCCESS) { ++ ret = _SUCCESS; ++ } ++ ++ return ret; ++} ++ ++static bool rtw_sctx_chk_waring_status(int status) ++{ ++ switch (status) { ++ case RTW_SCTX_DONE_UNKNOWN: ++ case RTW_SCTX_DONE_BUF_ALLOC: ++ case RTW_SCTX_DONE_BUF_FREE: ++ ++ case RTW_SCTX_DONE_DRV_STOP: ++ case RTW_SCTX_DONE_DEV_REMOVE: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++void rtw_sctx_done_err(struct submit_ctx **sctx, int status) ++{ ++ if (*sctx) { ++ if (rtw_sctx_chk_waring_status(status)) ++ DBG_871X("%s status:%d\n", __func__, status); ++ (*sctx)->status = status; ++ complete(&((*sctx)->done)); ++ *sctx = NULL; ++ } ++} ++ ++void rtw_sctx_done(struct submit_ctx **sctx) ++{ ++ rtw_sctx_done_err(sctx, RTW_SCTX_DONE_SUCCESS); ++} ++ ++int rtw_ack_tx_wait(struct xmit_priv *pxmitpriv, u32 timeout_ms) ++{ ++ struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; ++ ++ pack_tx_ops->submit_time = jiffies; ++ pack_tx_ops->timeout_ms = timeout_ms; ++ pack_tx_ops->status = RTW_SCTX_SUBMITTED; ++ ++ return rtw_sctx_wait(pack_tx_ops, __func__); ++} ++ ++void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status) ++{ ++ struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; ++ ++ if (pxmitpriv->ack_tx) { ++ rtw_sctx_done_err(&pack_tx_ops, status); ++ } else { ++ DBG_871X("%s ack_tx not set\n", __func__); ++ } ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/Hal8723BPwrSeq.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/Hal8723BPwrSeq.c +--- linux-4.3/3rdparty/rtl8723bs/hal/Hal8723BPwrSeq.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/Hal8723BPwrSeq.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,115 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++/*++ ++ This file includes all kinds of Power Action event for RTL8723B and corresponding hardware configurtions which are released from HW SD. ++ ++Major Change History: ++ When Who What ++ ---------- --------------- ------------------------------- ++ 2011-08-08 Roger Create. ++ ++--*/ ++ ++#include "Hal8723BPwrSeq.h" ++ ++/* ++ drivers should parse below arrays and do the corresponding actions ++*/ ++/* 3 Power on Array */ ++WLAN_PWR_CFG rtl8723B_power_on_flow[RTL8723B_TRANS_CARDEMU_TO_ACT_STEPS+RTL8723B_TRANS_END_STEPS]= ++{ ++ RTL8723B_TRANS_CARDEMU_TO_ACT ++ RTL8723B_TRANS_END ++}; ++ ++/* 3Radio off GPIO Array */ ++WLAN_PWR_CFG rtl8723B_radio_off_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_END_STEPS]= ++{ ++ RTL8723B_TRANS_ACT_TO_CARDEMU ++ RTL8723B_TRANS_END ++}; ++ ++/* 3Card Disable Array */ ++WLAN_PWR_CFG rtl8723B_card_disable_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723B_TRANS_END_STEPS]= ++{ ++ RTL8723B_TRANS_ACT_TO_CARDEMU ++ RTL8723B_TRANS_CARDEMU_TO_CARDDIS ++ RTL8723B_TRANS_END ++}; ++ ++/* 3 Card Enable Array */ ++WLAN_PWR_CFG rtl8723B_card_enable_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723B_TRANS_END_STEPS]= ++{ ++ RTL8723B_TRANS_CARDDIS_TO_CARDEMU ++ RTL8723B_TRANS_CARDEMU_TO_ACT ++ RTL8723B_TRANS_END ++}; ++ ++/* 3Suspend Array */ ++WLAN_PWR_CFG rtl8723B_suspend_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS+RTL8723B_TRANS_END_STEPS]= ++{ ++ RTL8723B_TRANS_ACT_TO_CARDEMU ++ RTL8723B_TRANS_CARDEMU_TO_SUS ++ RTL8723B_TRANS_END ++}; ++ ++/* 3 Resume Array */ ++WLAN_PWR_CFG rtl8723B_resume_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS+RTL8723B_TRANS_END_STEPS]= ++{ ++ RTL8723B_TRANS_SUS_TO_CARDEMU ++ RTL8723B_TRANS_CARDEMU_TO_ACT ++ RTL8723B_TRANS_END ++}; ++ ++/* 3HWPDN Array */ ++WLAN_PWR_CFG rtl8723B_hwpdn_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723B_TRANS_END_STEPS]= ++{ ++ RTL8723B_TRANS_ACT_TO_CARDEMU ++ RTL8723B_TRANS_CARDEMU_TO_PDN ++ RTL8723B_TRANS_END ++}; ++ ++/* 3 Enter LPS */ ++WLAN_PWR_CFG rtl8723B_enter_lps_flow[RTL8723B_TRANS_ACT_TO_LPS_STEPS+RTL8723B_TRANS_END_STEPS]= ++{ ++ /* FW behavior */ ++ RTL8723B_TRANS_ACT_TO_LPS ++ RTL8723B_TRANS_END ++}; ++ ++/* 3 Leave LPS */ ++WLAN_PWR_CFG rtl8723B_leave_lps_flow[RTL8723B_TRANS_LPS_TO_ACT_STEPS+RTL8723B_TRANS_END_STEPS]= ++{ ++ /* FW behavior */ ++ RTL8723B_TRANS_LPS_TO_ACT ++ RTL8723B_TRANS_END ++}; ++ ++/* 3 Enter SW LPS */ ++WLAN_PWR_CFG rtl8723B_enter_swlps_flow[RTL8723B_TRANS_ACT_TO_SWLPS_STEPS+RTL8723B_TRANS_END_STEPS]= ++{ ++ /* SW behavior */ ++ RTL8723B_TRANS_ACT_TO_SWLPS ++ RTL8723B_TRANS_END ++}; ++ ++/* 3 Leave SW LPS */ ++WLAN_PWR_CFG rtl8723B_leave_swlps_flow[RTL8723B_TRANS_SWLPS_TO_ACT_STEPS+RTL8723B_TRANS_END_STEPS]= ++{ ++ /* SW behavior */ ++ RTL8723B_TRANS_SWLPS_TO_ACT ++ RTL8723B_TRANS_END ++}; +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/Hal8723BReg.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/Hal8723BReg.h +--- linux-4.3/3rdparty/rtl8723bs/hal/Hal8723BReg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/Hal8723BReg.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,442 @@ ++/***************************************************************************** ++ *Copyright(c) 2009, RealTEK Technology Inc. All Right Reserved. ++ * ++ * Module: __INC_HAL8723BREG_H ++ * ++ * ++ * Note: 1. Define Mac register address and corresponding bit mask map ++ * ++ * ++ * Export: Constants, macro, functions(API), global variables(None). ++ * ++ * Abbrev: ++ * ++ * History: ++ * Data Who Remark ++ * ++ *****************************************************************************/ ++#ifndef __INC_HAL8723BREG_H ++#define __INC_HAL8723BREG_H ++ ++ ++ ++/* */ ++/* */ ++/* */ ++ ++/* */ ++/* */ ++/* 0x0000h ~ 0x00FFh System Configuration */ ++/* */ ++/* */ ++#define REG_SYS_ISO_CTRL_8723B 0x0000 /* 2 Byte */ ++#define REG_SYS_FUNC_EN_8723B 0x0002 /* 2 Byte */ ++#define REG_APS_FSMCO_8723B 0x0004 /* 4 Byte */ ++#define REG_SYS_CLKR_8723B 0x0008 /* 2 Byte */ ++#define REG_9346CR_8723B 0x000A /* 2 Byte */ ++#define REG_EE_VPD_8723B 0x000C /* 2 Byte */ ++#define REG_AFE_MISC_8723B 0x0010 /* 1 Byte */ ++#define REG_SPS0_CTRL_8723B 0x0011 /* 7 Byte */ ++#define REG_SPS_OCP_CFG_8723B 0x0018 /* 4 Byte */ ++#define REG_RSV_CTRL_8723B 0x001C /* 3 Byte */ ++#define REG_RF_CTRL_8723B 0x001F /* 1 Byte */ ++#define REG_LPLDO_CTRL_8723B 0x0023 /* 1 Byte */ ++#define REG_AFE_XTAL_CTRL_8723B 0x0024 /* 4 Byte */ ++#define REG_AFE_PLL_CTRL_8723B 0x0028 /* 4 Byte */ ++#define REG_MAC_PLL_CTRL_EXT_8723B 0x002c /* 4 Byte */ ++#define REG_EFUSE_CTRL_8723B 0x0030 ++#define REG_EFUSE_TEST_8723B 0x0034 ++#define REG_PWR_DATA_8723B 0x0038 ++#define REG_CAL_TIMER_8723B 0x003C ++#define REG_ACLK_MON_8723B 0x003E ++#define REG_GPIO_MUXCFG_8723B 0x0040 ++#define REG_GPIO_IO_SEL_8723B 0x0042 ++#define REG_MAC_PINMUX_CFG_8723B 0x0043 ++#define REG_GPIO_PIN_CTRL_8723B 0x0044 ++#define REG_GPIO_INTM_8723B 0x0048 ++#define REG_LEDCFG0_8723B 0x004C ++#define REG_LEDCFG1_8723B 0x004D ++#define REG_LEDCFG2_8723B 0x004E ++#define REG_LEDCFG3_8723B 0x004F ++#define REG_FSIMR_8723B 0x0050 ++#define REG_FSISR_8723B 0x0054 ++#define REG_HSIMR_8723B 0x0058 ++#define REG_HSISR_8723B 0x005c ++#define REG_GPIO_EXT_CTRL 0x0060 ++#define REG_MULTI_FUNC_CTRL_8723B 0x0068 ++#define REG_GPIO_STATUS_8723B 0x006C ++#define REG_SDIO_CTRL_8723B 0x0070 ++#define REG_OPT_CTRL_8723B 0x0074 ++#define REG_AFE_XTAL_CTRL_EXT_8723B 0x0078 ++#define REG_MCUFWDL_8723B 0x0080 ++#define REG_BT_PATCH_STATUS_8723B 0x0088 ++#define REG_HIMR0_8723B 0x00B0 ++#define REG_HISR0_8723B 0x00B4 ++#define REG_HIMR1_8723B 0x00B8 ++#define REG_HISR1_8723B 0x00BC ++#define REG_PMC_DBG_CTRL2_8723B 0x00CC ++#define REG_EFUSE_BURN_GNT_8723B 0x00CF ++#define REG_HPON_FSM_8723B 0x00EC ++#define REG_SYS_CFG_8723B 0x00F0 ++#define REG_SYS_CFG1_8723B 0x00FC ++#define REG_ROM_VERSION 0x00FD ++ ++/* */ ++/* */ ++/* 0x0100h ~ 0x01FFh MACTOP General Configuration */ ++/* */ ++/* */ ++#define REG_CR_8723B 0x0100 ++#define REG_PBP_8723B 0x0104 ++#define REG_PKT_BUFF_ACCESS_CTRL_8723B 0x0106 ++#define REG_TRXDMA_CTRL_8723B 0x010C ++#define REG_TRXFF_BNDY_8723B 0x0114 ++#define REG_TRXFF_STATUS_8723B 0x0118 ++#define REG_RXFF_PTR_8723B 0x011C ++#define REG_CPWM_8723B 0x012F ++#define REG_FWIMR_8723B 0x0130 ++#define REG_FWISR_8723B 0x0134 ++#define REG_FTIMR_8723B 0x0138 ++#define REG_PKTBUF_DBG_CTRL_8723B 0x0140 ++#define REG_RXPKTBUF_CTRL_8723B 0x0142 ++#define REG_PKTBUF_DBG_DATA_L_8723B 0x0144 ++#define REG_PKTBUF_DBG_DATA_H_8723B 0x0148 ++ ++#define REG_TC0_CTRL_8723B 0x0150 ++#define REG_TC1_CTRL_8723B 0x0154 ++#define REG_TC2_CTRL_8723B 0x0158 ++#define REG_TC3_CTRL_8723B 0x015C ++#define REG_TC4_CTRL_8723B 0x0160 ++#define REG_TCUNIT_BASE_8723B 0x0164 ++#define REG_RSVD3_8723B 0x0168 ++#define REG_C2HEVT_MSG_NORMAL_8723B 0x01A0 ++#define REG_C2HEVT_CMD_SEQ_88XX 0x01A1 ++#define REG_C2hEVT_CMD_CONTENT_88XX 0x01A2 ++#define REG_C2HEVT_CMD_LEN_88XX 0x01AE ++#define REG_C2HEVT_CLEAR_8723B 0x01AF ++#define REG_MCUTST_1_8723B 0x01C0 ++#define REG_MCUTST_WOWLAN_8723B 0x01C7 ++#define REG_FMETHR_8723B 0x01C8 ++#define REG_HMETFR_8723B 0x01CC ++#define REG_HMEBOX_0_8723B 0x01D0 ++#define REG_HMEBOX_1_8723B 0x01D4 ++#define REG_HMEBOX_2_8723B 0x01D8 ++#define REG_HMEBOX_3_8723B 0x01DC ++#define REG_LLT_INIT_8723B 0x01E0 ++#define REG_HMEBOX_EXT0_8723B 0x01F0 ++#define REG_HMEBOX_EXT1_8723B 0x01F4 ++#define REG_HMEBOX_EXT2_8723B 0x01F8 ++#define REG_HMEBOX_EXT3_8723B 0x01FC ++ ++/* */ ++/* */ ++/* 0x0200h ~ 0x027Fh TXDMA Configuration */ ++/* */ ++/* */ ++#define REG_RQPN_8723B 0x0200 ++#define REG_FIFOPAGE_8723B 0x0204 ++#define REG_DWBCN0_CTRL_8723B REG_TDECTRL ++#define REG_TXDMA_OFFSET_CHK_8723B 0x020C ++#define REG_TXDMA_STATUS_8723B 0x0210 ++#define REG_RQPN_NPQ_8723B 0x0214 ++#define REG_DWBCN1_CTRL_8723B 0x0228 ++ ++ ++/* */ ++/* */ ++/* 0x0280h ~ 0x02FFh RXDMA Configuration */ ++/* */ ++/* */ ++#define REG_RXDMA_AGG_PG_TH_8723B 0x0280 ++#define REG_FW_UPD_RDPTR_8723B 0x0284 /* FW shall update this register before FW write RXPKT_RELEASE_POLL to 1 */ ++#define REG_RXDMA_CONTROL_8723B 0x0286 /* Control the RX DMA. */ ++#define REG_RXPKT_NUM_8723B 0x0287 /* The number of packets in RXPKTBUF. */ ++#define REG_RXDMA_STATUS_8723B 0x0288 ++#define REG_RXDMA_PRO_8723B 0x0290 ++#define REG_EARLY_MODE_CONTROL_8723B 0x02BC ++#define REG_RSVD5_8723B 0x02F0 ++#define REG_RSVD6_8723B 0x02F4 ++ ++ ++/* */ ++/* */ ++/* 0x0300h ~ 0x03FFh PCIe */ ++/* */ ++/* */ ++#define REG_PCIE_CTRL_REG_8723B 0x0300 ++#define REG_INT_MIG_8723B 0x0304 /* Interrupt Migration */ ++#define REG_BCNQ_DESA_8723B 0x0308 /* TX Beacon Descriptor Address */ ++#define REG_HQ_DESA_8723B 0x0310 /* TX High Queue Descriptor Address */ ++#define REG_MGQ_DESA_8723B 0x0318 /* TX Manage Queue Descriptor Address */ ++#define REG_VOQ_DESA_8723B 0x0320 /* TX VO Queue Descriptor Address */ ++#define REG_VIQ_DESA_8723B 0x0328 /* TX VI Queue Descriptor Address */ ++#define REG_BEQ_DESA_8723B 0x0330 /* TX BE Queue Descriptor Address */ ++#define REG_BKQ_DESA_8723B 0x0338 /* TX BK Queue Descriptor Address */ ++#define REG_RX_DESA_8723B 0x0340 /* RX Queue Descriptor Address */ ++#define REG_DBI_WDATA_8723B 0x0348 /* DBI Write Data */ ++#define REG_DBI_RDATA_8723B 0x034C /* DBI Read Data */ ++#define REG_DBI_ADDR_8723B 0x0350 /* DBI Address */ ++#define REG_DBI_FLAG_8723B 0x0352 /* DBI Read/Write Flag */ ++#define REG_MDIO_WDATA_8723B 0x0354 /* MDIO for Write PCIE PHY */ ++#define REG_MDIO_RDATA_8723B 0x0356 /* MDIO for Reads PCIE PHY */ ++#define REG_MDIO_CTL_8723B 0x0358 /* MDIO for Control */ ++#define REG_DBG_SEL_8723B 0x0360 /* Debug Selection Register */ ++#define REG_PCIE_HRPWM_8723B 0x0361 /* PCIe RPWM */ ++#define REG_PCIE_HCPWM_8723B 0x0363 /* PCIe CPWM */ ++#define REG_PCIE_MULTIFET_CTRL_8723B 0x036A /* PCIE Multi-Fethc Control */ ++ ++/* spec version 11 */ ++/* */ ++/* */ ++/* 0x0400h ~ 0x047Fh Protocol Configuration */ ++/* */ ++/* */ ++#define REG_VOQ_INFORMATION_8723B 0x0400 ++#define REG_VIQ_INFORMATION_8723B 0x0404 ++#define REG_BEQ_INFORMATION_8723B 0x0408 ++#define REG_BKQ_INFORMATION_8723B 0x040C ++#define REG_MGQ_INFORMATION_8723B 0x0410 ++#define REG_HGQ_INFORMATION_8723B 0x0414 ++#define REG_BCNQ_INFORMATION_8723B 0x0418 ++#define REG_TXPKT_EMPTY_8723B 0x041A ++ ++#define REG_FWHW_TXQ_CTRL_8723B 0x0420 ++#define REG_HWSEQ_CTRL_8723B 0x0423 ++#define REG_TXPKTBUF_BCNQ_BDNY_8723B 0x0424 ++#define REG_TXPKTBUF_MGQ_BDNY_8723B 0x0425 ++#define REG_LIFECTRL_CTRL_8723B 0x0426 ++#define REG_MULTI_BCNQ_OFFSET_8723B 0x0427 ++#define REG_SPEC_SIFS_8723B 0x0428 ++#define REG_RL_8723B 0x042A ++#define REG_TXBF_CTRL_8723B 0x042C ++#define REG_DARFRC_8723B 0x0430 ++#define REG_RARFRC_8723B 0x0438 ++#define REG_RRSR_8723B 0x0440 ++#define REG_ARFR0_8723B 0x0444 ++#define REG_ARFR1_8723B 0x044C ++#define REG_CCK_CHECK_8723B 0x0454 ++#define REG_AMPDU_MAX_TIME_8723B 0x0456 ++#define REG_TXPKTBUF_BCNQ_BDNY1_8723B 0x0457 ++ ++#define REG_AMPDU_MAX_LENGTH_8723B 0x0458 ++#define REG_TXPKTBUF_WMAC_LBK_BF_HD_8723B 0x045D ++#define REG_NDPA_OPT_CTRL_8723B 0x045F ++#define REG_FAST_EDCA_CTRL_8723B 0x0460 ++#define REG_RD_RESP_PKT_TH_8723B 0x0463 ++#define REG_DATA_SC_8723B 0x0483 ++#define REG_TXRPT_START_OFFSET 0x04AC ++#define REG_POWER_STAGE1_8723B 0x04B4 ++#define REG_POWER_STAGE2_8723B 0x04B8 ++#define REG_AMPDU_BURST_MODE_8723B 0x04BC ++#define REG_PKT_VO_VI_LIFE_TIME_8723B 0x04C0 ++#define REG_PKT_BE_BK_LIFE_TIME_8723B 0x04C2 ++#define REG_STBC_SETTING_8723B 0x04C4 ++#define REG_HT_SINGLE_AMPDU_8723B 0x04C7 ++#define REG_PROT_MODE_CTRL_8723B 0x04C8 ++#define REG_MAX_AGGR_NUM_8723B 0x04CA ++#define REG_RTS_MAX_AGGR_NUM_8723B 0x04CB ++#define REG_BAR_MODE_CTRL_8723B 0x04CC ++#define REG_RA_TRY_RATE_AGG_LMT_8723B 0x04CF ++#define REG_MACID_PKT_DROP0_8723B 0x04D0 ++#define REG_MACID_PKT_SLEEP_8723B 0x04D4 ++ ++/* */ ++/* */ ++/* 0x0500h ~ 0x05FFh EDCA Configuration */ ++/* */ ++/* */ ++#define REG_EDCA_VO_PARAM_8723B 0x0500 ++#define REG_EDCA_VI_PARAM_8723B 0x0504 ++#define REG_EDCA_BE_PARAM_8723B 0x0508 ++#define REG_EDCA_BK_PARAM_8723B 0x050C ++#define REG_BCNTCFG_8723B 0x0510 ++#define REG_PIFS_8723B 0x0512 ++#define REG_RDG_PIFS_8723B 0x0513 ++#define REG_SIFS_CTX_8723B 0x0514 ++#define REG_SIFS_TRX_8723B 0x0516 ++#define REG_AGGR_BREAK_TIME_8723B 0x051A ++#define REG_SLOT_8723B 0x051B ++#define REG_TX_PTCL_CTRL_8723B 0x0520 ++#define REG_TXPAUSE_8723B 0x0522 ++#define REG_DIS_TXREQ_CLR_8723B 0x0523 ++#define REG_RD_CTRL_8723B 0x0524 ++/* */ ++/* Format for offset 540h-542h: */ ++/* [3:0]: TBTT prohibit setup in unit of 32us. The time for HW getting beacon content before TBTT. */ ++/* [7:4]: Reserved. */ ++/* [19:8]: TBTT prohibit hold in unit of 32us. The time for HW holding to send the beacon packet. */ ++/* [23:20]: Reserved */ ++/* Description: */ ++/* | */ ++/* |<--Setup--|--Hold------------>| */ ++/* --------------|---------------------- */ ++/* | */ ++/* TBTT */ ++/* Note: We cannot update beacon content to HW or send any AC packets during the time between Setup and Hold. */ ++/* Described by Designer Tim and Bruce, 2011-01-14. */ ++/* */ ++#define REG_TBTT_PROHIBIT_8723B 0x0540 ++#define REG_RD_NAV_NXT_8723B 0x0544 ++#define REG_NAV_PROT_LEN_8723B 0x0546 ++#define REG_BCN_CTRL_8723B 0x0550 ++#define REG_BCN_CTRL_1_8723B 0x0551 ++#define REG_MBID_NUM_8723B 0x0552 ++#define REG_DUAL_TSF_RST_8723B 0x0553 ++#define REG_BCN_INTERVAL_8723B 0x0554 ++#define REG_DRVERLYINT_8723B 0x0558 ++#define REG_BCNDMATIM_8723B 0x0559 ++#define REG_ATIMWND_8723B 0x055A ++#define REG_USTIME_TSF_8723B 0x055C ++#define REG_BCN_MAX_ERR_8723B 0x055D ++#define REG_RXTSF_OFFSET_CCK_8723B 0x055E ++#define REG_RXTSF_OFFSET_OFDM_8723B 0x055F ++#define REG_TSFTR_8723B 0x0560 ++#define REG_CTWND_8723B 0x0572 ++#define REG_SECONDARY_CCA_CTRL_8723B 0x0577 ++#define REG_PSTIMER_8723B 0x0580 ++#define REG_TIMER0_8723B 0x0584 ++#define REG_TIMER1_8723B 0x0588 ++#define REG_ACMHWCTRL_8723B 0x05C0 ++#define REG_SCH_TXCMD_8723B 0x05F8 ++ ++/* 0x0600h ~ 0x07FFh WMAC Configuration */ ++#define REG_MAC_CR_8723B 0x0600 ++#define REG_TCR_8723B 0x0604 ++#define REG_RCR_8723B 0x0608 ++#define REG_RX_PKT_LIMIT_8723B 0x060C ++#define REG_RX_DLK_TIME_8723B 0x060D ++#define REG_RX_DRVINFO_SZ_8723B 0x060F ++ ++#define REG_MACID_8723B 0x0610 ++#define REG_BSSID_8723B 0x0618 ++#define REG_MAR_8723B 0x0620 ++#define REG_MBIDCAMCFG_8723B 0x0628 ++ ++#define REG_USTIME_EDCA_8723B 0x0638 ++#define REG_MAC_SPEC_SIFS_8723B 0x063A ++#define REG_RESP_SIFP_CCK_8723B 0x063C ++#define REG_RESP_SIFS_OFDM_8723B 0x063E ++#define REG_ACKTO_8723B 0x0640 ++#define REG_CTS2TO_8723B 0x0641 ++#define REG_EIFS_8723B 0x0642 ++ ++#define REG_NAV_UPPER_8723B 0x0652 /* unit of 128 */ ++#define REG_TRXPTCL_CTL_8723B 0x0668 ++ ++/* Security */ ++#define REG_CAMCMD_8723B 0x0670 ++#define REG_CAMWRITE_8723B 0x0674 ++#define REG_CAMREAD_8723B 0x0678 ++#define REG_CAMDBG_8723B 0x067C ++#define REG_SECCFG_8723B 0x0680 ++ ++/* Power */ ++#define REG_WOW_CTRL_8723B 0x0690 ++#define REG_PS_RX_INFO_8723B 0x0692 ++#define REG_UAPSD_TID_8723B 0x0693 ++#define REG_WKFMCAM_CMD_8723B 0x0698 ++#define REG_WKFMCAM_NUM_8723B 0x0698 ++#define REG_WKFMCAM_RWD_8723B 0x069C ++#define REG_RXFLTMAP0_8723B 0x06A0 ++#define REG_RXFLTMAP1_8723B 0x06A2 ++#define REG_RXFLTMAP2_8723B 0x06A4 ++#define REG_BCN_PSR_RPT_8723B 0x06A8 ++#define REG_BT_COEX_TABLE_8723B 0x06C0 ++#define REG_BFMER0_INFO_8723B 0x06E4 ++#define REG_BFMER1_INFO_8723B 0x06EC ++#define REG_CSI_RPT_PARAM_BW20_8723B 0x06F4 ++#define REG_CSI_RPT_PARAM_BW40_8723B 0x06F8 ++#define REG_CSI_RPT_PARAM_BW80_8723B 0x06FC ++ ++/* Hardware Port 2 */ ++#define REG_MACID1_8723B 0x0700 ++#define REG_BSSID1_8723B 0x0708 ++#define REG_BFMEE_SEL_8723B 0x0714 ++#define REG_SND_PTCL_CTRL_8723B 0x0718 ++ ++ ++/* Redifine 8192C register definition for compatibility */ ++ ++/* TODO: use these definition when using REG_xxx naming rule. */ ++/* NOTE: DO NOT Remove these definition. Use later. */ ++#define EFUSE_CTRL_8723B REG_EFUSE_CTRL_8723B /* E-Fuse Control. */ ++#define EFUSE_TEST_8723B REG_EFUSE_TEST_8723B /* E-Fuse Test. */ ++#define MSR_8723B (REG_CR_8723B + 2) /* Media Status register */ ++#define ISR_8723B REG_HISR0_8723B ++#define TSFR_8723B REG_TSFTR_8723B /* Timing Sync Function Timer Register. */ ++ ++#define PBP_8723B REG_PBP_8723B ++ ++/* Redifine MACID register, to compatible prior ICs. */ ++#define IDR0_8723B REG_MACID_8723B /* MAC ID Register, Offset 0x0050-0x0053 */ ++#define IDR4_8723B (REG_MACID_8723B + 4) /* MAC ID Register, Offset 0x0054-0x0055 */ ++ ++/* 9. Security Control Registers (Offset:) */ ++#define RWCAM_8723B REG_CAMCMD_8723B /* IN 8190 Data Sheet is called CAMcmd */ ++#define WCAMI_8723B REG_CAMWRITE_8723B /* Software write CAM input content */ ++#define RCAMO_8723B REG_CAMREAD_8723B /* Software read/write CAM config */ ++#define CAMDBG_8723B REG_CAMDBG_8723B ++#define SECR_8723B REG_SECCFG_8723B /* Security Configuration Register */ ++ ++/* 8195 IMR/ISR bits (offset 0xB0, 8bits) */ ++#define IMR_DISABLED_8723B 0 ++/* IMR DW0(0x00B0-00B3) Bit 0-31 */ ++#define IMR_TIMER2_8723B BIT31 /* Timeout interrupt 2 */ ++#define IMR_TIMER1_8723B BIT30 /* Timeout interrupt 1 */ ++#define IMR_PSTIMEOUT_8723B BIT29 /* Power Save Time Out Interrupt */ ++#define IMR_GTINT4_8723B BIT28 /* When GTIMER4 expires, this bit is set to 1 */ ++#define IMR_GTINT3_8723B BIT27 /* When GTIMER3 expires, this bit is set to 1 */ ++#define IMR_TXBCN0ERR_8723B BIT26 /* Transmit Beacon0 Error */ ++#define IMR_TXBCN0OK_8723B BIT25 /* Transmit Beacon0 OK */ ++#define IMR_TSF_BIT32_TOGGLE_8723B BIT24 /* TSF Timer BIT32 toggle indication interrupt */ ++#define IMR_BCNDMAINT0_8723B BIT20 /* Beacon DMA Interrupt 0 */ ++#define IMR_BCNDERR0_8723B BIT16 /* Beacon Queue DMA OK0 */ ++#define IMR_HSISR_IND_ON_INT_8723B BIT15 /* HSISR Indicator (HSIMR & HSISR is true, this bit is set to 1) */ ++#define IMR_BCNDMAINT_E_8723B BIT14 /* Beacon DMA Interrupt Extension for Win7 */ ++#define IMR_ATIMEND_8723B BIT12 /* CTWidnow End or ATIM Window End */ ++#define IMR_C2HCMD_8723B BIT10 /* CPU to Host Command INT Status, Write 1 clear */ ++#define IMR_CPWM2_8723B BIT9 /* CPU power Mode exchange INT Status, Write 1 clear */ ++#define IMR_CPWM_8723B BIT8 /* CPU power Mode exchange INT Status, Write 1 clear */ ++#define IMR_HIGHDOK_8723B BIT7 /* High Queue DMA OK */ ++#define IMR_MGNTDOK_8723B BIT6 /* Management Queue DMA OK */ ++#define IMR_BKDOK_8723B BIT5 /* AC_BK DMA OK */ ++#define IMR_BEDOK_8723B BIT4 /* AC_BE DMA OK */ ++#define IMR_VIDOK_8723B BIT3 /* AC_VI DMA OK */ ++#define IMR_VODOK_8723B BIT2 /* AC_VO DMA OK */ ++#define IMR_RDU_8723B BIT1 /* Rx Descriptor Unavailable */ ++#define IMR_ROK_8723B BIT0 /* Receive DMA OK */ ++ ++/* IMR DW1(0x00B4-00B7) Bit 0-31 */ ++#define IMR_BCNDMAINT7_8723B BIT27 /* Beacon DMA Interrupt 7 */ ++#define IMR_BCNDMAINT6_8723B BIT26 /* Beacon DMA Interrupt 6 */ ++#define IMR_BCNDMAINT5_8723B BIT25 /* Beacon DMA Interrupt 5 */ ++#define IMR_BCNDMAINT4_8723B BIT24 /* Beacon DMA Interrupt 4 */ ++#define IMR_BCNDMAINT3_8723B BIT23 /* Beacon DMA Interrupt 3 */ ++#define IMR_BCNDMAINT2_8723B BIT22 /* Beacon DMA Interrupt 2 */ ++#define IMR_BCNDMAINT1_8723B BIT21 /* Beacon DMA Interrupt 1 */ ++#define IMR_BCNDOK7_8723B BIT20 /* Beacon Queue DMA OK Interrup 7 */ ++#define IMR_BCNDOK6_8723B BIT19 /* Beacon Queue DMA OK Interrup 6 */ ++#define IMR_BCNDOK5_8723B BIT18 /* Beacon Queue DMA OK Interrup 5 */ ++#define IMR_BCNDOK4_8723B BIT17 /* Beacon Queue DMA OK Interrup 4 */ ++#define IMR_BCNDOK3_8723B BIT16 /* Beacon Queue DMA OK Interrup 3 */ ++#define IMR_BCNDOK2_8723B BIT15 /* Beacon Queue DMA OK Interrup 2 */ ++#define IMR_BCNDOK1_8723B BIT14 /* Beacon Queue DMA OK Interrup 1 */ ++#define IMR_ATIMEND_E_8723B BIT13 /* ATIM Window End Extension for Win7 */ ++#define IMR_TXERR_8723B BIT11 /* Tx Error Flag Interrupt Status, write 1 clear. */ ++#define IMR_RXERR_8723B BIT10 /* Rx Error Flag INT Status, Write 1 clear */ ++#define IMR_TXFOVW_8723B BIT9 /* Transmit FIFO Overflow */ ++#define IMR_RXFOVW_8723B BIT8 /* Receive FIFO Overflow */ ++ ++/* 2 ACMHWCTRL 0x05C0 */ ++#define AcmHw_HwEn_8723B BIT(0) ++#define AcmHw_VoqEn_8723B BIT(1) ++#define AcmHw_ViqEn_8723B BIT(2) ++#define AcmHw_BeqEn_8723B BIT(3) ++#define AcmHw_VoqStatus_8723B BIT(5) ++#define AcmHw_ViqStatus_8723B BIT(6) ++#define AcmHw_BeqStatus_8723B BIT(7) ++ ++/* 8195 (RCR) Receive Configuration Register (Offset 0x608, 32 bits) */ ++#define RCR_TCPOFLD_EN BIT25 /* Enable TCP checksum offload */ ++ ++#endif /* #ifndef __INC_HAL8723BREG_H */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/HalBtc8723b1Ant.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalBtc8723b1Ant.c +--- linux-4.3/3rdparty/rtl8723bs/hal/HalBtc8723b1Ant.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalBtc8723b1Ant.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,3547 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#include "Mp_Precomp.h" ++ ++/* Global variables, these are static variables */ ++static COEX_DM_8723B_1ANT GLCoexDm8723b1Ant; ++static PCOEX_DM_8723B_1ANT pCoexDm =&GLCoexDm8723b1Ant; ++static COEX_STA_8723B_1ANT GLCoexSta8723b1Ant; ++static PCOEX_STA_8723B_1ANT pCoexSta =&GLCoexSta8723b1Ant; ++ ++static const char *const GLBtInfoSrc8723b1Ant[]={ ++ "BT Info[wifi fw]", ++ "BT Info[bt rsp]", ++ "BT Info[bt auto report]", ++}; ++ ++static u32 GLCoexVerDate8723b1Ant =20140507; ++static u32 GLCoexVer8723b1Ant = 0x4e; ++ ++/* local function proto type if needed */ ++/* local function start with halbtc8723b1ant_ */ ++static u8 ++halbtc8723b1ant_BtRssiState( ++ u8 levelNum, ++ u8 rssiThresh, ++ u8 rssiThresh1 ++ ) ++{ ++ s32 btRssi = 0; ++ u8 btRssiState =pCoexSta->preBtRssiState; ++ ++ btRssi = pCoexSta->btRssi; ++ ++ if (levelNum == 2) ++ { ++ if ((pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || ++ (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) ++ { ++ if (btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT)) ++ { ++ btRssiState = BTC_RSSI_STATE_HIGH; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); ++ } ++ else ++ { ++ btRssiState = BTC_RSSI_STATE_STAY_LOW; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); ++ } ++ } ++ else ++ { ++ if (btRssi < rssiThresh) ++ { ++ btRssiState = BTC_RSSI_STATE_LOW; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); ++ } ++ else ++ { ++ btRssiState = BTC_RSSI_STATE_STAY_HIGH; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); ++ } ++ } ++ } ++ else if (levelNum == 3) ++ { ++ if (rssiThresh > rssiThresh1) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi thresh error!!\n")); ++ return pCoexSta->preBtRssiState; ++ } ++ ++ if ((pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || ++ (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) ++ { ++ if (btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT)) ++ { ++ btRssiState = BTC_RSSI_STATE_MEDIUM; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); ++ } ++ else ++ { ++ btRssiState = BTC_RSSI_STATE_STAY_LOW; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); ++ } ++ } ++ else if ((pCoexSta->preBtRssiState == BTC_RSSI_STATE_MEDIUM) || ++ (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_MEDIUM)) ++ { ++ if (btRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT)) ++ { ++ btRssiState = BTC_RSSI_STATE_HIGH; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); ++ } ++ else if (btRssi < rssiThresh) ++ { ++ btRssiState = BTC_RSSI_STATE_LOW; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); ++ } ++ else ++ { ++ btRssiState = BTC_RSSI_STATE_STAY_MEDIUM; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Medium\n")); ++ } ++ } ++ else ++ { ++ if (btRssi < rssiThresh1) ++ { ++ btRssiState = BTC_RSSI_STATE_MEDIUM; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); ++ } ++ else ++ { ++ btRssiState = BTC_RSSI_STATE_STAY_HIGH; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); ++ } ++ } ++ } ++ ++ pCoexSta->preBtRssiState = btRssiState; ++ ++ return btRssiState; ++} ++ ++static void ++halbtc8723b1ant_UpdateRaMask( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++u32 disRateMask ++ ) ++{ ++ pCoexDm->curRaMask = disRateMask; ++ ++ if (bForceExec || (pCoexDm->preRaMask != pCoexDm->curRaMask)) ++ { ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_UPDATE_RAMASK, &pCoexDm->curRaMask); ++ } ++ pCoexDm->preRaMask = pCoexDm->curRaMask; ++} ++ ++static void ++halbtc8723b1ant_AutoRateFallbackRetry( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++u8 type ++ ) ++{ ++ bool bWifiUnderBMode =false; ++ ++ pCoexDm->curArfrType = type; ++ ++ if (bForceExec || (pCoexDm->preArfrType != pCoexDm->curArfrType)) ++ { ++ switch (pCoexDm->curArfrType) ++ { ++ case 0: /* normal mode */ ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x430, pCoexDm->backupArfrCnt1); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x434, pCoexDm->backupArfrCnt2); ++ break; ++ case 1: ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, &bWifiUnderBMode); ++ if (bWifiUnderBMode) ++ { ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x430, 0x0); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x434, 0x01010101); ++ } ++ else ++ { ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x430, 0x0); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x434, 0x04030201); ++ } ++ break; ++ default: ++ break; ++ } ++ } ++ ++ pCoexDm->preArfrType = pCoexDm->curArfrType; ++} ++ ++static void ++halbtc8723b1ant_RetryLimit( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++u8 type ++ ) ++{ ++ pCoexDm->curRetryLimitType = type; ++ ++ if (bForceExec || (pCoexDm->preRetryLimitType != pCoexDm->curRetryLimitType)) ++ { ++ switch (pCoexDm->curRetryLimitType) ++ { ++ case 0: /* normal mode */ ++ pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x42a, pCoexDm->backupRetryLimit); ++ break; ++ case 1: /* retry limit =8 */ ++ pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x42a, 0x0808); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ pCoexDm->preRetryLimitType = pCoexDm->curRetryLimitType; ++} ++ ++static void ++halbtc8723b1ant_AmpduMaxTime( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++u8 type ++ ) ++{ ++ pCoexDm->curAmpduTimeType = type; ++ ++ if (bForceExec || (pCoexDm->preAmpduTimeType != pCoexDm->curAmpduTimeType)) ++ { ++ switch (pCoexDm->curAmpduTimeType) ++ { ++ case 0: /* normal mode */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x456, pCoexDm->backupAmpduMaxTime); ++ break; ++ case 1: /* AMPDU timw = 0x38 * 32us */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x456, 0x38); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ pCoexDm->preAmpduTimeType = pCoexDm->curAmpduTimeType; ++} ++ ++static void ++halbtc8723b1ant_LimitedTx( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++u8 raMaskType, ++u8 arfrType, ++u8 retryLimitType, ++u8 ampduTimeType ++ ) ++{ ++ switch (raMaskType) ++ { ++ case 0: /* normal mode */ ++ halbtc8723b1ant_UpdateRaMask(pBtCoexist, bForceExec, 0x0); ++ break; ++ case 1: /* disable cck 1/2 */ ++ halbtc8723b1ant_UpdateRaMask(pBtCoexist, bForceExec, 0x00000003); ++ break; ++ case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */ ++ halbtc8723b1ant_UpdateRaMask(pBtCoexist, bForceExec, 0x0001f1f7); ++ break; ++ default: ++ break; ++ } ++ ++ halbtc8723b1ant_AutoRateFallbackRetry(pBtCoexist, bForceExec, arfrType); ++ halbtc8723b1ant_RetryLimit(pBtCoexist, bForceExec, retryLimitType); ++ halbtc8723b1ant_AmpduMaxTime(pBtCoexist, bForceExec, ampduTimeType); ++} ++ ++static void ++halbtc8723b1ant_LimitedRx( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++bool bRejApAggPkt, ++bool bBtCtrlAggBufSize, ++u8 aggBufSize ++ ) ++{ ++ bool bRejectRxAgg =bRejApAggPkt; ++ bool bBtCtrlRxAggSize =bBtCtrlAggBufSize; ++ u8 rxAggSize =aggBufSize; ++ ++ /* */ ++ /* Rx Aggregation related setting */ ++ /* */ ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, &bRejectRxAgg); ++ /* decide BT control aggregation buf size or not */ ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, &bBtCtrlRxAggSize); ++ /* aggregation buf size, only work when BT control Rx aggregation size. */ ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_AGG_BUF_SIZE, &rxAggSize); ++ /* real update aggregation setting */ ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); ++ ++ ++} ++ ++static void ++halbtc8723b1ant_QueryBtInfo( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ u8 H2C_Parameter[1] ={0}; ++ ++ pCoexSta->bC2hBtInfoReqSent = true; ++ ++ H2C_Parameter[0] |= BIT0; /* trigger */ ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n", ++ H2C_Parameter[0])); ++ ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x61, 1, H2C_Parameter); ++} ++ ++static void ++halbtc8723b1ant_MonitorBtCtr( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ u32 regHPTxRx, regLPTxRx, u4Tmp; ++ u32 regHPTx = 0, regHPRx = 0, regLPTx = 0, regLPRx = 0; ++ static u8 NumOfBtCounterChk; ++ ++ /* to avoid 0x76e[3] = 1 (WLAN_Act control by PTA) during IPS */ ++ /* if (! (pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x76e) & 0x8)) */ ++ ++ if (pCoexSta->bUnderIps) ++ { ++ pCoexSta->highPriorityTx = 65535; ++ pCoexSta->highPriorityRx = 65535; ++ pCoexSta->lowPriorityTx = 65535; ++ pCoexSta->lowPriorityRx = 65535; ++ return; ++ } ++ ++ regHPTxRx = 0x770; ++ regLPTxRx = 0x774; ++ ++ u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regHPTxRx); ++ regHPTx = u4Tmp & bMaskLWord; ++ regHPRx = (u4Tmp & bMaskHWord)>>16; ++ ++ u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regLPTxRx); ++ regLPTx = u4Tmp & bMaskLWord; ++ regLPRx = (u4Tmp & bMaskHWord)>>16; ++ ++ pCoexSta->highPriorityTx = regHPTx; ++ pCoexSta->highPriorityRx = regHPRx; ++ pCoexSta->lowPriorityTx = regLPTx; ++ pCoexSta->lowPriorityRx = regLPRx; ++ ++ if ((pCoexSta->lowPriorityTx >= 1050) && (!pCoexSta->bC2hBtInquiryPage)) ++ pCoexSta->popEventCnt++; ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Hi-Pri Rx/Tx: %d/%d, Lo-Pri Rx/Tx: %d/%d\n", ++ regHPRx, regHPTx, regLPRx, regLPTx)); ++ ++ /* reset counter */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); ++ ++ if ((regHPTx == 0) && (regHPRx == 0) && (regLPTx == 0) && (regLPRx == 0)) ++ { ++ NumOfBtCounterChk++; ++ if (NumOfBtCounterChk >= 3) ++{ ++ halbtc8723b1ant_QueryBtInfo(pBtCoexist); ++ NumOfBtCounterChk = 0; ++ } ++ } ++} ++ ++ ++static void ++halbtc8723b1ant_MonitorWiFiCtr( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ s32 wifiRssi = 0; ++ bool bWifiBusy = false, bWifiUnderBMode = false; ++ static u8 nCCKLockCounter = 0; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, &bWifiUnderBMode); ++ ++ if (pCoexSta->bUnderIps) ++ { ++ pCoexSta->nCRCOK_CCK = 0; ++ pCoexSta->nCRCOK_11g = 0; ++ pCoexSta->nCRCOK_11n = 0; ++ pCoexSta->nCRCOK_11nAgg = 0; ++ ++ pCoexSta->nCRCErr_CCK = 0; ++ pCoexSta->nCRCErr_11g = 0; ++ pCoexSta->nCRCErr_11n = 0; ++ pCoexSta->nCRCErr_11nAgg = 0; ++ } ++ else ++ { ++ pCoexSta->nCRCOK_CCK = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xf88); ++ pCoexSta->nCRCOK_11g = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0xf94); ++ pCoexSta->nCRCOK_11n = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0xf90); ++ pCoexSta->nCRCOK_11nAgg = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0xfb8); ++ ++ pCoexSta->nCRCErr_CCK = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xf84); ++ pCoexSta->nCRCErr_11g = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0xf96); ++ pCoexSta->nCRCErr_11n = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0xf92); ++ pCoexSta->nCRCErr_11nAgg = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0xfba); ++ } ++ ++ ++ /* reset counter */ ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xf16, 0x1, 0x1); ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xf16, 0x1, 0x0); ++ ++ if ((bWifiBusy) && (wifiRssi >= 30) && (!bWifiUnderBMode)) ++ { ++ if ((pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) || ++ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY) || ++ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_SCO_BUSY)) ++ { ++ if (pCoexSta->nCRCOK_CCK >(pCoexSta->nCRCOK_11g + pCoexSta->nCRCOK_11n + ++ pCoexSta->nCRCOK_11nAgg)) ++ { ++ if (nCCKLockCounter < 5) ++ nCCKLockCounter++; ++ } ++ else ++ { ++ if (nCCKLockCounter > 0) ++ nCCKLockCounter--; ++ } ++ ++ } ++ else ++ { ++ if (nCCKLockCounter > 0) ++ nCCKLockCounter--; ++ } ++ } ++ else ++ { ++ if (nCCKLockCounter > 0) ++ nCCKLockCounter--; ++ } ++ ++ if (!pCoexSta->bPreCCKLock) ++ { ++ ++ if (nCCKLockCounter >= 5) ++ pCoexSta->bCCKLock = true; ++ else ++ pCoexSta->bCCKLock = false; ++ } ++ else ++ { ++ if (nCCKLockCounter == 0) ++ pCoexSta->bCCKLock = false; ++ else ++ pCoexSta->bCCKLock = true; ++ } ++ ++ pCoexSta->bPreCCKLock = pCoexSta->bCCKLock; ++ ++ ++} ++ ++static bool ++halbtc8723b1ant_IsWifiStatusChanged( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ static bool bPreWifiBusy =false, bPreUnder4way =false, bPreBtHsOn =false; ++ bool bWifiBusy =false, bUnder4way =false, bBtHsOn =false; ++ bool bWifiConnected =false; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &bUnder4way); ++ ++ if (bWifiConnected) ++ { ++ if (bWifiBusy != bPreWifiBusy) ++ { ++ bPreWifiBusy = bWifiBusy; ++ return true; ++ } ++ if (bUnder4way != bPreUnder4way) ++ { ++ bPreUnder4way = bUnder4way; ++ return true; ++ } ++ if (bBtHsOn != bPreBtHsOn) ++ { ++ bPreBtHsOn = bBtHsOn; ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++static void ++halbtc8723b1ant_UpdateBtLinkInfo( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ PBTC_BT_LINK_INFO pBtLinkInfo =&pBtCoexist->btLinkInfo; ++ bool bBtHsOn =false; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); ++ ++ pBtLinkInfo->bBtLinkExist = pCoexSta->bBtLinkExist; ++ pBtLinkInfo->bScoExist = pCoexSta->bScoExist; ++ pBtLinkInfo->bA2dpExist = pCoexSta->bA2dpExist; ++ pBtLinkInfo->bPanExist = pCoexSta->bPanExist; ++ pBtLinkInfo->bHidExist = pCoexSta->bHidExist; ++ ++ /* work around for HS mode. */ ++ if (bBtHsOn) ++ { ++ pBtLinkInfo->bPanExist = true; ++ pBtLinkInfo->bBtLinkExist = true; ++ } ++ ++ /* check if Sco only */ ++ if (pBtLinkInfo->bScoExist && ++ !pBtLinkInfo->bA2dpExist && ++ !pBtLinkInfo->bPanExist && ++ !pBtLinkInfo->bHidExist) ++ pBtLinkInfo->bScoOnly = true; ++ else ++ pBtLinkInfo->bScoOnly = false; ++ ++ /* check if A2dp only */ ++ if (!pBtLinkInfo->bScoExist && ++ pBtLinkInfo->bA2dpExist && ++ !pBtLinkInfo->bPanExist && ++ !pBtLinkInfo->bHidExist) ++ pBtLinkInfo->bA2dpOnly = true; ++ else ++ pBtLinkInfo->bA2dpOnly = false; ++ ++ /* check if Pan only */ ++ if (!pBtLinkInfo->bScoExist && ++ !pBtLinkInfo->bA2dpExist && ++ pBtLinkInfo->bPanExist && ++ !pBtLinkInfo->bHidExist) ++ pBtLinkInfo->bPanOnly = true; ++ else ++ pBtLinkInfo->bPanOnly = false; ++ ++ /* check if Hid only */ ++ if (!pBtLinkInfo->bScoExist && ++ !pBtLinkInfo->bA2dpExist && ++ !pBtLinkInfo->bPanExist && ++ pBtLinkInfo->bHidExist) ++ pBtLinkInfo->bHidOnly = true; ++ else ++ pBtLinkInfo->bHidOnly = false; ++} ++ ++static u8 ++halbtc8723b1ant_ActionAlgorithm( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ PBTC_BT_LINK_INFO pBtLinkInfo =&pBtCoexist->btLinkInfo; ++ bool bBtHsOn =false; ++ u8 algorithm =BT_8723B_1ANT_COEX_ALGO_UNDEFINED; ++ u8 numOfDiffProfile = 0; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); ++ ++ if (!pBtLinkInfo->bBtLinkExist) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], No BT link exists!!!\n")); ++ return algorithm; ++ } ++ ++ if (pBtLinkInfo->bScoExist) ++ numOfDiffProfile++; ++ if (pBtLinkInfo->bHidExist) ++ numOfDiffProfile++; ++ if (pBtLinkInfo->bPanExist) ++ numOfDiffProfile++; ++ if (pBtLinkInfo->bA2dpExist) ++ numOfDiffProfile++; ++ ++ if (numOfDiffProfile == 1) ++ { ++ if (pBtLinkInfo->bScoExist) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO only\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; ++ } ++ else ++ { ++ if (pBtLinkInfo->bHidExist) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = HID only\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_HID; ++ } ++ else if (pBtLinkInfo->bA2dpExist) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = A2DP only\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_A2DP; ++ } ++ else if (pBtLinkInfo->bPanExist) ++ { ++ if (bBtHsOn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = PAN(HS) only\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_PANHS; ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = PAN(EDR) only\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR; ++ } ++ } ++ } ++ } ++ else if (numOfDiffProfile == 2) ++ { ++ if (pBtLinkInfo->bScoExist) ++ { ++ if (pBtLinkInfo->bHidExist) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + HID\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_HID; ++ } ++ else if (pBtLinkInfo->bA2dpExist) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + A2DP ==> SCO\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; ++ } ++ else if (pBtLinkInfo->bPanExist) ++ { ++ if (bBtHsOn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + PAN(HS)\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + PAN(EDR)\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; ++ } ++ } ++ } ++ else ++ { ++ if (pBtLinkInfo->bHidExist && ++ pBtLinkInfo->bA2dpExist) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = HID + A2DP\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP; ++ } ++ else if (pBtLinkInfo->bHidExist && ++ pBtLinkInfo->bPanExist) ++ { ++ if (bBtHsOn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = HID + PAN(HS)\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP; ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = HID + PAN(EDR)\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; ++ } ++ } ++ else if (pBtLinkInfo->bPanExist && ++ pBtLinkInfo->bA2dpExist) ++ { ++ if (bBtHsOn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = A2DP + PAN(HS)\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS; ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = A2DP + PAN(EDR)\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP; ++ } ++ } ++ } ++ } ++ else if (numOfDiffProfile == 3) ++ { ++ if (pBtLinkInfo->bScoExist) ++ { ++ if (pBtLinkInfo->bHidExist && ++ pBtLinkInfo->bA2dpExist) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_HID; ++ } ++ else if (pBtLinkInfo->bHidExist && ++ pBtLinkInfo->bPanExist) ++ { ++ if (bBtHsOn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + HID + PAN(HS)\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP; ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; ++ } ++ } ++ else if (pBtLinkInfo->bPanExist && ++ pBtLinkInfo->bA2dpExist) ++ { ++ if (bBtHsOn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; ++ } ++ } ++ } ++ else ++ { ++ if (pBtLinkInfo->bHidExist && ++ pBtLinkInfo->bPanExist && ++ pBtLinkInfo->bA2dpExist) ++ { ++ if (bBtHsOn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP; ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR; ++ } ++ } ++ } ++ } ++ else if (numOfDiffProfile >= 3) ++ { ++ if (pBtLinkInfo->bScoExist) ++ { ++ if (pBtLinkInfo->bHidExist && ++ pBtLinkInfo->bPanExist && ++ pBtLinkInfo->bA2dpExist) ++ { ++ if (bBtHsOn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n")); ++ ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR) ==>PAN(EDR)+HID\n")); ++ algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; ++ } ++ } ++ } ++ } ++ ++ return algorithm; ++} ++ ++static void ++halbtc8723b1ant_SetSwPenaltyTxRateAdaptive( ++PBTC_COEXIST pBtCoexist, ++bool bLowPenaltyRa ++ ) ++{ ++ u8 H2C_Parameter[6] ={0}; ++ ++ H2C_Parameter[0] = 0x6; /* opCode, 0x6 = Retry_Penalty */ ++ ++ if (bLowPenaltyRa) ++ { ++ H2C_Parameter[1] |= BIT0; ++ H2C_Parameter[2] = 0x00; /* normal rate except MCS7/6/5, OFDM54/48/36 */ ++ H2C_Parameter[3] = 0xf7; /* MCS7 or OFDM54 */ ++ H2C_Parameter[4] = 0xf8; /* MCS6 or OFDM48 */ ++ H2C_Parameter[5] = 0xf9; /* MCS5 or OFDM36 */ ++ } ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set WiFi Low-Penalty Retry: %s", ++ (bLowPenaltyRa? "ON!!":"OFF!!"))); ++ ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x69, 6, H2C_Parameter); ++} ++ ++static void ++halbtc8723b1ant_LowPenaltyRa( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++bool bLowPenaltyRa ++ ) ++{ ++ pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa; ++ ++ if (!bForceExec) ++ { ++ if (pCoexDm->bPreLowPenaltyRa == pCoexDm->bCurLowPenaltyRa) ++ return; ++ } ++ halbtc8723b1ant_SetSwPenaltyTxRateAdaptive(pBtCoexist, pCoexDm->bCurLowPenaltyRa); ++ ++ pCoexDm->bPreLowPenaltyRa = pCoexDm->bCurLowPenaltyRa; ++} ++ ++static void ++halbtc8723b1ant_SetCoexTable( ++PBTC_COEXIST pBtCoexist, ++u32 val0x6c0, ++u32 val0x6c4, ++u32 val0x6c8, ++u8 val0x6cc ++ ) ++{ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0)); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c0, val0x6c0); ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4)); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c4, val0x6c4); ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8)); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, val0x6c8); ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc)); ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cc, val0x6cc); ++} ++ ++static void ++halbtc8723b1ant_CoexTable( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++u32 val0x6c0, ++u32 val0x6c4, ++u32 val0x6c8, ++u8 val0x6cc ++ ) ++{ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6cc = 0x%x\n", ++ (bForceExec? "force to":""), val0x6c0, val0x6c4, val0x6cc)); ++ pCoexDm->curVal0x6c0 = val0x6c0; ++ pCoexDm->curVal0x6c4 = val0x6c4; ++ pCoexDm->curVal0x6c8 = val0x6c8; ++ pCoexDm->curVal0x6cc = val0x6cc; ++ ++ if (!bForceExec) { ++ if ((pCoexDm->preVal0x6c0 == pCoexDm->curVal0x6c0) && ++ (pCoexDm->preVal0x6c4 == pCoexDm->curVal0x6c4) && ++ (pCoexDm->preVal0x6c8 == pCoexDm->curVal0x6c8) && ++ (pCoexDm->preVal0x6cc == pCoexDm->curVal0x6cc)) ++ return; ++ } ++ halbtc8723b1ant_SetCoexTable(pBtCoexist, val0x6c0, val0x6c4, val0x6c8, val0x6cc); ++ ++ pCoexDm->preVal0x6c0 = pCoexDm->curVal0x6c0; ++ pCoexDm->preVal0x6c4 = pCoexDm->curVal0x6c4; ++ pCoexDm->preVal0x6c8 = pCoexDm->curVal0x6c8; ++ pCoexDm->preVal0x6cc = pCoexDm->curVal0x6cc; ++} ++ ++static void ++halbtc8723b1ant_CoexTableWithType( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++u8 type ++ ) ++{ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ********** CoexTable(%d) **********\n", type)); ++ ++ pCoexSta->nCoexTableType = type; ++ ++ switch (type) ++ { ++ case 0: ++ halbtc8723b1ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x55555555, 0xffffff, 0x3); ++ break; ++ case 1: ++ halbtc8723b1ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x5a5a5a5a, 0xffffff, 0x3); ++ break; ++ case 2: ++ halbtc8723b1ant_CoexTable(pBtCoexist, bForceExec, 0x5a5a5a5a, 0x5a5a5a5a, 0xffffff, 0x3); ++ break; ++ case 3: ++ halbtc8723b1ant_CoexTable(pBtCoexist, bForceExec, 0xaaaa5555, 0xaaaa5a5a, 0xffffff, 0x3); ++ break; ++ case 4: ++ halbtc8723b1ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0xaaaa5a5a, 0xffffff, 0x3); ++ break; ++ case 5: ++ halbtc8723b1ant_CoexTable(pBtCoexist, bForceExec, 0x5a5a5a5a, 0xaaaa5a5a, 0xffffff, 0x3); ++ break; ++ case 6: ++ halbtc8723b1ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0xaaaaaaaa, 0xffffff, 0x3); ++ break; ++ case 7: ++ halbtc8723b1ant_CoexTable(pBtCoexist, bForceExec, 0xaaaaaaaa, 0xaaaaaaaa, 0xffffff, 0x3); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void ++halbtc8723b1ant_SetFwIgnoreWlanAct( ++PBTC_COEXIST pBtCoexist, ++bool bEnable ++ ) ++{ ++ u8 H2C_Parameter[1] ={0}; ++ ++ if (bEnable) ++ { ++ H2C_Parameter[0] |= BIT0; /* function enable */ ++ } ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n", ++ H2C_Parameter[0])); ++ ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x63, 1, H2C_Parameter); ++} ++ ++static void ++halbtc8723b1ant_IgnoreWlanAct( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++bool bEnable ++ ) ++{ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn Ignore WlanAct %s\n", ++ (bForceExec? "force to":""), (bEnable? "ON":"OFF"))); ++ pCoexDm->bCurIgnoreWlanAct = bEnable; ++ ++ if (!bForceExec) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n", ++ pCoexDm->bPreIgnoreWlanAct, pCoexDm->bCurIgnoreWlanAct)); ++ ++ if (pCoexDm->bPreIgnoreWlanAct == pCoexDm->bCurIgnoreWlanAct) ++ return; ++ } ++ halbtc8723b1ant_SetFwIgnoreWlanAct(pBtCoexist, bEnable); ++ ++ pCoexDm->bPreIgnoreWlanAct = pCoexDm->bCurIgnoreWlanAct; ++} ++ ++static void ++halbtc8723b1ant_SetLpsRpwm( ++PBTC_COEXIST pBtCoexist, ++u8 lpsVal, ++u8 rpwmVal ++ ) ++{ ++ u8 lps =lpsVal; ++ u8 rpwm =rpwmVal; ++ ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_LPS_VAL, &lps); ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RPWM_VAL, &rpwm); ++} ++ ++static void ++halbtc8723b1ant_LpsRpwm( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++u8 lpsVal, ++u8 rpwmVal ++ ) ++{ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set lps/rpwm = 0x%x/0x%x\n", ++ (bForceExec? "force to":""), lpsVal, rpwmVal)); ++ pCoexDm->curLps = lpsVal; ++ pCoexDm->curRpwm = rpwmVal; ++ ++ if (!bForceExec) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], LPS-RxBeaconMode = 0x%x , LPS-RPWM = 0x%x!!\n", ++ pCoexDm->curLps, pCoexDm->curRpwm)); ++ ++ if ((pCoexDm->preLps == pCoexDm->curLps) && ++ (pCoexDm->preRpwm == pCoexDm->curRpwm)) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], LPS-RPWM_Last = 0x%x , LPS-RPWM_Now = 0x%x!!\n", ++ pCoexDm->preRpwm, pCoexDm->curRpwm)); ++ ++ return; ++ } ++ } ++ halbtc8723b1ant_SetLpsRpwm(pBtCoexist, lpsVal, rpwmVal); ++ ++ pCoexDm->preLps = pCoexDm->curLps; ++ pCoexDm->preRpwm = pCoexDm->curRpwm; ++} ++ ++static void ++halbtc8723b1ant_SwMechanism( ++PBTC_COEXIST pBtCoexist, ++bool bLowPenaltyRA ++ ) ++{ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], SM[LpRA] = %d\n", ++ bLowPenaltyRA)); ++ ++ halbtc8723b1ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, bLowPenaltyRA); ++} ++ ++static void ++halbtc8723b1ant_SetAntPath( ++PBTC_COEXIST pBtCoexist, ++u8 antPosType, ++bool bInitHwCfg, ++bool bWifiOff ++ ) ++{ ++ PBTC_BOARD_INFO pBoardInfo =&pBtCoexist->boardInfo; ++ u32 fwVer = 0, u4Tmp = 0, cntBtCalChk = 0; ++ bool bPgExtSwitch =false; ++ bool bUseExtSwitch =false; ++ bool bIsInMpMode = false; ++ u8 H2C_Parameter[2] ={0}, u1Tmp = 0; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_EXT_SWITCH, &bPgExtSwitch); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); /* [31:16]=fw ver, [15:0]=fw sub ver */ ++ ++ if ((fwVer>0 && fwVer<0xc0000) || bPgExtSwitch) ++ bUseExtSwitch = true; ++ ++ if (bInitHwCfg) ++ { ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x780); /* WiFi TRx Mask on */ ++ pBtCoexist->fBtcSetBtReg(pBtCoexist, BTC_BT_REG_RF, 0x3c, 0x15); /* BT TRx Mask on */ ++ ++ if (fwVer >= 0x180000) ++ { ++ /* Use H2C to set GNT_BT to HIGH */ ++ H2C_Parameter[0] = 1; ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x6E, 1, H2C_Parameter); ++ } ++ else ++ { ++ /* set grant_bt to high */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x765, 0x18); ++ } ++ /* set wlan_act control by PTA */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0x4); ++ ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x67, 0x20, 0x1); /* BT select s0/s1 is controlled by WiFi */ ++ ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x39, 0x8, 0x1); ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x974, 0xff); ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x944, 0x3, 0x3); ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x930, 0x77); ++ } ++ else if (bWifiOff) ++ { ++ if (fwVer >= 0x180000) ++ { ++ /* Use H2C to set GNT_BT to HIGH */ ++ H2C_Parameter[0] = 1; ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x6E, 1, H2C_Parameter); ++ } ++ else ++ { ++ /* set grant_bt to high */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x765, 0x18); ++ } ++ /* set wlan_act to always low */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0x4); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_IS_IN_MP_MODE, &bIsInMpMode); ++ if (!bIsInMpMode) ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x67, 0x20, 0x0); /* BT select s0/s1 is controlled by BT */ ++ else ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x67, 0x20, 0x1); /* BT select s0/s1 is controlled by WiFi */ ++ ++ /* 0x4c[24:23]= 00, Set Antenna control by BT_RFE_CTRL BT Vendor 0xac = 0xf002 */ ++ u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); ++ u4Tmp &= ~BIT23; ++ u4Tmp &= ~BIT24; ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x4c, u4Tmp); ++ } ++ else ++ { ++ /* Use H2C to set GNT_BT to LOW */ ++ if (fwVer >= 0x180000) ++ { ++ if (pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x765) != 0) ++ { ++ H2C_Parameter[0] = 0; ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x6E, 1, H2C_Parameter); ++ } ++ } ++ else ++ { ++ /* BT calibration check */ ++ while (cntBtCalChk <= 20) ++ { ++ u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x49d); ++ cntBtCalChk++; ++ if (u1Tmp & BIT0) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ########### BT is calibrating (wait cnt =%d) ###########\n", cntBtCalChk)); ++ mdelay(50); ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ********** BT is NOT calibrating (wait cnt =%d)**********\n", cntBtCalChk)); ++ break; ++ } ++ } ++ ++ /* set grant_bt to PTA */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x765, 0x0); ++ } ++ ++ if (pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x76e) != 0xc) ++ { ++ /* set wlan_act control by PTA */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); ++ } ++ } ++ ++ if (bUseExtSwitch) ++ { ++ if (bInitHwCfg) ++ { ++ /* 0x4c[23]= 0, 0x4c[24]= 1 Antenna control by WL/BT */ ++ u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); ++ u4Tmp &=~BIT23; ++ u4Tmp |= BIT24; ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x4c, u4Tmp); ++ ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x0); /* fixed internal switch S1->WiFi, S0->BT */ ++ ++ if (pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) ++ { ++ /* tell firmware "no antenna inverse" */ ++ H2C_Parameter[0] = 0; ++ H2C_Parameter[1] = 1; /* ext switch type */ ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x65, 2, H2C_Parameter); ++ } ++ else ++ { ++ /* tell firmware "antenna inverse" */ ++ H2C_Parameter[0] = 1; ++ H2C_Parameter[1] = 1; /* ext switch type */ ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x65, 2, H2C_Parameter); ++ } ++ } ++ ++ ++ /* ext switch setting */ ++ switch (antPosType) ++ { ++ case BTC_ANT_PATH_WIFI: ++ if (pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x1); ++ else ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x2); ++ break; ++ case BTC_ANT_PATH_BT: ++ if (pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x2); ++ else ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x1); ++ break; ++ default: ++ case BTC_ANT_PATH_PTA: ++ if (pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x1); ++ else ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x2); ++ break; ++ } ++ ++ } ++ else ++ { ++ if (bInitHwCfg) ++ { ++ /* 0x4c[23]= 1, 0x4c[24]= 0 Antenna control by 0x64 */ ++ u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); ++ u4Tmp |= BIT23; ++ u4Tmp &=~BIT24; ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x4c, u4Tmp); ++ ++ /* Fix Ext switch Main->S1, Aux->S0 */ ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x64, 0x1, 0x0); ++ ++ if (pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) ++ { ++ ++ /* tell firmware "no antenna inverse" */ ++ H2C_Parameter[0] = 0; ++ H2C_Parameter[1] = 0; /* internal switch type */ ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x65, 2, H2C_Parameter); ++ } ++ else ++ { ++ ++ /* tell firmware "antenna inverse" */ ++ H2C_Parameter[0] = 1; ++ H2C_Parameter[1] = 0; /* internal switch type */ ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x65, 2, H2C_Parameter); ++ } ++ } ++ ++ ++ /* internal switch setting */ ++ switch (antPosType) ++ { ++ case BTC_ANT_PATH_WIFI: ++ if (pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x0); ++ else ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x280); ++ break; ++ case BTC_ANT_PATH_BT: ++ if (pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x280); ++ else ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x0); ++ break; ++ default: ++ case BTC_ANT_PATH_PTA: ++ if (pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x200); ++ else ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x80); ++ break; ++ } ++ } ++} ++ ++static void ++halbtc8723b1ant_SetFwPstdma( ++PBTC_COEXIST pBtCoexist, ++u8 byte1, ++u8 byte2, ++u8 byte3, ++u8 byte4, ++u8 byte5 ++ ) ++{ ++ u8 H2C_Parameter[5] ={0}; ++ u8 realByte1 =byte1, realByte5 =byte5; ++ bool bApEnable =false; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, &bApEnable); ++ ++ if (bApEnable) ++ { ++ if (byte1&BIT4 && !(byte1&BIT5)) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], FW for 1Ant AP mode\n")); ++ realByte1 &= ~BIT4; ++ realByte1 |= BIT5; ++ ++ realByte5 |= BIT5; ++ realByte5 &= ~BIT6; ++ } ++ } ++ ++ H2C_Parameter[0] = realByte1; ++ H2C_Parameter[1] = byte2; ++ H2C_Parameter[2] = byte3; ++ H2C_Parameter[3] = byte4; ++ H2C_Parameter[4] = realByte5; ++ ++ pCoexDm->psTdmaPara[0] = realByte1; ++ pCoexDm->psTdmaPara[1] = byte2; ++ pCoexDm->psTdmaPara[2] = byte3; ++ pCoexDm->psTdmaPara[3] = byte4; ++ pCoexDm->psTdmaPara[4] = realByte5; ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], PS-TDMA H2C cmd = 0x%x%08x\n", ++ H2C_Parameter[0], ++ H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4])); ++ ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x60, 5, H2C_Parameter); ++} ++ ++ ++static void ++halbtc8723b1ant_PsTdma( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++bool bTurnOn, ++u8 type ++ ) ++{ ++ PBTC_BT_LINK_INFO pBtLinkInfo =&pBtCoexist->btLinkInfo; ++ bool bWifiBusy =false; ++ u8 rssiAdjustVal = 0; ++ u8 psTdmaByte4Val = 0x50, psTdmaByte0Val = 0x51, psTdmaByte3Val = 0x10; ++ s8 nWiFiDurationAdjust = 0x0; ++ /* u32 fwVer = 0; */ ++ ++ /* BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn %s PS TDMA, type =%d\n", */ ++ /* (bForceExec? "force to":""), (bTurnOn? "ON":"OFF"), type)); */ ++ pCoexDm->bCurPsTdmaOn = bTurnOn; ++ pCoexDm->curPsTdma = type; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); ++ ++ if (pCoexDm->bCurPsTdmaOn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ********** TDMA(on, %d) **********\n", ++ pCoexDm->curPsTdma)); ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ********** TDMA(off, %d) **********\n", ++ pCoexDm->curPsTdma)); ++ } ++ ++ if (!bForceExec) ++ { ++ if ((pCoexDm->bPrePsTdmaOn == pCoexDm->bCurPsTdmaOn) && ++ (pCoexDm->prePsTdma == pCoexDm->curPsTdma)) ++ return; ++ } ++ ++ if (pCoexSta->nScanAPNum <= 5) ++ nWiFiDurationAdjust = 5; ++ else if (pCoexSta->nScanAPNum >= 40) ++ nWiFiDurationAdjust = -15; ++ else if (pCoexSta->nScanAPNum >= 20) ++ nWiFiDurationAdjust = -10; ++ ++ if (!pCoexSta->bForceLpsOn) /* only for A2DP-only case 1/2/9/11 */ ++ { ++ psTdmaByte0Val = 0x61; /* no null-pkt */ ++ psTdmaByte3Val = 0x11; /* no tx-pause at BT-slot */ ++ psTdmaByte4Val = 0x10; /* 0x778 = d/1 toggle */ ++ } ++ ++ ++ if (bTurnOn) ++ { ++ if (pBtLinkInfo->bSlaveRole == true) ++ { ++ psTdmaByte4Val = psTdmaByte4Val | 0x1; /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */ ++ } ++ ++ ++ switch (type) ++ { ++ default: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x1a, 0x1a, 0x0, psTdmaByte4Val); ++ break; ++ case 1: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, psTdmaByte0Val, 0x3a+nWiFiDurationAdjust, 0x03, psTdmaByte3Val, psTdmaByte4Val); ++ break; ++ case 2: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, psTdmaByte0Val, 0x2d+nWiFiDurationAdjust, 0x03, psTdmaByte3Val, psTdmaByte4Val); ++ break; ++ case 3: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x1d, 0x1d, 0x0, 0x10); ++ break; ++ case 4: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x93, 0x15, 0x3, 0x14, 0x0); ++ break; ++ case 5: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x61, 0x15, 0x3, 0x11, 0x10); ++ break; ++ case 6: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x61, 0x20, 0x3, 0x11, 0x11); ++ break; ++ case 7: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x13, 0xc, 0x5, 0x0, 0x0); ++ break; ++ case 8: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x93, 0x25, 0x3, 0x10, 0x0); ++ break; ++ case 9: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, psTdmaByte0Val, 0x21, 0x3, psTdmaByte3Val, psTdmaByte4Val); ++ break; ++ case 10: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x13, 0xa, 0xa, 0x0, 0x40); ++ break; ++ case 11: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, psTdmaByte0Val, 0x21, 0x03, psTdmaByte3Val, psTdmaByte4Val); ++ break; ++ case 12: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x0a, 0x0a, 0x0, 0x50); ++ break; ++ case 13: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x12, 0x12, 0x0, 0x10); ++ break; ++ case 14: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x21, 0x3, 0x10, psTdmaByte4Val); ++ break; ++ case 15: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x13, 0xa, 0x3, 0x8, 0x0); ++ break; ++ case 16: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x93, 0x15, 0x3, 0x10, 0x0); ++ break; ++ case 18: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x93, 0x25, 0x3, 0x10, 0x0); ++ break; ++ case 20: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x61, 0x3f, 0x03, 0x11, 0x10); ++ break; ++ case 21: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x61, 0x25, 0x03, 0x11, 0x11); ++ break; ++ case 22: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x61, 0x25, 0x03, 0x11, 0x10); ++ break; ++ case 23: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x3, 0x31, 0x18); ++ break; ++ case 24: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x15, 0x3, 0x31, 0x18); ++ break; ++ case 25: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); ++ break; ++ case 26: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); ++ break; ++ case 27: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x3, 0x31, 0x98); ++ break; ++ case 28: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x69, 0x25, 0x3, 0x31, 0x0); ++ break; ++ case 29: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0xab, 0x1a, 0x1a, 0x1, 0x10); ++ break; ++ case 30: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x30, 0x3, 0x10, 0x10); ++ break; ++ case 31: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x1a, 0x1a, 0, 0x58); ++ break; ++ case 32: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x61, 0x35, 0x3, 0x11, 0x11); ++ break; ++ case 33: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0xa3, 0x25, 0x3, 0x30, 0x90); ++ break; ++ case 34: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x53, 0x1a, 0x1a, 0x0, 0x10); ++ break; ++ case 35: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x63, 0x1a, 0x1a, 0x0, 0x10); ++ break; ++ case 36: ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x12, 0x3, 0x14, 0x50); ++ break; ++ case 40: /* SoftAP only with no sta associated, BT disable , TDMA mode for power saving */ ++ /* here softap mode screen off will cost 70-80mA for phone */ ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x23, 0x18, 0x00, 0x10, 0x24); ++ break; ++ } ++ } ++ else ++ { ++ ++ /* disable PS tdma */ ++ switch (type) ++ { ++ case 8: /* PTA Control */ ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x8, 0x0, 0x0, 0x0, 0x0); ++ halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_PTA, false, false); ++ break; ++ case 0: ++ default: /* Software control, Antenna at BT side */ ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x0, 0x0); ++ halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, false, false); ++ break; ++ case 9: /* Software control, Antenna at WiFi side */ ++ halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x0, 0x0); ++ halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_WIFI, false, false); ++ break; ++ } ++ } ++ rssiAdjustVal = 0; ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, &rssiAdjustVal); ++ ++ /* update pre state */ ++ pCoexDm->bPrePsTdmaOn = pCoexDm->bCurPsTdmaOn; ++ pCoexDm->prePsTdma = pCoexDm->curPsTdma; ++} ++ ++static bool ++halbtc8723b1ant_IsCommonAction( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ bool bCommon =false, bWifiConnected =false, bWifiBusy =false; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); ++ ++ if (!bWifiConnected && ++ BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n")); ++ ++ /* halbtc8723b1ant_SwMechanism(pBtCoexist, false); */ ++ ++ bCommon = true; ++ } ++ else if (bWifiConnected && ++ (BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus)) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT non connected-idle!!\n")); ++ ++ /* halbtc8723b1ant_SwMechanism(pBtCoexist, false); */ ++ ++ bCommon = true; ++ } ++ else if (!bWifiConnected && ++ (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT connected-idle!!\n")); ++ ++ /* halbtc8723b1ant_SwMechanism(pBtCoexist, false); */ ++ ++ bCommon = true; ++ } ++ else if (bWifiConnected && ++ (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT connected-idle!!\n")); ++ ++ /* halbtc8723b1ant_SwMechanism(pBtCoexist, false); */ ++ ++ bCommon = true; ++ } ++ else if (!bWifiConnected && ++ (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE != pCoexDm->btStatus)) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT Busy!!\n")); ++ ++ /* halbtc8723b1ant_SwMechanism(pBtCoexist, false); */ ++ ++ bCommon = true; ++ } ++ else ++ { ++ if (bWifiBusy) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Connected-Busy + BT Busy!!\n")); ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Connected-Idle + BT Busy!!\n")); ++ } ++ ++ bCommon = false; ++ } ++ ++ return bCommon; ++} ++ ++ ++static void ++halbtc8723b1ant_TdmaDurationAdjustForAcl( ++PBTC_COEXIST pBtCoexist, ++u8 wifiStatus ++ ) ++{ ++ static s32 up, dn, m, n, WaitCount; ++ s32 result; /* 0: no change, +1: increase WiFi duration, -1: decrease WiFi duration */ ++ u8 retryCount = 0, btInfoExt; ++ bool bWifiBusy = false; ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], TdmaDurationAdjustForAcl()\n")); ++ ++ if (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY == wifiStatus) ++ bWifiBusy = true; ++ else ++ bWifiBusy = false; ++ ++ if ((BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == wifiStatus) || ++ (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifiStatus) || ++ (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == wifiStatus)) ++ { ++ if (pCoexDm->curPsTdma != 1 && ++ pCoexDm->curPsTdma != 2 && ++ pCoexDm->curPsTdma != 3 && ++ pCoexDm->curPsTdma != 9) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); ++ pCoexDm->psTdmaDuAdjType = 9; ++ ++ up = 0; ++ dn = 0; ++ m = 1; ++ n = 3; ++ result = 0; ++ WaitCount = 0; ++ } ++ return; ++ } ++ ++ if (!pCoexDm->bAutoTdmaAdjust) ++ { ++ pCoexDm->bAutoTdmaAdjust = true; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], first run TdmaDurationAdjust()!!\n")); ++ ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); ++ pCoexDm->psTdmaDuAdjType = 2; ++ /* */ ++ up = 0; ++ dn = 0; ++ m = 1; ++ n = 3; ++ result = 0; ++ WaitCount = 0; ++ } ++ else ++ { ++ /* accquire the BT TRx retry count from BT_Info byte2 */ ++ retryCount = pCoexSta->btRetryCnt; ++ btInfoExt = pCoexSta->btInfoExt; ++ /* BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount)); */ ++ /* BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], up =%d, dn =%d, m =%d, n =%d, WaitCount =%d\n", */ ++ /* up, dn, m, n, WaitCount)); */ ++ ++ if ((pCoexSta->lowPriorityTx) > 1050 || (pCoexSta->lowPriorityRx) > 1250) ++ retryCount++; ++ ++ result = 0; ++ WaitCount++; ++ ++ if (retryCount == 0) /* no retry in the last 2-second duration */ ++ { ++ up++; ++ dn--; ++ ++ if (dn <= 0) ++ dn = 0; ++ ++ if (up >= n) /* if 連續 n 個2秒 retry count為0, 則調寬WiFi duration */ ++ { ++ WaitCount = 0; ++ n = 3; ++ up = 0; ++ dn = 0; ++ result = 1; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Increase wifi duration!!\n")); ++ } ++ } ++ else if (retryCount <= 3) /* <=3 retry in the last 2-second duration */ ++ { ++ up--; ++ dn++; ++ ++ if (up <= 0) ++ up = 0; ++ ++ if (dn == 2) /* if 連續 2 個2秒 retry count< 3, 則調窄WiFi duration */ ++ { ++ if (WaitCount <= 2) ++ m++; /* 避免一直在兩個level中來回 */ ++ else ++ m = 1; ++ ++ if (m >= 20) /* m 最大值 = 20 ' 最大120秒 recheck是否調整 WiFi duration. */ ++ m = 20; ++ ++ n = 3*m; ++ up = 0; ++ dn = 0; ++ WaitCount = 0; ++ result = -1; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n")); ++ } ++ } ++ else /* retry count > 3, 只要1次 retry count > 3, 則調窄WiFi duration */ ++ { ++ if (WaitCount == 1) ++ m++; /* 避免一直在兩個level中來回 */ ++ else ++ m = 1; ++ ++ if (m >= 20) /* m 最大值 = 20 ' 最大120秒 recheck是否調整 WiFi duration. */ ++ m = 20; ++ ++ n = 3*m; ++ up = 0; ++ dn = 0; ++ WaitCount = 0; ++ result = -1; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")); ++ } ++ ++ if (result == -1) ++ { ++ if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(btInfoExt)) && ++ ((pCoexDm->curPsTdma == 1) ||(pCoexDm->curPsTdma == 2))) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); ++ pCoexDm->psTdmaDuAdjType = 9; ++ } ++ else if (pCoexDm->curPsTdma == 1) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); ++ pCoexDm->psTdmaDuAdjType = 2; ++ } ++ else if (pCoexDm->curPsTdma == 2) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); ++ pCoexDm->psTdmaDuAdjType = 9; ++ } ++ else if (pCoexDm->curPsTdma == 9) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); ++ pCoexDm->psTdmaDuAdjType = 11; ++ } ++ } ++ else if (result == 1) ++ { ++ if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(btInfoExt)) && ++ ((pCoexDm->curPsTdma == 1) ||(pCoexDm->curPsTdma == 2))) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); ++ pCoexDm->psTdmaDuAdjType = 9; ++ } ++ else if (pCoexDm->curPsTdma == 11) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); ++ pCoexDm->psTdmaDuAdjType = 9; ++ } ++ else if (pCoexDm->curPsTdma == 9) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); ++ pCoexDm->psTdmaDuAdjType = 2; ++ } ++ else if (pCoexDm->curPsTdma == 2) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1); ++ pCoexDm->psTdmaDuAdjType = 1; ++ } ++ } ++ else /* no change */ ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], ********** TDMA(on, %d) **********\n", ++ pCoexDm->curPsTdma)); ++ } ++ ++ if (pCoexDm->curPsTdma != 1 && ++ pCoexDm->curPsTdma != 2 && ++ pCoexDm->curPsTdma != 9 && ++ pCoexDm->curPsTdma != 11) ++ { ++ /* recover to previous adjust type */ ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, pCoexDm->psTdmaDuAdjType); ++ } ++ } ++} ++ ++static void ++halbtc8723b1ant_PsTdmaCheckForPowerSaveState( ++PBTC_COEXIST pBtCoexist, ++bool bNewPsState ++ ) ++{ ++ u8 lpsMode = 0x0; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_LPS_MODE, &lpsMode); ++ ++ if (lpsMode) /* already under LPS state */ ++ { ++ if (bNewPsState) ++ { ++ /* keep state under LPS, do nothing. */ ++ } ++ else ++ { ++ /* will leave LPS state, turn off psTdma first */ ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 0); ++ } ++ } ++ else /* NO PS state */ ++ { ++ if (bNewPsState) ++ { ++ /* will enter LPS state, turn off psTdma first */ ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 0); ++ } ++ else ++ { ++ /* keep state under NO PS state, do nothing. */ ++ } ++ } ++} ++ ++static void ++halbtc8723b1ant_PowerSaveState( ++PBTC_COEXIST pBtCoexist, ++u8 psType, ++u8 lpsVal, ++u8 rpwmVal ++ ) ++{ ++ bool bLowPwrDisable =false; ++ ++ switch (psType) ++ { ++ case BTC_PS_WIFI_NATIVE: ++ /* recover to original 32k low power setting */ ++ bLowPwrDisable = false; ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_NORMAL_LPS, NULL); ++ pCoexSta->bForceLpsOn = false; ++ break; ++ case BTC_PS_LPS_ON: ++ halbtc8723b1ant_PsTdmaCheckForPowerSaveState(pBtCoexist, true); ++ halbtc8723b1ant_LpsRpwm(pBtCoexist, NORMAL_EXEC, lpsVal, rpwmVal); ++ /* when coex force to enter LPS, do not enter 32k low power. */ ++ bLowPwrDisable = true; ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); ++ /* power save must executed before psTdma. */ ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_ENTER_LPS, NULL); ++ pCoexSta->bForceLpsOn = true; ++ break; ++ case BTC_PS_LPS_OFF: ++ halbtc8723b1ant_PsTdmaCheckForPowerSaveState(pBtCoexist, false); ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_LEAVE_LPS, NULL); ++ pCoexSta->bForceLpsOn = false; ++ break; ++ default: ++ break; ++ } ++} ++ ++/* */ ++/* */ ++/* Software Coex Mechanism start */ ++/* */ ++/* */ ++ ++/* */ ++/* */ ++/* Non-Software Coex Mechanism start */ ++/* */ ++/* */ ++static void ++halbtc8723b1ant_ActionWifiMultiPort( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); ++ ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 8); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); ++} ++ ++static void ++halbtc8723b1ant_ActionHs( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); ++} ++ ++static void ++halbtc8723b1ant_ActionBtInquiry( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ PBTC_BT_LINK_INFO pBtLinkInfo =&pBtCoexist->btLinkInfo; ++ bool bWifiConnected =false, bApEnable =false, bWifiBusy =false, bBtBusy =false; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, &bApEnable); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bBtBusy); ++ ++ if ((!bWifiConnected) && (!pCoexSta->bWiFiIsHighPriTask)) ++ { ++ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 8); ++ ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); ++ } ++ else if ((pBtLinkInfo->bScoExist) || (pBtLinkInfo->bHidExist) || (pBtLinkInfo->bA2dpExist) ) ++ { ++ /* SCO/HID/A2DP busy */ ++ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 32); ++ ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); ++ } ++ else if ((pBtLinkInfo->bPanExist) || (bWifiBusy)) ++ { ++ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 20); ++ ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); ++ } ++ else ++ { ++ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 8); ++ ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); ++ } ++} ++ ++static void ++halbtc8723b1ant_ActionBtScoHidOnlyBusy( ++PBTC_COEXIST pBtCoexist, ++u8 wifiStatus ++ ) ++{ ++ PBTC_BT_LINK_INFO pBtLinkInfo =&pBtCoexist->btLinkInfo; ++ bool bWifiConnected =false; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); ++ ++ /* tdma and coex table */ ++ ++ if (pBtLinkInfo->bScoExist) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 5); ++ } ++ else /* HID */ ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 5); ++ } ++} ++ ++static void ++halbtc8723b1ant_ActionWifiConnectedBtAclBusy( ++PBTC_COEXIST pBtCoexist, ++u8 wifiStatus ++ ) ++{ ++ u8 btRssiState; ++ ++ PBTC_BT_LINK_INFO pBtLinkInfo =&pBtCoexist->btLinkInfo; ++ btRssiState = halbtc8723b1ant_BtRssiState(2, 28, 0); ++ ++ if ((pCoexSta->lowPriorityRx >= 1000) && (pCoexSta->lowPriorityRx != 65535)) ++ { ++ pBtLinkInfo->bSlaveRole = true; ++ } ++ else ++ { ++ pBtLinkInfo->bSlaveRole = false; ++ } ++ ++ if (pBtLinkInfo->bHidOnly) /* HID */ ++ { ++ halbtc8723b1ant_ActionBtScoHidOnlyBusy(pBtCoexist, wifiStatus); ++ pCoexDm->bAutoTdmaAdjust = false; ++ return; ++ } ++ else if (pBtLinkInfo->bA2dpOnly) /* A2DP */ ++ { ++ if (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE == wifiStatus) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 32); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); ++ pCoexDm->bAutoTdmaAdjust = false; ++ } ++ else ++ { ++ halbtc8723b1ant_TdmaDurationAdjustForAcl(pBtCoexist, wifiStatus); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); ++ pCoexDm->bAutoTdmaAdjust = true; ++ } ++ } ++ else if (pBtLinkInfo->bHidExist&&pBtLinkInfo->bA2dpExist) /* HID+A2DP */ ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); ++ pCoexDm->bAutoTdmaAdjust = false; ++ ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); ++ } ++ else if ((pBtLinkInfo->bPanOnly) || (pBtLinkInfo->bHidExist&&pBtLinkInfo->bPanExist)) /* PAN(OPP, FTP), HID+PAN(OPP, FTP) */ ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); ++ pCoexDm->bAutoTdmaAdjust = false; ++ } ++ else if (((pBtLinkInfo->bA2dpExist) && (pBtLinkInfo->bPanExist)) || ++ (pBtLinkInfo->bHidExist&&pBtLinkInfo->bA2dpExist&&pBtLinkInfo->bPanExist)) /* A2DP+PAN(OPP, FTP), HID+A2DP+PAN(OPP, FTP) */ ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 13); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); ++ pCoexDm->bAutoTdmaAdjust = false; ++ } ++ else ++ { ++ /* BT no-profile busy (0x9) */ ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 32); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); ++ pCoexDm->bAutoTdmaAdjust = false; ++ } ++} ++ ++static void ++halbtc8723b1ant_ActionWifiNotConnected( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ /* power save state */ ++ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); ++ ++ /* tdma and coex table */ ++ halbtc8723b1ant_PsTdma(pBtCoexist, FORCE_EXEC, false, 8); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); ++} ++ ++static void ++halbtc8723b1ant_ActionWifiNotConnectedScan( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ PBTC_BT_LINK_INFO pBtLinkInfo =&pBtCoexist->btLinkInfo; ++ ++ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); ++ ++ /* tdma and coex table */ ++ if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) ++ { ++ if (pBtLinkInfo->bA2dpExist) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 32); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); ++ } ++ else if (pBtLinkInfo->bA2dpExist && pBtLinkInfo->bPanExist) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 22); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); ++ } ++ else ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 20); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); ++ } ++ } ++ else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || ++ (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus)) ++ { ++ halbtc8723b1ant_ActionBtScoHidOnlyBusy(pBtCoexist, ++ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN); ++ } ++ else ++ { ++ /* Bryant Add */ ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 8); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); ++ } ++} ++ ++static void ++halbtc8723b1ant_ActionWifiNotConnectedAssoAuth( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ PBTC_BT_LINK_INFO pBtLinkInfo =&pBtCoexist->btLinkInfo; ++ ++ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); ++ ++ /* tdma and coex table */ ++ if ((pBtLinkInfo->bScoExist) || (pBtLinkInfo->bHidExist) || (pBtLinkInfo->bA2dpExist)) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 32); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); ++ } ++ else if (pBtLinkInfo->bPanExist) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 20); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); ++ } ++ else ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 8); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); ++ } ++} ++ ++static void ++halbtc8723b1ant_ActionWifiConnectedScan( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ PBTC_BT_LINK_INFO pBtLinkInfo =&pBtCoexist->btLinkInfo; ++ ++ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); ++ ++ /* tdma and coex table */ ++ if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) ++ { ++ if (pBtLinkInfo->bA2dpExist) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 32); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); ++ } ++ else if (pBtLinkInfo->bA2dpExist && pBtLinkInfo->bPanExist) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 22); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); ++ } ++ else ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 20); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); ++ } ++ } ++ else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || ++ (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus)) ++ { ++ halbtc8723b1ant_ActionBtScoHidOnlyBusy(pBtCoexist, ++ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN); ++ } ++ else ++ { ++ /* Bryant Add */ ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 8); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); ++ } ++} ++ ++static void ++halbtc8723b1ant_ActionWifiConnectedSpecialPacket( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ PBTC_BT_LINK_INFO pBtLinkInfo =&pBtCoexist->btLinkInfo; ++ ++ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); ++ ++ /* tdma and coex table */ ++ if ((pBtLinkInfo->bScoExist) || (pBtLinkInfo->bHidExist) || (pBtLinkInfo->bA2dpExist)) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 32); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); ++ } ++ else if (pBtLinkInfo->bPanExist) ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 20); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); ++ } ++ else ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 8); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); ++ } ++} ++ ++static void ++halbtc8723b1ant_ActionWifiConnected( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ bool bWifiBusy =false; ++ bool bScan =false, bLink =false, bRoam =false; ++ bool bUnder4way =false, bApEnable =false; ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect() ===>\n")); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &bUnder4way); ++ if (bUnder4way) ++ { ++ halbtc8723b1ant_ActionWifiConnectedSpecialPacket(pBtCoexist); ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n")); ++ return; ++ } ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); ++ if (bScan || bLink || bRoam) ++ { ++ if (bScan) ++ halbtc8723b1ant_ActionWifiConnectedScan(pBtCoexist); ++ else ++ halbtc8723b1ant_ActionWifiConnectedSpecialPacket(pBtCoexist); ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n")); ++ return; ++ } ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, &bApEnable); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); ++ ++ /* power save state */ ++ if (!bApEnable && BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus && !pBtCoexist->btLinkInfo.bHidOnly) ++ { ++ if (pBtCoexist->btLinkInfo.bA2dpOnly) /* A2DP */ ++ { ++ if (!bWifiBusy) ++ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); ++ else /* busy */ ++ { ++ if (pCoexSta->nScanAPNum >= BT_8723B_1ANT_WIFI_NOISY_THRESH) /* no force LPS, no PS-TDMA, use pure TDMA */ ++ { ++ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); ++ } ++ else ++ { ++ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, 0x50, 0x4); ++ } ++ } ++ } ++ else if ((pCoexSta->bPanExist == false) && (pCoexSta->bA2dpExist == false) && (pCoexSta->bHidExist == false)) ++ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); ++ else ++ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, 0x50, 0x4); ++ } ++ else ++ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); ++ ++ /* tdma and coex table */ ++ if (!bWifiBusy) ++ { ++ if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) ++ { ++ halbtc8723b1ant_ActionWifiConnectedBtAclBusy(pBtCoexist, ++ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE); ++ } ++ else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || ++ (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus)) ++ { ++ halbtc8723b1ant_ActionBtScoHidOnlyBusy(pBtCoexist, ++ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE); ++ } ++ else ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 8); ++ ++ if ((pCoexSta->highPriorityTx) + (pCoexSta->highPriorityRx) <= 60) ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); ++ else ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); ++ } ++ } ++ else ++ { ++ if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) ++ { ++ halbtc8723b1ant_ActionWifiConnectedBtAclBusy(pBtCoexist, ++ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); ++ } ++ else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || ++ (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus)) ++ { ++ halbtc8723b1ant_ActionBtScoHidOnlyBusy(pBtCoexist, ++ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); ++ } ++ else ++ { ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 8); ++ ++ if ((pCoexSta->highPriorityTx) + (pCoexSta->highPriorityRx) <= 60) ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); ++ else ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); ++ } ++ } ++} ++ ++static void ++halbtc8723b1ant_RunSwCoexistMechanism( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ u8 algorithm = 0; ++ ++ algorithm = halbtc8723b1ant_ActionAlgorithm(pBtCoexist); ++ pCoexDm->curAlgorithm = algorithm; ++ ++ if (halbtc8723b1ant_IsCommonAction(pBtCoexist)) ++ { ++ ++ } ++ else ++ { ++ switch (pCoexDm->curAlgorithm) ++ { ++ case BT_8723B_1ANT_COEX_ALGO_SCO: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = SCO.\n")); ++ /* halbtc8723b1ant_ActionSco(pBtCoexist); */ ++ break; ++ case BT_8723B_1ANT_COEX_ALGO_HID: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID.\n")); ++ /* halbtc8723b1ant_ActionHid(pBtCoexist); */ ++ break; ++ case BT_8723B_1ANT_COEX_ALGO_A2DP: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = A2DP.\n")); ++ /* halbtc8723b1ant_ActionA2dp(pBtCoexist); */ ++ break; ++ case BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = A2DP+PAN(HS).\n")); ++ /* halbtc8723b1ant_ActionA2dpPanHs(pBtCoexist); */ ++ break; ++ case BT_8723B_1ANT_COEX_ALGO_PANEDR: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN(EDR).\n")); ++ /* halbtc8723b1ant_ActionPanEdr(pBtCoexist); */ ++ break; ++ case BT_8723B_1ANT_COEX_ALGO_PANHS: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HS mode.\n")); ++ /* halbtc8723b1ant_ActionPanHs(pBtCoexist); */ ++ break; ++ case BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN+A2DP.\n")); ++ /* halbtc8723b1ant_ActionPanEdrA2dp(pBtCoexist); */ ++ break; ++ case BT_8723B_1ANT_COEX_ALGO_PANEDR_HID: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN(EDR)+HID.\n")); ++ /* halbtc8723b1ant_ActionPanEdrHid(pBtCoexist); */ ++ break; ++ case BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID+A2DP+PAN.\n")); ++ /* halbtc8723b1ant_ActionHidA2dpPanEdr(pBtCoexist); */ ++ break; ++ case BT_8723B_1ANT_COEX_ALGO_HID_A2DP: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID+A2DP.\n")); ++ /* halbtc8723b1ant_ActionHidA2dp(pBtCoexist); */ ++ break; ++ default: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = coexist All Off!!\n")); ++ break; ++ } ++ pCoexDm->preAlgorithm = pCoexDm->curAlgorithm; ++ } ++} ++ ++static void ++halbtc8723b1ant_RunCoexistMechanism( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ PBTC_BT_LINK_INFO pBtLinkInfo =&pBtCoexist->btLinkInfo; ++ bool bWifiConnected =false, bBtHsOn =false; ++ bool bIncreaseScanDevNum =false; ++ bool bBtCtrlAggBufSize =false; ++ u8 aggBufSize =5; ++ u32 wifiLinkStatus = 0; ++ u32 numOfWifiLink = 0; ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism() ===>\n")); ++ ++ if (pBtCoexist->bManualControl) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n")); ++ return; ++ } ++ ++ if (pBtCoexist->bStopCoexDm) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n")); ++ return; ++ } ++ ++ if (pCoexSta->bUnderIps) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is under IPS !!!\n")); ++ return; ++ } ++ ++ if ((BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) || ++ (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || ++ (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus)) ++ { ++ bIncreaseScanDevNum = true; ++ } ++ ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, &bIncreaseScanDevNum); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifiLinkStatus); ++ numOfWifiLink = wifiLinkStatus>>16; ++ ++ if ((numOfWifiLink>=2) || (wifiLinkStatus&WIFI_P2P_GO_CONNECTED)) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("############# [BTCoex], Multi-Port numOfWifiLink = %d, wifiLinkStatus = 0x%x\n", numOfWifiLink, wifiLinkStatus)); ++ halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); ++ halbtc8723b1ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, bBtCtrlAggBufSize, aggBufSize); ++ ++ if ((pBtLinkInfo->bA2dpExist) && (pCoexSta->bC2hBtInquiryPage)) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("############# [BTCoex], BT Is Inquirying\n")); ++ halbtc8723b1ant_ActionBtInquiry(pBtCoexist); ++ } ++ else ++ halbtc8723b1ant_ActionWifiMultiPort(pBtCoexist); ++ ++ return; ++ } ++ ++ if ((pBtLinkInfo->bBtLinkExist) && (bWifiConnected)) ++ { ++ halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 1, 1, 0, 1); ++ ++ if (pBtLinkInfo->bScoExist) ++ halbtc8723b1ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, true, 0x5); ++ else ++ halbtc8723b1ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, true, 0x8); ++ ++ halbtc8723b1ant_SwMechanism(pBtCoexist, true); ++ halbtc8723b1ant_RunSwCoexistMechanism(pBtCoexist); /* just print debug message */ ++ } ++ else ++ { ++ halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); ++ ++ halbtc8723b1ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x5); ++ ++ halbtc8723b1ant_SwMechanism(pBtCoexist, false); ++ halbtc8723b1ant_RunSwCoexistMechanism(pBtCoexist); /* just print debug message */ ++ } ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); ++ if (pCoexSta->bC2hBtInquiryPage) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("############# [BTCoex], BT Is Inquirying\n")); ++ halbtc8723b1ant_ActionBtInquiry(pBtCoexist); ++ return; ++ } ++ else if (bBtHsOn) ++ { ++ halbtc8723b1ant_ActionHs(pBtCoexist); ++ return; ++ } ++ ++ ++ if (!bWifiConnected) ++ { ++ bool bScan =false, bLink =false, bRoam =false; ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is non connected-idle !!!\n")); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); ++ ++ if (bScan || bLink || bRoam) ++ { ++ if (bScan) ++ halbtc8723b1ant_ActionWifiNotConnectedScan(pBtCoexist); ++ else ++ halbtc8723b1ant_ActionWifiNotConnectedAssoAuth(pBtCoexist); ++ } ++ else ++ halbtc8723b1ant_ActionWifiNotConnected(pBtCoexist); ++ } ++ else /* wifi LPS/Busy */ ++ { ++ halbtc8723b1ant_ActionWifiConnected(pBtCoexist); ++ } ++} ++ ++static void ++halbtc8723b1ant_InitCoexDm( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ /* force to reset coex mechanism */ ++ ++ /* sw all off */ ++ halbtc8723b1ant_SwMechanism(pBtCoexist, false); ++ ++ /* halbtc8723b1ant_PsTdma(pBtCoexist, FORCE_EXEC, false, 8); */ ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 0); ++ ++ pCoexSta->popEventCnt = 0; ++} ++ ++static void ++halbtc8723b1ant_InitHwConfig( ++PBTC_COEXIST pBtCoexist, ++bool bBackUp, ++bool bWifiOnly ++ ) ++{ ++ u32 u4Tmp = 0;/* fwVer; */ ++ u8 u1Tmpa = 0, u1Tmpb = 0; ++ ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 1Ant Init HW Config!!\n")); ++ ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x550, 0x8, 0x1); /* enable TBTT nterrupt */ ++ ++ /* 0x790[5:0]= 0x5 */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x790, 0x5); ++ ++ /* Enable counter statistics */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x778, 0x1); ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x40, 0x20, 0x1); ++ ++ /* Antenna config */ ++ if (bWifiOnly) ++ { ++ halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_WIFI, true, false); ++ halbtc8723b1ant_PsTdma(pBtCoexist, FORCE_EXEC, false, 9); ++ } ++ else ++ halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, true, false); ++ ++ /* PTA parameter */ ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 0); ++ ++ u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x948); ++ u1Tmpa = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x765); ++ u1Tmpb = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x67); ++ ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("############# [BTCoex], 0x948 = 0x%x, 0x765 = 0x%x, 0x67 = 0x%x\n", ++ u4Tmp, u1Tmpa, u1Tmpb)); ++} ++ ++/* */ ++/* work around function start with wa_halbtc8723b1ant_ */ ++/* */ ++/* */ ++/* extern function start with EXhalbtc8723b1ant_ */ ++/* */ ++void ++EXhalbtc8723b1ant_PowerOnSetting( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ PBTC_BOARD_INFO pBoardInfo =&pBtCoexist->boardInfo; ++ u8 u1Tmp = 0x0; ++ u16 u2Tmp = 0x0; ++ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x67, 0x20); ++ ++ /* enable BB, REG_SYS_FUNC_EN such that we can write 0x948 correctly. */ ++ u2Tmp = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0x2); ++ pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x2, u2Tmp|BIT0|BIT1); ++ ++ /* set GRAN_BT = 1 */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x765, 0x18); ++ /* set WLAN_ACT = 0 */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0x4); ++ ++ /* */ ++ /* S0 or S1 setting and Local register setting(By the setting fw can get ant number, S0/S1, ... info) */ ++ /* Local setting bit define */ ++ /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ ++ /* BIT1: "0" for internal switch; "1" for external switch */ ++ /* BIT2: "0" for one antenna; "1" for two antenna */ ++ /* NOTE: here default all internal switch and 1-antenna ==> BIT1 = 0 and BIT2 = 0 */ ++ if (pBtCoexist->chipInterface == BTC_INTF_USB) ++ { ++ /* fixed at S0 for USB interface */ ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x0); ++ ++ u1Tmp |= 0x1; /* antenna inverse */ ++ pBtCoexist->fBtcWriteLocalReg1Byte(pBtCoexist, 0xfe08, u1Tmp); ++ ++ pBoardInfo->btdmAntPos = BTC_ANTENNA_AT_AUX_PORT; ++ } ++ else ++ { ++ /* for PCIE and SDIO interface, we check efuse 0xc3[6] */ ++ if (pBoardInfo->singleAntPath == 0) ++ { ++ /* set to S1 */ ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x280); ++ pBoardInfo->btdmAntPos = BTC_ANTENNA_AT_MAIN_PORT; ++ } ++ else if (pBoardInfo->singleAntPath == 1) ++ { ++ /* set to S0 */ ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x0); ++ u1Tmp |= 0x1; /* antenna inverse */ ++ pBoardInfo->btdmAntPos = BTC_ANTENNA_AT_AUX_PORT; ++ } ++ ++ if (pBtCoexist->chipInterface == BTC_INTF_PCI) ++ { ++ pBtCoexist->fBtcWriteLocalReg1Byte(pBtCoexist, 0x384, u1Tmp); ++ } ++ else if (pBtCoexist->chipInterface == BTC_INTF_SDIO) ++ { ++ pBtCoexist->fBtcWriteLocalReg1Byte(pBtCoexist, 0x60, u1Tmp); ++ } ++ } ++} ++ ++void ++EXhalbtc8723b1ant_InitHwConfig( ++PBTC_COEXIST pBtCoexist, ++bool bWifiOnly ++ ) ++{ ++ halbtc8723b1ant_InitHwConfig(pBtCoexist, true, bWifiOnly); ++} ++ ++void ++EXhalbtc8723b1ant_InitCoexDm( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); ++ ++ pBtCoexist->bStopCoexDm = false; ++ ++ halbtc8723b1ant_InitCoexDm(pBtCoexist); ++ ++ halbtc8723b1ant_QueryBtInfo(pBtCoexist); ++} ++ ++void ++EXhalbtc8723b1ant_DisplayCoexInfo( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ PBTC_BOARD_INFO pBoardInfo =&pBtCoexist->boardInfo; ++ PBTC_STACK_INFO pStackInfo =&pBtCoexist->stackInfo; ++ PBTC_BT_LINK_INFO pBtLinkInfo =&pBtCoexist->btLinkInfo; ++ u8 * cliBuf =pBtCoexist->cliBuf; ++ u8 u1Tmp[4], i, btInfoExt, psTdmaCase = 0; ++ u16 u2Tmp[4]; ++ u32 u4Tmp[4]; ++ bool bRoam =false, bScan =false, bLink =false, bWifiUnder5G =false, bWifiUnderBMode = false; ++ bool bBtHsOn =false, bWifiBusy =false; ++ s32 wifiRssi = 0, btHsRssi = 0; ++ u32 wifiBw, wifiTrafficDir, faOfdm, faCck, wifiLinkStatus; ++ u8 wifiDot11Chnl, wifiHsChnl; ++ u32 fwVer = 0, btPatchVer = 0; ++ static u8 PopReportIn10s = 0; ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); ++ CL_PRINTF(cliBuf); ++ ++ if (pBtCoexist->bManualControl) ++ { ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[Under Manual Control]============"); ++ CL_PRINTF(cliBuf); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n =========================================="); ++ CL_PRINTF(cliBuf); ++ } ++ if (pBtCoexist->bStopCoexDm) ++ { ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[Coex is STOPPED]============"); ++ CL_PRINTF(cliBuf); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n =========================================="); ++ CL_PRINTF(cliBuf); ++ } ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", "Ant PG Num/ Ant Mech/ Ant Pos:", \ ++ pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum, pBoardInfo->btdmAntPos); ++ CL_PRINTF(cliBuf); ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ ++ ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion); ++ CL_PRINTF(cliBuf); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer", \ ++ GLCoexVerDate8723b1Ant, GLCoexVer8723b1Ant, fwVer, btPatchVer, btPatchVer); ++ CL_PRINTF(cliBuf); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiDot11Chnl); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifiHsChnl); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", \ ++ wifiDot11Chnl, wifiHsChnl, bBtHsOn); ++ CL_PRINTF(cliBuf); ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", \ ++ pCoexDm->wifiChnlInfo[0], pCoexDm->wifiChnlInfo[1], ++ pCoexDm->wifiChnlInfo[2]); ++ CL_PRINTF(cliBuf); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", \ ++ wifiRssi-100, btHsRssi-100); ++ CL_PRINTF(cliBuf); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %s", "Wifi bLink/ bRoam/ bScan/ bHi-Pri", \ ++ bLink, bRoam, bScan, ((pCoexSta->bWiFiIsHighPriTask)? "1":"0")); ++ CL_PRINTF(cliBuf); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, &bWifiUnderBMode); ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s/ AP =%d/ %s ", "Wifi status", \ ++ (bWifiUnder5G? "5G":"2.4G"), ++ ((bWifiUnderBMode)? "11b": ((BTC_WIFI_BW_LEGACY ==wifiBw)? "11bg": (((BTC_WIFI_BW_HT40 ==wifiBw)? "HT40":"HT20")))), ++ ((!bWifiBusy)? "idle": ((BTC_WIFI_TRAFFIC_TX ==wifiTrafficDir)? "uplink":"downlink")), pCoexSta->nScanAPNum, (pCoexSta->bCCKLock)? "Lock":"noLock"); ++ CL_PRINTF(cliBuf); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifiLinkStatus); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", "sta/vwifi/hs/p2pGo/p2pGc", \ ++ ((wifiLinkStatus&WIFI_STA_CONNECTED)? 1:0), ((wifiLinkStatus&WIFI_AP_CONNECTED)? 1:0), ++ ((wifiLinkStatus&WIFI_HS_CONNECTED)? 1:0), ((wifiLinkStatus&WIFI_P2P_GO_CONNECTED)? 1:0), ++ ((wifiLinkStatus&WIFI_P2P_GC_CONNECTED)? 1:0)); ++ CL_PRINTF(cliBuf); ++ ++ ++ PopReportIn10s++; ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d/ %d] ", "BT [status/ rssi/ retryCnt/ popCnt]", \ ++ ((pBtCoexist->btInfo.bBtDisabled)? ("disabled"): ((pCoexSta->bC2hBtInquiryPage)?("inquiry/page scan"):((BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus)? "non-connected idle": ++ ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)? "connected-idle":"busy")))), ++ pCoexSta->btRssi, pCoexSta->btRetryCnt, pCoexSta->popEventCnt); ++ CL_PRINTF(cliBuf); ++ ++ if (PopReportIn10s >= 5) ++ { ++ pCoexSta->popEventCnt = 0; ++ PopReportIn10s = 0; ++ } ++ ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \ ++ pBtLinkInfo->bScoExist, pBtLinkInfo->bHidExist, pBtLinkInfo->bPanExist, pBtLinkInfo->bA2dpExist); ++ CL_PRINTF(cliBuf); ++ ++ if (pStackInfo->bProfileNotified) ++ { ++ pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_BT_LINK_INFO); ++ } ++ else ++ { ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Role", \ ++ (pBtLinkInfo->bSlaveRole)? "Slave":"Master"); ++ CL_PRINTF(cliBuf); ++ } ++ ++ ++ btInfoExt = pCoexSta->btInfoExt; ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Info A2DP rate", \ ++ (btInfoExt&BIT0)? "Basic rate":"EDR rate"); ++ CL_PRINTF(cliBuf); ++ ++ for (i = 0; ibtInfoC2hCnt[i]) ++ { ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8723b1Ant[i], \ ++ pCoexSta->btInfoC2h[i][0], pCoexSta->btInfoC2h[i][1], ++ pCoexSta->btInfoC2h[i][2], pCoexSta->btInfoC2h[i][3], ++ pCoexSta->btInfoC2h[i][4], pCoexSta->btInfoC2h[i][5], ++ pCoexSta->btInfoC2h[i][6], pCoexSta->btInfoC2hCnt[i]); ++ CL_PRINTF(cliBuf); ++ } ++ } ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s, (0x%x/0x%x)", "PS state, IPS/LPS, (lps/rpwm)", \ ++ ((pCoexSta->bUnderIps? "IPS ON":"IPS OFF")), ++ ((pCoexSta->bUnderLps? "LPS ON":"LPS OFF")), ++ pBtCoexist->btInfo.lpsVal, ++ pBtCoexist->btInfo.rpwmVal); ++ CL_PRINTF(cliBuf); ++ pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); ++ ++ if (!pBtCoexist->bManualControl) ++ { ++ /* Sw mechanism */ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw mechanism]============"); ++ CL_PRINTF(cliBuf); ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "SM[LowPenaltyRA]", \ ++ pCoexDm->bCurLowPenaltyRa); ++ CL_PRINTF(cliBuf); ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %d ", "DelBA/ BtCtrlAgg/ AggSize", \ ++ (pBtCoexist->btInfo.bRejectAggPkt? "Yes":"No"), (pBtCoexist->btInfo.bBtCtrlAggBufSize? "Yes":"No"), ++ pBtCoexist->btInfo.aggBufSize); ++ CL_PRINTF(cliBuf); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Rate Mask", \ ++ pBtCoexist->btInfo.raMask); ++ CL_PRINTF(cliBuf); ++ ++ /* Fw mechanism */ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw mechanism]============"); ++ CL_PRINTF(cliBuf); ++ ++ psTdmaCase = pCoexDm->curPsTdma; ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", "PS TDMA", \ ++ pCoexDm->psTdmaPara[0], pCoexDm->psTdmaPara[1], ++ pCoexDm->psTdmaPara[2], pCoexDm->psTdmaPara[3], ++ pCoexDm->psTdmaPara[4], psTdmaCase, pCoexDm->bAutoTdmaAdjust); ++ CL_PRINTF(cliBuf); ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "Coex Table Type", \ ++ pCoexSta->nCoexTableType); ++ CL_PRINTF(cliBuf); ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "IgnWlanAct", \ ++ pCoexDm->bCurIgnoreWlanAct); ++ CL_PRINTF(cliBuf); ++ ++ /* ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Latest error condition(should be 0)", \ ++ pCoexDm->errorCondition); ++ CL_PRINTF(cliBuf); ++ */ ++ } ++ ++ /* Hw setting */ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============"); ++ CL_PRINTF(cliBuf); ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "backup ARFR1/ARFR2/RL/AMaxTime", \ ++ pCoexDm->backupArfrCnt1, pCoexDm->backupArfrCnt2, pCoexDm->backupRetryLimit, pCoexDm->backupAmpduMaxTime); ++ CL_PRINTF(cliBuf); ++ ++ u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x430); ++ u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x434); ++ u2Tmp[0] = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0x42a); ++ u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x456); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "0x430/0x434/0x42a/0x456", \ ++ u4Tmp[0], u4Tmp[1], u2Tmp[0], u1Tmp[0]); ++ CL_PRINTF(cliBuf); ++ ++ u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x778); ++ u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6cc); ++ u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x880); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x778/0x6cc/0x880[29:25]", \ ++ u1Tmp[0], u4Tmp[0], (u4Tmp[1]&0x3e000000) >> 25); ++ CL_PRINTF(cliBuf); ++ ++ u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x948); ++ u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x67); ++ u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x764); ++ u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x76e); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x948/ 0x67[5] / 0x764 / 0x76e", \ ++ u4Tmp[0], ((u1Tmp[0]&0x20)>> 5), (u4Tmp[1] & 0xffff), u1Tmp[1]); ++ CL_PRINTF(cliBuf); ++ ++ u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x92c); ++ u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x930); ++ u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x944); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]", \ ++ u4Tmp[0]&0x3, u4Tmp[1]&0xff, u4Tmp[2]&0x3); ++ CL_PRINTF(cliBuf); ++ ++ u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x39); ++ u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x40); ++ u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); ++ u1Tmp[2] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x64); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x38[11]/0x40/0x4c[24:23]/0x64[0]", \ ++ ((u1Tmp[0] & 0x8)>>3), u1Tmp[1], ((u4Tmp[0]&0x01800000)>>23), u1Tmp[2]&0x1); ++ CL_PRINTF(cliBuf); ++ ++ u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x550); ++ u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x522); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", \ ++ u4Tmp[0], u1Tmp[0]); ++ CL_PRINTF(cliBuf); ++ ++ u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xc50); ++ u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x49c); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0xc50(dig)/0x49c(null-drop)", \ ++ u4Tmp[0]&0xff, u1Tmp[0]); ++ CL_PRINTF(cliBuf); ++ ++ u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xda0); ++ u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xda4); ++ u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xda8); ++ u4Tmp[3] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xcf0); ++ ++ u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xa5b); ++ u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xa5c); ++ ++ faOfdm = ((u4Tmp[0]&0xffff0000) >> 16) + ((u4Tmp[1]&0xffff0000) >> 16) + (u4Tmp[1] & 0xffff) + (u4Tmp[2] & 0xffff) + \ ++ ((u4Tmp[3]&0xffff0000) >> 16) + (u4Tmp[3] & 0xffff) ; ++ faCck = (u1Tmp[0] << 8) + u1Tmp[1]; ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "OFDM-CCA/OFDM-FA/CCK-FA", \ ++ u4Tmp[0]&0xffff, faOfdm, faCck); ++ CL_PRINTF(cliBuf); ++ ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", "CRC_OK CCK/11g/11n/11n-Agg", \ ++ pCoexSta->nCRCOK_CCK, pCoexSta->nCRCOK_11g, pCoexSta->nCRCOK_11n, pCoexSta->nCRCOK_11nAgg); ++ CL_PRINTF(cliBuf); ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", "CRC_Err CCK/11g/11n/11n-Agg", \ ++ pCoexSta->nCRCErr_CCK, pCoexSta->nCRCErr_11g, pCoexSta->nCRCErr_11n, pCoexSta->nCRCErr_11nAgg); ++ CL_PRINTF(cliBuf); ++ ++ u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c0); ++ u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c4); ++ u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c8); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8(coexTable)", \ ++ u4Tmp[0], u4Tmp[1], u4Tmp[2]); ++ CL_PRINTF(cliBuf); ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x770(high-pri rx/tx)", \ ++ pCoexSta->highPriorityRx, pCoexSta->highPriorityTx); ++ CL_PRINTF(cliBuf); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)", \ ++ pCoexSta->lowPriorityRx, pCoexSta->lowPriorityTx); ++ CL_PRINTF(cliBuf); ++ ++ pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_COEX_STATISTICS); ++} ++ ++ ++void ++EXhalbtc8723b1ant_IpsNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ) ++{ ++ if (pBtCoexist->bManualControl || pBtCoexist->bStopCoexDm) ++ return; ++ ++ if (BTC_IPS_ENTER == type) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); ++ pCoexSta->bUnderIps = true; ++ ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 0); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); ++ halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, false, true); ++ } ++ else if (BTC_IPS_LEAVE == type) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")); ++ pCoexSta->bUnderIps = false; ++ ++ halbtc8723b1ant_InitHwConfig(pBtCoexist, false, false); ++ halbtc8723b1ant_InitCoexDm(pBtCoexist); ++ halbtc8723b1ant_QueryBtInfo(pBtCoexist); ++ } ++} ++ ++void ++EXhalbtc8723b1ant_LpsNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ) ++{ ++ if (pBtCoexist->bManualControl || pBtCoexist->bStopCoexDm) ++ return; ++ ++ if (BTC_LPS_ENABLE == type) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); ++ pCoexSta->bUnderLps = true; ++ } ++ else if (BTC_LPS_DISABLE == type) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")); ++ pCoexSta->bUnderLps = false; ++ } ++} ++ ++void ++EXhalbtc8723b1ant_ScanNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ) ++{ ++ bool bWifiConnected =false, bBtHsOn =false; ++ u32 wifiLinkStatus = 0; ++ u32 numOfWifiLink = 0; ++ bool bBtCtrlAggBufSize =false; ++ u8 aggBufSize =5; ++ ++ u8 u1Tmpa, u1Tmpb; ++ u32 u4Tmp; ++ ++ if (pBtCoexist->bManualControl || ++ pBtCoexist->bStopCoexDm) ++ return; ++ ++ if (BTC_SCAN_START == type) ++ { ++ pCoexSta->bWiFiIsHighPriTask = true; ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); ++ ++ halbtc8723b1ant_PsTdma(pBtCoexist, FORCE_EXEC, false, 8); /* Force antenna setup for no scan result issue */ ++ u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x948); ++ u1Tmpa = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x765); ++ u1Tmpb = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x67); ++ ++ ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], 0x948 = 0x%x, 0x765 = 0x%x, 0x67 = 0x%x\n", ++ u4Tmp, u1Tmpa, u1Tmpb)); ++ } ++ else ++ { ++ pCoexSta->bWiFiIsHighPriTask = false; ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_AP_NUM, &pCoexSta->nScanAPNum); ++ } ++ ++ if (pBtCoexist->btInfo.bBtDisabled) ++ return; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); ++ ++ halbtc8723b1ant_QueryBtInfo(pBtCoexist); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifiLinkStatus); ++ numOfWifiLink = wifiLinkStatus>>16; ++ if (numOfWifiLink >= 2) ++ { ++ halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); ++ halbtc8723b1ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, bBtCtrlAggBufSize, aggBufSize); ++ halbtc8723b1ant_ActionWifiMultiPort(pBtCoexist); ++ return; ++ } ++ ++ if (pCoexSta->bC2hBtInquiryPage) ++ { ++ halbtc8723b1ant_ActionBtInquiry(pBtCoexist); ++ return; ++ } ++ else if (bBtHsOn) ++ { ++ halbtc8723b1ant_ActionHs(pBtCoexist); ++ return; ++ } ++ ++ if (BTC_SCAN_START == type) ++ { ++ /* BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); */ ++ if (!bWifiConnected) /* non-connected scan */ ++ { ++ halbtc8723b1ant_ActionWifiNotConnectedScan(pBtCoexist); ++ } ++ else /* wifi is connected */ ++ { ++ halbtc8723b1ant_ActionWifiConnectedScan(pBtCoexist); ++ } ++ } ++ else if (BTC_SCAN_FINISH == type) ++ { ++ /* BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); */ ++ if (!bWifiConnected) /* non-connected scan */ ++ { ++ halbtc8723b1ant_ActionWifiNotConnected(pBtCoexist); ++ } ++ else ++ { ++ halbtc8723b1ant_ActionWifiConnected(pBtCoexist); ++ } ++ } ++} ++ ++void ++EXhalbtc8723b1ant_ConnectNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ) ++{ ++ bool bWifiConnected =false, bBtHsOn =false; ++ u32 wifiLinkStatus = 0; ++ u32 numOfWifiLink = 0; ++ bool bBtCtrlAggBufSize =false; ++ u8 aggBufSize =5; ++ ++ if (pBtCoexist->bManualControl || ++ pBtCoexist->bStopCoexDm || ++ pBtCoexist->btInfo.bBtDisabled) ++ return; ++ ++ if (BTC_ASSOCIATE_START == type) ++ { ++ pCoexSta->bWiFiIsHighPriTask = true; ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); ++ pCoexDm->nArpCnt = 0; ++ } ++ else ++ { ++ pCoexSta->bWiFiIsHighPriTask = false; ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); ++ /* pCoexDm->nArpCnt = 0; */ ++ } ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifiLinkStatus); ++ numOfWifiLink = wifiLinkStatus>>16; ++ if (numOfWifiLink >= 2) ++ { ++ halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); ++ halbtc8723b1ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, bBtCtrlAggBufSize, aggBufSize); ++ halbtc8723b1ant_ActionWifiMultiPort(pBtCoexist); ++ return; ++ } ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); ++ if (pCoexSta->bC2hBtInquiryPage) ++ { ++ halbtc8723b1ant_ActionBtInquiry(pBtCoexist); ++ return; ++ } ++ else if (bBtHsOn) ++ { ++ halbtc8723b1ant_ActionHs(pBtCoexist); ++ return; ++ } ++ ++ if (BTC_ASSOCIATE_START == type) ++ { ++ /* BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); */ ++ halbtc8723b1ant_ActionWifiNotConnectedAssoAuth(pBtCoexist); ++ } ++ else if (BTC_ASSOCIATE_FINISH == type) ++ { ++ /* BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); */ ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); ++ if (!bWifiConnected) /* non-connected scan */ ++ { ++ halbtc8723b1ant_ActionWifiNotConnected(pBtCoexist); ++ } ++ else ++ { ++ halbtc8723b1ant_ActionWifiConnected(pBtCoexist); ++ } ++ } ++} ++ ++void ++EXhalbtc8723b1ant_MediaStatusNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ) ++{ ++ u8 H2C_Parameter[3] ={0}; ++ u32 wifiBw; ++ u8 wifiCentralChnl; ++ bool bWifiUnderBMode = false; ++ ++ if (pBtCoexist->bManualControl || ++ pBtCoexist->bStopCoexDm || ++ pBtCoexist->btInfo.bBtDisabled) ++ return; ++ ++ if (BTC_MEDIA_CONNECT == type) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n")); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, &bWifiUnderBMode); ++ ++ /* Set CCK Tx/Rx high Pri except 11b mode */ ++ if (bWifiUnderBMode) ++ { ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cd, 0x00); /* CCK Tx */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cf, 0x00); /* CCK Rx */ ++ } ++ else ++ { ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cd, 0x10); /* CCK Tx */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cf, 0x10); /* CCK Rx */ ++ } ++ ++ pCoexDm->backupArfrCnt1 = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x430); ++ pCoexDm->backupArfrCnt2 = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x434); ++ pCoexDm->backupRetryLimit = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0x42a); ++ pCoexDm->backupAmpduMaxTime = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x456); ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n")); ++ pCoexDm->nArpCnt = 0; ++ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cd, 0x0); /* CCK Tx */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cf, 0x0); /* CCK Rx */ ++ } ++ ++ /* only 2.4G we need to inform bt the chnl mask */ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifiCentralChnl); ++ if ((BTC_MEDIA_CONNECT == type) && ++ (wifiCentralChnl <= 14)) ++ { ++ /* H2C_Parameter[0] = 0x1; */ ++ H2C_Parameter[0] = 0x0; ++ H2C_Parameter[1] = wifiCentralChnl; ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); ++ if (BTC_WIFI_BW_HT40 == wifiBw) ++ H2C_Parameter[2] = 0x30; ++ else ++ H2C_Parameter[2] = 0x20; ++ } ++ ++ pCoexDm->wifiChnlInfo[0] = H2C_Parameter[0]; ++ pCoexDm->wifiChnlInfo[1] = H2C_Parameter[1]; ++ pCoexDm->wifiChnlInfo[2] = H2C_Parameter[2]; ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x66 = 0x%x\n", ++ H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2])); ++ ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x66, 3, H2C_Parameter); ++} ++ ++void ++EXhalbtc8723b1ant_SpecialPacketNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ) ++{ ++ bool bBtHsOn =false; ++ u32 wifiLinkStatus = 0; ++ u32 numOfWifiLink = 0; ++ bool bBtCtrlAggBufSize =false; ++ u8 aggBufSize =5; ++ ++ if (pBtCoexist->bManualControl || ++ pBtCoexist->bStopCoexDm || ++ pBtCoexist->btInfo.bBtDisabled) ++ return; ++ ++ if (BTC_PACKET_DHCP == type || ++ BTC_PACKET_EAPOL == type || ++ BTC_PACKET_ARP == type) ++ { ++ if (BTC_PACKET_ARP == type) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], special Packet ARP notify\n")); ++ ++ pCoexDm->nArpCnt++; ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], ARP Packet Count = %d\n", pCoexDm->nArpCnt)); ++ ++ if (pCoexDm->nArpCnt >= 10) /* if APR PKT > 10 after connect, do not go to ActionWifiConnectedSpecialPacket(pBtCoexist) */ ++ { ++ pCoexSta->bWiFiIsHighPriTask = false; ++ } ++ else ++ { ++ pCoexSta->bWiFiIsHighPriTask = true; ++ } ++ } ++ else ++ { ++ pCoexSta->bWiFiIsHighPriTask = true; ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], special Packet DHCP or EAPOL notify\n")); ++ } ++ } ++ else ++ { ++ pCoexSta->bWiFiIsHighPriTask = false; ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], special Packet [Type = %d] notify\n", type)); ++ } ++ ++ pCoexSta->specialPktPeriodCnt = 0; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifiLinkStatus); ++ numOfWifiLink = wifiLinkStatus>>16; ++ if (numOfWifiLink >= 2) ++ { ++ halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); ++ halbtc8723b1ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, bBtCtrlAggBufSize, aggBufSize); ++ halbtc8723b1ant_ActionWifiMultiPort(pBtCoexist); ++ return; ++ } ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); ++ if (pCoexSta->bC2hBtInquiryPage) ++ { ++ halbtc8723b1ant_ActionBtInquiry(pBtCoexist); ++ return; ++ } ++ else if (bBtHsOn) ++ { ++ halbtc8723b1ant_ActionHs(pBtCoexist); ++ return; ++ } ++ ++ if (BTC_PACKET_DHCP == type || ++ BTC_PACKET_EAPOL == type || ++ ((BTC_PACKET_ARP == type) && (pCoexSta->bWiFiIsHighPriTask))) ++ { ++ halbtc8723b1ant_ActionWifiConnectedSpecialPacket(pBtCoexist); ++ } ++} ++ ++void ++EXhalbtc8723b1ant_BtInfoNotify( ++PBTC_COEXIST pBtCoexist, ++u8 * tmpBuf, ++u8 length ++ ) ++{ ++ u8 btInfo = 0; ++ u8 i, rspSource = 0; ++ bool bWifiConnected =false; ++ bool bBtBusy =false; ++ ++ pCoexSta->bC2hBtInfoReqSent = false; ++ ++ rspSource = tmpBuf[0]&0xf; ++ if (rspSource >= BT_INFO_SRC_8723B_1ANT_MAX) ++ rspSource = BT_INFO_SRC_8723B_1ANT_WIFI_FW; ++ pCoexSta->btInfoC2hCnt[rspSource]++; ++ ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Bt info[%d], length =%d, hex data =[", rspSource, length)); ++ for (i = 0; ibtInfoC2h[rspSource][i] = tmpBuf[i]; ++ if (i == 1) ++ btInfo = tmpBuf[i]; ++ if (i == length-1) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i])); ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x, ", tmpBuf[i])); ++ } ++ } ++ ++ if (BT_INFO_SRC_8723B_1ANT_WIFI_FW != rspSource) ++ { ++ pCoexSta->btRetryCnt = /* [3:0] */ ++ pCoexSta->btInfoC2h[rspSource][2]&0xf; ++ ++ if (pCoexSta->btRetryCnt >= 1) ++ pCoexSta->popEventCnt++; ++ ++ if (pCoexSta->btInfoC2h[rspSource][2]&0x20) ++ pCoexSta->bC2hBtPage = true; ++ else ++ pCoexSta->bC2hBtPage = false; ++ ++ pCoexSta->btRssi = ++ pCoexSta->btInfoC2h[rspSource][3]*2-90; ++ /* pCoexSta->btInfoC2h[rspSource][3]*2+10; */ ++ ++ pCoexSta->btInfoExt = ++ pCoexSta->btInfoC2h[rspSource][4]; ++ ++ pCoexSta->bBtTxRxMask = (pCoexSta->btInfoC2h[rspSource][2]&0x40); ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TX_RX_MASK, &pCoexSta->bBtTxRxMask); ++ if (!pCoexSta->bBtTxRxMask) ++ { ++ /* BT into is responded by BT FW and BT RF REG 0x3C != 0x15 => Need to switch BT TRx Mask */ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Switch BT TRx Mask since BT RF REG 0x3C != 0x15\n")); ++ pBtCoexist->fBtcSetBtReg(pBtCoexist, BTC_BT_REG_RF, 0x3c, 0x15); ++ } ++ ++ /* Here we need to resend some wifi info to BT */ ++ /* because bt is reset and loss of the info. */ ++ if (pCoexSta->btInfoExt & BIT1) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n")); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); ++ if (bWifiConnected) ++ { ++ EXhalbtc8723b1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_CONNECT); ++ } ++ else ++ { ++ EXhalbtc8723b1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); ++ } ++ } ++ ++ if (pCoexSta->btInfoExt & BIT3) ++ { ++ if (!pBtCoexist->bManualControl && !pBtCoexist->bStopCoexDm) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n")); ++ halbtc8723b1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, false); ++ } ++ } ++ else ++ { ++ /* BT already NOT ignore Wlan active, do nothing here. */ ++ } ++ } ++ ++ /* check BIT2 first ==> check if bt is under inquiry or page scan */ ++ if (btInfo & BT_INFO_8723B_1ANT_B_INQ_PAGE) ++ pCoexSta->bC2hBtInquiryPage = true; ++ else ++ pCoexSta->bC2hBtInquiryPage = false; ++ ++ /* set link exist status */ ++ if (!(btInfo&BT_INFO_8723B_1ANT_B_CONNECTION)) ++ { ++ pCoexSta->bBtLinkExist = false; ++ pCoexSta->bPanExist = false; ++ pCoexSta->bA2dpExist = false; ++ pCoexSta->bHidExist = false; ++ pCoexSta->bScoExist = false; ++ } ++ else /* connection exists */ ++ { ++ pCoexSta->bBtLinkExist = true; ++ if (btInfo & BT_INFO_8723B_1ANT_B_FTP) ++ pCoexSta->bPanExist = true; ++ else ++ pCoexSta->bPanExist = false; ++ if (btInfo & BT_INFO_8723B_1ANT_B_A2DP) ++ pCoexSta->bA2dpExist = true; ++ else ++ pCoexSta->bA2dpExist = false; ++ if (btInfo & BT_INFO_8723B_1ANT_B_HID) ++ pCoexSta->bHidExist = true; ++ else ++ pCoexSta->bHidExist = false; ++ if (btInfo & BT_INFO_8723B_1ANT_B_SCO_ESCO) ++ pCoexSta->bScoExist = true; ++ else ++ pCoexSta->bScoExist = false; ++ } ++ ++ halbtc8723b1ant_UpdateBtLinkInfo(pBtCoexist); ++ ++ btInfo = btInfo & 0x1f; /* mask profile bit for connect-ilde identification (for CSR case: A2DP idle --> 0x41) */ ++ ++ if (!(btInfo&BT_INFO_8723B_1ANT_B_CONNECTION)) ++ { ++ pCoexDm->btStatus = BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n")); ++ } ++ else if (btInfo == BT_INFO_8723B_1ANT_B_CONNECTION) /* connection exists but no busy */ ++ { ++ pCoexDm->btStatus = BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n")); ++ } ++ else if ((btInfo&BT_INFO_8723B_1ANT_B_SCO_ESCO) || ++ (btInfo&BT_INFO_8723B_1ANT_B_SCO_BUSY)) ++ { ++ pCoexDm->btStatus = BT_8723B_1ANT_BT_STATUS_SCO_BUSY; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT SCO busy!!!\n")); ++ } ++ else if (btInfo&BT_INFO_8723B_1ANT_B_ACL_BUSY) ++ { ++ if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY != pCoexDm->btStatus) ++ pCoexDm->bAutoTdmaAdjust = false; ++ pCoexDm->btStatus = BT_8723B_1ANT_BT_STATUS_ACL_BUSY; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT ACL busy!!!\n")); ++ } ++ else ++ { ++ pCoexDm->btStatus = BT_8723B_1ANT_BT_STATUS_MAX; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n")); ++ } ++ ++ if ((BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) || ++ (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || ++ (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus)) ++ bBtBusy = true; ++ else ++ bBtBusy = false; ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bBtBusy); ++ ++ halbtc8723b1ant_RunCoexistMechanism(pBtCoexist); ++} ++ ++void ++EXhalbtc8723b1ant_HaltNotify( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n")); ++ ++ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); ++ halbtc8723b1ant_PsTdma(pBtCoexist, FORCE_EXEC, false, 0); ++ halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, false, true); ++ ++ halbtc8723b1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, true); ++ ++ EXhalbtc8723b1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); ++ ++ pBtCoexist->bStopCoexDm = true; ++} ++ ++void ++EXhalbtc8723b1ant_PnpNotify( ++PBTC_COEXIST pBtCoexist, ++u8 pnpState ++ ) ++{ ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify\n")); ++ ++ if (BTC_WIFI_PNP_SLEEP == pnpState) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify to SLEEP\n")); ++ ++ halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); ++ halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 0); ++ halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); ++ halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, false, true); ++ ++ pBtCoexist->bStopCoexDm = true; ++ } ++ else if (BTC_WIFI_PNP_WAKE_UP == pnpState) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify to WAKE UP\n")); ++ pBtCoexist->bStopCoexDm = false; ++ halbtc8723b1ant_InitHwConfig(pBtCoexist, false, false); ++ halbtc8723b1ant_InitCoexDm(pBtCoexist); ++ halbtc8723b1ant_QueryBtInfo(pBtCoexist); ++ } ++} ++ ++void ++EXhalbtc8723b1ant_Periodical( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ static u8 disVerInfoCnt = 0; ++ u32 fwVer = 0, btPatchVer = 0; ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ==========================Periodical ===========================\n")); ++ ++ if (disVerInfoCnt <= 5) ++ { ++ disVerInfoCnt += 1; ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", \ ++ GLCoexVerDate8723b1Ant, GLCoexVer8723b1Ant, fwVer, btPatchVer, btPatchVer)); ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); ++ } ++ ++ halbtc8723b1ant_MonitorBtCtr(pBtCoexist); ++ halbtc8723b1ant_MonitorWiFiCtr(pBtCoexist); ++ ++ if (halbtc8723b1ant_IsWifiStatusChanged(pBtCoexist) || ++ pCoexDm->bAutoTdmaAdjust) ++ { ++ ++ halbtc8723b1ant_RunCoexistMechanism(pBtCoexist); ++ } ++ ++ pCoexSta->specialPktPeriodCnt++; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/HalBtc8723b1Ant.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalBtc8723b1Ant.h +--- linux-4.3/3rdparty/rtl8723bs/hal/HalBtc8723b1Ant.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalBtc8723b1Ant.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,243 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++/* The following is for 8723B 1ANT BT Co-exist definition */ ++#define BT_INFO_8723B_1ANT_B_FTP BIT7 ++#define BT_INFO_8723B_1ANT_B_A2DP BIT6 ++#define BT_INFO_8723B_1ANT_B_HID BIT5 ++#define BT_INFO_8723B_1ANT_B_SCO_BUSY BIT4 ++#define BT_INFO_8723B_1ANT_B_ACL_BUSY BIT3 ++#define BT_INFO_8723B_1ANT_B_INQ_PAGE BIT2 ++#define BT_INFO_8723B_1ANT_B_SCO_ESCO BIT1 ++#define BT_INFO_8723B_1ANT_B_CONNECTION BIT0 ++ ++#define BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ ++ (((_BT_INFO_EXT_&BIT0))? true:false) ++ ++#define BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT 2 ++ ++#define BT_8723B_1ANT_WIFI_NOISY_THRESH 30 /* max: 255 */ ++ ++typedef enum _BT_INFO_SRC_8723B_1ANT{ ++ BT_INFO_SRC_8723B_1ANT_WIFI_FW = 0x0, ++ BT_INFO_SRC_8723B_1ANT_BT_RSP = 0x1, ++ BT_INFO_SRC_8723B_1ANT_BT_ACTIVE_SEND = 0x2, ++ BT_INFO_SRC_8723B_1ANT_MAX ++}BT_INFO_SRC_8723B_1ANT,*PBT_INFO_SRC_8723B_1ANT; ++ ++typedef enum _BT_8723B_1ANT_BT_STATUS{ ++ BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, ++ BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, ++ BT_8723B_1ANT_BT_STATUS_INQ_PAGE = 0x2, ++ BT_8723B_1ANT_BT_STATUS_ACL_BUSY = 0x3, ++ BT_8723B_1ANT_BT_STATUS_SCO_BUSY = 0x4, ++ BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, ++ BT_8723B_1ANT_BT_STATUS_MAX ++}BT_8723B_1ANT_BT_STATUS,*PBT_8723B_1ANT_BT_STATUS; ++ ++typedef enum _BT_8723B_1ANT_WIFI_STATUS{ ++ BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, ++ BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, ++ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, ++ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT = 0x3, ++ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, ++ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, ++ BT_8723B_1ANT_WIFI_STATUS_MAX ++}BT_8723B_1ANT_WIFI_STATUS,*PBT_8723B_1ANT_WIFI_STATUS; ++ ++typedef enum _BT_8723B_1ANT_COEX_ALGO{ ++ BT_8723B_1ANT_COEX_ALGO_UNDEFINED = 0x0, ++ BT_8723B_1ANT_COEX_ALGO_SCO = 0x1, ++ BT_8723B_1ANT_COEX_ALGO_HID = 0x2, ++ BT_8723B_1ANT_COEX_ALGO_A2DP = 0x3, ++ BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, ++ BT_8723B_1ANT_COEX_ALGO_PANEDR = 0x5, ++ BT_8723B_1ANT_COEX_ALGO_PANHS = 0x6, ++ BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, ++ BT_8723B_1ANT_COEX_ALGO_PANEDR_HID = 0x8, ++ BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, ++ BT_8723B_1ANT_COEX_ALGO_HID_A2DP = 0xa, ++ BT_8723B_1ANT_COEX_ALGO_MAX = 0xb, ++}BT_8723B_1ANT_COEX_ALGO,*PBT_8723B_1ANT_COEX_ALGO; ++ ++typedef struct _COEX_DM_8723B_1ANT{ ++ /* fw mechanism */ ++ bool bCurIgnoreWlanAct; ++ bool bPreIgnoreWlanAct; ++ u8 prePsTdma; ++ u8 curPsTdma; ++ u8 psTdmaPara[5]; ++ u8 psTdmaDuAdjType; ++ bool bAutoTdmaAdjust; ++ bool bPrePsTdmaOn; ++ bool bCurPsTdmaOn; ++ bool bPreBtAutoReport; ++ bool bCurBtAutoReport; ++ u8 preLps; ++ u8 curLps; ++ u8 preRpwm; ++ u8 curRpwm; ++ ++ /* sw mechanism */ ++ bool bPreLowPenaltyRa; ++ bool bCurLowPenaltyRa; ++ u32 preVal0x6c0; ++ u32 curVal0x6c0; ++ u32 preVal0x6c4; ++ u32 curVal0x6c4; ++ u32 preVal0x6c8; ++ u32 curVal0x6c8; ++ u8 preVal0x6cc; ++ u8 curVal0x6cc; ++ bool bLimitedDig; ++ ++ u32 backupArfrCnt1; /* Auto Rate Fallback Retry cnt */ ++ u32 backupArfrCnt2; /* Auto Rate Fallback Retry cnt */ ++ u16 backupRetryLimit; ++ u8 backupAmpduMaxTime; ++ ++ /* algorithm related */ ++ u8 preAlgorithm; ++ u8 curAlgorithm; ++ u8 btStatus; ++ u8 wifiChnlInfo[3]; ++ ++ u32 preRaMask; ++ u32 curRaMask; ++ u8 preArfrType; ++ u8 curArfrType; ++ u8 preRetryLimitType; ++ u8 curRetryLimitType; ++ u8 preAmpduTimeType; ++ u8 curAmpduTimeType; ++ u32 nArpCnt; ++ ++ u8 errorCondition; ++} COEX_DM_8723B_1ANT, *PCOEX_DM_8723B_1ANT; ++ ++typedef struct _COEX_STA_8723B_1ANT{ ++ bool bBtLinkExist; ++ bool bScoExist; ++ bool bA2dpExist; ++ bool bHidExist; ++ bool bPanExist; ++ ++ bool bUnderLps; ++ bool bUnderIps; ++ u32 specialPktPeriodCnt; ++ u32 highPriorityTx; ++ u32 highPriorityRx; ++ u32 lowPriorityTx; ++ u32 lowPriorityRx; ++ s8 btRssi; ++ bool bBtTxRxMask; ++ u8 preBtRssiState; ++ u8 preWifiRssiState[4]; ++ bool bC2hBtInfoReqSent; ++ u8 btInfoC2h[BT_INFO_SRC_8723B_1ANT_MAX][10]; ++ u32 btInfoC2hCnt[BT_INFO_SRC_8723B_1ANT_MAX]; ++ bool bC2hBtInquiryPage; ++ bool bC2hBtPage; /* Add for win8.1 page out issue */ ++ bool bWiFiIsHighPriTask; /* Add for win8.1 page out issue */ ++ u8 btRetryCnt; ++ u8 btInfoExt; ++ u32 popEventCnt; ++ u8 nScanAPNum; ++ ++ u32 nCRCOK_CCK; ++ u32 nCRCOK_11g; ++ u32 nCRCOK_11n; ++ u32 nCRCOK_11nAgg; ++ ++ u32 nCRCErr_CCK; ++ u32 nCRCErr_11g; ++ u32 nCRCErr_11n; ++ u32 nCRCErr_11nAgg; ++ ++ bool bCCKLock; ++ bool bPreCCKLock; ++ u8 nCoexTableType; ++ ++ bool bForceLpsOn; ++}COEX_STA_8723B_1ANT, *PCOEX_STA_8723B_1ANT; ++ ++/* */ ++/* The following is interface which will notify coex module. */ ++/* */ ++void ++EXhalbtc8723b1ant_PowerOnSetting( ++PBTC_COEXIST pBtCoexist ++ ); ++void ++EXhalbtc8723b1ant_InitHwConfig( ++PBTC_COEXIST pBtCoexist, ++bool bWifiOnly ++ ); ++void ++EXhalbtc8723b1ant_InitCoexDm( ++PBTC_COEXIST pBtCoexist ++ ); ++void ++EXhalbtc8723b1ant_IpsNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ); ++void ++EXhalbtc8723b1ant_LpsNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ); ++void ++EXhalbtc8723b1ant_ScanNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ); ++void ++EXhalbtc8723b1ant_ConnectNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ); ++void ++EXhalbtc8723b1ant_MediaStatusNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ); ++void ++EXhalbtc8723b1ant_SpecialPacketNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ); ++void ++EXhalbtc8723b1ant_BtInfoNotify( ++PBTC_COEXIST pBtCoexist, ++u8 * tmpBuf, ++u8 length ++ ); ++void ++EXhalbtc8723b1ant_HaltNotify( ++PBTC_COEXIST pBtCoexist ++ ); ++void ++EXhalbtc8723b1ant_PnpNotify( ++PBTC_COEXIST pBtCoexist, ++u8 pnpState ++ ); ++void ++EXhalbtc8723b1ant_Periodical( ++PBTC_COEXIST pBtCoexist ++ ); ++void ++EXhalbtc8723b1ant_DisplayCoexInfo( ++PBTC_COEXIST pBtCoexist ++ ); +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/HalBtc8723b2Ant.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalBtc8723b2Ant.c +--- linux-4.3/3rdparty/rtl8723bs/hal/HalBtc8723b2Ant.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalBtc8723b2Ant.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,4077 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#include "Mp_Precomp.h" ++ ++/* Global variables, these are static variables */ ++static COEX_DM_8723B_2ANT GLCoexDm8723b2Ant; ++static PCOEX_DM_8723B_2ANT pCoexDm =&GLCoexDm8723b2Ant; ++static COEX_STA_8723B_2ANT GLCoexSta8723b2Ant; ++static PCOEX_STA_8723B_2ANT pCoexSta =&GLCoexSta8723b2Ant; ++ ++static const char *const GLBtInfoSrc8723b2Ant[]={ ++ "BT Info[wifi fw]", ++ "BT Info[bt rsp]", ++ "BT Info[bt auto report]", ++}; ++ ++static u32 GLCoexVerDate8723b2Ant =20131211; ++static u32 GLCoexVer8723b2Ant = 0x40; ++ ++/* local function start with halbtc8723b2ant_ */ ++static u8 ++halbtc8723b2ant_BtRssiState( ++ u8 levelNum, ++ u8 rssiThresh, ++ u8 rssiThresh1 ++ ) ++{ ++ s32 btRssi = 0; ++ u8 btRssiState =pCoexSta->preBtRssiState; ++ ++ btRssi = pCoexSta->btRssi; ++ ++ if (levelNum == 2) ++ { ++ if ((pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || ++ (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) ++ { ++ if (btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) ++ { ++ btRssiState = BTC_RSSI_STATE_HIGH; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); ++ } ++ else ++ { ++ btRssiState = BTC_RSSI_STATE_STAY_LOW; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); ++ } ++ } ++ else ++ { ++ if (btRssi < rssiThresh) ++ { ++ btRssiState = BTC_RSSI_STATE_LOW; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); ++ } ++ else ++ { ++ btRssiState = BTC_RSSI_STATE_STAY_HIGH; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); ++ } ++ } ++ } ++ else if (levelNum == 3) ++ { ++ if (rssiThresh > rssiThresh1) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi thresh error!!\n")); ++ return pCoexSta->preBtRssiState; ++ } ++ ++ if ((pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || ++ (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) ++ { ++ if (btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) ++ { ++ btRssiState = BTC_RSSI_STATE_MEDIUM; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); ++ } ++ else ++ { ++ btRssiState = BTC_RSSI_STATE_STAY_LOW; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); ++ } ++ } ++ else if ((pCoexSta->preBtRssiState == BTC_RSSI_STATE_MEDIUM) || ++ (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_MEDIUM)) ++ { ++ if (btRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) ++ { ++ btRssiState = BTC_RSSI_STATE_HIGH; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); ++ } ++ else if (btRssi < rssiThresh) ++ { ++ btRssiState = BTC_RSSI_STATE_LOW; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); ++ } ++ else ++ { ++ btRssiState = BTC_RSSI_STATE_STAY_MEDIUM; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Medium\n")); ++ } ++ } ++ else ++ { ++ if (btRssi < rssiThresh1) ++ { ++ btRssiState = BTC_RSSI_STATE_MEDIUM; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); ++ } ++ else ++ { ++ btRssiState = BTC_RSSI_STATE_STAY_HIGH; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); ++ } ++ } ++ } ++ ++ pCoexSta->preBtRssiState = btRssiState; ++ ++ return btRssiState; ++} ++ ++static u8 ++halbtc8723b2ant_WifiRssiState( ++PBTC_COEXIST pBtCoexist, ++u8 index, ++u8 levelNum, ++u8 rssiThresh, ++u8 rssiThresh1 ++ ) ++{ ++ s32 wifiRssi = 0; ++ u8 wifiRssiState =pCoexSta->preWifiRssiState[index]; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); ++ ++ if (levelNum == 2) ++ { ++ if ((pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || ++ (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) ++ { ++ if (wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) ++ { ++ wifiRssiState = BTC_RSSI_STATE_HIGH; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); ++ } ++ else ++ { ++ wifiRssiState = BTC_RSSI_STATE_STAY_LOW; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); ++ } ++ } ++ else ++ { ++ if (wifiRssi < rssiThresh) ++ { ++ wifiRssiState = BTC_RSSI_STATE_LOW; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); ++ } ++ else ++ { ++ wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); ++ } ++ } ++ } ++ else if (levelNum == 3) ++ { ++ if (rssiThresh > rssiThresh1) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI thresh error!!\n")); ++ return pCoexSta->preWifiRssiState[index]; ++ } ++ ++ if ((pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || ++ (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) ++ { ++ if (wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) ++ { ++ wifiRssiState = BTC_RSSI_STATE_MEDIUM; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); ++ } ++ else ++ { ++ wifiRssiState = BTC_RSSI_STATE_STAY_LOW; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); ++ } ++ } ++ else if ((pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_MEDIUM) || ++ (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_MEDIUM)) ++ { ++ if (wifiRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) ++ { ++ wifiRssiState = BTC_RSSI_STATE_HIGH; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); ++ } ++ else if (wifiRssi < rssiThresh) ++ { ++ wifiRssiState = BTC_RSSI_STATE_LOW; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); ++ } ++ else ++ { ++ wifiRssiState = BTC_RSSI_STATE_STAY_MEDIUM; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Medium\n")); ++ } ++ } ++ else ++ { ++ if (wifiRssi < rssiThresh1) ++ { ++ wifiRssiState = BTC_RSSI_STATE_MEDIUM; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); ++ } ++ else ++ { ++ wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); ++ } ++ } ++ } ++ ++ pCoexSta->preWifiRssiState[index] = wifiRssiState; ++ ++ return wifiRssiState; ++} ++ ++static void ++halbtc8723b2ant_LimitedRx( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++bool bRejApAggPkt, ++bool bBtCtrlAggBufSize, ++u8 aggBufSize ++ ) ++{ ++ bool bRejectRxAgg =bRejApAggPkt; ++ bool bBtCtrlRxAggSize =bBtCtrlAggBufSize; ++ u8 rxAggSize =aggBufSize; ++ ++ /* */ ++ /* Rx Aggregation related setting */ ++ /* */ ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, &bRejectRxAgg); ++ /* decide BT control aggregation buf size or not */ ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, &bBtCtrlRxAggSize); ++ /* aggregation buf size, only work when BT control Rx aggregation size. */ ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_AGG_BUF_SIZE, &rxAggSize); ++ /* real update aggregation setting */ ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); ++} ++ ++static void ++halbtc8723b2ant_MonitorBtCtr( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ u32 regHPTxRx, regLPTxRx, u4Tmp; ++ u32 regHPTx = 0, regHPRx = 0, regLPTx = 0, regLPRx = 0; ++ ++ regHPTxRx = 0x770; ++ regLPTxRx = 0x774; ++ ++ u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regHPTxRx); ++ regHPTx = u4Tmp & bMaskLWord; ++ regHPRx = (u4Tmp & bMaskHWord)>>16; ++ ++ u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regLPTxRx); ++ regLPTx = u4Tmp & bMaskLWord; ++ regLPRx = (u4Tmp & bMaskHWord)>>16; ++ ++ pCoexSta->highPriorityTx = regHPTx; ++ pCoexSta->highPriorityRx = regHPRx; ++ pCoexSta->lowPriorityTx = regLPTx; ++ pCoexSta->lowPriorityRx = regLPRx; ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], High Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n", ++ regHPTxRx, regHPTx, regHPTx, regHPRx, regHPRx)); ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], Low Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n", ++ regLPTxRx, regLPTx, regLPTx, regLPRx, regLPRx)); ++ ++ /* reset counter */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); ++} ++ ++static void ++halbtc8723b2ant_QueryBtInfo( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ u8 H2C_Parameter[1] ={0}; ++ ++ pCoexSta->bC2hBtInfoReqSent = true; ++ ++ H2C_Parameter[0] |= BIT0; /* trigger */ ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n", ++ H2C_Parameter[0])); ++ ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x61, 1, H2C_Parameter); ++} ++ ++static bool ++halbtc8723b2ant_IsWifiStatusChanged( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ static bool bPreWifiBusy =false, bPreUnder4way =false, bPreBtHsOn =false; ++ bool bWifiBusy =false, bUnder4way =false, bBtHsOn =false; ++ bool bWifiConnected =false; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &bUnder4way); ++ ++ if (bWifiConnected) ++ { ++ if (bWifiBusy != bPreWifiBusy) ++ { ++ bPreWifiBusy = bWifiBusy; ++ return true; ++ } ++ if (bUnder4way != bPreUnder4way) ++ { ++ bPreUnder4way = bUnder4way; ++ return true; ++ } ++ if (bBtHsOn != bPreBtHsOn) ++ { ++ bPreBtHsOn = bBtHsOn; ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++static void ++halbtc8723b2ant_UpdateBtLinkInfo( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ PBTC_BT_LINK_INFO pBtLinkInfo =&pBtCoexist->btLinkInfo; ++ bool bBtHsOn =false; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); ++ ++ pBtLinkInfo->bBtLinkExist = pCoexSta->bBtLinkExist; ++ pBtLinkInfo->bScoExist = pCoexSta->bScoExist; ++ pBtLinkInfo->bA2dpExist = pCoexSta->bA2dpExist; ++ pBtLinkInfo->bPanExist = pCoexSta->bPanExist; ++ pBtLinkInfo->bHidExist = pCoexSta->bHidExist; ++ ++ /* work around for HS mode. */ ++ if (bBtHsOn) ++ { ++ pBtLinkInfo->bPanExist = true; ++ pBtLinkInfo->bBtLinkExist = true; ++ } ++ /* check if Sco only */ ++ if (pBtLinkInfo->bScoExist && ++ !pBtLinkInfo->bA2dpExist && ++ !pBtLinkInfo->bPanExist && ++ !pBtLinkInfo->bHidExist) ++ pBtLinkInfo->bScoOnly = true; ++ else ++ pBtLinkInfo->bScoOnly = false; ++ ++ /* check if A2dp only */ ++ if (!pBtLinkInfo->bScoExist && ++ pBtLinkInfo->bA2dpExist && ++ !pBtLinkInfo->bPanExist && ++ !pBtLinkInfo->bHidExist) ++ pBtLinkInfo->bA2dpOnly = true; ++ else ++ pBtLinkInfo->bA2dpOnly = false; ++ ++ /* check if Pan only */ ++ if (!pBtLinkInfo->bScoExist && ++ !pBtLinkInfo->bA2dpExist && ++ pBtLinkInfo->bPanExist && ++ !pBtLinkInfo->bHidExist) ++ pBtLinkInfo->bPanOnly = true; ++ else ++ pBtLinkInfo->bPanOnly = false; ++ ++ /* check if Hid only */ ++ if (!pBtLinkInfo->bScoExist && ++ !pBtLinkInfo->bA2dpExist && ++ !pBtLinkInfo->bPanExist && ++ pBtLinkInfo->bHidExist) ++ pBtLinkInfo->bHidOnly = true; ++ else ++ pBtLinkInfo->bHidOnly = false; ++} ++ ++static u8 ++halbtc8723b2ant_ActionAlgorithm( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ PBTC_BT_LINK_INFO pBtLinkInfo =&pBtCoexist->btLinkInfo; ++ bool bBtHsOn =false; ++ u8 algorithm =BT_8723B_2ANT_COEX_ALGO_UNDEFINED; ++ u8 numOfDiffProfile = 0; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); ++ ++ if (!pBtLinkInfo->bBtLinkExist) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], No BT link exists!!!\n")); ++ return algorithm; ++ } ++ ++ if (pBtLinkInfo->bScoExist) ++ numOfDiffProfile++; ++ if (pBtLinkInfo->bHidExist) ++ numOfDiffProfile++; ++ if (pBtLinkInfo->bPanExist) ++ numOfDiffProfile++; ++ if (pBtLinkInfo->bA2dpExist) ++ numOfDiffProfile++; ++ ++ if (numOfDiffProfile == 1) ++ { ++ if (pBtLinkInfo->bScoExist) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO only\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_SCO; ++ } ++ else ++ { ++ if (pBtLinkInfo->bHidExist) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID only\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_HID; ++ } ++ else if (pBtLinkInfo->bA2dpExist) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP only\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_A2DP; ++ } ++ else if (pBtLinkInfo->bPanExist) ++ { ++ if (bBtHsOn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(HS) only\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_PANHS; ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(EDR) only\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR; ++ } ++ } ++ } ++ } ++ else if (numOfDiffProfile == 2) ++ { ++ if (pBtLinkInfo->bScoExist) ++ { ++ if (pBtLinkInfo->bHidExist) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; ++ } ++ else if (pBtLinkInfo->bA2dpExist) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP ==> SCO\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; ++ } ++ else if (pBtLinkInfo->bPanExist) ++ { ++ if (bBtHsOn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(HS)\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_SCO; ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(EDR)\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; ++ } ++ } ++ } ++ else ++ { ++ if (pBtLinkInfo->bHidExist && ++ pBtLinkInfo->bA2dpExist) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_HID_A2DP; ++ } ++ else if (pBtLinkInfo->bHidExist && ++ pBtLinkInfo->bPanExist) ++ { ++ if (bBtHsOn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(HS)\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_HID; ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(EDR)\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; ++ } ++ } ++ else if (pBtLinkInfo->bPanExist && ++ pBtLinkInfo->bA2dpExist) ++ { ++ if (bBtHsOn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(HS)\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS; ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(EDR)\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP; ++ } ++ } ++ } ++ } ++ else if (numOfDiffProfile == 3) ++ { ++ if (pBtLinkInfo->bScoExist) ++ { ++ if (pBtLinkInfo->bHidExist && ++ pBtLinkInfo->bA2dpExist) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP ==> HID\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; ++ } ++ else if (pBtLinkInfo->bHidExist && ++ pBtLinkInfo->bPanExist) ++ { ++ if (bBtHsOn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(HS)\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(EDR)\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; ++ } ++ } ++ else if (pBtLinkInfo->bPanExist && ++ pBtLinkInfo->bA2dpExist) ++ { ++ if (bBtHsOn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(HS)\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; ++ } ++ } ++ } ++ else ++ { ++ if (pBtLinkInfo->bHidExist && ++ pBtLinkInfo->bPanExist && ++ pBtLinkInfo->bA2dpExist) ++ { ++ if (bBtHsOn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(HS)\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_HID_A2DP; ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(EDR)\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR; ++ } ++ } ++ } ++ } ++ else if (numOfDiffProfile >= 3) ++ { ++ if (pBtLinkInfo->bScoExist) ++ { ++ if (pBtLinkInfo->bHidExist && ++ pBtLinkInfo->bPanExist && ++ pBtLinkInfo->bA2dpExist) ++ { ++ if (bBtHsOn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n")); ++ ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP + PAN(EDR) ==>PAN(EDR)+HID\n")); ++ algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; ++ } ++ } ++ } ++ } ++ ++ return algorithm; ++} ++ ++static void ++halbtc8723b2ant_SetFwDacSwingLevel( ++PBTC_COEXIST pBtCoexist, ++u8 dacSwingLvl ++ ) ++{ ++ u8 H2C_Parameter[1] ={0}; ++ ++ /* There are several type of dacswing */ ++ /* 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 */ ++ H2C_Parameter[0] = dacSwingLvl; ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Set Dac Swing Level = 0x%x\n", dacSwingLvl)); ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x64 = 0x%x\n", H2C_Parameter[0])); ++ ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x64, 1, H2C_Parameter); ++} ++ ++static void ++halbtc8723b2ant_SetFwDecBtPwr( ++PBTC_COEXIST pBtCoexist, ++u8 decBtPwrLvl ++ ) ++{ ++ u8 H2C_Parameter[1] ={0}; ++ ++ H2C_Parameter[0] = decBtPwrLvl; ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], decrease Bt Power level = %d, FW write 0x62 = 0x%x\n", ++ decBtPwrLvl, H2C_Parameter[0])); ++ ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x62, 1, H2C_Parameter); ++} ++ ++static void ++halbtc8723b2ant_DecBtPwr( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++u8 decBtPwrLvl ++ ) ++{ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s Dec BT power level = %d\n", ++ (bForceExec? "force to":""), decBtPwrLvl)); ++ pCoexDm->curBtDecPwrLvl = decBtPwrLvl; ++ ++ if (!bForceExec) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], preBtDecPwrLvl =%d, curBtDecPwrLvl =%d\n", ++ pCoexDm->preBtDecPwrLvl, pCoexDm->curBtDecPwrLvl)); ++ ++ if (pCoexDm->preBtDecPwrLvl == pCoexDm->curBtDecPwrLvl) ++ return; ++ } ++ halbtc8723b2ant_SetFwDecBtPwr(pBtCoexist, pCoexDm->curBtDecPwrLvl); ++ ++ pCoexDm->preBtDecPwrLvl = pCoexDm->curBtDecPwrLvl; ++} ++ ++static void ++halbtc8723b2ant_FwDacSwingLvl( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++u8 fwDacSwingLvl ++ ) ++{ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set FW Dac Swing level = %d\n", ++ (bForceExec? "force to":""), fwDacSwingLvl)); ++ pCoexDm->curFwDacSwingLvl = fwDacSwingLvl; ++ ++ if (!bForceExec) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], preFwDacSwingLvl =%d, curFwDacSwingLvl =%d\n", ++ pCoexDm->preFwDacSwingLvl, pCoexDm->curFwDacSwingLvl)); ++ ++ if (pCoexDm->preFwDacSwingLvl == pCoexDm->curFwDacSwingLvl) ++ return; ++ } ++ ++ halbtc8723b2ant_SetFwDacSwingLevel(pBtCoexist, pCoexDm->curFwDacSwingLvl); ++ ++ pCoexDm->preFwDacSwingLvl = pCoexDm->curFwDacSwingLvl; ++} ++ ++static void ++halbtc8723b2ant_SetSwRfRxLpfCorner( ++PBTC_COEXIST pBtCoexist, ++bool bRxRfShrinkOn ++ ) ++{ ++ if (bRxRfShrinkOn) ++ { ++ /* Shrink RF Rx LPF corner */ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Shrink RF Rx LPF corner!!\n")); ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, 0xffffc); ++ } ++ else ++ { ++ /* Resume RF Rx LPF corner */ ++ /* After initialized, we can use pCoexDm->btRf0x1eBackup */ ++ if (pBtCoexist->bInitilized) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Resume RF Rx LPF corner!!\n")); ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, pCoexDm->btRf0x1eBackup); ++ } ++ } ++} ++ ++static void ++halbtc8723b2ant_RfShrink( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++bool bRxRfShrinkOn ++ ) ++{ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn Rx RF Shrink = %s\n", ++ (bForceExec? "force to":""), ((bRxRfShrinkOn)? "ON":"OFF"))); ++ pCoexDm->bCurRfRxLpfShrink = bRxRfShrinkOn; ++ ++ if (!bForceExec) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreRfRxLpfShrink =%d, bCurRfRxLpfShrink =%d\n", ++ pCoexDm->bPreRfRxLpfShrink, pCoexDm->bCurRfRxLpfShrink)); ++ ++ if (pCoexDm->bPreRfRxLpfShrink == pCoexDm->bCurRfRxLpfShrink) ++ return; ++ } ++ halbtc8723b2ant_SetSwRfRxLpfCorner(pBtCoexist, pCoexDm->bCurRfRxLpfShrink); ++ ++ pCoexDm->bPreRfRxLpfShrink = pCoexDm->bCurRfRxLpfShrink; ++} ++ ++static void ++halbtc8723b2ant_SetSwPenaltyTxRateAdaptive( ++PBTC_COEXIST pBtCoexist, ++bool bLowPenaltyRa ++ ) ++{ ++ u8 H2C_Parameter[6] ={0}; ++ ++ H2C_Parameter[0] = 0x6; /* opCode, 0x6 = Retry_Penalty */ ++ ++ if (bLowPenaltyRa) ++ { ++ H2C_Parameter[1] |= BIT0; ++ H2C_Parameter[2] = 0x00; /* normal rate except MCS7/6/5, OFDM54/48/36 */ ++ H2C_Parameter[3] = 0xf7; /* MCS7 or OFDM54 */ ++ H2C_Parameter[4] = 0xf8; /* MCS6 or OFDM48 */ ++ H2C_Parameter[5] = 0xf9; /* MCS5 or OFDM36 */ ++ } ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set WiFi Low-Penalty Retry: %s", ++ (bLowPenaltyRa? "ON!!":"OFF!!"))); ++ ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x69, 6, H2C_Parameter); ++} ++ ++static void ++halbtc8723b2ant_LowPenaltyRa( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++bool bLowPenaltyRa ++ ) ++{ ++ /* return; */ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn LowPenaltyRA = %s\n", ++ (bForceExec? "force to":""), ((bLowPenaltyRa)? "ON":"OFF"))); ++ pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa; ++ ++ if (!bForceExec) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreLowPenaltyRa =%d, bCurLowPenaltyRa =%d\n", ++ pCoexDm->bPreLowPenaltyRa, pCoexDm->bCurLowPenaltyRa)); ++ ++ if (pCoexDm->bPreLowPenaltyRa == pCoexDm->bCurLowPenaltyRa) ++ return; ++ } ++ halbtc8723b2ant_SetSwPenaltyTxRateAdaptive(pBtCoexist, pCoexDm->bCurLowPenaltyRa); ++ ++ pCoexDm->bPreLowPenaltyRa = pCoexDm->bCurLowPenaltyRa; ++} ++ ++static void ++halbtc8723b2ant_SetDacSwingReg( ++PBTC_COEXIST pBtCoexist, ++u32 level ++ ) ++{ ++ u8 val =(u8)level; ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Write SwDacSwing = 0x%x\n", level)); ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x883, 0x3e, val); ++} ++ ++static void ++halbtc8723b2ant_SetSwFullTimeDacSwing( ++PBTC_COEXIST pBtCoexist, ++bool bSwDacSwingOn, ++u32 swDacSwingLvl ++ ) ++{ ++ if (bSwDacSwingOn) ++ { ++ halbtc8723b2ant_SetDacSwingReg(pBtCoexist, swDacSwingLvl); ++ } ++ else ++ { ++ halbtc8723b2ant_SetDacSwingReg(pBtCoexist, 0x18); ++ } ++} ++ ++ ++static void ++halbtc8723b2ant_DacSwing( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++bool bDacSwingOn, ++u32 dacSwingLvl ++ ) ++{ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn DacSwing =%s, dacSwingLvl = 0x%x\n", ++ (bForceExec? "force to":""), ((bDacSwingOn)? "ON":"OFF"), dacSwingLvl)); ++ pCoexDm->bCurDacSwingOn = bDacSwingOn; ++ pCoexDm->curDacSwingLvl = dacSwingLvl; ++ ++ if (!bForceExec) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreDacSwingOn =%d, preDacSwingLvl = 0x%x, bCurDacSwingOn =%d, curDacSwingLvl = 0x%x\n", ++ pCoexDm->bPreDacSwingOn, pCoexDm->preDacSwingLvl, ++ pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl)); ++ ++ if ((pCoexDm->bPreDacSwingOn == pCoexDm->bCurDacSwingOn) && ++ (pCoexDm->preDacSwingLvl == pCoexDm->curDacSwingLvl)) ++ return; ++ } ++ mdelay(30); ++ halbtc8723b2ant_SetSwFullTimeDacSwing(pBtCoexist, bDacSwingOn, dacSwingLvl); ++ ++ pCoexDm->bPreDacSwingOn = pCoexDm->bCurDacSwingOn; ++ pCoexDm->preDacSwingLvl = pCoexDm->curDacSwingLvl; ++} ++ ++static void ++halbtc8723b2ant_SetAgcTable( ++PBTC_COEXIST pBtCoexist, ++bool bAgcTableEn ++ ) ++{ ++ u8 rssiAdjustVal = 0; ++ ++ /* BB AGC Gain Table */ ++ if (bAgcTableEn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB Agc Table On!\n")); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6e1A0001); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6d1B0001); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6c1C0001); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6b1D0001); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6a1E0001); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x691F0001); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x68200001); ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB Agc Table Off!\n")); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xaa1A0001); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa91B0001); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa81C0001); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa71D0001); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa61E0001); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa51F0001); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa4200001); ++ } ++ ++ ++ /* RF Gain */ ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000); ++ if (bAgcTableEn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table On!\n")); ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x38fff); ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x38ffe); ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table Off!\n")); ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x380c3); ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x28ce6); ++ } ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0xef, 0xfffff, 0x0); ++ ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0xed, 0xfffff, 0x1); ++ if (bAgcTableEn) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table On!\n")); ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x40, 0xfffff, 0x38fff); ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x40, 0xfffff, 0x38ffe); ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table Off!\n")); ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x40, 0xfffff, 0x380c3); ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x40, 0xfffff, 0x28ce6); ++ } ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0xed, 0xfffff, 0x0); ++ ++ /* set rssiAdjustVal for wifi module. */ ++ if (bAgcTableEn) ++ { ++ rssiAdjustVal = 8; ++ } ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, &rssiAdjustVal); ++} ++ ++static void ++halbtc8723b2ant_AgcTable( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++bool bAgcTableEn ++ ) ++{ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s %s Agc Table\n", ++ (bForceExec? "force to":""), ((bAgcTableEn)? "Enable":"Disable"))); ++ pCoexDm->bCurAgcTableEn = bAgcTableEn; ++ ++ if (!bForceExec) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAgcTableEn =%d, bCurAgcTableEn =%d\n", ++ pCoexDm->bPreAgcTableEn, pCoexDm->bCurAgcTableEn)); ++ ++ if (pCoexDm->bPreAgcTableEn == pCoexDm->bCurAgcTableEn) ++ return; ++ } ++ halbtc8723b2ant_SetAgcTable(pBtCoexist, bAgcTableEn); ++ ++ pCoexDm->bPreAgcTableEn = pCoexDm->bCurAgcTableEn; ++} ++ ++static void ++halbtc8723b2ant_SetCoexTable( ++PBTC_COEXIST pBtCoexist, ++u32 val0x6c0, ++u32 val0x6c4, ++u32 val0x6c8, ++u8 val0x6cc ++ ) ++{ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0)); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c0, val0x6c0); ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4)); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c4, val0x6c4); ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8)); ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, val0x6c8); ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc)); ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cc, val0x6cc); ++} ++ ++static void ++halbtc8723b2ant_CoexTable( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++u32 val0x6c0, ++u32 val0x6c4, ++u32 val0x6c8, ++u8 val0x6cc ++ ) ++{ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n", ++ (bForceExec? "force to":""), val0x6c0, val0x6c4, val0x6c8, val0x6cc)); ++ pCoexDm->curVal0x6c0 = val0x6c0; ++ pCoexDm->curVal0x6c4 = val0x6c4; ++ pCoexDm->curVal0x6c8 = val0x6c8; ++ pCoexDm->curVal0x6cc = val0x6cc; ++ ++ if (!bForceExec) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], preVal0x6c0 = 0x%x, preVal0x6c4 = 0x%x, preVal0x6c8 = 0x%x, preVal0x6cc = 0x%x !!\n", ++ pCoexDm->preVal0x6c0, pCoexDm->preVal0x6c4, pCoexDm->preVal0x6c8, pCoexDm->preVal0x6cc)); ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], curVal0x6c0 = 0x%x, curVal0x6c4 = 0x%x, curVal0x6c8 = 0x%x, curVal0x6cc = 0x%x !!\n", ++ pCoexDm->curVal0x6c0, pCoexDm->curVal0x6c4, pCoexDm->curVal0x6c8, pCoexDm->curVal0x6cc)); ++ ++ if ((pCoexDm->preVal0x6c0 == pCoexDm->curVal0x6c0) && ++ (pCoexDm->preVal0x6c4 == pCoexDm->curVal0x6c4) && ++ (pCoexDm->preVal0x6c8 == pCoexDm->curVal0x6c8) && ++ (pCoexDm->preVal0x6cc == pCoexDm->curVal0x6cc)) ++ return; ++ } ++ halbtc8723b2ant_SetCoexTable(pBtCoexist, val0x6c0, val0x6c4, val0x6c8, val0x6cc); ++ ++ pCoexDm->preVal0x6c0 = pCoexDm->curVal0x6c0; ++ pCoexDm->preVal0x6c4 = pCoexDm->curVal0x6c4; ++ pCoexDm->preVal0x6c8 = pCoexDm->curVal0x6c8; ++ pCoexDm->preVal0x6cc = pCoexDm->curVal0x6cc; ++} ++ ++static void ++halbtc8723b2ant_CoexTableWithType( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++u8 type ++ ) ++{ ++ switch (type) ++ { ++ case 0: ++ halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x55555555, 0xffff, 0x3); ++ break; ++ case 1: ++ halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x5afa5afa, 0xffff, 0x3); ++ break; ++ case 2: ++ halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x5a5a5a5a, 0x5a5a5a5a, 0xffff, 0x3); ++ break; ++ case 3: ++ halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0xaaaaaaaa, 0xaaaaaaaa, 0xffff, 0x3); ++ break; ++ case 4: ++ halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0xffffffff, 0xffffffff, 0xffff, 0x3); ++ break; ++ case 5: ++ halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x5fff5fff, 0x5fff5fff, 0xffff, 0x3); ++ break; ++ case 6: ++ halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x55ff55ff, 0x5a5a5a5a, 0xffff, 0x3); ++ break; ++ case 7: ++ halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x55ff55ff, 0xfafafafa, 0xffff, 0x3); ++ break; ++ case 8: ++ halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x5aea5aea, 0x5aea5aea, 0xffff, 0x3); ++ break; ++ case 9: ++ halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x55ff55ff, 0x5aea5aea, 0xffff, 0x3); ++ break; ++ case 10: ++ halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x55ff55ff, 0x5aff5aff, 0xffff, 0x3); ++ break; ++ case 11: ++ halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x55ff55ff, 0x5a5f5a5f, 0xffff, 0x3); ++ break; ++ case 12: ++ halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x55ff55ff, 0x5f5f5f5f, 0xffff, 0x3); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void ++halbtc8723b2ant_SetFwIgnoreWlanAct( ++PBTC_COEXIST pBtCoexist, ++bool bEnable ++ ) ++{ ++ u8 H2C_Parameter[1] ={0}; ++ ++ if (bEnable) ++ { ++ H2C_Parameter[0] |= BIT0; /* function enable */ ++ } ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n", ++ H2C_Parameter[0])); ++ ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x63, 1, H2C_Parameter); ++} ++ ++static void ++halbtc8723b2ant_IgnoreWlanAct( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++bool bEnable ++ ) ++{ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn Ignore WlanAct %s\n", ++ (bForceExec? "force to":""), (bEnable? "ON":"OFF"))); ++ pCoexDm->bCurIgnoreWlanAct = bEnable; ++ ++ if (!bForceExec) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n", ++ pCoexDm->bPreIgnoreWlanAct, pCoexDm->bCurIgnoreWlanAct)); ++ ++ if (pCoexDm->bPreIgnoreWlanAct == pCoexDm->bCurIgnoreWlanAct) ++ return; ++ } ++ halbtc8723b2ant_SetFwIgnoreWlanAct(pBtCoexist, bEnable); ++ ++ pCoexDm->bPreIgnoreWlanAct = pCoexDm->bCurIgnoreWlanAct; ++} ++ ++static void ++halbtc8723b2ant_SetFwPstdma( ++PBTC_COEXIST pBtCoexist, ++u8 byte1, ++u8 byte2, ++u8 byte3, ++u8 byte4, ++u8 byte5 ++ ) ++{ ++ u8 H2C_Parameter[5] ={0}; ++ ++ H2C_Parameter[0] = byte1; ++ H2C_Parameter[1] = byte2; ++ H2C_Parameter[2] = byte3; ++ H2C_Parameter[3] = byte4; ++ H2C_Parameter[4] = byte5; ++ ++ pCoexDm->psTdmaPara[0] = byte1; ++ pCoexDm->psTdmaPara[1] = byte2; ++ pCoexDm->psTdmaPara[2] = byte3; ++ pCoexDm->psTdmaPara[3] = byte4; ++ pCoexDm->psTdmaPara[4] = byte5; ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x60(5bytes) = 0x%x%08x\n", ++ H2C_Parameter[0], ++ H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4])); ++ ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x60, 5, H2C_Parameter); ++} ++ ++static void ++halbtc8723b2ant_SwMechanism1( ++PBTC_COEXIST pBtCoexist, ++bool bShrinkRxLPF, ++bool bLowPenaltyRA, ++bool bLimitedDIG, ++bool bBTLNAConstrain ++ ) ++{ ++ halbtc8723b2ant_RfShrink(pBtCoexist, NORMAL_EXEC, bShrinkRxLPF); ++ halbtc8723b2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, bLowPenaltyRA); ++} ++ ++static void ++halbtc8723b2ant_SwMechanism2( ++PBTC_COEXIST pBtCoexist, ++bool bAGCTableShift, ++bool bADCBackOff, ++bool bSWDACSwing, ++u32 dacSwingLvl ++ ) ++{ ++ halbtc8723b2ant_AgcTable(pBtCoexist, NORMAL_EXEC, bAGCTableShift); ++ halbtc8723b2ant_DacSwing(pBtCoexist, NORMAL_EXEC, bSWDACSwing, dacSwingLvl); ++} ++ ++static void ++halbtc8723b2ant_SetAntPath( ++PBTC_COEXIST pBtCoexist, ++u8 antPosType, ++bool bInitHwCfg, ++bool bWifiOff ++ ) ++{ ++ PBTC_BOARD_INFO pBoardInfo =&pBtCoexist->boardInfo; ++ u32 fwVer = 0, u4Tmp = 0; ++ bool bPgExtSwitch =false; ++ bool bUseExtSwitch =false; ++ u8 H2C_Parameter[2] ={0}; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_EXT_SWITCH, &bPgExtSwitch); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); /* [31:16]=fw ver, [15:0]=fw sub ver */ ++ ++ if ((fwVer>0 && fwVer<0xc0000) || bPgExtSwitch) ++ bUseExtSwitch = true; ++ ++ if (bInitHwCfg) ++ { ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x39, 0x8, 0x1); ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x974, 0xff); ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x944, 0x3, 0x3); ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x930, 0x77); ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x67, 0x20, 0x1); ++ ++ if (fwVer >= 0x180000) ++ { ++ /* Use H2C to set GNT_BT to LOW */ ++ H2C_Parameter[0] = 0; ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x6E, 1, H2C_Parameter); ++ } ++ else ++ { ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x765, 0x0); ++ } ++ ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x0); ++ ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); /* WiFi TRx Mask off */ ++ pBtCoexist->fBtcSetBtReg(pBtCoexist, BTC_BT_REG_RF, 0x3c, 0x01); /* BT TRx Mask off */ ++ ++ if (pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) ++ { ++ /* tell firmware "no antenna inverse" */ ++ H2C_Parameter[0] = 0; ++ } ++ else ++ { ++ /* tell firmware "antenna inverse" */ ++ H2C_Parameter[0] = 1; ++ } ++ ++ if (bUseExtSwitch) ++ { ++ /* ext switch type */ ++ H2C_Parameter[1] = 1; ++ } ++ else ++ { ++ /* int switch type */ ++ H2C_Parameter[1] = 0; ++ } ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x65, 2, H2C_Parameter); ++ } ++ ++ /* ext switch setting */ ++ if (bUseExtSwitch) ++ { ++ if (bInitHwCfg) ++ { ++ /* 0x4c[23]= 0, 0x4c[24]= 1 Antenna control by WL/BT */ ++ u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); ++ u4Tmp &=~BIT23; ++ u4Tmp |= BIT24; ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x4c, u4Tmp); ++ } ++ ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x0); /* fixed internal switch S1->WiFi, S0->BT */ ++ switch (antPosType) ++ { ++ case BTC_ANT_WIFI_AT_MAIN: ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x1); /* ext switch main at wifi */ ++ break; ++ case BTC_ANT_WIFI_AT_AUX: ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x2); /* ext switch aux at wifi */ ++ break; ++ } ++ } ++ else /* internal switch */ ++ { ++ if (bInitHwCfg) ++ { ++ /* 0x4c[23]= 0, 0x4c[24]= 1 Antenna control by WL/BT */ ++ u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); ++ u4Tmp |= BIT23; ++ u4Tmp &=~BIT24; ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x4c, u4Tmp); ++ } ++ ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x64, 0x1, 0x0); /* fixed external switch S1->Main, S0->Aux */ ++ switch (antPosType) ++ { ++ case BTC_ANT_WIFI_AT_MAIN: ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x0); /* fixed internal switch S1->WiFi, S0->BT */ ++ break; ++ case BTC_ANT_WIFI_AT_AUX: ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x280); /* fixed internal switch S0->WiFi, S1->BT */ ++ break; ++ } ++ } ++} ++ ++static void ++halbtc8723b2ant_PsTdma( ++PBTC_COEXIST pBtCoexist, ++bool bForceExec, ++bool bTurnOn, ++u8 type ++ ) ++{ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn %s PS TDMA, type =%d\n", ++ (bForceExec? "force to":""), (bTurnOn? "ON":"OFF"), type)); ++ pCoexDm->bCurPsTdmaOn = bTurnOn; ++ pCoexDm->curPsTdma = type; ++ ++ if (!bForceExec) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", ++ pCoexDm->bPrePsTdmaOn, pCoexDm->bCurPsTdmaOn)); ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n", ++ pCoexDm->prePsTdma, pCoexDm->curPsTdma)); ++ ++ if ((pCoexDm->bPrePsTdmaOn == pCoexDm->bCurPsTdmaOn) && ++ (pCoexDm->prePsTdma == pCoexDm->curPsTdma)) ++ return; ++ } ++ if (bTurnOn) ++ { ++ switch (type) ++ { ++ case 1: ++ default: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x90); ++ break; ++ case 2: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0xe1, 0x90); ++ break; ++ case 3: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1c, 0x3, 0xf1, 0x90); ++ break; ++ case 4: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x10, 0x03, 0xf1, 0x90); ++ break; ++ case 5: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0x60, 0x90); ++ break; ++ case 6: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0x60, 0x90); ++ break; ++ case 7: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1c, 0x3, 0x70, 0x90); ++ break; ++ case 8: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xa3, 0x10, 0x3, 0x70, 0x90); ++ break; ++ case 9: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x90); ++ break; ++ case 10: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0xe1, 0x90); ++ break; ++ case 11: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0xa, 0xe1, 0x90); ++ break; ++ case 12: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x5, 0x5, 0xe1, 0x90); ++ break; ++ case 13: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0x60, 0x90); ++ break; ++ case 14: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0x60, 0x90); ++ break; ++ case 15: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0xa, 0x60, 0x90); ++ break; ++ case 16: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x5, 0x5, 0x60, 0x90); ++ break; ++ case 17: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xa3, 0x2f, 0x2f, 0x60, 0x90); ++ break; ++ case 18: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x5, 0x5, 0xe1, 0x90); ++ break; ++ case 19: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x25, 0xe1, 0x90); ++ break; ++ case 20: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x25, 0x60, 0x90); ++ break; ++ case 21: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x15, 0x03, 0x70, 0x90); ++ break; ++ case 71: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x90); ++ break; ++ } ++ } ++ else ++ { ++ /* disable PS tdma */ ++ switch (type) ++ { ++ case 0: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x40, 0x0); ++ break; ++ case 1: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x48, 0x0); ++ break; ++ default: ++ halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x40, 0x0); ++ break; ++ } ++ } ++ ++ /* update pre state */ ++ pCoexDm->bPrePsTdmaOn = pCoexDm->bCurPsTdmaOn; ++ pCoexDm->prePsTdma = pCoexDm->curPsTdma; ++} ++ ++static void ++halbtc8723b2ant_CoexAllOff( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ /* fw all off */ ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 1); ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); ++ ++ /* sw all off */ ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ ++ /* hw all off */ ++ /* pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); */ ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); ++} ++ ++static void ++halbtc8723b2ant_InitCoexDm( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ /* force to reset coex mechanism */ ++ ++ halbtc8723b2ant_PsTdma(pBtCoexist, FORCE_EXEC, false, 1); ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, FORCE_EXEC, 6); ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, FORCE_EXEC, 0); ++ ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++} ++ ++static void ++halbtc8723b2ant_ActionBtInquiry( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ bool bWifiConnected =false; ++ bool bLowPwrDisable =true; ++ ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); ++ ++ if (bWifiConnected) ++ { ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); ++ } ++ else ++ { ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 1); ++ } ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, FORCE_EXEC, 6); ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); ++ ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ ++ pCoexDm->bNeedRecover0x948 = true; ++ pCoexDm->backup0x948 = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x948); ++ ++ halbtc8723b2ant_SetAntPath(pBtCoexist, BTC_ANT_WIFI_AT_AUX, false, false); ++} ++ ++static bool ++halbtc8723b2ant_IsCommonAction( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ u8 btRssiState =BTC_RSSI_STATE_HIGH; ++ bool bCommon =false, bWifiConnected =false, bWifiBusy =false; ++ bool bBtHsOn =false, bLowPwrDisable =false; ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); ++ ++ if (!bWifiConnected) ++ { ++ bLowPwrDisable = false; ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); ++ halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8); ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non-connected idle!!\n")); ++ ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 1); ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); ++ ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ ++ bCommon = true; ++ } ++ else ++ { ++ if (BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) ++ { ++ bLowPwrDisable = false; ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); ++ halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8); ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT non connected-idle!!\n")); ++ ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 1); ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0xb); ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); ++ ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ ++ bCommon = true; ++ } ++ else if (BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ++ { ++ bLowPwrDisable = true; ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); ++ ++ if (bBtHsOn) ++ return false; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT connected-idle!!\n")); ++ halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8); ++ ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 1); ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0xb); ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); ++ ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ ++ bCommon = true; ++ } ++ else ++ { ++ bLowPwrDisable = true; ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); ++ ++ if (bWifiBusy) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Connected-Busy + BT Busy!!\n")); ++ bCommon = false; ++ } ++ else ++ { ++ if (bBtHsOn) ++ return false; ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Connected-Idle + BT Busy!!\n")); ++ btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); ++ halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8); ++ ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 21); ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0xb); ++ if (BTC_RSSI_HIGH(btRssiState)) ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); ++ else ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ bCommon = true; ++ } ++ } ++ } ++ ++ return bCommon; ++} ++ ++static void ++halbtc8723b2ant_TdmaDurationAdjust( ++PBTC_COEXIST pBtCoexist, ++bool bScoHid, ++bool bTxPause, ++u8 maxInterval ++ ) ++{ ++ static s32 up, dn, m, n, WaitCount; ++ s32 result; /* 0: no change, +1: increase WiFi duration, -1: decrease WiFi duration */ ++ u8 retryCount = 0; ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], TdmaDurationAdjust()\n")); ++ ++ if (!pCoexDm->bAutoTdmaAdjust) ++ { ++ pCoexDm->bAutoTdmaAdjust = true; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], first run TdmaDurationAdjust()!!\n")); ++ { ++ if (bScoHid) ++ { ++ if (bTxPause) ++ { ++ if (maxInterval == 1) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 13); ++ pCoexDm->psTdmaDuAdjType = 13; ++ } ++ else if (maxInterval == 2) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); ++ pCoexDm->psTdmaDuAdjType = 14; ++ } ++ else if (maxInterval == 3) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); ++ pCoexDm->psTdmaDuAdjType = 15; ++ } ++ else ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); ++ pCoexDm->psTdmaDuAdjType = 15; ++ } ++ } ++ else ++ { ++ if (maxInterval == 1) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); ++ pCoexDm->psTdmaDuAdjType = 9; ++ } ++ else if (maxInterval == 2) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); ++ pCoexDm->psTdmaDuAdjType = 10; ++ } ++ else if (maxInterval == 3) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); ++ pCoexDm->psTdmaDuAdjType = 11; ++ } ++ else ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); ++ pCoexDm->psTdmaDuAdjType = 11; ++ } ++ } ++ } ++ else ++ { ++ if (bTxPause) ++ { ++ if (maxInterval == 1) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5); ++ pCoexDm->psTdmaDuAdjType = 5; ++ } ++ else if (maxInterval == 2) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); ++ pCoexDm->psTdmaDuAdjType = 6; ++ } ++ else if (maxInterval == 3) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); ++ pCoexDm->psTdmaDuAdjType = 7; ++ } ++ else ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); ++ pCoexDm->psTdmaDuAdjType = 7; ++ } ++ } ++ else ++ { ++ if (maxInterval == 1) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1); ++ pCoexDm->psTdmaDuAdjType = 1; ++ } ++ else if (maxInterval == 2) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); ++ pCoexDm->psTdmaDuAdjType = 2; ++ } ++ else if (maxInterval == 3) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); ++ pCoexDm->psTdmaDuAdjType = 3; ++ } ++ else ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); ++ pCoexDm->psTdmaDuAdjType = 3; ++ } ++ } ++ } ++ } ++ /* */ ++ up = 0; ++ dn = 0; ++ m = 1; ++ n = 3; ++ result = 0; ++ WaitCount = 0; ++ } ++ else ++ { ++ /* accquire the BT TRx retry count from BT_Info byte2 */ ++ retryCount = pCoexSta->btRetryCnt; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount)); ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], up =%d, dn =%d, m =%d, n =%d, WaitCount =%d\n", ++ up, dn, m, n, WaitCount)); ++ result = 0; ++ WaitCount++; ++ ++ if (retryCount == 0) /* no retry in the last 2-second duration */ ++ { ++ up++; ++ dn--; ++ ++ if (dn <= 0) ++ dn = 0; ++ ++ if (up >= n) /* if 連續 n 個2秒 retry count為0, 則調寬WiFi duration */ ++ { ++ WaitCount = 0; ++ n = 3; ++ up = 0; ++ dn = 0; ++ result = 1; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Increase wifi duration!!\n")); ++ } ++ } ++ else if (retryCount <= 3) /* <=3 retry in the last 2-second duration */ ++ { ++ up--; ++ dn++; ++ ++ if (up <= 0) ++ up = 0; ++ ++ if (dn == 2) /* if 連續 2 個2秒 retry count< 3, 則調窄WiFi duration */ ++ { ++ if (WaitCount <= 2) ++ m++; /* 避免一直在兩個level中來回 */ ++ else ++ m = 1; ++ ++ if (m >= 20) /* m 最大值 = 20 ' 最大120秒 recheck是否調整 WiFi duration. */ ++ m = 20; ++ ++ n = 3*m; ++ up = 0; ++ dn = 0; ++ WaitCount = 0; ++ result = -1; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n")); ++ } ++ } ++ else /* retry count > 3, 只要1次 retry count > 3, 則調窄WiFi duration */ ++ { ++ if (WaitCount == 1) ++ m++; /* 避免一直在兩個level中來回 */ ++ else ++ m = 1; ++ ++ if (m >= 20) /* m 最大值 = 20 ' 最大120秒 recheck是否調整 WiFi duration. */ ++ m = 20; ++ ++ n = 3*m; ++ up = 0; ++ dn = 0; ++ WaitCount = 0; ++ result = -1; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")); ++ } ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], max Interval = %d\n", maxInterval)); ++ if (maxInterval == 1) ++ { ++ if (bTxPause) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); ++ ++ if (pCoexDm->curPsTdma == 71) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5); ++ pCoexDm->psTdmaDuAdjType = 5; ++ } ++ else if (pCoexDm->curPsTdma == 1) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5); ++ pCoexDm->psTdmaDuAdjType = 5; ++ } ++ else if (pCoexDm->curPsTdma == 2) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); ++ pCoexDm->psTdmaDuAdjType = 6; ++ } ++ else if (pCoexDm->curPsTdma == 3) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); ++ pCoexDm->psTdmaDuAdjType = 7; ++ } ++ else if (pCoexDm->curPsTdma == 4) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8); ++ pCoexDm->psTdmaDuAdjType = 8; ++ } ++ if (pCoexDm->curPsTdma == 9) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 13); ++ pCoexDm->psTdmaDuAdjType = 13; ++ } ++ else if (pCoexDm->curPsTdma == 10) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); ++ pCoexDm->psTdmaDuAdjType = 14; ++ } ++ else if (pCoexDm->curPsTdma == 11) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); ++ pCoexDm->psTdmaDuAdjType = 15; ++ } ++ else if (pCoexDm->curPsTdma == 12) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16); ++ pCoexDm->psTdmaDuAdjType = 16; ++ } ++ ++ if (result == -1) ++ { ++ if (pCoexDm->curPsTdma == 5) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); ++ pCoexDm->psTdmaDuAdjType = 6; ++ } ++ else if (pCoexDm->curPsTdma == 6) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); ++ pCoexDm->psTdmaDuAdjType = 7; ++ } ++ else if (pCoexDm->curPsTdma == 7) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8); ++ pCoexDm->psTdmaDuAdjType = 8; ++ } ++ else if (pCoexDm->curPsTdma == 13) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); ++ pCoexDm->psTdmaDuAdjType = 14; ++ } ++ else if (pCoexDm->curPsTdma == 14) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); ++ pCoexDm->psTdmaDuAdjType = 15; ++ } ++ else if (pCoexDm->curPsTdma == 15) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16); ++ pCoexDm->psTdmaDuAdjType = 16; ++ } ++ } ++ else if (result == 1) ++ { ++ if (pCoexDm->curPsTdma == 8) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); ++ pCoexDm->psTdmaDuAdjType = 7; ++ } ++ else if (pCoexDm->curPsTdma == 7) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); ++ pCoexDm->psTdmaDuAdjType = 6; ++ } ++ else if (pCoexDm->curPsTdma == 6) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5); ++ pCoexDm->psTdmaDuAdjType = 5; ++ } ++ else if (pCoexDm->curPsTdma == 16) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); ++ pCoexDm->psTdmaDuAdjType = 15; ++ } ++ else if (pCoexDm->curPsTdma == 15) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); ++ pCoexDm->psTdmaDuAdjType = 14; ++ } ++ else if (pCoexDm->curPsTdma == 14) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 13); ++ pCoexDm->psTdmaDuAdjType = 13; ++ } ++ } ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); ++ if (pCoexDm->curPsTdma == 5) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 71); ++ pCoexDm->psTdmaDuAdjType = 71; ++ } ++ else if (pCoexDm->curPsTdma == 6) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); ++ pCoexDm->psTdmaDuAdjType = 2; ++ } ++ else if (pCoexDm->curPsTdma == 7) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); ++ pCoexDm->psTdmaDuAdjType = 3; ++ } ++ else if (pCoexDm->curPsTdma == 8) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4); ++ pCoexDm->psTdmaDuAdjType = 4; ++ } ++ if (pCoexDm->curPsTdma == 13) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); ++ pCoexDm->psTdmaDuAdjType = 9; ++ } ++ else if (pCoexDm->curPsTdma == 14) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); ++ pCoexDm->psTdmaDuAdjType = 10; ++ } ++ else if (pCoexDm->curPsTdma == 15) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); ++ pCoexDm->psTdmaDuAdjType = 11; ++ } ++ else if (pCoexDm->curPsTdma == 16) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12); ++ pCoexDm->psTdmaDuAdjType = 12; ++ } ++ ++ if (result == -1) ++ { ++ if (pCoexDm->curPsTdma == 71) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1); ++ pCoexDm->psTdmaDuAdjType = 1; ++ } ++ else if (pCoexDm->curPsTdma == 1) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); ++ pCoexDm->psTdmaDuAdjType = 2; ++ } ++ else if (pCoexDm->curPsTdma == 2) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); ++ pCoexDm->psTdmaDuAdjType = 3; ++ } ++ else if (pCoexDm->curPsTdma == 3) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4); ++ pCoexDm->psTdmaDuAdjType = 4; ++ } ++ else if (pCoexDm->curPsTdma == 9) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); ++ pCoexDm->psTdmaDuAdjType = 10; ++ } ++ else if (pCoexDm->curPsTdma == 10) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); ++ pCoexDm->psTdmaDuAdjType = 11; ++ } ++ else if (pCoexDm->curPsTdma == 11) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12); ++ pCoexDm->psTdmaDuAdjType = 12; ++ } ++ } ++ else if (result == 1) ++ { ++ if (pCoexDm->curPsTdma == 4) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); ++ pCoexDm->psTdmaDuAdjType = 3; ++ } ++ else if (pCoexDm->curPsTdma == 3) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); ++ pCoexDm->psTdmaDuAdjType = 2; ++ } ++ else if (pCoexDm->curPsTdma == 2) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1); ++ pCoexDm->psTdmaDuAdjType = 1; ++ } ++ else if (pCoexDm->curPsTdma == 1) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 71); ++ pCoexDm->psTdmaDuAdjType = 71; ++ } ++ else if (pCoexDm->curPsTdma == 12) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); ++ pCoexDm->psTdmaDuAdjType = 11; ++ } ++ else if (pCoexDm->curPsTdma == 11) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); ++ pCoexDm->psTdmaDuAdjType = 10; ++ } ++ else if (pCoexDm->curPsTdma == 10) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); ++ pCoexDm->psTdmaDuAdjType = 9; ++ } ++ } ++ } ++ } ++ else if (maxInterval == 2) ++ { ++ if (bTxPause) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); ++ if (pCoexDm->curPsTdma == 1) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); ++ pCoexDm->psTdmaDuAdjType = 6; ++ } ++ else if (pCoexDm->curPsTdma == 2) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); ++ pCoexDm->psTdmaDuAdjType = 6; ++ } ++ else if (pCoexDm->curPsTdma == 3) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); ++ pCoexDm->psTdmaDuAdjType = 7; ++ } ++ else if (pCoexDm->curPsTdma == 4) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8); ++ pCoexDm->psTdmaDuAdjType = 8; ++ } ++ if (pCoexDm->curPsTdma == 9) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); ++ pCoexDm->psTdmaDuAdjType = 14; ++ } ++ else if (pCoexDm->curPsTdma == 10) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); ++ pCoexDm->psTdmaDuAdjType = 14; ++ } ++ else if (pCoexDm->curPsTdma == 11) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); ++ pCoexDm->psTdmaDuAdjType = 15; ++ } ++ else if (pCoexDm->curPsTdma == 12) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16); ++ pCoexDm->psTdmaDuAdjType = 16; ++ } ++ if (result == -1) ++ { ++ if (pCoexDm->curPsTdma == 5) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); ++ pCoexDm->psTdmaDuAdjType = 6; ++ } ++ else if (pCoexDm->curPsTdma == 6) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); ++ pCoexDm->psTdmaDuAdjType = 7; ++ } ++ else if (pCoexDm->curPsTdma == 7) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8); ++ pCoexDm->psTdmaDuAdjType = 8; ++ } ++ else if (pCoexDm->curPsTdma == 13) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); ++ pCoexDm->psTdmaDuAdjType = 14; ++ } ++ else if (pCoexDm->curPsTdma == 14) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); ++ pCoexDm->psTdmaDuAdjType = 15; ++ } ++ else if (pCoexDm->curPsTdma == 15) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16); ++ pCoexDm->psTdmaDuAdjType = 16; ++ } ++ } ++ else if (result == 1) ++ { ++ if (pCoexDm->curPsTdma == 8) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); ++ pCoexDm->psTdmaDuAdjType = 7; ++ } ++ else if (pCoexDm->curPsTdma == 7) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); ++ pCoexDm->psTdmaDuAdjType = 6; ++ } ++ else if (pCoexDm->curPsTdma == 6) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6); ++ pCoexDm->psTdmaDuAdjType = 6; ++ } ++ else if (pCoexDm->curPsTdma == 16) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); ++ pCoexDm->psTdmaDuAdjType = 15; ++ } ++ else if (pCoexDm->curPsTdma == 15) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); ++ pCoexDm->psTdmaDuAdjType = 14; ++ } ++ else if (pCoexDm->curPsTdma == 14) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14); ++ pCoexDm->psTdmaDuAdjType = 14; ++ } ++ } ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); ++ if (pCoexDm->curPsTdma == 5) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); ++ pCoexDm->psTdmaDuAdjType = 2; ++ } ++ else if (pCoexDm->curPsTdma == 6) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); ++ pCoexDm->psTdmaDuAdjType = 2; ++ } ++ else if (pCoexDm->curPsTdma == 7) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); ++ pCoexDm->psTdmaDuAdjType = 3; ++ } ++ else if (pCoexDm->curPsTdma == 8) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4); ++ pCoexDm->psTdmaDuAdjType = 4; ++ } ++ if (pCoexDm->curPsTdma == 13) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); ++ pCoexDm->psTdmaDuAdjType = 10; ++ } ++ else if (pCoexDm->curPsTdma == 14) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); ++ pCoexDm->psTdmaDuAdjType = 10; ++ } ++ else if (pCoexDm->curPsTdma == 15) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); ++ pCoexDm->psTdmaDuAdjType = 11; ++ } ++ else if (pCoexDm->curPsTdma == 16) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12); ++ pCoexDm->psTdmaDuAdjType = 12; ++ } ++ if (result == -1) ++ { ++ if (pCoexDm->curPsTdma == 1) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); ++ pCoexDm->psTdmaDuAdjType = 2; ++ } ++ else if (pCoexDm->curPsTdma == 2) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); ++ pCoexDm->psTdmaDuAdjType = 3; ++ } ++ else if (pCoexDm->curPsTdma == 3) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4); ++ pCoexDm->psTdmaDuAdjType = 4; ++ } ++ else if (pCoexDm->curPsTdma == 9) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); ++ pCoexDm->psTdmaDuAdjType = 10; ++ } ++ else if (pCoexDm->curPsTdma == 10) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); ++ pCoexDm->psTdmaDuAdjType = 11; ++ } ++ else if (pCoexDm->curPsTdma == 11) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12); ++ pCoexDm->psTdmaDuAdjType = 12; ++ } ++ } ++ else if (result == 1) ++ { ++ if (pCoexDm->curPsTdma == 4) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); ++ pCoexDm->psTdmaDuAdjType = 3; ++ } ++ else if (pCoexDm->curPsTdma == 3) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); ++ pCoexDm->psTdmaDuAdjType = 2; ++ } ++ else if (pCoexDm->curPsTdma == 2) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2); ++ pCoexDm->psTdmaDuAdjType = 2; ++ } ++ else if (pCoexDm->curPsTdma == 12) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); ++ pCoexDm->psTdmaDuAdjType = 11; ++ } ++ else if (pCoexDm->curPsTdma == 11) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); ++ pCoexDm->psTdmaDuAdjType = 10; ++ } ++ else if (pCoexDm->curPsTdma == 10) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10); ++ pCoexDm->psTdmaDuAdjType = 10; ++ } ++ } ++ } ++ } ++ else if (maxInterval == 3) ++ { ++ if (bTxPause) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); ++ if (pCoexDm->curPsTdma == 1) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); ++ pCoexDm->psTdmaDuAdjType = 7; ++ } ++ else if (pCoexDm->curPsTdma == 2) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); ++ pCoexDm->psTdmaDuAdjType = 7; ++ } ++ else if (pCoexDm->curPsTdma == 3) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); ++ pCoexDm->psTdmaDuAdjType = 7; ++ } ++ else if (pCoexDm->curPsTdma == 4) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8); ++ pCoexDm->psTdmaDuAdjType = 8; ++ } ++ if (pCoexDm->curPsTdma == 9) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); ++ pCoexDm->psTdmaDuAdjType = 15; ++ } ++ else if (pCoexDm->curPsTdma == 10) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); ++ pCoexDm->psTdmaDuAdjType = 15; ++ } ++ else if (pCoexDm->curPsTdma == 11) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); ++ pCoexDm->psTdmaDuAdjType = 15; ++ } ++ else if (pCoexDm->curPsTdma == 12) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16); ++ pCoexDm->psTdmaDuAdjType = 16; ++ } ++ if (result == -1) ++ { ++ if (pCoexDm->curPsTdma == 5) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); ++ pCoexDm->psTdmaDuAdjType = 7; ++ } ++ else if (pCoexDm->curPsTdma == 6) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); ++ pCoexDm->psTdmaDuAdjType = 7; ++ } ++ else if (pCoexDm->curPsTdma == 7) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8); ++ pCoexDm->psTdmaDuAdjType = 8; ++ } ++ else if (pCoexDm->curPsTdma == 13) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); ++ pCoexDm->psTdmaDuAdjType = 15; ++ } ++ else if (pCoexDm->curPsTdma == 14) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); ++ pCoexDm->psTdmaDuAdjType = 15; ++ } ++ else if (pCoexDm->curPsTdma == 15) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16); ++ pCoexDm->psTdmaDuAdjType = 16; ++ } ++ } ++ else if (result == 1) ++ { ++ if (pCoexDm->curPsTdma == 8) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); ++ pCoexDm->psTdmaDuAdjType = 7; ++ } ++ else if (pCoexDm->curPsTdma == 7) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); ++ pCoexDm->psTdmaDuAdjType = 7; ++ } ++ else if (pCoexDm->curPsTdma == 6) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7); ++ pCoexDm->psTdmaDuAdjType = 7; ++ } ++ else if (pCoexDm->curPsTdma == 16) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); ++ pCoexDm->psTdmaDuAdjType = 15; ++ } ++ else if (pCoexDm->curPsTdma == 15) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); ++ pCoexDm->psTdmaDuAdjType = 15; ++ } ++ else if (pCoexDm->curPsTdma == 14) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15); ++ pCoexDm->psTdmaDuAdjType = 15; ++ } ++ } ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); ++ if (pCoexDm->curPsTdma == 5) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); ++ pCoexDm->psTdmaDuAdjType = 3; ++ } ++ else if (pCoexDm->curPsTdma == 6) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); ++ pCoexDm->psTdmaDuAdjType = 3; ++ } ++ else if (pCoexDm->curPsTdma == 7) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); ++ pCoexDm->psTdmaDuAdjType = 3; ++ } ++ else if (pCoexDm->curPsTdma == 8) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4); ++ pCoexDm->psTdmaDuAdjType = 4; ++ } ++ if (pCoexDm->curPsTdma == 13) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); ++ pCoexDm->psTdmaDuAdjType = 11; ++ } ++ else if (pCoexDm->curPsTdma == 14) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); ++ pCoexDm->psTdmaDuAdjType = 11; ++ } ++ else if (pCoexDm->curPsTdma == 15) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); ++ pCoexDm->psTdmaDuAdjType = 11; ++ } ++ else if (pCoexDm->curPsTdma == 16) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12); ++ pCoexDm->psTdmaDuAdjType = 12; ++ } ++ if (result == -1) ++ { ++ if (pCoexDm->curPsTdma == 1) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); ++ pCoexDm->psTdmaDuAdjType = 3; ++ } ++ else if (pCoexDm->curPsTdma == 2) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); ++ pCoexDm->psTdmaDuAdjType = 3; ++ } ++ else if (pCoexDm->curPsTdma == 3) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4); ++ pCoexDm->psTdmaDuAdjType = 4; ++ } ++ else if (pCoexDm->curPsTdma == 9) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); ++ pCoexDm->psTdmaDuAdjType = 11; ++ } ++ else if (pCoexDm->curPsTdma == 10) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); ++ pCoexDm->psTdmaDuAdjType = 11; ++ } ++ else if (pCoexDm->curPsTdma == 11) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12); ++ pCoexDm->psTdmaDuAdjType = 12; ++ } ++ } ++ else if (result == 1) ++ { ++ if (pCoexDm->curPsTdma == 4) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); ++ pCoexDm->psTdmaDuAdjType = 3; ++ } ++ else if (pCoexDm->curPsTdma == 3) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); ++ pCoexDm->psTdmaDuAdjType = 3; ++ } ++ else if (pCoexDm->curPsTdma == 2) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3); ++ pCoexDm->psTdmaDuAdjType = 3; ++ } ++ else if (pCoexDm->curPsTdma == 12) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); ++ pCoexDm->psTdmaDuAdjType = 11; ++ } ++ else if (pCoexDm->curPsTdma == 11) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); ++ pCoexDm->psTdmaDuAdjType = 11; ++ } ++ else if (pCoexDm->curPsTdma == 10) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11); ++ pCoexDm->psTdmaDuAdjType = 11; ++ } ++ } ++ } ++ } ++ } ++ ++ /* if current PsTdma not match with the recorded one (when scan, dhcp...), */ ++ /* then we have to adjust it back to the previous record one. */ ++ if (pCoexDm->curPsTdma != pCoexDm->psTdmaDuAdjType) ++ { ++ bool bScan =false, bLink =false, bRoam =false; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], PsTdma type dismatch!!!, curPsTdma =%d, recordPsTdma =%d\n", ++ pCoexDm->curPsTdma, pCoexDm->psTdmaDuAdjType)); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); ++ ++ if (!bScan && !bLink && !bRoam) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, pCoexDm->psTdmaDuAdjType); ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n")); ++ } ++ } ++} ++ ++/* SCO only or SCO+PAN(HS) */ ++static void ++halbtc8723b2ant_ActionSco( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ u8 wifiRssiState, btRssiState; ++ u32 wifiBw; ++ ++ wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); ++ btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); ++ ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); ++ ++ halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8); ++ ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 4); ++ ++ if (BTC_RSSI_HIGH(btRssiState)) ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); ++ else ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); ++ ++ if (BTC_WIFI_BW_LEGACY == wifiBw) /* for SCO quality at 11b/g mode */ ++ { ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); ++ } ++ else /* for SCO quality & wifi performance balance at 11n mode */ ++ { ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 8); ++ } ++ ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 0); /* for voice quality */ ++ ++ /* sw mechanism */ ++ if (BTC_WIFI_BW_HT40 == wifiBw) ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, true, 0x4); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, true, 0x4); ++ } ++ } ++ else ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, true, 0x4); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, true, 0x4); ++ } ++ } ++} ++ ++ ++static void ++halbtc8723b2ant_ActionHid( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ u8 wifiRssiState, btRssiState; ++ u32 wifiBw; ++ ++ wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); ++ btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); ++ ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); ++ ++ halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8); ++ ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); ++ ++ if (BTC_RSSI_HIGH(btRssiState)) ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); ++ else ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); ++ ++ if (BTC_WIFI_BW_LEGACY == wifiBw) /* for HID at 11b/g mode */ ++ { ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); ++ } ++ else /* for HID quality & wifi performance balance at 11n mode */ ++ { ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 9); ++ } ++ ++ if ((btRssiState == BTC_RSSI_STATE_HIGH) || ++ (btRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9); ++ } ++ else ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 13); ++ } ++ ++ /* sw mechanism */ ++ if (BTC_WIFI_BW_HT40 == wifiBw) ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, false, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ } ++ } ++ else ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, false, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ } ++ } ++} ++ ++/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ ++static void ++halbtc8723b2ant_ActionA2dp( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ u8 wifiRssiState, wifiRssiState1, btRssiState; ++ u32 wifiBw; ++ u8 apNum = 0; ++ ++ wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); ++ wifiRssiState1 = halbtc8723b2ant_WifiRssiState(pBtCoexist, 1, 2, 40, 0); ++ btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_AP_NUM, &apNum); ++ ++ /* define the office environment */ ++ if (apNum >= 10 && BTC_RSSI_HIGH(wifiRssiState1)) ++ { ++ /* DbgPrint(" AP#>10(%d)\n", apNum); */ ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); ++ halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8); ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 1); ++ ++ /* sw mechanism */ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); ++ if (BTC_WIFI_BW_HT40 == wifiBw) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, true, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, true, 0x18); ++ } ++ return; ++ } ++ ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); ++ halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8); ++ ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); ++ ++ if (BTC_RSSI_HIGH(btRssiState)) ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); ++ else ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); ++ ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); ++ ++ if ((btRssiState == BTC_RSSI_STATE_HIGH) || ++ (btRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, false, false, 1); ++ } ++ else ++ { ++ halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, false, true, 1); ++ } ++ ++ /* sw mechanism */ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); ++ if (BTC_WIFI_BW_HT40 == wifiBw) ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, false, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ } ++ } ++ else ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, false, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ } ++ } ++} ++ ++static void ++halbtc8723b2ant_ActionA2dpPanHs( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ u8 wifiRssiState, btRssiState; ++ u32 wifiBw; ++ ++ wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); ++ btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); ++ ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); ++ ++ halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8); ++ ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); ++ ++ if (BTC_RSSI_HIGH(btRssiState)) ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); ++ else ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); ++ ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); ++ ++ halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, false, true, 2); ++ ++ /* sw mechanism */ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); ++ if (BTC_WIFI_BW_HT40 == wifiBw) ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, false, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ } ++ } ++ else ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, false, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ } ++ } ++} ++ ++static void ++halbtc8723b2ant_ActionPanEdr( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ u8 wifiRssiState, btRssiState; ++ u32 wifiBw; ++ ++ wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); ++ btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); ++ ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); ++ ++ halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8); ++ ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); ++ ++ if (BTC_RSSI_HIGH(btRssiState)) ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); ++ else ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); ++ ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 10); ++ ++ if ((btRssiState == BTC_RSSI_STATE_HIGH) || ++ (btRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1); ++ } ++ else ++ { ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5); ++ } ++ ++ /* sw mechanism */ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); ++ if (BTC_WIFI_BW_HT40 == wifiBw) ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, false, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ } ++ } ++ else ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, false, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ } ++ } ++} ++ ++ ++/* PAN(HS) only */ ++static void ++halbtc8723b2ant_ActionPanHs( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ u8 wifiRssiState, btRssiState; ++ u32 wifiBw; ++ ++ wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); ++ btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); ++ ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); ++ ++ halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8); ++ ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); ++ ++ if (BTC_RSSI_HIGH(btRssiState)) ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); ++ else ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); ++ ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); ++ ++ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 1); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); ++ if (BTC_WIFI_BW_HT40 == wifiBw) ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, false, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ } ++ } ++ else ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, false, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ } ++ } ++} ++ ++/* PAN(EDR)+A2DP */ ++static void ++halbtc8723b2ant_ActionPanEdrA2dp( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ u8 wifiRssiState, btRssiState; ++ u32 wifiBw; ++ ++ wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); ++ btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); ++ ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); ++ ++ halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8); ++ ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); ++ ++ if (BTC_RSSI_HIGH(btRssiState)) ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); ++ else ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); ++ ++ if ((btRssiState == BTC_RSSI_STATE_HIGH) || ++ (btRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 12); ++ if (BTC_WIFI_BW_HT40 == wifiBw) ++ halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, false, true, 3); ++ else ++ halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, false, false, 3); ++ } ++ else ++ { ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); ++ halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, false, true, 3); ++ } ++ ++ /* sw mechanism */ ++ if (BTC_WIFI_BW_HT40 == wifiBw) ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, false, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ } ++ } ++ else ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, false, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, false, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ } ++ } ++} ++ ++static void ++halbtc8723b2ant_ActionPanEdrHid( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ u8 wifiRssiState, btRssiState; ++ u32 wifiBw; ++ ++ wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); ++ btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); ++ ++ halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8); ++ ++ if (BTC_RSSI_HIGH(btRssiState)) ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); ++ else ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); ++ ++ if ((btRssiState == BTC_RSSI_STATE_HIGH) || ++ (btRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ if (BTC_WIFI_BW_HT40 == wifiBw) ++ { ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 3); ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 11); ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x780); ++ } ++ else ++ { ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); ++ } ++ halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, true, false, 2); ++ } ++ else ++ { ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 11); ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); ++ halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, true, true, 2); ++ } ++ ++ /* sw mechanism */ ++ if (BTC_WIFI_BW_HT40 == wifiBw) ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, false, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ } ++ } ++ else ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, false, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ } ++ } ++} ++ ++/* HID+A2DP+PAN(EDR) */ ++static void ++halbtc8723b2ant_ActionHidA2dpPanEdr( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ u8 wifiRssiState, btRssiState; ++ u32 wifiBw; ++ ++ wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); ++ btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); ++ ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); ++ ++ halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8); ++ ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); ++ ++ if (BTC_RSSI_HIGH(btRssiState)) ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); ++ else ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); ++ ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); ++ ++ if ((btRssiState == BTC_RSSI_STATE_HIGH) || ++ (btRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ if (BTC_WIFI_BW_HT40 == wifiBw) ++ halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, true, true, 2); ++ else ++ halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, true, false, 3); ++ } ++ else ++ { ++ halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, true, true, 3); ++ } ++ ++ /* sw mechanism */ ++ if (BTC_WIFI_BW_HT40 == wifiBw) ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, false, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ } ++ } ++ else ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, false, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ } ++ } ++} ++ ++static void ++halbtc8723b2ant_ActionHidA2dp( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ u8 wifiRssiState, btRssiState; ++ u32 wifiBw; ++ u8 apNum = 0; ++ ++ wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); ++ /* btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); */ ++ btRssiState = halbtc8723b2ant_BtRssiState(3, 29, 37); ++ ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); ++ ++ halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, true, 0x5); ++ ++ halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); ++ if (BTC_WIFI_BW_LEGACY == wifiBw) ++ { ++ if (BTC_RSSI_HIGH(btRssiState)) ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); ++ else if (BTC_RSSI_MEDIUM(btRssiState)) ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); ++ else ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); ++ } ++ else ++ { /* only 802.11N mode we have to dec bt power to 4 degree */ ++ if (BTC_RSSI_HIGH(btRssiState)) ++ { ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_AP_NUM, &apNum); ++ /* need to check ap Number of Not */ ++ if (apNum < 10) ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); ++ else ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); ++ } ++ else if (BTC_RSSI_MEDIUM(btRssiState)) ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); ++ else ++ halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); ++ } ++ ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); ++ ++ if ((btRssiState == BTC_RSSI_STATE_HIGH) || ++ (btRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, true, false, 2); ++ } ++ else ++ { ++ halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, true, true, 2); ++ } ++ ++ /* sw mechanism */ ++ if (BTC_WIFI_BW_HT40 == wifiBw) ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, false, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, true, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ } ++ } ++ else ++ { ++ if ((wifiRssiState == BTC_RSSI_STATE_HIGH) || ++ (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)) ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, false, 0x18); ++ } ++ else ++ { ++ halbtc8723b2ant_SwMechanism1(pBtCoexist, false, true, false, false); ++ halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18); ++ } ++ } ++} ++ ++static void ++halbtc8723b2ant_RunCoexistMechanism( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ u8 algorithm = 0; ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism() ===>\n")); ++ ++ if (pBtCoexist->bManualControl) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n")); ++ return; ++ } ++ ++ if (pCoexSta->bUnderIps) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is under IPS !!!\n")); ++ return; ++ } ++ ++ algorithm = halbtc8723b2ant_ActionAlgorithm(pBtCoexist); ++ if (pCoexSta->bC2hBtInquiryPage && (BT_8723B_2ANT_COEX_ALGO_PANHS!=algorithm)) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT is under inquiry/page scan !!\n")); ++ halbtc8723b2ant_ActionBtInquiry(pBtCoexist); ++ return; ++ } ++ else ++ { ++ if (pCoexDm->bNeedRecover0x948) ++ { ++ pCoexDm->bNeedRecover0x948 = false; ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, pCoexDm->backup0x948); ++ } ++ } ++ ++ pCoexDm->curAlgorithm = algorithm; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Algorithm = %d\n", pCoexDm->curAlgorithm)); ++ ++ if (halbtc8723b2ant_IsCommonAction(pBtCoexist)) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant common.\n")); ++ pCoexDm->bAutoTdmaAdjust = false; ++ } ++ else ++ { ++ if (pCoexDm->curAlgorithm != pCoexDm->preAlgorithm) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], preAlgorithm =%d, curAlgorithm =%d\n", ++ pCoexDm->preAlgorithm, pCoexDm->curAlgorithm)); ++ pCoexDm->bAutoTdmaAdjust = false; ++ } ++ switch (pCoexDm->curAlgorithm) ++ { ++ case BT_8723B_2ANT_COEX_ALGO_SCO: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = SCO.\n")); ++ halbtc8723b2ant_ActionSco(pBtCoexist); ++ break; ++ case BT_8723B_2ANT_COEX_ALGO_HID: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID.\n")); ++ halbtc8723b2ant_ActionHid(pBtCoexist); ++ break; ++ case BT_8723B_2ANT_COEX_ALGO_A2DP: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = A2DP.\n")); ++ halbtc8723b2ant_ActionA2dp(pBtCoexist); ++ break; ++ case BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n")); ++ halbtc8723b2ant_ActionA2dpPanHs(pBtCoexist); ++ break; ++ case BT_8723B_2ANT_COEX_ALGO_PANEDR: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n")); ++ halbtc8723b2ant_ActionPanEdr(pBtCoexist); ++ break; ++ case BT_8723B_2ANT_COEX_ALGO_PANHS: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HS mode.\n")); ++ halbtc8723b2ant_ActionPanHs(pBtCoexist); ++ break; ++ case BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n")); ++ halbtc8723b2ant_ActionPanEdrA2dp(pBtCoexist); ++ break; ++ case BT_8723B_2ANT_COEX_ALGO_PANEDR_HID: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n")); ++ halbtc8723b2ant_ActionPanEdrHid(pBtCoexist); ++ break; ++ case BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n")); ++ halbtc8723b2ant_ActionHidA2dpPanEdr(pBtCoexist); ++ break; ++ case BT_8723B_2ANT_COEX_ALGO_HID_A2DP: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n")); ++ halbtc8723b2ant_ActionHidA2dp(pBtCoexist); ++ break; ++ default: ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n")); ++ halbtc8723b2ant_CoexAllOff(pBtCoexist); ++ break; ++ } ++ pCoexDm->preAlgorithm = pCoexDm->curAlgorithm; ++ } ++} ++ ++static void ++halbtc8723b2ant_WifiOffHwCfg( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ bool bIsInMpMode = false; ++ u8 H2C_Parameter[2] ={0}; ++ u32 fwVer = 0; ++ ++ /* set wlan_act to low */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0x4); ++ ++ pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x780); /* WiFi goto standby while GNT_BT 0-->1 */ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); ++ if (fwVer >= 0x180000) ++ { ++ /* Use H2C to set GNT_BT to HIGH */ ++ H2C_Parameter[0] = 1; ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x6E, 1, H2C_Parameter); ++ } ++ else ++ { ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x765, 0x18); ++ } ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_IS_IN_MP_MODE, &bIsInMpMode); ++ if (!bIsInMpMode) ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x67, 0x20, 0x0); /* BT select s0/s1 is controlled by BT */ ++ else ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x67, 0x20, 0x1); /* BT select s0/s1 is controlled by WiFi */ ++} ++ ++static void ++halbtc8723b2ant_InitHwConfig( ++PBTC_COEXIST pBtCoexist, ++bool bBackUp ++ ) ++{ ++ u8 u1Tmp = 0; ++ ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 2Ant Init HW Config!!\n")); ++ ++ /* backup rf 0x1e value */ ++ pCoexDm->btRf0x1eBackup = ++ pBtCoexist->fBtcGetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff); ++ ++ /* 0x790[5:0]= 0x5 */ ++ u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x790); ++ u1Tmp &= 0xc0; ++ u1Tmp |= 0x5; ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x790, u1Tmp); ++ ++ /* Antenna config */ ++ halbtc8723b2ant_SetAntPath(pBtCoexist, BTC_ANT_WIFI_AT_MAIN, true, false); ++ ++ /* PTA parameter */ ++ halbtc8723b2ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 0); ++ ++ /* Enable counter statistics */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); /* 0x76e[3] = 1, WLAN_Act control by PTA */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x778, 0x3); ++ pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x40, 0x20, 0x1); ++} ++ ++/* */ ++/* work around function start with wa_halbtc8723b2ant_ */ ++/* */ ++/* */ ++/* extern function start with EXhalbtc8723b2ant_ */ ++/* */ ++void ++EXhalbtc8723b2ant_PowerOnSetting( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ PBTC_BOARD_INFO pBoardInfo =&pBtCoexist->boardInfo; ++ u8 u1Tmp = 0x4; /* Set BIT2 by default since it's 2ant case */ ++ u16 u2Tmp = 0x0; ++ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x67, 0x20); ++ ++ /* enable BB, REG_SYS_FUNC_EN such that we can write 0x948 correctly. */ ++ u2Tmp = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0x2); ++ pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x2, u2Tmp|BIT0|BIT1); ++ ++ /* set GRAN_BT = 1 */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x765, 0x18); ++ /* set WLAN_ACT = 0 */ ++ pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0x4); ++ ++ /* */ ++ /* S0 or S1 setting and Local register setting(By the setting fw can get ant number, S0/S1, ... info) */ ++ /* Local setting bit define */ ++ /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ ++ /* BIT1: "0" for internal switch; "1" for external switch */ ++ /* BIT2: "0" for one antenna; "1" for two antenna */ ++ /* NOTE: here default all internal switch and 1-antenna ==> BIT1 = 0 and BIT2 = 0 */ ++ if (pBtCoexist->chipInterface == BTC_INTF_USB) ++ { ++ /* fixed at S0 for USB interface */ ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x0); ++ ++ u1Tmp |= 0x1; /* antenna inverse */ ++ pBtCoexist->fBtcWriteLocalReg1Byte(pBtCoexist, 0xfe08, u1Tmp); ++ ++ pBoardInfo->btdmAntPos = BTC_ANTENNA_AT_AUX_PORT; ++ } ++ else ++ { ++ /* for PCIE and SDIO interface, we check efuse 0xc3[6] */ ++ if (pBoardInfo->singleAntPath == 0) ++ { ++ /* set to S1 */ ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x280); ++ pBoardInfo->btdmAntPos = BTC_ANTENNA_AT_MAIN_PORT; ++ } ++ else if (pBoardInfo->singleAntPath == 1) ++ { ++ /* set to S0 */ ++ pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x0); ++ u1Tmp |= 0x1; /* antenna inverse */ ++ pBoardInfo->btdmAntPos = BTC_ANTENNA_AT_AUX_PORT; ++ } ++ ++ if (pBtCoexist->chipInterface == BTC_INTF_PCI) ++ { ++ pBtCoexist->fBtcWriteLocalReg1Byte(pBtCoexist, 0x384, u1Tmp); ++ } ++ else if (pBtCoexist->chipInterface == BTC_INTF_SDIO) ++ { ++ pBtCoexist->fBtcWriteLocalReg1Byte(pBtCoexist, 0x60, u1Tmp); ++ } ++ } ++} ++ ++void ++EXhalbtc8723b2ant_InitHwConfig( ++PBTC_COEXIST pBtCoexist, ++bool bWifiOnly ++ ) ++{ ++ halbtc8723b2ant_InitHwConfig(pBtCoexist, true); ++} ++ ++void ++EXhalbtc8723b2ant_InitCoexDm( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); ++ ++ halbtc8723b2ant_InitCoexDm(pBtCoexist); ++} ++ ++void ++EXhalbtc8723b2ant_DisplayCoexInfo( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ PBTC_BOARD_INFO pBoardInfo =&pBtCoexist->boardInfo; ++ PBTC_STACK_INFO pStackInfo =&pBtCoexist->stackInfo; ++ PBTC_BT_LINK_INFO pBtLinkInfo =&pBtCoexist->btLinkInfo; ++ u8 * cliBuf =pBtCoexist->cliBuf; ++ u8 u1Tmp[4], i, btInfoExt, psTdmaCase = 0; ++ u32 u4Tmp[4]; ++ bool bRoam =false, bScan =false, bLink =false, bWifiUnder5G =false; ++ bool bBtHsOn =false, bWifiBusy =false; ++ s32 wifiRssi = 0, btHsRssi = 0; ++ u32 wifiBw, wifiTrafficDir, faOfdm, faCck; ++ u8 wifiDot11Chnl, wifiHsChnl; ++ u32 fwVer = 0, btPatchVer = 0; ++ u8 apNum = 0; ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); ++ CL_PRINTF(cliBuf); ++ ++ if (pBtCoexist->bManualControl) ++ { ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[Under Manual Control]============"); ++ CL_PRINTF(cliBuf); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n =========================================="); ++ CL_PRINTF(cliBuf); ++ } ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", \ ++ pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum); ++ CL_PRINTF(cliBuf); ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ ++ ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion); ++ CL_PRINTF(cliBuf); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer", \ ++ GLCoexVerDate8723b2Ant, GLCoexVer8723b2Ant, fwVer, btPatchVer, btPatchVer); ++ CL_PRINTF(cliBuf); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiDot11Chnl); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifiHsChnl); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", \ ++ wifiDot11Chnl, wifiHsChnl, bBtHsOn); ++ CL_PRINTF(cliBuf); ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", \ ++ pCoexDm->wifiChnlInfo[0], pCoexDm->wifiChnlInfo[1], ++ pCoexDm->wifiChnlInfo[2]); ++ CL_PRINTF(cliBuf); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_AP_NUM, &apNum); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", "Wifi rssi/ HS rssi/ AP#", \ ++ wifiRssi, btHsRssi, apNum); ++ CL_PRINTF(cliBuf); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "Wifi bLink/ bRoam/ bScan", \ ++ bLink, bRoam, bScan); ++ CL_PRINTF(cliBuf); ++ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", "Wifi status", \ ++ (bWifiUnder5G? "5G":"2.4G"), ++ ((BTC_WIFI_BW_LEGACY ==wifiBw)? "Legacy": (((BTC_WIFI_BW_HT40 ==wifiBw)? "HT40":"HT20"))), ++ ((!bWifiBusy)? "idle": ((BTC_WIFI_TRAFFIC_TX ==wifiTrafficDir)? "uplink":"downlink"))); ++ CL_PRINTF(cliBuf); ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", \ ++ ((pBtCoexist->btInfo.bBtDisabled)? ("disabled"): ((pCoexSta->bC2hBtInquiryPage)?("inquiry/page scan"):((BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus)? "non-connected idle": ++ ((BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)? "connected-idle":"busy")))), ++ pCoexSta->btRssi, pCoexSta->btRetryCnt); ++ CL_PRINTF(cliBuf); ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \ ++ pBtLinkInfo->bScoExist, pBtLinkInfo->bHidExist, pBtLinkInfo->bPanExist, pBtLinkInfo->bA2dpExist); ++ CL_PRINTF(cliBuf); ++ pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_BT_LINK_INFO); ++ ++ btInfoExt = pCoexSta->btInfoExt; ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Info A2DP rate", \ ++ (btInfoExt&BIT0)? "Basic rate":"EDR rate"); ++ CL_PRINTF(cliBuf); ++ ++ for (i = 0; ibtInfoC2hCnt[i]) ++ { ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8723b2Ant[i], \ ++ pCoexSta->btInfoC2h[i][0], pCoexSta->btInfoC2h[i][1], ++ pCoexSta->btInfoC2h[i][2], pCoexSta->btInfoC2h[i][3], ++ pCoexSta->btInfoC2h[i][4], pCoexSta->btInfoC2h[i][5], ++ pCoexSta->btInfoC2h[i][6], pCoexSta->btInfoC2hCnt[i]); ++ CL_PRINTF(cliBuf); ++ } ++ } ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s", "PS state, IPS/LPS", \ ++ ((pCoexSta->bUnderIps? "IPS ON":"IPS OFF")), ++ ((pCoexSta->bUnderLps? "LPS ON":"LPS OFF"))); ++ CL_PRINTF(cliBuf); ++ pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); ++ ++ /* Sw mechanism */ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw mechanism]============"); ++ CL_PRINTF(cliBuf); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "SM1[ShRf/ LpRA/ LimDig]", \ ++ pCoexDm->bCurRfRxLpfShrink, pCoexDm->bCurLowPenaltyRa, pCoexDm->bLimitedDig); ++ CL_PRINTF(cliBuf); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", \ ++ pCoexDm->bCurAgcTableEn, pCoexDm->bCurAdcBackOff, pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl); ++ CL_PRINTF(cliBuf); ++ ++ /* Fw mechanism */ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw mechanism]============"); ++ CL_PRINTF(cliBuf); ++ ++ psTdmaCase = pCoexDm->curPsTdma; ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", "PS TDMA", \ ++ pCoexDm->psTdmaPara[0], pCoexDm->psTdmaPara[1], ++ pCoexDm->psTdmaPara[2], pCoexDm->psTdmaPara[3], ++ pCoexDm->psTdmaPara[4], psTdmaCase, pCoexDm->bAutoTdmaAdjust); ++ CL_PRINTF(cliBuf); ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "DecBtPwr/ IgnWlanAct", \ ++ pCoexDm->curBtDecPwrLvl, pCoexDm->bCurIgnoreWlanAct); ++ CL_PRINTF(cliBuf); ++ ++ /* Hw setting */ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============"); ++ CL_PRINTF(cliBuf); ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", \ ++ pCoexDm->btRf0x1eBackup); ++ CL_PRINTF(cliBuf); ++ ++ u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x778); ++ u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x880); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x778/0x880[29:25]", \ ++ u1Tmp[0], (u4Tmp[0]&0x3e000000) >> 25); ++ CL_PRINTF(cliBuf); ++ ++ ++ u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x948); ++ u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x67); ++ u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x765); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x948/ 0x67[5] / 0x765", \ ++ u4Tmp[0], ((u1Tmp[0]&0x20)>> 5), u1Tmp[1]); ++ CL_PRINTF(cliBuf); ++ ++ u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x92c); ++ u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x930); ++ u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x944); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]", \ ++ u4Tmp[0]&0x3, u4Tmp[1]&0xff, u4Tmp[2]&0x3); ++ CL_PRINTF(cliBuf); ++ ++ ++ u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x39); ++ u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x40); ++ u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); ++ u1Tmp[2] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x64); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x38[11]/0x40/0x4c[24:23]/0x64[0]", \ ++ ((u1Tmp[0] & 0x8)>>3), u1Tmp[1], ((u4Tmp[0]&0x01800000)>>23), u1Tmp[2]&0x1); ++ CL_PRINTF(cliBuf); ++ ++ u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x550); ++ u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x522); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", \ ++ u4Tmp[0], u1Tmp[0]); ++ CL_PRINTF(cliBuf); ++ ++ u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xc50); ++ u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x49c); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0xc50(dig)/0x49c(null-drop)", \ ++ u4Tmp[0]&0xff, u1Tmp[0]); ++ CL_PRINTF(cliBuf); ++ ++ u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xda0); ++ u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xda4); ++ u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xda8); ++ u4Tmp[3] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xcf0); ++ ++ u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xa5b); ++ u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xa5c); ++ ++ faOfdm = ((u4Tmp[0]&0xffff0000) >> 16) + ((u4Tmp[1]&0xffff0000) >> 16) + (u4Tmp[1] & 0xffff) + (u4Tmp[2] & 0xffff) + \ ++ ((u4Tmp[3]&0xffff0000) >> 16) + (u4Tmp[3] & 0xffff) ; ++ faCck = (u1Tmp[0] << 8) + u1Tmp[1]; ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "OFDM-CCA/OFDM-FA/CCK-FA", \ ++ u4Tmp[0]&0xffff, faOfdm, faCck); ++ CL_PRINTF(cliBuf); ++ ++ u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c0); ++ u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c4); ++ u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c8); ++ u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x6cc); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", \ ++ u4Tmp[0], u4Tmp[1], u4Tmp[2], u1Tmp[0]); ++ CL_PRINTF(cliBuf); ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x770(high-pri rx/tx)", \ ++ pCoexSta->highPriorityRx, pCoexSta->highPriorityTx); ++ CL_PRINTF(cliBuf); ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)", \ ++ pCoexSta->lowPriorityRx, pCoexSta->lowPriorityTx); ++ CL_PRINTF(cliBuf); ++ ++ halbtc8723b2ant_MonitorBtCtr(pBtCoexist); ++ pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_COEX_STATISTICS); ++} ++ ++ ++void ++EXhalbtc8723b2ant_IpsNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ) ++{ ++ if (BTC_IPS_ENTER == type) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); ++ pCoexSta->bUnderIps = true; ++ halbtc8723b2ant_WifiOffHwCfg(pBtCoexist); ++ halbtc8723b2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, true); ++ halbtc8723b2ant_CoexAllOff(pBtCoexist); ++ } ++ else if (BTC_IPS_LEAVE == type) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")); ++ pCoexSta->bUnderIps = false; ++ halbtc8723b2ant_InitHwConfig(pBtCoexist, false); ++ halbtc8723b2ant_InitCoexDm(pBtCoexist); ++ halbtc8723b2ant_QueryBtInfo(pBtCoexist); ++ } ++} ++ ++void ++EXhalbtc8723b2ant_LpsNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ) ++{ ++ if (BTC_LPS_ENABLE == type) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); ++ pCoexSta->bUnderLps = true; ++ } ++ else if (BTC_LPS_DISABLE == type) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")); ++ pCoexSta->bUnderLps = false; ++ } ++} ++ ++void ++EXhalbtc8723b2ant_ScanNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ) ++{ ++ if (BTC_SCAN_START == type) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); ++ } ++ else if (BTC_SCAN_FINISH == type) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); ++ } ++} ++ ++void ++EXhalbtc8723b2ant_ConnectNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ) ++{ ++ if (BTC_ASSOCIATE_START == type) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); ++ } ++ else if (BTC_ASSOCIATE_FINISH == type) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); ++ } ++} ++ ++void ++EXhalbtc8723b2ant_MediaStatusNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ) ++{ ++ u8 H2C_Parameter[3] ={0}; ++ u32 wifiBw; ++ u8 wifiCentralChnl; ++ u8 apNum = 0; ++ ++ if (BTC_MEDIA_CONNECT == type) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n")); ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n")); ++ } ++ ++ /* only 2.4G we need to inform bt the chnl mask */ ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifiCentralChnl); ++ if ((BTC_MEDIA_CONNECT == type) && ++ (wifiCentralChnl <= 14)) ++ { ++ H2C_Parameter[0] = 0x1; ++ H2C_Parameter[1] = wifiCentralChnl; ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); ++ if (BTC_WIFI_BW_HT40 == wifiBw) ++ H2C_Parameter[2] = 0x30; ++ else ++ { ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_AP_NUM, &apNum); ++ if (apNum < 10) ++ H2C_Parameter[2] = 0x30; ++ else ++ H2C_Parameter[2] = 0x20; ++ } ++ } ++ ++ pCoexDm->wifiChnlInfo[0] = H2C_Parameter[0]; ++ pCoexDm->wifiChnlInfo[1] = H2C_Parameter[1]; ++ pCoexDm->wifiChnlInfo[2] = H2C_Parameter[2]; ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x66 = 0x%x\n", ++ H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2])); ++ ++ pBtCoexist->fBtcFillH2c(pBtCoexist, 0x66, 3, H2C_Parameter); ++} ++ ++void ++EXhalbtc8723b2ant_SpecialPacketNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ) ++{ ++ if (type == BTC_PACKET_DHCP) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], DHCP Packet notify\n")); ++ } ++} ++ ++void ++EXhalbtc8723b2ant_BtInfoNotify( ++PBTC_COEXIST pBtCoexist, ++u8 * tmpBuf, ++u8 length ++ ) ++{ ++ u8 btInfo = 0; ++ u8 i, rspSource = 0; ++ bool bBtBusy =false, bLimitedDig =false; ++ bool bWifiConnected =false; ++ ++ pCoexSta->bC2hBtInfoReqSent = false; ++ ++ rspSource = tmpBuf[0]&0xf; ++ if (rspSource >= BT_INFO_SRC_8723B_2ANT_MAX) ++ rspSource = BT_INFO_SRC_8723B_2ANT_WIFI_FW; ++ pCoexSta->btInfoC2hCnt[rspSource]++; ++ ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Bt info[%d], length =%d, hex data =[", rspSource, length)); ++ for (i = 0; ibtInfoC2h[rspSource][i] = tmpBuf[i]; ++ if (i == 1) ++ btInfo = tmpBuf[i]; ++ if (i == length-1) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i])); ++ } ++ else ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x, ", tmpBuf[i])); ++ } ++ } ++ ++ if (pBtCoexist->bManualControl) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), return for Manual CTRL<===\n")); ++ return; ++ } ++ ++ if (BT_INFO_SRC_8723B_2ANT_WIFI_FW != rspSource) ++ { ++ pCoexSta->btRetryCnt = /* [3:0] */ ++ pCoexSta->btInfoC2h[rspSource][2]&0xf; ++ ++ pCoexSta->btRssi = ++ pCoexSta->btInfoC2h[rspSource][3]*2+10; ++ ++ pCoexSta->btInfoExt = ++ pCoexSta->btInfoC2h[rspSource][4]; ++ ++ pCoexSta->bBtTxRxMask = (pCoexSta->btInfoC2h[rspSource][2]&0x40); ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TX_RX_MASK, &pCoexSta->bBtTxRxMask); ++ if (pCoexSta->bBtTxRxMask) ++ { ++ /* BT into is responded by BT FW and BT RF REG 0x3C != 0x01 => Need to switch BT TRx Mask */ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Switch BT TRx Mask since BT RF REG 0x3C != 0x01\n")); ++ pBtCoexist->fBtcSetBtReg(pBtCoexist, BTC_BT_REG_RF, 0x3c, 0x01); ++ } ++ ++ /* Here we need to resend some wifi info to BT */ ++ /* because bt is reset and loss of the info. */ ++ if ((pCoexSta->btInfoExt & BIT1)) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n")); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); ++ if (bWifiConnected) ++ { ++ EXhalbtc8723b2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_CONNECT); ++ } ++ else ++ { ++ EXhalbtc8723b2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); ++ } ++ } ++ ++ if ((pCoexSta->btInfoExt & BIT3)) ++ { ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n")); ++ halbtc8723b2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, false); ++ } ++ else ++ { ++ /* BT already NOT ignore Wlan active, do nothing here. */ ++ } ++ } ++ ++ /* check BIT2 first ==> check if bt is under inquiry or page scan */ ++ if (btInfo & BT_INFO_8723B_2ANT_B_INQ_PAGE) ++ pCoexSta->bC2hBtInquiryPage = true; ++ else ++ pCoexSta->bC2hBtInquiryPage = false; ++ ++ /* set link exist status */ ++ if (!(btInfo&BT_INFO_8723B_2ANT_B_CONNECTION)) ++ { ++ pCoexSta->bBtLinkExist = false; ++ pCoexSta->bPanExist = false; ++ pCoexSta->bA2dpExist = false; ++ pCoexSta->bHidExist = false; ++ pCoexSta->bScoExist = false; ++ } ++ else /* connection exists */ ++ { ++ pCoexSta->bBtLinkExist = true; ++ if (btInfo & BT_INFO_8723B_2ANT_B_FTP) ++ pCoexSta->bPanExist = true; ++ else ++ pCoexSta->bPanExist = false; ++ if (btInfo & BT_INFO_8723B_2ANT_B_A2DP) ++ pCoexSta->bA2dpExist = true; ++ else ++ pCoexSta->bA2dpExist = false; ++ if (btInfo & BT_INFO_8723B_2ANT_B_HID) ++ pCoexSta->bHidExist = true; ++ else ++ pCoexSta->bHidExist = false; ++ if (btInfo & BT_INFO_8723B_2ANT_B_SCO_ESCO) ++ pCoexSta->bScoExist = true; ++ else ++ pCoexSta->bScoExist = false; ++ } ++ ++ halbtc8723b2ant_UpdateBtLinkInfo(pBtCoexist); ++ ++ if (!(btInfo&BT_INFO_8723B_2ANT_B_CONNECTION)) ++ { ++ pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n")); ++ } ++ else if (btInfo == BT_INFO_8723B_2ANT_B_CONNECTION) /* connection exists but no busy */ ++ { ++ pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n")); ++ } ++ else if ((btInfo&BT_INFO_8723B_2ANT_B_SCO_ESCO) || ++ (btInfo&BT_INFO_8723B_2ANT_B_SCO_BUSY)) ++ { ++ pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_SCO_BUSY; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT SCO busy!!!\n")); ++ } ++ else if (btInfo&BT_INFO_8723B_2ANT_B_ACL_BUSY) ++ { ++ pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_ACL_BUSY; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT ACL busy!!!\n")); ++ } ++ else ++ { ++ pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_MAX; ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n")); ++ } ++ ++ if ((BT_8723B_2ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) || ++ (BT_8723B_2ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || ++ (BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus)) ++ { ++ bBtBusy = true; ++ bLimitedDig = true; ++ } ++ else ++ { ++ bBtBusy = false; ++ bLimitedDig = false; ++ } ++ ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bBtBusy); ++ ++ pCoexDm->bLimitedDig = bLimitedDig; ++ pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_LIMITED_DIG, &bLimitedDig); ++ ++ halbtc8723b2ant_RunCoexistMechanism(pBtCoexist); ++} ++ ++void ++EXhalbtc8723b2ant_HaltNotify( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n")); ++ ++ halbtc8723b2ant_WifiOffHwCfg(pBtCoexist); ++ pBtCoexist->fBtcSetBtReg(pBtCoexist, BTC_BT_REG_RF, 0x3c, 0x15); /* BT goto standby while GNT_BT 1-->0 */ ++ halbtc8723b2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, true); ++ ++ EXhalbtc8723b2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); ++} ++ ++void ++EXhalbtc8723b2ant_PnpNotify( ++PBTC_COEXIST pBtCoexist, ++u8 pnpState ++ ) ++{ ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify\n")); ++ ++ if (BTC_WIFI_PNP_SLEEP == pnpState) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify to SLEEP\n")); ++ } ++ else if (BTC_WIFI_PNP_WAKE_UP == pnpState) ++ { ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify to WAKE UP\n")); ++ halbtc8723b2ant_InitHwConfig(pBtCoexist, false); ++ halbtc8723b2ant_InitCoexDm(pBtCoexist); ++ halbtc8723b2ant_QueryBtInfo(pBtCoexist); ++ } ++} ++ ++void ++EXhalbtc8723b2ant_Periodical( ++PBTC_COEXIST pBtCoexist ++ ) ++{ ++ static u8 disVerInfoCnt = 0; ++ u32 fwVer = 0, btPatchVer = 0; ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ==========================Periodical ===========================\n")); ++ ++ if (disVerInfoCnt <= 5) ++ { ++ disVerInfoCnt += 1; ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); ++ pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", \ ++ GLCoexVerDate8723b2Ant, GLCoexVer8723b2Ant, fwVer, btPatchVer, btPatchVer)); ++ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); ++ } ++ ++ if (halbtc8723b2ant_IsWifiStatusChanged(pBtCoexist) || ++ pCoexDm->bAutoTdmaAdjust) ++ { ++ halbtc8723b2ant_RunCoexistMechanism(pBtCoexist); ++ } ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/HalBtc8723b2Ant.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalBtc8723b2Ant.h +--- linux-4.3/3rdparty/rtl8723bs/hal/HalBtc8723b2Ant.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalBtc8723b2Ant.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,205 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++/* The following is for 8723B 2Ant BT Co-exist definition */ ++#define BT_INFO_8723B_2ANT_B_FTP BIT7 ++#define BT_INFO_8723B_2ANT_B_A2DP BIT6 ++#define BT_INFO_8723B_2ANT_B_HID BIT5 ++#define BT_INFO_8723B_2ANT_B_SCO_BUSY BIT4 ++#define BT_INFO_8723B_2ANT_B_ACL_BUSY BIT3 ++#define BT_INFO_8723B_2ANT_B_INQ_PAGE BIT2 ++#define BT_INFO_8723B_2ANT_B_SCO_ESCO BIT1 ++#define BT_INFO_8723B_2ANT_B_CONNECTION BIT0 ++ ++#define BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT 2 ++ ++typedef enum _BT_INFO_SRC_8723B_2ANT{ ++ BT_INFO_SRC_8723B_2ANT_WIFI_FW = 0x0, ++ BT_INFO_SRC_8723B_2ANT_BT_RSP = 0x1, ++ BT_INFO_SRC_8723B_2ANT_BT_ACTIVE_SEND = 0x2, ++ BT_INFO_SRC_8723B_2ANT_MAX ++}BT_INFO_SRC_8723B_2ANT,*PBT_INFO_SRC_8723B_2ANT; ++ ++typedef enum _BT_8723B_2ANT_BT_STATUS{ ++ BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, ++ BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, ++ BT_8723B_2ANT_BT_STATUS_INQ_PAGE = 0x2, ++ BT_8723B_2ANT_BT_STATUS_ACL_BUSY = 0x3, ++ BT_8723B_2ANT_BT_STATUS_SCO_BUSY = 0x4, ++ BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, ++ BT_8723B_2ANT_BT_STATUS_MAX ++}BT_8723B_2ANT_BT_STATUS,*PBT_8723B_2ANT_BT_STATUS; ++ ++typedef enum _BT_8723B_2ANT_COEX_ALGO{ ++ BT_8723B_2ANT_COEX_ALGO_UNDEFINED = 0x0, ++ BT_8723B_2ANT_COEX_ALGO_SCO = 0x1, ++ BT_8723B_2ANT_COEX_ALGO_HID = 0x2, ++ BT_8723B_2ANT_COEX_ALGO_A2DP = 0x3, ++ BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS = 0x4, ++ BT_8723B_2ANT_COEX_ALGO_PANEDR = 0x5, ++ BT_8723B_2ANT_COEX_ALGO_PANHS = 0x6, ++ BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP = 0x7, ++ BT_8723B_2ANT_COEX_ALGO_PANEDR_HID = 0x8, ++ BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, ++ BT_8723B_2ANT_COEX_ALGO_HID_A2DP = 0xa, ++ BT_8723B_2ANT_COEX_ALGO_MAX = 0xb, ++}BT_8723B_2ANT_COEX_ALGO,*PBT_8723B_2ANT_COEX_ALGO; ++ ++typedef struct _COEX_DM_8723B_2ANT{ ++ /* fw mechanism */ ++ u8 preBtDecPwrLvl; ++ u8 curBtDecPwrLvl; ++ u8 preFwDacSwingLvl; ++ u8 curFwDacSwingLvl; ++ bool bCurIgnoreWlanAct; ++ bool bPreIgnoreWlanAct; ++ u8 prePsTdma; ++ u8 curPsTdma; ++ u8 psTdmaPara[5]; ++ u8 psTdmaDuAdjType; ++ bool bResetTdmaAdjust; ++ bool bAutoTdmaAdjust; ++ bool bPrePsTdmaOn; ++ bool bCurPsTdmaOn; ++ bool bPreBtAutoReport; ++ bool bCurBtAutoReport; ++ ++ /* sw mechanism */ ++ bool bPreRfRxLpfShrink; ++ bool bCurRfRxLpfShrink; ++ u32 btRf0x1eBackup; ++ bool bPreLowPenaltyRa; ++ bool bCurLowPenaltyRa; ++ bool bPreDacSwingOn; ++ u32 preDacSwingLvl; ++ bool bCurDacSwingOn; ++ u32 curDacSwingLvl; ++ bool bPreAdcBackOff; ++ bool bCurAdcBackOff; ++ bool bPreAgcTableEn; ++ bool bCurAgcTableEn; ++ u32 preVal0x6c0; ++ u32 curVal0x6c0; ++ u32 preVal0x6c4; ++ u32 curVal0x6c4; ++ u32 preVal0x6c8; ++ u32 curVal0x6c8; ++ u8 preVal0x6cc; ++ u8 curVal0x6cc; ++ bool bLimitedDig; ++ ++ /* algorithm related */ ++ u8 preAlgorithm; ++ u8 curAlgorithm; ++ u8 btStatus; ++ u8 wifiChnlInfo[3]; ++ ++ bool bNeedRecover0x948; ++ u32 backup0x948; ++} COEX_DM_8723B_2ANT, *PCOEX_DM_8723B_2ANT; ++ ++typedef struct _COEX_STA_8723B_2ANT{ ++ bool bBtLinkExist; ++ bool bScoExist; ++ bool bA2dpExist; ++ bool bHidExist; ++ bool bPanExist; ++ ++ bool bUnderLps; ++ bool bUnderIps; ++ u32 highPriorityTx; ++ u32 highPriorityRx; ++ u32 lowPriorityTx; ++ u32 lowPriorityRx; ++ u8 btRssi; ++ bool bBtTxRxMask; ++ u8 preBtRssiState; ++ u8 preWifiRssiState[4]; ++ bool bC2hBtInfoReqSent; ++ u8 btInfoC2h[BT_INFO_SRC_8723B_2ANT_MAX][10]; ++ u32 btInfoC2hCnt[BT_INFO_SRC_8723B_2ANT_MAX]; ++ bool bC2hBtInquiryPage; ++ u8 btRetryCnt; ++ u8 btInfoExt; ++}COEX_STA_8723B_2ANT, *PCOEX_STA_8723B_2ANT; ++ ++/* */ ++/* The following is interface which will notify coex module. */ ++/* */ ++void ++EXhalbtc8723b2ant_PowerOnSetting( ++PBTC_COEXIST pBtCoexist ++ ); ++void ++EXhalbtc8723b2ant_InitHwConfig( ++PBTC_COEXIST pBtCoexist, ++bool bWifiOnly ++ ); ++void ++EXhalbtc8723b2ant_InitCoexDm( ++PBTC_COEXIST pBtCoexist ++ ); ++void ++EXhalbtc8723b2ant_IpsNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ); ++void ++EXhalbtc8723b2ant_LpsNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ); ++void ++EXhalbtc8723b2ant_ScanNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ); ++void ++EXhalbtc8723b2ant_ConnectNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ); ++void ++EXhalbtc8723b2ant_MediaStatusNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ); ++void ++EXhalbtc8723b2ant_SpecialPacketNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ); ++void ++EXhalbtc8723b2ant_BtInfoNotify( ++PBTC_COEXIST pBtCoexist, ++u8 * tmpBuf, ++u8 length ++ ); ++void ++EXhalbtc8723b2ant_HaltNotify( ++PBTC_COEXIST pBtCoexist ++ ); ++void ++EXhalbtc8723b2ant_PnpNotify( ++PBTC_COEXIST pBtCoexist, ++u8 pnpState ++ ); ++void ++EXhalbtc8723b2ant_Periodical( ++PBTC_COEXIST pBtCoexist ++ ); ++void ++EXhalbtc8723b2ant_DisplayCoexInfo( ++PBTC_COEXIST pBtCoexist ++ ); +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/hal_btcoex.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/hal_btcoex.c +--- linux-4.3/3rdparty/rtl8723bs/hal/hal_btcoex.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/hal_btcoex.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,1754 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2013 Realtek 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. ++ * ++ ******************************************************************************/ ++#define __HAL_BTCOEX_C__ ++ ++#include ++#include ++#include ++#include ++ ++/* Global variables */ ++static const char *const BtProfileString[] = ++{ ++ "NONE", ++ "A2DP", ++ "PAN", ++ "HID", ++ "SCO", ++}; ++ ++static const char *const BtSpecString[] = ++{ ++ "1.0b", ++ "1.1", ++ "1.2", ++ "2.0+EDR", ++ "2.1+EDR", ++ "3.0+HS", ++ "4.0", ++}; ++ ++static const char *const BtLinkRoleString[] = ++{ ++ "Master", ++ "Slave", ++}; ++ ++static const char *const h2cStaString[] = ++{ ++ "successful", ++ "h2c busy", ++ "rf off", ++ "fw not read", ++}; ++ ++static const char *const ioStaString[] = ++{ ++ "success", ++ "can not IO", ++ "rf off", ++ "fw not read", ++ "wait io timeout", ++ "invalid len", ++ "idle Q empty", ++ "insert waitQ fail", ++ "unknown fail", ++ "wrong level", ++ "h2c stopped", ++}; ++ ++BTC_COEXIST GLBtCoexist; ++static u8 GLBtcWiFiInScanState; ++static u8 GLBtcWiFiInIQKState; ++ ++u32 GLBtcDbgType[BTC_MSG_MAX]; ++static u8 GLBtcDbgBuf[BT_TMP_BUF_SIZE]; ++ ++typedef struct _btcoexdbginfo ++{ ++ u8 *info; ++ u32 size; /* buffer total size */ ++ u32 len; /* now used length */ ++} BTCDBGINFO, *PBTCDBGINFO; ++ ++static BTCDBGINFO GLBtcDbgInfo; ++ ++#define BT_Operation(Adapter) false ++ ++static void DBG_BT_INFO_INIT(PBTCDBGINFO pinfo, u8 *pbuf, u32 size) ++{ ++ if (NULL == pinfo) return; ++ ++ memset(pinfo, 0, sizeof(BTCDBGINFO)); ++ ++ if (pbuf && size) { ++ pinfo->info = pbuf; ++ pinfo->size = size; ++ } ++} ++ ++void DBG_BT_INFO(u8 *dbgmsg) ++{ ++ PBTCDBGINFO pinfo; ++ u32 msglen; ++ u8 *pbuf; ++ ++ ++ pinfo = &GLBtcDbgInfo; ++ ++ if (NULL == pinfo->info) ++ return; ++ ++ msglen = strlen(dbgmsg); ++ if (pinfo->len + msglen > pinfo->size) ++ return; ++ ++ pbuf = pinfo->info + pinfo->len; ++ memcpy(pbuf, dbgmsg, msglen); ++ pinfo->len += msglen; ++} ++ ++/* */ ++/* Debug related function */ ++/* */ ++static u8 halbtcoutsrc_IsBtCoexistAvailable(PBTC_COEXIST pBtCoexist) ++{ ++ if (!pBtCoexist->bBinded || ++ NULL == pBtCoexist->Adapter) ++ { ++ return false; ++ } ++ return true; ++} ++ ++static void halbtcoutsrc_DbgInit(void) ++{ ++ u8 i; ++ ++ for (i = 0; iAdapter; ++ ++ pBtCoexist->btInfo.bBtCtrlLps = true; ++ pBtCoexist->btInfo.bBtLpsOn = false; ++ ++ rtw_btcoex_LPS_Leave(padapter); ++} ++ ++static void halbtcoutsrc_EnterLps(PBTC_COEXIST pBtCoexist) ++{ ++ struct adapter *padapter; ++ ++ ++ padapter = pBtCoexist->Adapter; ++ ++ pBtCoexist->btInfo.bBtCtrlLps = true; ++ pBtCoexist->btInfo.bBtLpsOn = true; ++ ++ rtw_btcoex_LPS_Enter(padapter); ++} ++ ++static void halbtcoutsrc_NormalLps(PBTC_COEXIST pBtCoexist) ++{ ++ struct adapter *padapter; ++ ++ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Normal LPS behavior!!!\n")); ++ ++ padapter = pBtCoexist->Adapter; ++ ++ if (pBtCoexist->btInfo.bBtCtrlLps) ++ { ++ pBtCoexist->btInfo.bBtLpsOn = false; ++ rtw_btcoex_LPS_Leave(padapter); ++ pBtCoexist->btInfo.bBtCtrlLps = false; ++ ++ /* recover the LPS state to the original */ ++ } ++} ++ ++/* ++ * Constraint: ++ * 1. this function will request pwrctrl->lock ++ */ ++static void halbtcoutsrc_LeaveLowPower(PBTC_COEXIST pBtCoexist) ++{ ++ struct adapter *padapter; ++ struct hal_com_data *pHalData; ++ s32 ready; ++ unsigned long stime; ++ unsigned long utime; ++ u32 timeout; /* unit: ms */ ++ ++ ++ padapter = pBtCoexist->Adapter; ++ pHalData = GET_HAL_DATA(padapter); ++ ready = _FAIL; ++#ifdef LPS_RPWM_WAIT_MS ++ timeout = LPS_RPWM_WAIT_MS; ++#else /* !LPS_RPWM_WAIT_MS */ ++ timeout = 30; ++#endif /* !LPS_RPWM_WAIT_MS */ ++ ++ stime = jiffies; ++ do { ++ ready = rtw_register_task_alive(padapter, BTCOEX_ALIVE); ++ if (_SUCCESS == ready) ++ break; ++ ++ utime = jiffies_to_msecs(jiffies - stime); ++ if (utime > timeout) ++ break; ++ ++ msleep(1); ++ } while (1); ++} ++ ++/* ++ * Constraint: ++ * 1. this function will request pwrctrl->lock ++ */ ++static void halbtcoutsrc_NormalLowPower(PBTC_COEXIST pBtCoexist) ++{ ++ struct adapter *padapter; ++ ++ ++ padapter = pBtCoexist->Adapter; ++ rtw_unregister_task_alive(padapter, BTCOEX_ALIVE); ++} ++ ++static void halbtcoutsrc_DisableLowPower(PBTC_COEXIST pBtCoexist, u8 bLowPwrDisable) ++{ ++ pBtCoexist->btInfo.bBtDisableLowPwr = bLowPwrDisable; ++ if (bLowPwrDisable) ++ halbtcoutsrc_LeaveLowPower(pBtCoexist); /* leave 32k low power. */ ++ else ++ halbtcoutsrc_NormalLowPower(pBtCoexist); /* original 32k low power behavior. */ ++} ++ ++static void halbtcoutsrc_AggregationCheck(PBTC_COEXIST pBtCoexist) ++{ ++ struct adapter *padapter; ++ bool bNeedToAct; ++ ++ ++ padapter = pBtCoexist->Adapter; ++ bNeedToAct = false; ++ ++ if (pBtCoexist->btInfo.bRejectAggPkt) ++ rtw_btcoex_RejectApAggregatedPacket(padapter, true); ++ else ++ { ++ if (pBtCoexist->btInfo.bPreBtCtrlAggBufSize != ++ pBtCoexist->btInfo.bBtCtrlAggBufSize) ++ { ++ bNeedToAct = true; ++ pBtCoexist->btInfo.bPreBtCtrlAggBufSize = pBtCoexist->btInfo.bBtCtrlAggBufSize; ++ } ++ ++ if (pBtCoexist->btInfo.bBtCtrlAggBufSize) ++ { ++ if (pBtCoexist->btInfo.preAggBufSize != ++ pBtCoexist->btInfo.aggBufSize) ++ { ++ bNeedToAct = true; ++ } ++ pBtCoexist->btInfo.preAggBufSize = pBtCoexist->btInfo.aggBufSize; ++ } ++ ++ if (bNeedToAct) ++ { ++ rtw_btcoex_RejectApAggregatedPacket(padapter, true); ++ rtw_btcoex_RejectApAggregatedPacket(padapter, false); ++ } ++ } ++} ++ ++static u8 halbtcoutsrc_IsWifiBusy(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv; ++ ++ ++ pmlmepriv = &padapter->mlmepriv; ++ ++ if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE) == true) ++ { ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ++ return true; ++ if (true == pmlmepriv->LinkDetectInfo.bBusyTraffic) ++ return true; ++ } ++ ++ return false; ++} ++ ++static u32 _halbtcoutsrc_GetWifiLinkStatus(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv; ++ u8 bp2p; ++ u32 portConnectedStatus; ++ ++ ++ pmlmepriv = &padapter->mlmepriv; ++ bp2p = false; ++ portConnectedStatus = 0; ++ ++ if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE) == true) ++ { ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ++ { ++ if (true == bp2p) ++ portConnectedStatus |= WIFI_P2P_GO_CONNECTED; ++ else ++ portConnectedStatus |= WIFI_AP_CONNECTED; ++ } ++ else ++ { ++ if (true == bp2p) ++ portConnectedStatus |= WIFI_P2P_GC_CONNECTED; ++ else ++ portConnectedStatus |= WIFI_STA_CONNECTED; ++ } ++ } ++ ++ return portConnectedStatus; ++} ++ ++static u32 halbtcoutsrc_GetWifiLinkStatus(PBTC_COEXIST pBtCoexist) ++{ ++ /* */ ++ /* return value: */ ++ /* [31:16]=> connected port number */ ++ /* [15:0]=> port connected bit define */ ++ /* */ ++ ++ struct adapter *padapter; ++ u32 retVal; ++ u32 portConnectedStatus, numOfConnectedPort; ++ ++ ++ padapter = pBtCoexist->Adapter; ++ portConnectedStatus = 0; ++ numOfConnectedPort = 0; ++ ++ retVal = _halbtcoutsrc_GetWifiLinkStatus(padapter); ++ if (retVal) ++ { ++ portConnectedStatus |= retVal; ++ numOfConnectedPort++; ++ } ++ ++ retVal = (numOfConnectedPort << 16) | portConnectedStatus; ++ ++ return retVal; ++} ++ ++static u32 halbtcoutsrc_GetBtPatchVer(PBTC_COEXIST pBtCoexist) ++{ ++ return pBtCoexist->btInfo.btRealFwVer; ++} ++ ++static s32 halbtcoutsrc_GetWifiRssi(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData; ++ s32 UndecoratedSmoothedPWDB = 0; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ ++ UndecoratedSmoothedPWDB = pHalData->dmpriv.EntryMinUndecoratedSmoothedPWDB; ++ ++ return UndecoratedSmoothedPWDB; ++} ++ ++static u8 halbtcoutsrc_GetWifiScanAPNum(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext; ++ static u8 scan_AP_num = 0; ++ ++ pmlmeext = &padapter->mlmeextpriv; ++ ++ if (GLBtcWiFiInScanState == false) { ++ if (pmlmeext->sitesurvey_res.bss_cnt > 0xFF) ++ scan_AP_num = 0xFF; ++ else ++ scan_AP_num = (u8)pmlmeext->sitesurvey_res.bss_cnt; ++ } ++ ++ return scan_AP_num; ++} ++ ++static u8 halbtcoutsrc_Get(void *pBtcContext, u8 getType, void *pOutBuf) ++{ ++ PBTC_COEXIST pBtCoexist; ++ struct adapter *padapter; ++ struct hal_com_data *pHalData; ++ struct mlme_ext_priv *mlmeext; ++ u8 *pu8; ++ s32 *pS4Tmp; ++ u32 *pU4Tmp; ++ u8 *pU1Tmp; ++ u8 ret; ++ ++ ++ pBtCoexist = (PBTC_COEXIST)pBtcContext; ++ if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) ++ return false; ++ ++ padapter = pBtCoexist->Adapter; ++ pHalData = GET_HAL_DATA(padapter); ++ mlmeext = &padapter->mlmeextpriv; ++ pu8 = (u8 *)pOutBuf; ++ pS4Tmp = (s32*)pOutBuf; ++ pU4Tmp = (u32*)pOutBuf; ++ pU1Tmp = (u8 *)pOutBuf; ++ ret = true; ++ ++ switch (getType) ++ { ++ case BTC_GET_BL_HS_OPERATION: ++ *pu8 = false; ++ ret = false; ++ break; ++ ++ case BTC_GET_BL_HS_CONNECTING: ++ *pu8 = false; ++ ret = false; ++ break; ++ ++ case BTC_GET_BL_WIFI_CONNECTED: ++ *pu8 = check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE); ++ break; ++ ++ case BTC_GET_BL_WIFI_BUSY: ++ *pu8 = halbtcoutsrc_IsWifiBusy(padapter); ++ break; ++ ++ case BTC_GET_BL_WIFI_SCAN: ++ /* Use the value of the new variable GLBtcWiFiInScanState to judge whether WiFi is in scan state or not, since the originally used flag ++ WIFI_SITE_MONITOR in fwstate may not be cleared in time */ ++ *pu8 = GLBtcWiFiInScanState; ++ break; ++ ++ case BTC_GET_BL_WIFI_LINK: ++ *pu8 = check_fwstate(&padapter->mlmepriv, WIFI_UNDER_LINKING); ++ break; ++ ++ case BTC_GET_BL_WIFI_ROAM: ++ *pu8 = check_fwstate(&padapter->mlmepriv, WIFI_UNDER_LINKING); ++ break; ++ ++ case BTC_GET_BL_WIFI_4_WAY_PROGRESS: ++ *pu8 = false; ++ break; ++ ++ case BTC_GET_BL_WIFI_UNDER_5G: ++ *pu8 = (pHalData->CurrentBandType == 1)? true : false; ++ break; ++ ++ case BTC_GET_BL_WIFI_AP_MODE_ENABLE: ++ *pu8 = check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE); ++ break; ++ ++ case BTC_GET_BL_WIFI_ENABLE_ENCRYPTION: ++ *pu8 = padapter->securitypriv.dot11PrivacyAlgrthm == 0? false: true; ++ break; ++ ++ case BTC_GET_BL_WIFI_UNDER_B_MODE: ++ if (mlmeext->cur_wireless_mode == WIRELESS_11B) ++ *pu8 = true; ++ else ++ *pu8 = false; ++ break; ++ ++ case BTC_GET_BL_WIFI_IS_IN_MP_MODE: ++ *pu8 = false; ++ break; ++ ++ case BTC_GET_BL_EXT_SWITCH: ++ *pu8 = false; ++ break; ++ ++ case BTC_GET_S4_WIFI_RSSI: ++ *pS4Tmp = halbtcoutsrc_GetWifiRssi(padapter); ++ break; ++ ++ case BTC_GET_S4_HS_RSSI: ++ *pS4Tmp = 0; ++ ret = false; ++ break; ++ ++ case BTC_GET_U4_WIFI_BW: ++ if (IsLegacyOnly(mlmeext->cur_wireless_mode)) ++ *pU4Tmp = BTC_WIFI_BW_LEGACY; ++ else if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_20) ++ *pU4Tmp = BTC_WIFI_BW_HT20; ++ else if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_40) ++ *pU4Tmp = BTC_WIFI_BW_HT40; ++ else ++ *pU4Tmp = BTC_WIFI_BW_HT40; /* todo */ ++ break; ++ ++ case BTC_GET_U4_WIFI_TRAFFIC_DIRECTION: ++ { ++ PRT_LINK_DETECT_T plinkinfo; ++ plinkinfo = &padapter->mlmepriv.LinkDetectInfo; ++ ++ if (plinkinfo->NumTxOkInPeriod > plinkinfo->NumRxOkInPeriod) ++ *pU4Tmp = BTC_WIFI_TRAFFIC_TX; ++ else ++ *pU4Tmp = BTC_WIFI_TRAFFIC_RX; ++ } ++ break; ++ ++ case BTC_GET_U4_WIFI_FW_VER: ++ *pU4Tmp = pHalData->FirmwareVersion << 16; ++ *pU4Tmp |= pHalData->FirmwareSubVersion; ++ break; ++ ++ case BTC_GET_U4_WIFI_LINK_STATUS: ++ *pU4Tmp = halbtcoutsrc_GetWifiLinkStatus(pBtCoexist); ++ break; ++ ++ case BTC_GET_U4_BT_PATCH_VER: ++ *pU4Tmp = halbtcoutsrc_GetBtPatchVer(pBtCoexist); ++ break; ++ ++ case BTC_GET_U1_WIFI_DOT11_CHNL: ++ *pU1Tmp = padapter->mlmeextpriv.cur_channel; ++ break; ++ ++ case BTC_GET_U1_WIFI_CENTRAL_CHNL: ++ *pU1Tmp = pHalData->CurrentChannel; ++ break; ++ ++ case BTC_GET_U1_WIFI_HS_CHNL: ++ *pU1Tmp = 0; ++ ret = false; ++ break; ++ ++ case BTC_GET_U1_MAC_PHY_MODE: ++ *pU1Tmp = BTC_SMSP; ++/* *pU1Tmp = BTC_DMSP; */ ++/* *pU1Tmp = BTC_DMDP; */ ++/* *pU1Tmp = BTC_MP_UNKNOWN; */ ++ break; ++ ++ case BTC_GET_U1_AP_NUM: ++ *pU1Tmp = halbtcoutsrc_GetWifiScanAPNum(padapter); ++ break; ++ ++ /* 1Ant =========== */ ++ case BTC_GET_U1_LPS_MODE: ++ *pU1Tmp = padapter->dvobj->pwrctl_priv.pwr_mode; ++ break; ++ ++ default: ++ ret = false; ++ break; ++ } ++ ++ return ret; ++} ++ ++static u8 halbtcoutsrc_Set(void *pBtcContext, u8 setType, void *pInBuf) ++{ ++ PBTC_COEXIST pBtCoexist; ++ struct adapter *padapter; ++ struct hal_com_data *pHalData; ++ u8 *pu8; ++ u8 *pU1Tmp; ++ u32 *pU4Tmp; ++ u8 ret; ++ ++ ++ pBtCoexist = (PBTC_COEXIST)pBtcContext; ++ padapter = pBtCoexist->Adapter; ++ pHalData = GET_HAL_DATA(padapter); ++ pu8 = (u8 *)pInBuf; ++ pU1Tmp = (u8 *)pInBuf; ++ pU4Tmp = (u32*)pInBuf; ++ ret = true; ++ ++ if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) ++ return false; ++ ++ switch (setType) ++ { ++ /* set some u8 type variables. */ ++ case BTC_SET_BL_BT_DISABLE: ++ pBtCoexist->btInfo.bBtDisabled = *pu8; ++ break; ++ ++ case BTC_SET_BL_BT_TRAFFIC_BUSY: ++ pBtCoexist->btInfo.bBtBusy = *pu8; ++ break; ++ ++ case BTC_SET_BL_BT_LIMITED_DIG: ++ pBtCoexist->btInfo.bLimitedDig = *pu8; ++ break; ++ ++ case BTC_SET_BL_FORCE_TO_ROAM: ++ pBtCoexist->btInfo.bForceToRoam = *pu8; ++ break; ++ ++ case BTC_SET_BL_TO_REJ_AP_AGG_PKT: ++ pBtCoexist->btInfo.bRejectAggPkt = *pu8; ++ break; ++ ++ case BTC_SET_BL_BT_CTRL_AGG_SIZE: ++ pBtCoexist->btInfo.bBtCtrlAggBufSize = *pu8; ++ break; ++ ++ case BTC_SET_BL_INC_SCAN_DEV_NUM: ++ pBtCoexist->btInfo.bIncreaseScanDevNum = *pu8; ++ break; ++ ++ case BTC_SET_BL_BT_TX_RX_MASK: ++ pBtCoexist->btInfo.bBtTxRxMask = *pu8; ++ break; ++ ++ /* set some u8 type variables. */ ++ case BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON: ++ pBtCoexist->btInfo.rssiAdjustForAgcTableOn = *pU1Tmp; ++ break; ++ ++ case BTC_SET_U1_AGG_BUF_SIZE: ++ pBtCoexist->btInfo.aggBufSize = *pU1Tmp; ++ break; ++ ++ /* the following are some action which will be triggered */ ++ case BTC_SET_ACT_GET_BT_RSSI: ++ ret = false; ++ break; ++ ++ case BTC_SET_ACT_AGGREGATE_CTRL: ++ halbtcoutsrc_AggregationCheck(pBtCoexist); ++ break; ++ ++ /* 1Ant =========== */ ++ /* set some u8 type variables. */ ++ case BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE: ++ pBtCoexist->btInfo.rssiAdjustFor1AntCoexType = *pU1Tmp; ++ break; ++ ++ case BTC_SET_U1_LPS_VAL: ++ pBtCoexist->btInfo.lpsVal = *pU1Tmp; ++ break; ++ ++ case BTC_SET_U1_RPWM_VAL: ++ pBtCoexist->btInfo.rpwmVal = *pU1Tmp; ++ break; ++ ++ /* the following are some action which will be triggered */ ++ case BTC_SET_ACT_LEAVE_LPS: ++ halbtcoutsrc_LeaveLps(pBtCoexist); ++ break; ++ ++ case BTC_SET_ACT_ENTER_LPS: ++ halbtcoutsrc_EnterLps(pBtCoexist); ++ break; ++ ++ case BTC_SET_ACT_NORMAL_LPS: ++ halbtcoutsrc_NormalLps(pBtCoexist); ++ break; ++ ++ case BTC_SET_ACT_DISABLE_LOW_POWER: ++ halbtcoutsrc_DisableLowPower(pBtCoexist, *pu8); ++ break; ++ ++ case BTC_SET_ACT_UPDATE_RAMASK: ++ pBtCoexist->btInfo.raMask = *pU4Tmp; ++ ++ if (check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE) == true) ++ { ++ struct sta_info *psta; ++ struct wlan_bssid_ex * cur_network; ++ ++ cur_network = &padapter->mlmeextpriv.mlmext_info.network; ++ psta = rtw_get_stainfo(&padapter->stapriv, cur_network->MacAddress); ++ rtw_hal_update_ra_mask(psta, 0); ++ } ++ break; ++ ++ case BTC_SET_ACT_SEND_MIMO_PS: ++ ret = false; ++ break; ++ ++ case BTC_SET_ACT_CTRL_BT_INFO: ++ ret = false; ++ break; ++ ++ case BTC_SET_ACT_CTRL_BT_COEX: ++ ret = false; ++ break; ++ case BTC_SET_ACT_CTRL_8723B_ANT: ++ ret = false; ++ break; ++ /* */ ++ default: ++ ret = false; ++ break; ++ } ++ ++ return ret; ++} ++ ++static void halbtcoutsrc_DisplayFwPwrModeCmd(PBTC_COEXIST pBtCoexist) ++{ ++ u8 *cliBuf = pBtCoexist->cliBuf; ++ ++ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x %02x ", "Power mode cmd ", \ ++ pBtCoexist->pwrModeVal[0], pBtCoexist->pwrModeVal[1], ++ pBtCoexist->pwrModeVal[2], pBtCoexist->pwrModeVal[3], ++ pBtCoexist->pwrModeVal[4], pBtCoexist->pwrModeVal[5]); ++ CL_PRINTF(cliBuf); ++} ++ ++/* */ ++/* IO related function */ ++/* */ ++static u8 halbtcoutsrc_Read1Byte(void *pBtcContext, u32 RegAddr) ++{ ++ PBTC_COEXIST pBtCoexist; ++ struct adapter *padapter; ++ ++ ++ pBtCoexist = (PBTC_COEXIST)pBtcContext; ++ padapter = pBtCoexist->Adapter; ++ ++ return rtw_read8(padapter, RegAddr); ++} ++ ++static u16 halbtcoutsrc_Read2Byte(void *pBtcContext, u32 RegAddr) ++{ ++ PBTC_COEXIST pBtCoexist; ++ struct adapter *padapter; ++ ++ ++ pBtCoexist = (PBTC_COEXIST)pBtcContext; ++ padapter = pBtCoexist->Adapter; ++ ++ return rtw_read16(padapter, RegAddr); ++} ++ ++static u32 halbtcoutsrc_Read4Byte(void *pBtcContext, u32 RegAddr) ++{ ++ PBTC_COEXIST pBtCoexist; ++ struct adapter *padapter; ++ ++ ++ pBtCoexist = (PBTC_COEXIST)pBtcContext; ++ padapter = pBtCoexist->Adapter; ++ ++ return rtw_read32(padapter, RegAddr); ++} ++ ++static void halbtcoutsrc_Write1Byte(void *pBtcContext, u32 RegAddr, u8 Data) ++{ ++ PBTC_COEXIST pBtCoexist; ++ struct adapter *padapter; ++ ++ ++ pBtCoexist = (PBTC_COEXIST)pBtcContext; ++ padapter = pBtCoexist->Adapter; ++ ++ rtw_write8(padapter, RegAddr, Data); ++} ++ ++static void halbtcoutsrc_BitMaskWrite1Byte(void *pBtcContext, u32 regAddr, u8 bitMask, u8 data1b) ++{ ++ PBTC_COEXIST pBtCoexist; ++ struct adapter *padapter; ++ u8 originalValue, bitShift; ++ u8 i; ++ ++ ++ pBtCoexist = (PBTC_COEXIST)pBtcContext; ++ padapter = pBtCoexist->Adapter; ++ originalValue = 0; ++ bitShift = 0; ++ ++ if (bitMask != 0xFF) ++ { ++ originalValue = rtw_read8(padapter, regAddr); ++ ++ for (i = 0; i<=7; i++) ++ { ++ if ((bitMask>>i)&0x1) ++ break; ++ } ++ bitShift = i; ++ ++ data1b = (originalValue & ~bitMask) | ((data1b << bitShift) & bitMask); ++ } ++ ++ rtw_write8(padapter, regAddr, data1b); ++} ++ ++static void halbtcoutsrc_Write2Byte(void *pBtcContext, u32 RegAddr, u16 Data) ++{ ++ PBTC_COEXIST pBtCoexist; ++ struct adapter *padapter; ++ ++ ++ pBtCoexist = (PBTC_COEXIST)pBtcContext; ++ padapter = pBtCoexist->Adapter; ++ ++ rtw_write16(padapter, RegAddr, Data); ++} ++ ++static void halbtcoutsrc_Write4Byte(void *pBtcContext, u32 RegAddr, u32 Data) ++{ ++ PBTC_COEXIST pBtCoexist; ++ struct adapter *padapter; ++ ++ ++ pBtCoexist = (PBTC_COEXIST)pBtcContext; ++ padapter = pBtCoexist->Adapter; ++ ++ rtw_write32(padapter, RegAddr, Data); ++} ++ ++static void halbtcoutsrc_WriteLocalReg1Byte(void *pBtcContext, u32 RegAddr, u8 Data) ++{ ++ PBTC_COEXIST pBtCoexist =(PBTC_COEXIST)pBtcContext; ++ struct adapter * Adapter =pBtCoexist->Adapter; ++ ++ if (BTC_INTF_SDIO == pBtCoexist->chipInterface) ++ { ++ rtw_write8(Adapter, SDIO_LOCAL_BASE | RegAddr, Data); ++ } ++ else ++ { ++ rtw_write8(Adapter, RegAddr, Data); ++ } ++} ++ ++static void halbtcoutsrc_SetBbReg(void *pBtcContext, u32 RegAddr, u32 BitMask, u32 Data) ++{ ++ PBTC_COEXIST pBtCoexist; ++ struct adapter *padapter; ++ ++ ++ pBtCoexist = (PBTC_COEXIST)pBtcContext; ++ padapter = pBtCoexist->Adapter; ++ ++ PHY_SetBBReg(padapter, RegAddr, BitMask, Data); ++} ++ ++ ++static u32 halbtcoutsrc_GetBbReg(void *pBtcContext, u32 RegAddr, u32 BitMask) ++{ ++ PBTC_COEXIST pBtCoexist; ++ struct adapter *padapter; ++ ++ ++ pBtCoexist = (PBTC_COEXIST)pBtcContext; ++ padapter = pBtCoexist->Adapter; ++ ++ return PHY_QueryBBReg(padapter, RegAddr, BitMask); ++} ++ ++static void halbtcoutsrc_SetRfReg(void *pBtcContext, u8 eRFPath, u32 RegAddr, u32 BitMask, u32 Data) ++{ ++ PBTC_COEXIST pBtCoexist; ++ struct adapter *padapter; ++ ++ ++ pBtCoexist = (PBTC_COEXIST)pBtcContext; ++ padapter = pBtCoexist->Adapter; ++ ++ PHY_SetRFReg(padapter, eRFPath, RegAddr, BitMask, Data); ++} ++ ++static u32 halbtcoutsrc_GetRfReg(void *pBtcContext, u8 eRFPath, u32 RegAddr, u32 BitMask) ++{ ++ PBTC_COEXIST pBtCoexist; ++ struct adapter *padapter; ++ ++ ++ pBtCoexist = (PBTC_COEXIST)pBtcContext; ++ padapter = pBtCoexist->Adapter; ++ ++ return PHY_QueryRFReg(padapter, eRFPath, RegAddr, BitMask); ++} ++ ++static void halbtcoutsrc_SetBtReg(void *pBtcContext, u8 RegType, u32 RegAddr, u32 Data) ++{ ++ PBTC_COEXIST pBtCoexist; ++ struct adapter *padapter; ++ u8 CmdBuffer1[4] = {0}; ++ u8 CmdBuffer2[4] = {0}; ++ u8 *AddrToSet = (u8 *)&RegAddr; ++ u8 *ValueToSet = (u8 *)&Data; ++ u8 OperVer = 0; ++ u8 ReqNum = 0; ++ ++ pBtCoexist = (PBTC_COEXIST)pBtcContext; ++ padapter = pBtCoexist->Adapter; ++ ++ CmdBuffer1[0] |= (OperVer & 0x0f); /* Set OperVer */ ++ CmdBuffer1[0] |= ((ReqNum << 4) & 0xf0); /* Set ReqNum */ ++ CmdBuffer1[1] = 0x0d; /* Set OpCode to BT_LO_OP_WRITE_REG_VALUE */ ++ CmdBuffer1[2] = ValueToSet[0]; /* Set WriteRegValue */ ++ rtw_hal_fill_h2c_cmd(padapter, 0x67, 4, &(CmdBuffer1[0])); ++ ++ msleep(200); ++ ReqNum++; ++ ++ CmdBuffer2[0] |= (OperVer & 0x0f); /* Set OperVer */ ++ CmdBuffer2[0] |= ((ReqNum << 4) & 0xf0); /* Set ReqNum */ ++ CmdBuffer2[1] = 0x0c; /* Set OpCode of BT_LO_OP_WRITE_REG_ADDR */ ++ CmdBuffer2[3] = AddrToSet[0]; /* Set WriteRegAddr */ ++ rtw_hal_fill_h2c_cmd(padapter, 0x67, 4, &(CmdBuffer2[0])); ++} ++ ++static u32 halbtcoutsrc_GetBtReg(void *pBtcContext, u8 RegType, u32 RegAddr) ++{ ++ /* To be implemented. Always return 0 temporarily */ ++ return 0; ++} ++ ++static void halbtcoutsrc_FillH2cCmd(void *pBtcContext, u8 elementId, u32 cmdLen, u8 *pCmdBuffer) ++{ ++ PBTC_COEXIST pBtCoexist; ++ struct adapter *padapter; ++ ++ ++ pBtCoexist = (PBTC_COEXIST)pBtcContext; ++ padapter = pBtCoexist->Adapter; ++ ++ rtw_hal_fill_h2c_cmd(padapter, elementId, cmdLen, pCmdBuffer); ++} ++ ++static void halbtcoutsrc_DisplayDbgMsg(void *pBtcContext, u8 dispType) ++{ ++ PBTC_COEXIST pBtCoexist; ++ ++ ++ pBtCoexist = (PBTC_COEXIST)pBtcContext; ++ switch (dispType) ++ { ++ case BTC_DBG_DISP_COEX_STATISTICS: ++ break; ++ case BTC_DBG_DISP_BT_LINK_INFO: ++ break; ++ case BTC_DBG_DISP_FW_PWR_MODE_CMD: ++ halbtcoutsrc_DisplayFwPwrModeCmd(pBtCoexist); ++ break; ++ default: ++ break; ++ } ++} ++ ++/* */ ++/* Extern functions called by other module */ ++/* */ ++static u8 EXhalbtcoutsrc_BindBtCoexWithAdapter(void *padapter) ++{ ++ PBTC_COEXIST pBtCoexist =&GLBtCoexist; ++ ++ if (pBtCoexist->bBinded) ++ return false; ++ else ++ pBtCoexist->bBinded = true; ++ ++ pBtCoexist->statistics.cntBind++; ++ ++ pBtCoexist->Adapter = padapter; ++ ++ pBtCoexist->stackInfo.bProfileNotified = false; ++ ++ pBtCoexist->btInfo.bBtCtrlAggBufSize = false; ++ pBtCoexist->btInfo.aggBufSize = 5; ++ ++ pBtCoexist->btInfo.bIncreaseScanDevNum = false; ++ ++ /* set default antenna position to main port */ ++ pBtCoexist->boardInfo.btdmAntPos = BTC_ANTENNA_AT_MAIN_PORT; ++ ++ return true; ++} ++ ++u8 EXhalbtcoutsrc_InitlizeVariables(void *padapter) ++{ ++ PBTC_COEXIST pBtCoexist = &GLBtCoexist; ++ ++ /* pBtCoexist->statistics.cntBind++; */ ++ ++ halbtcoutsrc_DbgInit(); ++ ++ pBtCoexist->chipInterface = BTC_INTF_SDIO; ++ ++ EXhalbtcoutsrc_BindBtCoexWithAdapter(padapter); ++ ++ pBtCoexist->fBtcRead1Byte = halbtcoutsrc_Read1Byte; ++ pBtCoexist->fBtcWrite1Byte = halbtcoutsrc_Write1Byte; ++ pBtCoexist->fBtcWrite1ByteBitMask = halbtcoutsrc_BitMaskWrite1Byte; ++ pBtCoexist->fBtcRead2Byte = halbtcoutsrc_Read2Byte; ++ pBtCoexist->fBtcWrite2Byte = halbtcoutsrc_Write2Byte; ++ pBtCoexist->fBtcRead4Byte = halbtcoutsrc_Read4Byte; ++ pBtCoexist->fBtcWrite4Byte = halbtcoutsrc_Write4Byte; ++ pBtCoexist->fBtcWriteLocalReg1Byte = halbtcoutsrc_WriteLocalReg1Byte; ++ ++ pBtCoexist->fBtcSetBbReg = halbtcoutsrc_SetBbReg; ++ pBtCoexist->fBtcGetBbReg = halbtcoutsrc_GetBbReg; ++ ++ pBtCoexist->fBtcSetRfReg = halbtcoutsrc_SetRfReg; ++ pBtCoexist->fBtcGetRfReg = halbtcoutsrc_GetRfReg; ++ ++ pBtCoexist->fBtcFillH2c = halbtcoutsrc_FillH2cCmd; ++ pBtCoexist->fBtcDispDbgMsg = halbtcoutsrc_DisplayDbgMsg; ++ ++ pBtCoexist->fBtcGet = halbtcoutsrc_Get; ++ pBtCoexist->fBtcSet = halbtcoutsrc_Set; ++ pBtCoexist->fBtcGetBtReg = halbtcoutsrc_GetBtReg; ++ pBtCoexist->fBtcSetBtReg = halbtcoutsrc_SetBtReg; ++ ++ pBtCoexist->cliBuf = &GLBtcDbgBuf[0]; ++ ++ pBtCoexist->boardInfo.singleAntPath = 0; ++ ++ GLBtcWiFiInScanState = false; ++ ++ GLBtcWiFiInIQKState = false; ++ ++ return true; ++} ++ ++void EXhalbtcoutsrc_PowerOnSetting(PBTC_COEXIST pBtCoexist) ++{ ++ if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) ++ return; ++ ++ /* Power on setting function is only added in 8723B currently */ ++ if (pBtCoexist->boardInfo.btdmAntNum == 2) ++ EXhalbtc8723b2ant_PowerOnSetting(pBtCoexist); ++ else if (pBtCoexist->boardInfo.btdmAntNum == 1) ++ EXhalbtc8723b1ant_PowerOnSetting(pBtCoexist); ++} ++ ++void EXhalbtcoutsrc_InitHwConfig(PBTC_COEXIST pBtCoexist, u8 bWifiOnly) ++{ ++ if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) ++ return; ++ ++ pBtCoexist->statistics.cntInitHwConfig++; ++ ++ if (pBtCoexist->boardInfo.btdmAntNum == 2) ++ EXhalbtc8723b2ant_InitHwConfig(pBtCoexist, bWifiOnly); ++ else if (pBtCoexist->boardInfo.btdmAntNum == 1) ++ EXhalbtc8723b1ant_InitHwConfig(pBtCoexist, bWifiOnly); ++} ++ ++void EXhalbtcoutsrc_InitCoexDm(PBTC_COEXIST pBtCoexist) ++{ ++ if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) ++ return; ++ ++ pBtCoexist->statistics.cntInitCoexDm++; ++ ++ if (pBtCoexist->boardInfo.btdmAntNum == 2) ++ EXhalbtc8723b2ant_InitCoexDm(pBtCoexist); ++ else if (pBtCoexist->boardInfo.btdmAntNum == 1) ++ EXhalbtc8723b1ant_InitCoexDm(pBtCoexist); ++ ++ pBtCoexist->bInitilized = true; ++} ++ ++void EXhalbtcoutsrc_IpsNotify(PBTC_COEXIST pBtCoexist, u8 type) ++{ ++ u8 ipsType; ++ ++ if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) ++ return; ++ ++ pBtCoexist->statistics.cntIpsNotify++; ++ if (pBtCoexist->bManualControl) ++ return; ++ ++ if (IPS_NONE == type) ++ ipsType = BTC_IPS_LEAVE; ++ else ++ ipsType = BTC_IPS_ENTER; ++ ++ /* All notify is called in cmd thread, don't need to leave low power again */ ++/* halbtcoutsrc_LeaveLowPower(pBtCoexist); */ ++ ++ if (pBtCoexist->boardInfo.btdmAntNum == 2) ++ EXhalbtc8723b2ant_IpsNotify(pBtCoexist, ipsType); ++ else if (pBtCoexist->boardInfo.btdmAntNum == 1) ++ EXhalbtc8723b1ant_IpsNotify(pBtCoexist, ipsType); ++ ++/* halbtcoutsrc_NormalLowPower(pBtCoexist); */ ++} ++ ++void EXhalbtcoutsrc_LpsNotify(PBTC_COEXIST pBtCoexist, u8 type) ++{ ++ u8 lpsType; ++ ++ ++ if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) ++ return; ++ ++ pBtCoexist->statistics.cntLpsNotify++; ++ if (pBtCoexist->bManualControl) ++ return; ++ ++ if (PS_MODE_ACTIVE == type) ++ lpsType = BTC_LPS_DISABLE; ++ else ++ lpsType = BTC_LPS_ENABLE; ++ ++ if (pBtCoexist->boardInfo.btdmAntNum == 2) ++ EXhalbtc8723b2ant_LpsNotify(pBtCoexist, lpsType); ++ else if (pBtCoexist->boardInfo.btdmAntNum == 1) ++ EXhalbtc8723b1ant_LpsNotify(pBtCoexist, lpsType); ++} ++ ++void EXhalbtcoutsrc_ScanNotify(PBTC_COEXIST pBtCoexist, u8 type) ++{ ++ u8 scanType; ++ ++ if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) ++ return; ++ pBtCoexist->statistics.cntScanNotify++; ++ if (pBtCoexist->bManualControl) ++ return; ++ ++ if (type) ++ { ++ scanType = BTC_SCAN_START; ++ GLBtcWiFiInScanState = true; ++ } ++ else ++ { ++ scanType = BTC_SCAN_FINISH; ++ GLBtcWiFiInScanState = false; ++ } ++ ++ /* All notify is called in cmd thread, don't need to leave low power again */ ++/* halbtcoutsrc_LeaveLowPower(pBtCoexist); */ ++ ++ if (pBtCoexist->boardInfo.btdmAntNum == 2) ++ EXhalbtc8723b2ant_ScanNotify(pBtCoexist, scanType); ++ else if (pBtCoexist->boardInfo.btdmAntNum == 1) ++ EXhalbtc8723b1ant_ScanNotify(pBtCoexist, scanType); ++ ++/* halbtcoutsrc_NormalLowPower(pBtCoexist); */ ++} ++ ++void EXhalbtcoutsrc_ConnectNotify(PBTC_COEXIST pBtCoexist, u8 action) ++{ ++ u8 assoType; ++ ++ if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) ++ return; ++ pBtCoexist->statistics.cntConnectNotify++; ++ if (pBtCoexist->bManualControl) ++ return; ++ ++ if (action) ++ assoType = BTC_ASSOCIATE_START; ++ else ++ assoType = BTC_ASSOCIATE_FINISH; ++ ++ /* All notify is called in cmd thread, don't need to leave low power again */ ++/* halbtcoutsrc_LeaveLowPower(pBtCoexist); */ ++ ++ if (pBtCoexist->boardInfo.btdmAntNum == 2) ++ EXhalbtc8723b2ant_ConnectNotify(pBtCoexist, assoType); ++ else if (pBtCoexist->boardInfo.btdmAntNum == 1) ++ EXhalbtc8723b1ant_ConnectNotify(pBtCoexist, assoType); ++ ++/* halbtcoutsrc_NormalLowPower(pBtCoexist); */ ++} ++ ++void EXhalbtcoutsrc_MediaStatusNotify(PBTC_COEXIST pBtCoexist, RT_MEDIA_STATUS mediaStatus) ++{ ++ u8 mStatus; ++ ++ if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) ++ return; ++ ++ pBtCoexist->statistics.cntMediaStatusNotify++; ++ if (pBtCoexist->bManualControl) ++ return; ++ ++ if (RT_MEDIA_CONNECT == mediaStatus) ++ mStatus = BTC_MEDIA_CONNECT; ++ else ++ mStatus = BTC_MEDIA_DISCONNECT; ++ ++ /* All notify is called in cmd thread, don't need to leave low power again */ ++/* halbtcoutsrc_LeaveLowPower(pBtCoexist); */ ++ ++ if (pBtCoexist->boardInfo.btdmAntNum == 2) ++ EXhalbtc8723b2ant_MediaStatusNotify(pBtCoexist, mStatus); ++ else if (pBtCoexist->boardInfo.btdmAntNum == 1) ++ EXhalbtc8723b1ant_MediaStatusNotify(pBtCoexist, mStatus); ++ ++/* halbtcoutsrc_NormalLowPower(pBtCoexist); */ ++} ++ ++void EXhalbtcoutsrc_SpecialPacketNotify(PBTC_COEXIST pBtCoexist, u8 pktType) ++{ ++ u8 packetType; ++ ++ if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) ++ return; ++ pBtCoexist->statistics.cntSpecialPacketNotify++; ++ if (pBtCoexist->bManualControl) ++ return; ++ ++ if (PACKET_DHCP == pktType) ++ packetType = BTC_PACKET_DHCP; ++ else if (PACKET_EAPOL == pktType) ++ packetType = BTC_PACKET_EAPOL; ++ else if (PACKET_ARP == pktType) ++ packetType = BTC_PACKET_ARP; ++ else ++ { ++ packetType = BTC_PACKET_UNKNOWN; ++ return; ++ } ++ ++ /* All notify is called in cmd thread, don't need to leave low power again */ ++/* halbtcoutsrc_LeaveLowPower(pBtCoexist); */ ++ ++ if (pBtCoexist->boardInfo.btdmAntNum == 2) ++ EXhalbtc8723b2ant_SpecialPacketNotify(pBtCoexist, packetType); ++ else if (pBtCoexist->boardInfo.btdmAntNum == 1) ++ EXhalbtc8723b1ant_SpecialPacketNotify(pBtCoexist, packetType); ++ ++/* halbtcoutsrc_NormalLowPower(pBtCoexist); */ ++} ++ ++void EXhalbtcoutsrc_BtInfoNotify(PBTC_COEXIST pBtCoexist, u8 *tmpBuf, u8 length) ++{ ++ if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) ++ return; ++ ++ pBtCoexist->statistics.cntBtInfoNotify++; ++ ++ /* All notify is called in cmd thread, don't need to leave low power again */ ++/* halbtcoutsrc_LeaveLowPower(pBtCoexist); */ ++ ++ if (pBtCoexist->boardInfo.btdmAntNum == 2) ++ EXhalbtc8723b2ant_BtInfoNotify(pBtCoexist, tmpBuf, length); ++ else if (pBtCoexist->boardInfo.btdmAntNum == 1) ++ EXhalbtc8723b1ant_BtInfoNotify(pBtCoexist, tmpBuf, length); ++ ++/* halbtcoutsrc_NormalLowPower(pBtCoexist); */ ++} ++ ++void EXhalbtcoutsrc_HaltNotify(PBTC_COEXIST pBtCoexist) ++{ ++ if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) ++ return; ++ ++ if (pBtCoexist->boardInfo.btdmAntNum == 2) ++ EXhalbtc8723b2ant_HaltNotify(pBtCoexist); ++ else if (pBtCoexist->boardInfo.btdmAntNum == 1) ++ EXhalbtc8723b1ant_HaltNotify(pBtCoexist); ++ ++ pBtCoexist->bBinded = false; ++} ++ ++void EXhalbtcoutsrc_PnpNotify(PBTC_COEXIST pBtCoexist, u8 pnpState) ++{ ++ if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) ++ return; ++ ++ /* */ ++ /* currently only 1ant we have to do the notification, */ ++ /* once pnp is notified to sleep state, we have to leave LPS that we can sleep normally. */ ++ /* */ ++ ++ if (pBtCoexist->boardInfo.btdmAntNum == 1) ++ EXhalbtc8723b1ant_PnpNotify(pBtCoexist, pnpState); ++ else if (pBtCoexist->boardInfo.btdmAntNum == 2) ++ EXhalbtc8723b2ant_PnpNotify(pBtCoexist, pnpState); ++} ++ ++void EXhalbtcoutsrc_Periodical(PBTC_COEXIST pBtCoexist) ++{ ++ if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) ++ return; ++ pBtCoexist->statistics.cntPeriodical++; ++ ++ /* Periodical should be called in cmd thread, */ ++ /* don't need to leave low power again */ ++/* halbtcoutsrc_LeaveLowPower(pBtCoexist); */ ++ ++ if (pBtCoexist->boardInfo.btdmAntNum == 2) ++ EXhalbtc8723b2ant_Periodical(pBtCoexist); ++ else if (pBtCoexist->boardInfo.btdmAntNum == 1) ++ EXhalbtc8723b1ant_Periodical(pBtCoexist); ++ ++/* halbtcoutsrc_NormalLowPower(pBtCoexist); */ ++} ++ ++void EXhalbtcoutsrc_SetChipType(u8 chipType) ++{ ++ GLBtCoexist.boardInfo.btChipType = BTC_CHIP_RTL8723B; ++} ++ ++void EXhalbtcoutsrc_SetAntNum(u8 type, u8 antNum) ++{ ++ if (BT_COEX_ANT_TYPE_PG == type) ++ { ++ GLBtCoexist.boardInfo.pgAntNum = antNum; ++ GLBtCoexist.boardInfo.btdmAntNum = antNum; ++ } ++ else if (BT_COEX_ANT_TYPE_ANTDIV == type) ++ { ++ GLBtCoexist.boardInfo.btdmAntNum = antNum; ++ /* GLBtCoexist.boardInfo.btdmAntPos = BTC_ANTENNA_AT_MAIN_PORT; */ ++ } ++ else if (BT_COEX_ANT_TYPE_DETECTED == type) ++ { ++ GLBtCoexist.boardInfo.btdmAntNum = antNum; ++ /* GLBtCoexist.boardInfo.btdmAntPos = BTC_ANTENNA_AT_MAIN_PORT; */ ++ } ++} ++ ++/* */ ++/* Currently used by 8723b only, S0 or S1 */ ++/* */ ++void EXhalbtcoutsrc_SetSingleAntPath(u8 singleAntPath) ++{ ++ GLBtCoexist.boardInfo.singleAntPath = singleAntPath; ++} ++ ++void EXhalbtcoutsrc_DisplayBtCoexInfo(PBTC_COEXIST pBtCoexist) ++{ ++ if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) ++ return; ++ ++ halbtcoutsrc_LeaveLowPower(pBtCoexist); ++ ++ if (pBtCoexist->boardInfo.btdmAntNum == 2) ++ EXhalbtc8723b2ant_DisplayCoexInfo(pBtCoexist); ++ else if (pBtCoexist->boardInfo.btdmAntNum == 1) ++ EXhalbtc8723b1ant_DisplayCoexInfo(pBtCoexist); ++ ++ halbtcoutsrc_NormalLowPower(pBtCoexist); ++} ++ ++/* ++ * Description: ++ *Run BT-Coexist mechansim or not ++ * ++ */ ++void hal_btcoex_SetBTCoexist(struct adapter *padapter, u8 bBtExist) ++{ ++ struct hal_com_data *pHalData; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ pHalData->bt_coexist.bBtExist = bBtExist; ++} ++ ++/* ++ * Dewcription: ++ *Check is co-exist mechanism enabled or not ++ * ++ * Return: ++ *true Enable BT co-exist mechanism ++ *false Disable BT co-exist mechanism ++ */ ++u8 hal_btcoex_IsBtExist(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ return pHalData->bt_coexist.bBtExist; ++} ++ ++u8 hal_btcoex_IsBtDisabled(struct adapter *padapter) ++{ ++ if (!hal_btcoex_IsBtExist(padapter)) ++ return true; ++ ++ if (GLBtCoexist.btInfo.bBtDisabled) ++ return true; ++ else ++ return false; ++} ++ ++void hal_btcoex_SetChipType(struct adapter *padapter, u8 chipType) ++{ ++ struct hal_com_data *pHalData; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ pHalData->bt_coexist.btChipType = chipType; ++ ++ EXhalbtcoutsrc_SetChipType(chipType); ++} ++ ++void hal_btcoex_SetPgAntNum(struct adapter *padapter, u8 antNum) ++{ ++ struct hal_com_data *pHalData; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ ++ pHalData->bt_coexist.btTotalAntNum = antNum; ++ EXhalbtcoutsrc_SetAntNum(BT_COEX_ANT_TYPE_PG, antNum); ++} ++ ++void hal_btcoex_SetSingleAntPath(struct adapter *padapter, u8 singleAntPath) ++{ ++ EXhalbtcoutsrc_SetSingleAntPath(singleAntPath); ++} ++ ++u8 hal_btcoex_Initialize(struct adapter *padapter) ++{ ++ u8 ret1; ++ u8 ret2; ++ ++ ++ memset(&GLBtCoexist, 0, sizeof(GLBtCoexist)); ++ ret1 = EXhalbtcoutsrc_InitlizeVariables((void*)padapter); ++ ret2 = (ret1 ==true) ? true : false; ++ ++ return ret2; ++} ++ ++void hal_btcoex_PowerOnSetting(struct adapter *padapter) ++{ ++ EXhalbtcoutsrc_PowerOnSetting(&GLBtCoexist); ++} ++ ++void hal_btcoex_InitHwConfig(struct adapter *padapter, u8 bWifiOnly) ++{ ++ if (!hal_btcoex_IsBtExist(padapter)) ++ return; ++ ++ EXhalbtcoutsrc_InitHwConfig(&GLBtCoexist, bWifiOnly); ++ EXhalbtcoutsrc_InitCoexDm(&GLBtCoexist); ++} ++ ++void hal_btcoex_IpsNotify(struct adapter *padapter, u8 type) ++{ ++ EXhalbtcoutsrc_IpsNotify(&GLBtCoexist, type); ++} ++ ++void hal_btcoex_LpsNotify(struct adapter *padapter, u8 type) ++{ ++ EXhalbtcoutsrc_LpsNotify(&GLBtCoexist, type); ++} ++ ++void hal_btcoex_ScanNotify(struct adapter *padapter, u8 type) ++{ ++ EXhalbtcoutsrc_ScanNotify(&GLBtCoexist, type); ++} ++ ++void hal_btcoex_ConnectNotify(struct adapter *padapter, u8 action) ++{ ++ EXhalbtcoutsrc_ConnectNotify(&GLBtCoexist, action); ++} ++ ++void hal_btcoex_MediaStatusNotify(struct adapter *padapter, u8 mediaStatus) ++{ ++ EXhalbtcoutsrc_MediaStatusNotify(&GLBtCoexist, mediaStatus); ++} ++ ++void hal_btcoex_SpecialPacketNotify(struct adapter *padapter, u8 pktType) ++{ ++ EXhalbtcoutsrc_SpecialPacketNotify(&GLBtCoexist, pktType); ++} ++ ++void hal_btcoex_IQKNotify(struct adapter *padapter, u8 state) ++{ ++ GLBtcWiFiInIQKState = state; ++} ++ ++void hal_btcoex_BtInfoNotify(struct adapter *padapter, u8 length, u8 *tmpBuf) ++{ ++ if (GLBtcWiFiInIQKState == true) ++ return; ++ ++ EXhalbtcoutsrc_BtInfoNotify(&GLBtCoexist, tmpBuf, length); ++} ++ ++void hal_btcoex_SuspendNotify(struct adapter *padapter, u8 state) ++{ ++ if (state == 1) ++ state = BTC_WIFI_PNP_SLEEP; ++ else ++ state = BTC_WIFI_PNP_WAKE_UP; ++ ++ EXhalbtcoutsrc_PnpNotify(&GLBtCoexist, state); ++} ++ ++void hal_btcoex_HaltNotify(struct adapter *padapter) ++{ ++ EXhalbtcoutsrc_HaltNotify(&GLBtCoexist); ++} ++ ++void hal_btcoex_Hanlder(struct adapter *padapter) ++{ ++ EXhalbtcoutsrc_Periodical(&GLBtCoexist); ++} ++ ++s32 hal_btcoex_IsBTCoexCtrlAMPDUSize(struct adapter *padapter) ++{ ++ return (s32)GLBtCoexist.btInfo.bBtCtrlAggBufSize; ++} ++ ++void hal_btcoex_SetManualControl(struct adapter *padapter, u8 bmanual) ++{ ++ GLBtCoexist.bManualControl = bmanual; ++} ++ ++u8 hal_btcoex_IsBtControlLps(struct adapter *padapter) ++{ ++ if (hal_btcoex_IsBtExist(padapter) == false) ++ return false; ++ ++ if (GLBtCoexist.btInfo.bBtDisabled) ++ return false; ++ ++ if (GLBtCoexist.btInfo.bBtCtrlLps) ++ return true; ++ ++ return false; ++} ++ ++u8 hal_btcoex_IsLpsOn(struct adapter *padapter) ++{ ++ if (hal_btcoex_IsBtExist(padapter) == false) ++ return false; ++ ++ if (GLBtCoexist.btInfo.bBtDisabled) ++ return false; ++ ++ if (GLBtCoexist.btInfo.bBtLpsOn) ++ return true; ++ ++ return false; ++} ++ ++u8 hal_btcoex_RpwmVal(struct adapter *padapter) ++{ ++ return GLBtCoexist.btInfo.rpwmVal; ++} ++ ++u8 hal_btcoex_LpsVal(struct adapter *padapter) ++{ ++ return GLBtCoexist.btInfo.lpsVal; ++} ++ ++u32 hal_btcoex_GetRaMask(struct adapter *padapter) ++{ ++ if (!hal_btcoex_IsBtExist(padapter)) ++ return 0; ++ ++ if (GLBtCoexist.btInfo.bBtDisabled) ++ return 0; ++ ++ if (GLBtCoexist.boardInfo.btdmAntNum != 1) ++ return 0; ++ ++ return GLBtCoexist.btInfo.raMask; ++} ++ ++void hal_btcoex_RecordPwrMode(struct adapter *padapter, u8 *pCmdBuf, u8 cmdLen) ++{ ++ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write pwrModeCmd = 0x%04x%08x\n", ++ pCmdBuf[0]<<8|pCmdBuf[1], ++ pCmdBuf[2]<<24|pCmdBuf[3]<<16|pCmdBuf[4]<<8|pCmdBuf[5])); ++ ++ memcpy(GLBtCoexist.pwrModeVal, pCmdBuf, cmdLen); ++} ++ ++void hal_btcoex_DisplayBtCoexInfo(struct adapter *padapter, u8 *pbuf, u32 bufsize) ++{ ++ PBTCDBGINFO pinfo; ++ ++ ++ pinfo = &GLBtcDbgInfo; ++ DBG_BT_INFO_INIT(pinfo, pbuf, bufsize); ++ EXhalbtcoutsrc_DisplayBtCoexInfo(&GLBtCoexist); ++ DBG_BT_INFO_INIT(pinfo, NULL, 0); ++} ++ ++void hal_btcoex_SetDBG(struct adapter *padapter, u32 *pDbgModule) ++{ ++ u32 i; ++ ++ ++ if (NULL == pDbgModule) ++ return; ++ ++ for (i = 0; i= leftSize)) ++ goto exit; ++ pstr += count; ++ leftSize -= count; ++ ++ count = rtw_sprintf(pstr, leftSize, "BTCOEX Debug Setting:\n"); ++ if ((count < 0) || (count >= leftSize)) ++ goto exit; ++ pstr += count; ++ leftSize -= count; ++ ++ count = rtw_sprintf(pstr, leftSize, ++ "INTERFACE / ALGORITHM: 0x%08X / 0x%08X\n\n", ++ GLBtcDbgType[BTC_MSG_INTERFACE], ++ GLBtcDbgType[BTC_MSG_ALGORITHM]); ++ if ((count < 0) || (count >= leftSize)) ++ goto exit; ++ pstr += count; ++ leftSize -= count; ++ ++ count = rtw_sprintf(pstr, leftSize, "INTERFACE Debug Setting Definition:\n"); ++ if ((count < 0) || (count >= leftSize)) ++ goto exit; ++ pstr += count; ++ leftSize -= count; ++ count = rtw_sprintf(pstr, leftSize, "\tbit[0]=%d for INTF_INIT\n", ++ (GLBtcDbgType[BTC_MSG_INTERFACE]&INTF_INIT)?1:0); ++ if ((count < 0) || (count >= leftSize)) ++ goto exit; ++ pstr += count; ++ leftSize -= count; ++ count = rtw_sprintf(pstr, leftSize, "\tbit[2]=%d for INTF_NOTIFY\n\n", ++ (GLBtcDbgType[BTC_MSG_INTERFACE]&INTF_NOTIFY)?1:0); ++ if ((count < 0) || (count >= leftSize)) ++ goto exit; ++ pstr += count; ++ leftSize -= count; ++ ++ count = rtw_sprintf(pstr, leftSize, "ALGORITHM Debug Setting Definition:\n"); ++ if ((count < 0) || (count >= leftSize)) ++ goto exit; ++ pstr += count; ++ leftSize -= count; ++ count = rtw_sprintf(pstr, leftSize, "\tbit[0]=%d for BT_RSSI_STATE\n", ++ (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_BT_RSSI_STATE)?1:0); ++ if ((count < 0) || (count >= leftSize)) ++ goto exit; ++ pstr += count; ++ leftSize -= count; ++ count = rtw_sprintf(pstr, leftSize, "\tbit[1]=%d for WIFI_RSSI_STATE\n", ++ (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_WIFI_RSSI_STATE)?1:0); ++ if ((count < 0) || (count >= leftSize)) ++ goto exit; ++ pstr += count; ++ leftSize -= count; ++ count = rtw_sprintf(pstr, leftSize, "\tbit[2]=%d for BT_MONITOR\n", ++ (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_BT_MONITOR)?1:0); ++ if ((count < 0) || (count >= leftSize)) ++ goto exit; ++ pstr += count; ++ leftSize -= count; ++ count = rtw_sprintf(pstr, leftSize, "\tbit[3]=%d for TRACE\n", ++ (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_TRACE)?1:0); ++ if ((count < 0) || (count >= leftSize)) ++ goto exit; ++ pstr += count; ++ leftSize -= count; ++ count = rtw_sprintf(pstr, leftSize, "\tbit[4]=%d for TRACE_FW\n", ++ (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_TRACE_FW)?1:0); ++ if ((count < 0) || (count >= leftSize)) ++ goto exit; ++ pstr += count; ++ leftSize -= count; ++ count = rtw_sprintf(pstr, leftSize, "\tbit[5]=%d for TRACE_FW_DETAIL\n", ++ (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_TRACE_FW_DETAIL)?1:0); ++ if ((count < 0) || (count >= leftSize)) ++ goto exit; ++ pstr += count; ++ leftSize -= count; ++ count = rtw_sprintf(pstr, leftSize, "\tbit[6]=%d for TRACE_FW_EXEC\n", ++ (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_TRACE_FW_EXEC)?1:0); ++ if ((count < 0) || (count >= leftSize)) ++ goto exit; ++ pstr += count; ++ leftSize -= count; ++ count = rtw_sprintf(pstr, leftSize, "\tbit[7]=%d for TRACE_SW\n", ++ (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_TRACE_SW)?1:0); ++ if ((count < 0) || (count >= leftSize)) ++ goto exit; ++ pstr += count; ++ leftSize -= count; ++ count = rtw_sprintf(pstr, leftSize, "\tbit[8]=%d for TRACE_SW_DETAIL\n", ++ (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_TRACE_SW_DETAIL)?1:0); ++ if ((count < 0) || (count >= leftSize)) ++ goto exit; ++ pstr += count; ++ leftSize -= count; ++ count = rtw_sprintf(pstr, leftSize, "\tbit[9]=%d for TRACE_SW_EXEC\n", ++ (GLBtcDbgType[BTC_MSG_ALGORITHM]&ALGO_TRACE_SW_EXEC)?1:0); ++ if ((count < 0) || (count >= leftSize)) ++ goto exit; ++ pstr += count; ++ leftSize -= count; ++ ++exit: ++ count = pstr - pStrBuf; ++/* DBG_871X(FUNC_ADPT_FMT ": usedsize =%d\n", FUNC_ADPT_ARG(padapter), count); */ ++ ++ return count; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/HalBtcOutSrc.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalBtcOutSrc.h +--- linux-4.3/3rdparty/rtl8723bs/hal/HalBtcOutSrc.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalBtcOutSrc.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,706 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __HALBTC_OUT_SRC_H__ ++#define __HALBTC_OUT_SRC_H__ ++ ++#define NORMAL_EXEC false ++#define FORCE_EXEC true ++ ++#define BTC_RF_OFF 0x0 ++#define BTC_RF_ON 0x1 ++ ++#define BTC_RF_A 0x0 ++#define BTC_RF_B 0x1 ++#define BTC_RF_C 0x2 ++#define BTC_RF_D 0x3 ++ ++#define BTC_SMSP SINGLEMAC_SINGLEPHY ++#define BTC_DMDP DUALMAC_DUALPHY ++#define BTC_DMSP DUALMAC_SINGLEPHY ++#define BTC_MP_UNKNOWN 0xff ++ ++#define BT_COEX_ANT_TYPE_PG 0 ++#define BT_COEX_ANT_TYPE_ANTDIV 1 ++#define BT_COEX_ANT_TYPE_DETECTED 2 ++ ++#define BTC_MIMO_PS_STATIC 0 /* 1ss */ ++#define BTC_MIMO_PS_DYNAMIC 1 /* 2ss */ ++ ++#define BTC_RATE_DISABLE 0 ++#define BTC_RATE_ENABLE 1 ++ ++/* single Antenna definition */ ++#define BTC_ANT_PATH_WIFI 0 ++#define BTC_ANT_PATH_BT 1 ++#define BTC_ANT_PATH_PTA 2 ++/* dual Antenna definition */ ++#define BTC_ANT_WIFI_AT_MAIN 0 ++#define BTC_ANT_WIFI_AT_AUX 1 ++/* coupler Antenna definition */ ++#define BTC_ANT_WIFI_AT_CPL_MAIN 0 ++#define BTC_ANT_WIFI_AT_CPL_AUX 1 ++ ++typedef enum _BTC_POWERSAVE_TYPE{ ++ BTC_PS_WIFI_NATIVE = 0, /* wifi original power save behavior */ ++ BTC_PS_LPS_ON = 1, ++ BTC_PS_LPS_OFF = 2, ++ BTC_PS_MAX ++} BTC_POWERSAVE_TYPE, *PBTC_POWERSAVE_TYPE; ++ ++typedef enum _BTC_BT_REG_TYPE{ ++ BTC_BT_REG_RF = 0, ++ BTC_BT_REG_MODEM = 1, ++ BTC_BT_REG_BLUEWIZE = 2, ++ BTC_BT_REG_VENDOR = 3, ++ BTC_BT_REG_LE = 4, ++ BTC_BT_REG_MAX ++} BTC_BT_REG_TYPE, *PBTC_BT_REG_TYPE; ++ ++typedef enum _BTC_CHIP_INTERFACE{ ++ BTC_INTF_UNKNOWN = 0, ++ BTC_INTF_PCI = 1, ++ BTC_INTF_USB = 2, ++ BTC_INTF_SDIO = 3, ++ BTC_INTF_MAX ++} BTC_CHIP_INTERFACE, *PBTC_CHIP_INTERFACE; ++ ++typedef enum _BTC_CHIP_TYPE{ ++ BTC_CHIP_UNDEF = 0, ++ BTC_CHIP_CSR_BC4 = 1, ++ BTC_CHIP_CSR_BC8 = 2, ++ BTC_CHIP_RTL8723A = 3, ++ BTC_CHIP_RTL8821 = 4, ++ BTC_CHIP_RTL8723B = 5, ++ BTC_CHIP_MAX ++} BTC_CHIP_TYPE, *PBTC_CHIP_TYPE; ++ ++typedef enum _BTC_MSG_TYPE{ ++ BTC_MSG_INTERFACE = 0x0, ++ BTC_MSG_ALGORITHM = 0x1, ++ BTC_MSG_MAX ++}BTC_MSG_TYPE; ++extern u32 GLBtcDbgType[]; ++ ++/* following is for BTC_MSG_INTERFACE */ ++#define INTF_INIT BIT0 ++#define INTF_NOTIFY BIT2 ++ ++/* following is for BTC_ALGORITHM */ ++#define ALGO_BT_RSSI_STATE BIT0 ++#define ALGO_WIFI_RSSI_STATE BIT1 ++#define ALGO_BT_MONITOR BIT2 ++#define ALGO_TRACE BIT3 ++#define ALGO_TRACE_FW BIT4 ++#define ALGO_TRACE_FW_DETAIL BIT5 ++#define ALGO_TRACE_FW_EXEC BIT6 ++#define ALGO_TRACE_SW BIT7 ++#define ALGO_TRACE_SW_DETAIL BIT8 ++#define ALGO_TRACE_SW_EXEC BIT9 ++ ++/* following is for wifi link status */ ++#define WIFI_STA_CONNECTED BIT0 ++#define WIFI_AP_CONNECTED BIT1 ++#define WIFI_HS_CONNECTED BIT2 ++#define WIFI_P2P_GO_CONNECTED BIT3 ++#define WIFI_P2P_GC_CONNECTED BIT4 ++ ++/* following is for command line utility */ ++#define CL_SPRINTF snprintf ++#define CL_PRINTF DCMD_Printf ++ ++/* The following is for dbgview print */ ++#if DBG ++#define BTC_PRINT(dbgtype, dbgflag, printstr)\ ++{\ ++ if (GLBtcDbgType[dbgtype] & dbgflag)\ ++ {\ ++ DbgPrint printstr;\ ++ }\ ++} ++ ++#define BTC_PRINT_F(dbgtype, dbgflag, printstr)\ ++{\ ++ if (GLBtcDbgType[dbgtype] & dbgflag)\ ++ {\ ++ DbgPrint("%s(): ", __func__);\ ++ DbgPrint printstr;\ ++ }\ ++} ++ ++#define BTC_PRINT_ADDR(dbgtype, dbgflag, printstr, _Ptr)\ ++{\ ++ if (GLBtcDbgType[dbgtype] & dbgflag)\ ++ {\ ++ int __i; \ ++ u8 *ptr = (u8 *)_Ptr; \ ++ DbgPrint printstr; \ ++ DbgPrint(" "); \ ++ for (__i = 0; __i<6; __i++) \ ++ DbgPrint("%02X%s", ptr[__i], (__i ==5)?"":"-"); \ ++ DbgPrint("\n"); \ ++ }\ ++} ++ ++#define BTC_PRINT_DATA(dbgtype, dbgflag, _TitleString, _HexData, _HexDataLen)\ ++{\ ++ if (GLBtcDbgType[dbgtype] & dbgflag)\ ++ {\ ++ int __i; \ ++ u8 *ptr = (u8 *)_HexData; \ ++ DbgPrint(_TitleString); \ ++ for (__i = 0; __i<(int)_HexDataLen; __i++) \ ++ { \ ++ DbgPrint("%02X%s", ptr[__i], (((__i + 1) % 4) == 0)?" ":" ");\ ++ if (((__i + 1) % 16) == 0) DbgPrint("\n");\ ++ } \ ++ DbgPrint("\n"); \ ++ }\ ++} ++ ++#else ++#define BTC_PRINT(dbgtype, dbgflag, printstr) ++#define BTC_PRINT_F(dbgtype, dbgflag, printstr) ++#define BTC_PRINT_ADDR(dbgtype, dbgflag, printstr, _Ptr) ++#define BTC_PRINT_DATA(dbgtype, dbgflag, _TitleString, _HexData, _HexDataLen) ++#endif ++ ++typedef struct _BTC_BOARD_INFO{ ++ /* The following is some board information */ ++ u8 btChipType; ++ u8 pgAntNum; /* pg ant number */ ++ u8 btdmAntNum; /* ant number for btdm */ ++ u8 btdmAntPos; /* Bryant Add to indicate Antenna Position for (pgAntNum = 2) && (btdmAntNum = 1) (DPDT+1Ant case) */ ++ u8 singleAntPath; /* current used for 8723b only, 1 =>s0, 0 =>s1 */ ++ /* bool bBtExist; */ ++} BTC_BOARD_INFO, *PBTC_BOARD_INFO; ++ ++typedef enum _BTC_DBG_OPCODE{ ++ BTC_DBG_SET_COEX_NORMAL = 0x0, ++ BTC_DBG_SET_COEX_WIFI_ONLY = 0x1, ++ BTC_DBG_SET_COEX_BT_ONLY = 0x2, ++ BTC_DBG_SET_COEX_DEC_BT_PWR = 0x3, ++ BTC_DBG_SET_COEX_BT_AFH_MAP = 0x4, ++ BTC_DBG_SET_COEX_BT_IGNORE_WLAN_ACT = 0x5, ++ BTC_DBG_MAX ++}BTC_DBG_OPCODE,*PBTC_DBG_OPCODE; ++ ++typedef enum _BTC_RSSI_STATE{ ++ BTC_RSSI_STATE_HIGH = 0x0, ++ BTC_RSSI_STATE_MEDIUM = 0x1, ++ BTC_RSSI_STATE_LOW = 0x2, ++ BTC_RSSI_STATE_STAY_HIGH = 0x3, ++ BTC_RSSI_STATE_STAY_MEDIUM = 0x4, ++ BTC_RSSI_STATE_STAY_LOW = 0x5, ++ BTC_RSSI_MAX ++}BTC_RSSI_STATE,*PBTC_RSSI_STATE; ++#define BTC_RSSI_HIGH(_rssi_) ((_rssi_==BTC_RSSI_STATE_HIGH||_rssi_==BTC_RSSI_STATE_STAY_HIGH)? true:false) ++#define BTC_RSSI_MEDIUM(_rssi_) ((_rssi_==BTC_RSSI_STATE_MEDIUM||_rssi_==BTC_RSSI_STATE_STAY_MEDIUM)? true:false) ++#define BTC_RSSI_LOW(_rssi_) ((_rssi_==BTC_RSSI_STATE_LOW||_rssi_==BTC_RSSI_STATE_STAY_LOW)? true:false) ++ ++typedef enum _BTC_WIFI_ROLE{ ++ BTC_ROLE_STATION = 0x0, ++ BTC_ROLE_AP = 0x1, ++ BTC_ROLE_IBSS = 0x2, ++ BTC_ROLE_HS_MODE = 0x3, ++ BTC_ROLE_MAX ++}BTC_WIFI_ROLE,*PBTC_WIFI_ROLE; ++ ++typedef enum _BTC_WIFI_BW_MODE{ ++ BTC_WIFI_BW_LEGACY = 0x0, ++ BTC_WIFI_BW_HT20 = 0x1, ++ BTC_WIFI_BW_HT40 = 0x2, ++ BTC_WIFI_BW_MAX ++}BTC_WIFI_BW_MODE,*PBTC_WIFI_BW_MODE; ++ ++typedef enum _BTC_WIFI_TRAFFIC_DIR{ ++ BTC_WIFI_TRAFFIC_TX = 0x0, ++ BTC_WIFI_TRAFFIC_RX = 0x1, ++ BTC_WIFI_TRAFFIC_MAX ++}BTC_WIFI_TRAFFIC_DIR,*PBTC_WIFI_TRAFFIC_DIR; ++ ++typedef enum _BTC_WIFI_PNP{ ++ BTC_WIFI_PNP_WAKE_UP = 0x0, ++ BTC_WIFI_PNP_SLEEP = 0x1, ++ BTC_WIFI_PNP_MAX ++}BTC_WIFI_PNP,*PBTC_WIFI_PNP; ++ ++/* for 8723b-d cut large current issue */ ++typedef enum _BT_WIFI_COEX_STATE{ ++ BTC_WIFI_STAT_INIT, ++ BTC_WIFI_STAT_IQK, ++ BTC_WIFI_STAT_NORMAL_OFF, ++ BTC_WIFI_STAT_MP_OFF, ++ BTC_WIFI_STAT_NORMAL, ++ BTC_WIFI_STAT_ANT_DIV, ++ BTC_WIFI_STAT_MAX ++}BT_WIFI_COEX_STATE,*PBT_WIFI_COEX_STATE; ++ ++/* defined for BFP_BTC_GET */ ++typedef enum _BTC_GET_TYPE{ ++ /* type bool */ ++ BTC_GET_BL_HS_OPERATION, ++ BTC_GET_BL_HS_CONNECTING, ++ BTC_GET_BL_WIFI_CONNECTED, ++ BTC_GET_BL_WIFI_BUSY, ++ BTC_GET_BL_WIFI_SCAN, ++ BTC_GET_BL_WIFI_LINK, ++ BTC_GET_BL_WIFI_ROAM, ++ BTC_GET_BL_WIFI_4_WAY_PROGRESS, ++ BTC_GET_BL_WIFI_UNDER_5G, ++ BTC_GET_BL_WIFI_AP_MODE_ENABLE, ++ BTC_GET_BL_WIFI_ENABLE_ENCRYPTION, ++ BTC_GET_BL_WIFI_UNDER_B_MODE, ++ BTC_GET_BL_EXT_SWITCH, ++ BTC_GET_BL_WIFI_IS_IN_MP_MODE, ++ ++ /* type s32 */ ++ BTC_GET_S4_WIFI_RSSI, ++ BTC_GET_S4_HS_RSSI, ++ ++ /* type u32 */ ++ BTC_GET_U4_WIFI_BW, ++ BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, ++ BTC_GET_U4_WIFI_FW_VER, ++ BTC_GET_U4_WIFI_LINK_STATUS, ++ BTC_GET_U4_BT_PATCH_VER, ++ ++ /* type u8 */ ++ BTC_GET_U1_WIFI_DOT11_CHNL, ++ BTC_GET_U1_WIFI_CENTRAL_CHNL, ++ BTC_GET_U1_WIFI_HS_CHNL, ++ BTC_GET_U1_MAC_PHY_MODE, ++ BTC_GET_U1_AP_NUM, ++ ++ /* for 1Ant ====== */ ++ BTC_GET_U1_LPS_MODE, ++ ++ BTC_GET_MAX ++}BTC_GET_TYPE,*PBTC_GET_TYPE; ++ ++/* defined for BFP_BTC_SET */ ++typedef enum _BTC_SET_TYPE{ ++ /* type bool */ ++ BTC_SET_BL_BT_DISABLE, ++ BTC_SET_BL_BT_TRAFFIC_BUSY, ++ BTC_SET_BL_BT_LIMITED_DIG, ++ BTC_SET_BL_FORCE_TO_ROAM, ++ BTC_SET_BL_TO_REJ_AP_AGG_PKT, ++ BTC_SET_BL_BT_CTRL_AGG_SIZE, ++ BTC_SET_BL_INC_SCAN_DEV_NUM, ++ BTC_SET_BL_BT_TX_RX_MASK, ++ ++ /* type u8 */ ++ BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, ++ BTC_SET_U1_AGG_BUF_SIZE, ++ ++ /* type trigger some action */ ++ BTC_SET_ACT_GET_BT_RSSI, ++ BTC_SET_ACT_AGGREGATE_CTRL, ++ /* for 1Ant ====== */ ++ /* type bool */ ++ ++ /* type u8 */ ++ BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, ++ BTC_SET_U1_LPS_VAL, ++ BTC_SET_U1_RPWM_VAL, ++ /* type trigger some action */ ++ BTC_SET_ACT_LEAVE_LPS, ++ BTC_SET_ACT_ENTER_LPS, ++ BTC_SET_ACT_NORMAL_LPS, ++ BTC_SET_ACT_DISABLE_LOW_POWER, ++ BTC_SET_ACT_UPDATE_RAMASK, ++ BTC_SET_ACT_SEND_MIMO_PS, ++ /* BT Coex related */ ++ BTC_SET_ACT_CTRL_BT_INFO, ++ BTC_SET_ACT_CTRL_BT_COEX, ++ BTC_SET_ACT_CTRL_8723B_ANT, ++ /* */ ++ BTC_SET_MAX ++}BTC_SET_TYPE,*PBTC_SET_TYPE; ++ ++typedef enum _BTC_DBG_DISP_TYPE{ ++ BTC_DBG_DISP_COEX_STATISTICS = 0x0, ++ BTC_DBG_DISP_BT_LINK_INFO = 0x1, ++ BTC_DBG_DISP_FW_PWR_MODE_CMD = 0x2, ++ BTC_DBG_DISP_MAX ++}BTC_DBG_DISP_TYPE,*PBTC_DBG_DISP_TYPE; ++ ++typedef enum _BTC_NOTIFY_TYPE_IPS{ ++ BTC_IPS_LEAVE = 0x0, ++ BTC_IPS_ENTER = 0x1, ++ BTC_IPS_MAX ++}BTC_NOTIFY_TYPE_IPS,*PBTC_NOTIFY_TYPE_IPS; ++typedef enum _BTC_NOTIFY_TYPE_LPS{ ++ BTC_LPS_DISABLE = 0x0, ++ BTC_LPS_ENABLE = 0x1, ++ BTC_LPS_MAX ++}BTC_NOTIFY_TYPE_LPS,*PBTC_NOTIFY_TYPE_LPS; ++typedef enum _BTC_NOTIFY_TYPE_SCAN{ ++ BTC_SCAN_FINISH = 0x0, ++ BTC_SCAN_START = 0x1, ++ BTC_SCAN_MAX ++}BTC_NOTIFY_TYPE_SCAN,*PBTC_NOTIFY_TYPE_SCAN; ++typedef enum _BTC_NOTIFY_TYPE_ASSOCIATE{ ++ BTC_ASSOCIATE_FINISH = 0x0, ++ BTC_ASSOCIATE_START = 0x1, ++ BTC_ASSOCIATE_MAX ++}BTC_NOTIFY_TYPE_ASSOCIATE,*PBTC_NOTIFY_TYPE_ASSOCIATE; ++typedef enum _BTC_NOTIFY_TYPE_MEDIA_STATUS{ ++ BTC_MEDIA_DISCONNECT = 0x0, ++ BTC_MEDIA_CONNECT = 0x1, ++ BTC_MEDIA_MAX ++}BTC_NOTIFY_TYPE_MEDIA_STATUS,*PBTC_NOTIFY_TYPE_MEDIA_STATUS; ++typedef enum _BTC_NOTIFY_TYPE_SPECIAL_PACKET{ ++ BTC_PACKET_UNKNOWN = 0x0, ++ BTC_PACKET_DHCP = 0x1, ++ BTC_PACKET_ARP = 0x2, ++ BTC_PACKET_EAPOL = 0x3, ++ BTC_PACKET_MAX ++}BTC_NOTIFY_TYPE_SPECIAL_PACKET,*PBTC_NOTIFY_TYPE_SPECIAL_PACKET; ++typedef enum _BTC_NOTIFY_TYPE_STACK_OPERATION{ ++ BTC_STACK_OP_NONE = 0x0, ++ BTC_STACK_OP_INQ_PAGE_PAIR_START = 0x1, ++ BTC_STACK_OP_INQ_PAGE_PAIR_FINISH = 0x2, ++ BTC_STACK_OP_MAX ++}BTC_NOTIFY_TYPE_STACK_OPERATION,*PBTC_NOTIFY_TYPE_STACK_OPERATION; ++ ++/* Bryant Add */ ++typedef enum _BTC_ANTENNA_POS{ ++ BTC_ANTENNA_AT_MAIN_PORT = 0x1, ++ BTC_ANTENNA_AT_AUX_PORT = 0x2, ++}BTC_ANTENNA_POS,*PBTC_ANTENNA_POS; ++ ++typedef u8 ++(*BFP_BTC_R1)( ++void * pBtcContext, ++u32 RegAddr ++ ); ++typedef u16 ++(*BFP_BTC_R2)( ++void * pBtcContext, ++u32 RegAddr ++ ); ++typedef u32 ++(*BFP_BTC_R4)( ++void * pBtcContext, ++u32 RegAddr ++ ); ++typedef void ++(*BFP_BTC_W1)( ++void * pBtcContext, ++u32 RegAddr, ++u8 Data ++ ); ++typedef void ++(*BFP_BTC_W1_BIT_MASK)( ++void * pBtcContext, ++u32 regAddr, ++u8 bitMask, ++u8 data1b ++ ); ++typedef void ++(*BFP_BTC_W2)( ++void * pBtcContext, ++u32 RegAddr, ++u16 Data ++ ); ++typedef void ++(*BFP_BTC_W4)( ++void * pBtcContext, ++u32 RegAddr, ++u32 Data ++ ); ++typedef void ++(*BFP_BTC_LOCAL_REG_W1)( ++void * pBtcContext, ++u32 RegAddr, ++u8 Data ++ ); ++typedef void ++(*BFP_BTC_SET_BB_REG)( ++void * pBtcContext, ++u32 RegAddr, ++u32 BitMask, ++u32 Data ++ ); ++typedef u32 ++(*BFP_BTC_GET_BB_REG)( ++void * pBtcContext, ++u32 RegAddr, ++u32 BitMask ++ ); ++typedef void ++(*BFP_BTC_SET_RF_REG)( ++void * pBtcContext, ++u8 eRFPath, ++u32 RegAddr, ++u32 BitMask, ++u32 Data ++ ); ++typedef u32 ++(*BFP_BTC_GET_RF_REG)( ++void * pBtcContext, ++u8 eRFPath, ++u32 RegAddr, ++u32 BitMask ++ ); ++typedef void ++(*BFP_BTC_FILL_H2C)( ++void * pBtcContext, ++u8 elementId, ++u32 cmdLen, ++u8 * pCmdBuffer ++ ); ++ ++typedef u8 ++(*BFP_BTC_GET)( ++void * pBtCoexist, ++u8 getType, ++ void * pOutBuf ++ ); ++ ++typedef u8 ++(*BFP_BTC_SET)( ++void * pBtCoexist, ++u8 setType, ++ void * pInBuf ++ ); ++typedef void ++(*BFP_BTC_SET_BT_REG)( ++void * pBtcContext, ++u8 regType, ++u32 offset, ++u32 value ++ ); ++typedef u32 ++(*BFP_BTC_GET_BT_REG)( ++void * pBtcContext, ++u8 regType, ++u32 offset ++ ); ++typedef void ++(*BFP_BTC_DISP_DBG_MSG)( ++void * pBtCoexist, ++u8 dispType ++ ); ++ ++typedef struct _BTC_BT_INFO{ ++ bool bBtDisabled; ++ u8 rssiAdjustForAgcTableOn; ++ u8 rssiAdjustFor1AntCoexType; ++ bool bPreBtCtrlAggBufSize; ++ bool bBtCtrlAggBufSize; ++ bool bRejectAggPkt; ++ bool bIncreaseScanDevNum; ++ bool bBtTxRxMask; ++ u8 preAggBufSize; ++ u8 aggBufSize; ++ bool bBtBusy; ++ bool bLimitedDig; ++ u16 btHciVer; ++ u16 btRealFwVer; ++ u8 btFwVer; ++ u32 getBtFwVerCnt; ++ ++ bool bBtDisableLowPwr; ++ ++ bool bBtCtrlLps; ++ bool bBtLpsOn; ++ bool bForceToRoam; /* for 1Ant solution */ ++ u8 lpsVal; ++ u8 rpwmVal; ++ u32 raMask; ++} BTC_BT_INFO, *PBTC_BT_INFO; ++ ++typedef struct _BTC_STACK_INFO{ ++ bool bProfileNotified; ++ u16 hciVersion; /* stack hci version */ ++ u8 numOfLink; ++ bool bBtLinkExist; ++ bool bScoExist; ++ bool bAclExist; ++ bool bA2dpExist; ++ bool bHidExist; ++ u8 numOfHid; ++ bool bPanExist; ++ bool bUnknownAclExist; ++ s8 minBtRssi; ++} BTC_STACK_INFO, *PBTC_STACK_INFO; ++ ++typedef struct _BTC_BT_LINK_INFO{ ++ bool bBtLinkExist; ++ bool bScoExist; ++ bool bScoOnly; ++ bool bA2dpExist; ++ bool bA2dpOnly; ++ bool bHidExist; ++ bool bHidOnly; ++ bool bPanExist; ++ bool bPanOnly; ++ bool bSlaveRole; ++} BTC_BT_LINK_INFO, *PBTC_BT_LINK_INFO; ++ ++typedef struct _BTC_STATISTICS{ ++ u32 cntBind; ++ u32 cntPowerOn; ++ u32 cntInitHwConfig; ++ u32 cntInitCoexDm; ++ u32 cntIpsNotify; ++ u32 cntLpsNotify; ++ u32 cntScanNotify; ++ u32 cntConnectNotify; ++ u32 cntMediaStatusNotify; ++ u32 cntSpecialPacketNotify; ++ u32 cntBtInfoNotify; ++ u32 cntRfStatusNotify; ++ u32 cntPeriodical; ++ u32 cntCoexDmSwitch; ++ u32 cntStackOperationNotify; ++ u32 cntDbgCtrl; ++} BTC_STATISTICS, *PBTC_STATISTICS; ++ ++typedef struct _BTC_COEXIST{ ++ bool bBinded; /* make sure only one adapter can bind the data context */ ++ void * Adapter; /* default adapter */ ++ BTC_BOARD_INFO boardInfo; ++ BTC_BT_INFO btInfo; /* some bt info referenced by non-bt module */ ++ BTC_STACK_INFO stackInfo; ++ BTC_BT_LINK_INFO btLinkInfo; ++ BTC_CHIP_INTERFACE chipInterface; ++ ++ bool bInitilized; ++ bool bStopCoexDm; ++ bool bManualControl; ++ u8 * cliBuf; ++ BTC_STATISTICS statistics; ++ u8 pwrModeVal[10]; ++ ++ /* function pointers */ ++ /* io related */ ++ BFP_BTC_R1 fBtcRead1Byte; ++ BFP_BTC_W1 fBtcWrite1Byte; ++ BFP_BTC_W1_BIT_MASK fBtcWrite1ByteBitMask; ++ BFP_BTC_R2 fBtcRead2Byte; ++ BFP_BTC_W2 fBtcWrite2Byte; ++ BFP_BTC_R4 fBtcRead4Byte; ++ BFP_BTC_W4 fBtcWrite4Byte; ++ BFP_BTC_LOCAL_REG_W1 fBtcWriteLocalReg1Byte; ++ /* read/write bb related */ ++ BFP_BTC_SET_BB_REG fBtcSetBbReg; ++ BFP_BTC_GET_BB_REG fBtcGetBbReg; ++ ++ /* read/write rf related */ ++ BFP_BTC_SET_RF_REG fBtcSetRfReg; ++ BFP_BTC_GET_RF_REG fBtcGetRfReg; ++ ++ /* fill h2c related */ ++ BFP_BTC_FILL_H2C fBtcFillH2c; ++ /* other */ ++ BFP_BTC_DISP_DBG_MSG fBtcDispDbgMsg; ++ /* normal get/set related */ ++ BFP_BTC_GET fBtcGet; ++ BFP_BTC_SET fBtcSet; ++ ++ BFP_BTC_GET_BT_REG fBtcGetBtReg; ++ BFP_BTC_SET_BT_REG fBtcSetBtReg; ++} BTC_COEXIST, *PBTC_COEXIST; ++ ++extern BTC_COEXIST GLBtCoexist; ++ ++u8 ++EXhalbtcoutsrc_InitlizeVariables( ++void * Adapter ++ ); ++void ++EXhalbtcoutsrc_PowerOnSetting( ++PBTC_COEXIST pBtCoexist ++ ); ++void ++EXhalbtcoutsrc_InitHwConfig( ++PBTC_COEXIST pBtCoexist, ++u8 bWifiOnly ++ ); ++void ++EXhalbtcoutsrc_InitCoexDm( ++PBTC_COEXIST pBtCoexist ++ ); ++void ++EXhalbtcoutsrc_IpsNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ); ++void ++EXhalbtcoutsrc_LpsNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ); ++void ++EXhalbtcoutsrc_ScanNotify( ++PBTC_COEXIST pBtCoexist, ++u8 type ++ ); ++void ++EXhalbtcoutsrc_ConnectNotify( ++PBTC_COEXIST pBtCoexist, ++u8 action ++ ); ++void ++EXhalbtcoutsrc_MediaStatusNotify( ++PBTC_COEXIST pBtCoexist, ++RT_MEDIA_STATUS mediaStatus ++ ); ++void ++EXhalbtcoutsrc_SpecialPacketNotify( ++PBTC_COEXIST pBtCoexist, ++u8 pktType ++ ); ++void ++EXhalbtcoutsrc_BtInfoNotify( ++PBTC_COEXIST pBtCoexist, ++u8 * tmpBuf, ++u8 length ++ ); ++void ++EXhalbtcoutsrc_HaltNotify( ++PBTC_COEXIST pBtCoexist ++ ); ++void ++EXhalbtcoutsrc_PnpNotify( ++PBTC_COEXIST pBtCoexist, ++u8 pnpState ++ ); ++void ++EXhalbtcoutsrc_Periodical( ++PBTC_COEXIST pBtCoexist ++ ); ++void ++EXhalbtcoutsrc_SetChipType( ++u8 chipType ++ ); ++void ++EXhalbtcoutsrc_SetAntNum( ++u8 type, ++u8 antNum ++ ); ++void ++EXhalbtcoutsrc_SetSingleAntPath( ++u8 singleAntPath ++ ); ++void ++EXhalbtcoutsrc_DisplayBtCoexInfo( ++PBTC_COEXIST pBtCoexist ++ ); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/hal_com.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/hal_com.c +--- linux-4.3/3rdparty/rtl8723bs/hal/hal_com.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/hal_com.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,1464 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _HAL_COM_C_ ++ ++#include ++#include ++#include "hal_com_h2c.h" ++ ++#include "odm_precomp.h" ++ ++u8 rtw_hal_data_init(struct adapter *padapter) ++{ ++ if (is_primary_adapter(padapter)) /* if (padapter->isprimary) */ ++ { ++ padapter->hal_data_sz = sizeof(struct hal_com_data); ++ padapter->HalData = vzalloc(padapter->hal_data_sz); ++ if (padapter->HalData == NULL) { ++ DBG_8192C("cant not alloc memory for HAL DATA\n"); ++ return _FAIL; ++ } ++ } ++ return _SUCCESS; ++} ++ ++void rtw_hal_data_deinit(struct adapter *padapter) ++{ ++ if (is_primary_adapter(padapter)) /* if (padapter->isprimary) */ ++ { ++ if (padapter->HalData) ++ { ++ #ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE ++ phy_free_filebuf(padapter); ++ #endif ++ vfree(padapter->HalData); ++ padapter->HalData = NULL; ++ padapter->hal_data_sz = 0; ++ } ++ } ++} ++ ++ ++void dump_chip_info(HAL_VERSION ChipVersion) ++{ ++ int cnt = 0; ++ u8 buf[128]; ++ ++ cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8723B_"); ++ cnt += sprintf((buf+cnt), "%s_", IS_NORMAL_CHIP(ChipVersion)?"Normal_Chip":"Test_Chip"); ++ if (IS_CHIP_VENDOR_TSMC(ChipVersion)) ++ cnt += sprintf((buf+cnt), "%s_","TSMC"); ++ else if (IS_CHIP_VENDOR_UMC(ChipVersion)) ++ cnt += sprintf((buf+cnt), "%s_","UMC"); ++ else if (IS_CHIP_VENDOR_SMIC(ChipVersion)) ++ cnt += sprintf((buf+cnt), "%s_","SMIC"); ++ ++ if (IS_A_CUT(ChipVersion)) cnt += sprintf((buf+cnt), "A_CUT_"); ++ else if (IS_B_CUT(ChipVersion)) cnt += sprintf((buf+cnt), "B_CUT_"); ++ else if (IS_C_CUT(ChipVersion)) cnt += sprintf((buf+cnt), "C_CUT_"); ++ else if (IS_D_CUT(ChipVersion)) cnt += sprintf((buf+cnt), "D_CUT_"); ++ else if (IS_E_CUT(ChipVersion)) cnt += sprintf((buf+cnt), "E_CUT_"); ++ else if (IS_I_CUT(ChipVersion)) cnt += sprintf((buf+cnt), "I_CUT_"); ++ else if (IS_J_CUT(ChipVersion)) cnt += sprintf((buf+cnt), "J_CUT_"); ++ else if (IS_K_CUT(ChipVersion)) cnt += sprintf((buf+cnt), "K_CUT_"); ++ else cnt += sprintf((buf+cnt), "UNKNOWN_CUT(%d)_", ChipVersion.CUTVersion); ++ ++ if (IS_1T1R(ChipVersion)) cnt += sprintf((buf+cnt), "1T1R_"); ++ else if (IS_1T2R(ChipVersion)) cnt += sprintf((buf+cnt), "1T2R_"); ++ else if (IS_2T2R(ChipVersion)) cnt += sprintf((buf+cnt), "2T2R_"); ++ else cnt += sprintf((buf+cnt), "UNKNOWN_RFTYPE(%d)_", ChipVersion.RFType); ++ ++ cnt += sprintf((buf+cnt), "RomVer(%d)\n", ChipVersion.ROMVer); ++ ++ DBG_871X("%s", buf); ++} ++ ++ ++#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 ++ ++/* ++ * Description: ++ *Use hardware(efuse), driver parameter(registry) and default channel plan ++ *to decide which one should be used. ++ * ++ * Parameters: ++ *padapter pointer of adapter ++ *hw_channel_plan channel plan from HW (efuse/eeprom) ++ * BIT[7] software configure mode; 0:Enable, 1:disable ++ * BIT[6:0] Channel Plan ++ *sw_channel_plan channel plan from SW (registry/module param) ++ *def_channel_plan channel plan used when HW/SW both invalid ++ *AutoLoadFail efuse autoload fail or not ++ * ++ * Return: ++ *Final channel plan decision ++ * ++ */ ++u8 ++hal_com_config_channel_plan( ++struct adapter *padapter, ++u8 hw_channel_plan, ++u8 sw_channel_plan, ++u8 def_channel_plan, ++bool AutoLoadFail ++ ) ++{ ++ struct hal_com_data *pHalData; ++ u8 chnlPlan; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ pHalData->bDisableSWChannelPlan = false; ++ chnlPlan = def_channel_plan; ++ ++ if (0xFF == hw_channel_plan) ++ AutoLoadFail = true; ++ ++ if (false == AutoLoadFail) ++ { ++ u8 hw_chnlPlan; ++ ++ hw_chnlPlan = hw_channel_plan & (~EEPROM_CHANNEL_PLAN_BY_HW_MASK); ++ if (rtw_is_channel_plan_valid(hw_chnlPlan)) ++ { ++#ifndef CONFIG_SW_CHANNEL_PLAN ++ if (hw_channel_plan & EEPROM_CHANNEL_PLAN_BY_HW_MASK) ++ pHalData->bDisableSWChannelPlan = true; ++#endif /* !CONFIG_SW_CHANNEL_PLAN */ ++ ++ chnlPlan = hw_chnlPlan; ++ } ++ } ++ ++ if ((false == pHalData->bDisableSWChannelPlan) ++ && rtw_is_channel_plan_valid(sw_channel_plan)) ++ { ++ chnlPlan = sw_channel_plan; ++ } ++ ++ return chnlPlan; ++} ++ ++bool ++HAL_IsLegalChannel( ++struct adapter *Adapter, ++u32 Channel ++ ) ++{ ++ bool bLegalChannel = true; ++ ++ if (Channel > 14) { ++ bLegalChannel = false; ++ DBG_871X("Channel > 14 but wireless_mode do not support 5G\n"); ++ } else if ((Channel <= 14) && (Channel >= 1)) { ++ if (IsSupported24G(Adapter->registrypriv.wireless_mode) == false) { ++ bLegalChannel = false; ++ DBG_871X("(Channel <= 14) && (Channel >= 1) but wireless_mode do not support 2.4G\n"); ++ } ++ } else { ++ bLegalChannel = false; ++ DBG_871X("Channel is Invalid !!!\n"); ++ } ++ ++ return bLegalChannel; ++} ++ ++u8 MRateToHwRate(u8 rate) ++{ ++ u8 ret = DESC_RATE1M; ++ ++ switch (rate) ++ { ++ case MGN_1M: ret = DESC_RATE1M; break; ++ case MGN_2M: ret = DESC_RATE2M; break; ++ case MGN_5_5M: ret = DESC_RATE5_5M; break; ++ case MGN_11M: ret = DESC_RATE11M; break; ++ case MGN_6M: ret = DESC_RATE6M; break; ++ case MGN_9M: ret = DESC_RATE9M; break; ++ case MGN_12M: ret = DESC_RATE12M; break; ++ case MGN_18M: ret = DESC_RATE18M; break; ++ case MGN_24M: ret = DESC_RATE24M; break; ++ case MGN_36M: ret = DESC_RATE36M; break; ++ case MGN_48M: ret = DESC_RATE48M; break; ++ case MGN_54M: ret = DESC_RATE54M; break; ++ ++ case MGN_MCS0: ret = DESC_RATEMCS0; break; ++ case MGN_MCS1: ret = DESC_RATEMCS1; break; ++ case MGN_MCS2: ret = DESC_RATEMCS2; break; ++ case MGN_MCS3: ret = DESC_RATEMCS3; break; ++ case MGN_MCS4: ret = DESC_RATEMCS4; break; ++ case MGN_MCS5: ret = DESC_RATEMCS5; break; ++ case MGN_MCS6: ret = DESC_RATEMCS6; break; ++ case MGN_MCS7: ret = DESC_RATEMCS7; break; ++ case MGN_MCS8: ret = DESC_RATEMCS8; break; ++ case MGN_MCS9: ret = DESC_RATEMCS9; break; ++ case MGN_MCS10: ret = DESC_RATEMCS10; break; ++ case MGN_MCS11: ret = DESC_RATEMCS11; break; ++ case MGN_MCS12: ret = DESC_RATEMCS12; break; ++ case MGN_MCS13: ret = DESC_RATEMCS13; break; ++ case MGN_MCS14: ret = DESC_RATEMCS14; break; ++ case MGN_MCS15: ret = DESC_RATEMCS15; break; ++ case MGN_MCS16: ret = DESC_RATEMCS16; break; ++ case MGN_MCS17: ret = DESC_RATEMCS17; break; ++ case MGN_MCS18: ret = DESC_RATEMCS18; break; ++ case MGN_MCS19: ret = DESC_RATEMCS19; break; ++ case MGN_MCS20: ret = DESC_RATEMCS20; break; ++ case MGN_MCS21: ret = DESC_RATEMCS21; break; ++ case MGN_MCS22: ret = DESC_RATEMCS22; break; ++ case MGN_MCS23: ret = DESC_RATEMCS23; break; ++ case MGN_MCS24: ret = DESC_RATEMCS24; break; ++ case MGN_MCS25: ret = DESC_RATEMCS25; break; ++ case MGN_MCS26: ret = DESC_RATEMCS26; break; ++ case MGN_MCS27: ret = DESC_RATEMCS27; break; ++ case MGN_MCS28: ret = DESC_RATEMCS28; break; ++ case MGN_MCS29: ret = DESC_RATEMCS29; break; ++ case MGN_MCS30: ret = DESC_RATEMCS30; break; ++ case MGN_MCS31: ret = DESC_RATEMCS31; break; ++ ++ case MGN_VHT1SS_MCS0: ret = DESC_RATEVHTSS1MCS0; break; ++ case MGN_VHT1SS_MCS1: ret = DESC_RATEVHTSS1MCS1; break; ++ case MGN_VHT1SS_MCS2: ret = DESC_RATEVHTSS1MCS2; break; ++ case MGN_VHT1SS_MCS3: ret = DESC_RATEVHTSS1MCS3; break; ++ case MGN_VHT1SS_MCS4: ret = DESC_RATEVHTSS1MCS4; break; ++ case MGN_VHT1SS_MCS5: ret = DESC_RATEVHTSS1MCS5; break; ++ case MGN_VHT1SS_MCS6: ret = DESC_RATEVHTSS1MCS6; break; ++ case MGN_VHT1SS_MCS7: ret = DESC_RATEVHTSS1MCS7; break; ++ case MGN_VHT1SS_MCS8: ret = DESC_RATEVHTSS1MCS8; break; ++ case MGN_VHT1SS_MCS9: ret = DESC_RATEVHTSS1MCS9; break; ++ case MGN_VHT2SS_MCS0: ret = DESC_RATEVHTSS2MCS0; break; ++ case MGN_VHT2SS_MCS1: ret = DESC_RATEVHTSS2MCS1; break; ++ case MGN_VHT2SS_MCS2: ret = DESC_RATEVHTSS2MCS2; break; ++ case MGN_VHT2SS_MCS3: ret = DESC_RATEVHTSS2MCS3; break; ++ case MGN_VHT2SS_MCS4: ret = DESC_RATEVHTSS2MCS4; break; ++ case MGN_VHT2SS_MCS5: ret = DESC_RATEVHTSS2MCS5; break; ++ case MGN_VHT2SS_MCS6: ret = DESC_RATEVHTSS2MCS6; break; ++ case MGN_VHT2SS_MCS7: ret = DESC_RATEVHTSS2MCS7; break; ++ case MGN_VHT2SS_MCS8: ret = DESC_RATEVHTSS2MCS8; break; ++ case MGN_VHT2SS_MCS9: ret = DESC_RATEVHTSS2MCS9; break; ++ case MGN_VHT3SS_MCS0: ret = DESC_RATEVHTSS3MCS0; break; ++ case MGN_VHT3SS_MCS1: ret = DESC_RATEVHTSS3MCS1; break; ++ case MGN_VHT3SS_MCS2: ret = DESC_RATEVHTSS3MCS2; break; ++ case MGN_VHT3SS_MCS3: ret = DESC_RATEVHTSS3MCS3; break; ++ case MGN_VHT3SS_MCS4: ret = DESC_RATEVHTSS3MCS4; break; ++ case MGN_VHT3SS_MCS5: ret = DESC_RATEVHTSS3MCS5; break; ++ case MGN_VHT3SS_MCS6: ret = DESC_RATEVHTSS3MCS6; break; ++ case MGN_VHT3SS_MCS7: ret = DESC_RATEVHTSS3MCS7; break; ++ case MGN_VHT3SS_MCS8: ret = DESC_RATEVHTSS3MCS8; break; ++ case MGN_VHT3SS_MCS9: ret = DESC_RATEVHTSS3MCS9; break; ++ case MGN_VHT4SS_MCS0: ret = DESC_RATEVHTSS4MCS0; break; ++ case MGN_VHT4SS_MCS1: ret = DESC_RATEVHTSS4MCS1; break; ++ case MGN_VHT4SS_MCS2: ret = DESC_RATEVHTSS4MCS2; break; ++ case MGN_VHT4SS_MCS3: ret = DESC_RATEVHTSS4MCS3; break; ++ case MGN_VHT4SS_MCS4: ret = DESC_RATEVHTSS4MCS4; break; ++ case MGN_VHT4SS_MCS5: ret = DESC_RATEVHTSS4MCS5; break; ++ case MGN_VHT4SS_MCS6: ret = DESC_RATEVHTSS4MCS6; break; ++ case MGN_VHT4SS_MCS7: ret = DESC_RATEVHTSS4MCS7; break; ++ case MGN_VHT4SS_MCS8: ret = DESC_RATEVHTSS4MCS8; break; ++ case MGN_VHT4SS_MCS9: ret = DESC_RATEVHTSS4MCS9; break; ++ default: break; ++ } ++ ++ return ret; ++} ++ ++u8 HwRateToMRate(u8 rate) ++{ ++ u8 ret_rate = MGN_1M; ++ ++ switch (rate) ++ { ++ ++ case DESC_RATE1M: ret_rate = MGN_1M; break; ++ case DESC_RATE2M: ret_rate = MGN_2M; break; ++ case DESC_RATE5_5M: ret_rate = MGN_5_5M; break; ++ case DESC_RATE11M: ret_rate = MGN_11M; break; ++ case DESC_RATE6M: ret_rate = MGN_6M; break; ++ case DESC_RATE9M: ret_rate = MGN_9M; break; ++ case DESC_RATE12M: ret_rate = MGN_12M; break; ++ case DESC_RATE18M: ret_rate = MGN_18M; break; ++ case DESC_RATE24M: ret_rate = MGN_24M; break; ++ case DESC_RATE36M: ret_rate = MGN_36M; break; ++ case DESC_RATE48M: ret_rate = MGN_48M; break; ++ case DESC_RATE54M: ret_rate = MGN_54M; break; ++ case DESC_RATEMCS0: ret_rate = MGN_MCS0; break; ++ case DESC_RATEMCS1: ret_rate = MGN_MCS1; break; ++ case DESC_RATEMCS2: ret_rate = MGN_MCS2; break; ++ case DESC_RATEMCS3: ret_rate = MGN_MCS3; break; ++ case DESC_RATEMCS4: ret_rate = MGN_MCS4; break; ++ case DESC_RATEMCS5: ret_rate = MGN_MCS5; break; ++ case DESC_RATEMCS6: ret_rate = MGN_MCS6; break; ++ case DESC_RATEMCS7: ret_rate = MGN_MCS7; break; ++ case DESC_RATEMCS8: ret_rate = MGN_MCS8; break; ++ case DESC_RATEMCS9: ret_rate = MGN_MCS9; break; ++ case DESC_RATEMCS10: ret_rate = MGN_MCS10; break; ++ case DESC_RATEMCS11: ret_rate = MGN_MCS11; break; ++ case DESC_RATEMCS12: ret_rate = MGN_MCS12; break; ++ case DESC_RATEMCS13: ret_rate = MGN_MCS13; break; ++ case DESC_RATEMCS14: ret_rate = MGN_MCS14; break; ++ case DESC_RATEMCS15: ret_rate = MGN_MCS15; break; ++ case DESC_RATEMCS16: ret_rate = MGN_MCS16; break; ++ case DESC_RATEMCS17: ret_rate = MGN_MCS17; break; ++ case DESC_RATEMCS18: ret_rate = MGN_MCS18; break; ++ case DESC_RATEMCS19: ret_rate = MGN_MCS19; break; ++ case DESC_RATEMCS20: ret_rate = MGN_MCS20; break; ++ case DESC_RATEMCS21: ret_rate = MGN_MCS21; break; ++ case DESC_RATEMCS22: ret_rate = MGN_MCS22; break; ++ case DESC_RATEMCS23: ret_rate = MGN_MCS23; break; ++ case DESC_RATEMCS24: ret_rate = MGN_MCS24; break; ++ case DESC_RATEMCS25: ret_rate = MGN_MCS25; break; ++ case DESC_RATEMCS26: ret_rate = MGN_MCS26; break; ++ case DESC_RATEMCS27: ret_rate = MGN_MCS27; break; ++ case DESC_RATEMCS28: ret_rate = MGN_MCS28; break; ++ case DESC_RATEMCS29: ret_rate = MGN_MCS29; break; ++ case DESC_RATEMCS30: ret_rate = MGN_MCS30; break; ++ case DESC_RATEMCS31: ret_rate = MGN_MCS31; break; ++ case DESC_RATEVHTSS1MCS0: ret_rate = MGN_VHT1SS_MCS0; break; ++ case DESC_RATEVHTSS1MCS1: ret_rate = MGN_VHT1SS_MCS1; break; ++ case DESC_RATEVHTSS1MCS2: ret_rate = MGN_VHT1SS_MCS2; break; ++ case DESC_RATEVHTSS1MCS3: ret_rate = MGN_VHT1SS_MCS3; break; ++ case DESC_RATEVHTSS1MCS4: ret_rate = MGN_VHT1SS_MCS4; break; ++ case DESC_RATEVHTSS1MCS5: ret_rate = MGN_VHT1SS_MCS5; break; ++ case DESC_RATEVHTSS1MCS6: ret_rate = MGN_VHT1SS_MCS6; break; ++ case DESC_RATEVHTSS1MCS7: ret_rate = MGN_VHT1SS_MCS7; break; ++ case DESC_RATEVHTSS1MCS8: ret_rate = MGN_VHT1SS_MCS8; break; ++ case DESC_RATEVHTSS1MCS9: ret_rate = MGN_VHT1SS_MCS9; break; ++ case DESC_RATEVHTSS2MCS0: ret_rate = MGN_VHT2SS_MCS0; break; ++ case DESC_RATEVHTSS2MCS1: ret_rate = MGN_VHT2SS_MCS1; break; ++ case DESC_RATEVHTSS2MCS2: ret_rate = MGN_VHT2SS_MCS2; break; ++ case DESC_RATEVHTSS2MCS3: ret_rate = MGN_VHT2SS_MCS3; break; ++ case DESC_RATEVHTSS2MCS4: ret_rate = MGN_VHT2SS_MCS4; break; ++ case DESC_RATEVHTSS2MCS5: ret_rate = MGN_VHT2SS_MCS5; break; ++ case DESC_RATEVHTSS2MCS6: ret_rate = MGN_VHT2SS_MCS6; break; ++ case DESC_RATEVHTSS2MCS7: ret_rate = MGN_VHT2SS_MCS7; break; ++ case DESC_RATEVHTSS2MCS8: ret_rate = MGN_VHT2SS_MCS8; break; ++ case DESC_RATEVHTSS2MCS9: ret_rate = MGN_VHT2SS_MCS9; break; ++ case DESC_RATEVHTSS3MCS0: ret_rate = MGN_VHT3SS_MCS0; break; ++ case DESC_RATEVHTSS3MCS1: ret_rate = MGN_VHT3SS_MCS1; break; ++ case DESC_RATEVHTSS3MCS2: ret_rate = MGN_VHT3SS_MCS2; break; ++ case DESC_RATEVHTSS3MCS3: ret_rate = MGN_VHT3SS_MCS3; break; ++ case DESC_RATEVHTSS3MCS4: ret_rate = MGN_VHT3SS_MCS4; break; ++ case DESC_RATEVHTSS3MCS5: ret_rate = MGN_VHT3SS_MCS5; break; ++ case DESC_RATEVHTSS3MCS6: ret_rate = MGN_VHT3SS_MCS6; break; ++ case DESC_RATEVHTSS3MCS7: ret_rate = MGN_VHT3SS_MCS7; break; ++ case DESC_RATEVHTSS3MCS8: ret_rate = MGN_VHT3SS_MCS8; break; ++ case DESC_RATEVHTSS3MCS9: ret_rate = MGN_VHT3SS_MCS9; break; ++ case DESC_RATEVHTSS4MCS0: ret_rate = MGN_VHT4SS_MCS0; break; ++ case DESC_RATEVHTSS4MCS1: ret_rate = MGN_VHT4SS_MCS1; break; ++ case DESC_RATEVHTSS4MCS2: ret_rate = MGN_VHT4SS_MCS2; break; ++ case DESC_RATEVHTSS4MCS3: ret_rate = MGN_VHT4SS_MCS3; break; ++ case DESC_RATEVHTSS4MCS4: ret_rate = MGN_VHT4SS_MCS4; break; ++ case DESC_RATEVHTSS4MCS5: ret_rate = MGN_VHT4SS_MCS5; break; ++ case DESC_RATEVHTSS4MCS6: ret_rate = MGN_VHT4SS_MCS6; break; ++ case DESC_RATEVHTSS4MCS7: ret_rate = MGN_VHT4SS_MCS7; break; ++ case DESC_RATEVHTSS4MCS8: ret_rate = MGN_VHT4SS_MCS8; break; ++ case DESC_RATEVHTSS4MCS9: ret_rate = MGN_VHT4SS_MCS9; break; ++ ++ default: ++ DBG_871X("HwRateToMRate(): Non supported Rate [%x]!!!\n", rate); ++ break; ++ } ++ ++ return ret_rate; ++} ++ ++void HalSetBrateCfg(struct adapter *Adapter, u8 *mBratesOS, u16 *pBrateCfg) ++{ ++ u8 i, is_brate, brate; ++ ++ for (i = 0;i < NDIS_802_11_LENGTH_RATES_EX; i++) { ++ is_brate = mBratesOS[i] & IEEE80211_BASIC_RATE_MASK; ++ brate = mBratesOS[i] & 0x7f; ++ ++ if (is_brate) { ++ switch (brate) { ++ case IEEE80211_CCK_RATE_1MB: ++ *pBrateCfg |= RATE_1M; ++ break; ++ case IEEE80211_CCK_RATE_2MB: ++ *pBrateCfg |= RATE_2M; ++ break; ++ case IEEE80211_CCK_RATE_5MB: ++ *pBrateCfg |= RATE_5_5M; ++ break; ++ case IEEE80211_CCK_RATE_11MB: ++ *pBrateCfg |= RATE_11M; ++ break; ++ case IEEE80211_OFDM_RATE_6MB: ++ *pBrateCfg |= RATE_6M; ++ break; ++ case IEEE80211_OFDM_RATE_9MB: ++ *pBrateCfg |= RATE_9M; ++ break; ++ case IEEE80211_OFDM_RATE_12MB: ++ *pBrateCfg |= RATE_12M; ++ break; ++ case IEEE80211_OFDM_RATE_18MB: ++ *pBrateCfg |= RATE_18M; ++ break; ++ case IEEE80211_OFDM_RATE_24MB: ++ *pBrateCfg |= RATE_24M; ++ break; ++ case IEEE80211_OFDM_RATE_36MB: ++ *pBrateCfg |= RATE_36M; ++ break; ++ case IEEE80211_OFDM_RATE_48MB: ++ *pBrateCfg |= RATE_48M; ++ break; ++ case IEEE80211_OFDM_RATE_54MB: ++ *pBrateCfg |= RATE_54M; ++ break; ++ } ++ } ++ } ++} ++ ++static void _OneOutPipeMapping(struct adapter *padapter) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ ++ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ ++ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */ ++ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[0];/* BE */ ++ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];/* BK */ ++ ++ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ ++ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ ++ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ ++ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ ++} ++ ++static void ++_TwoOutPipeMapping( ++struct adapter *padapter, ++bool bWIFICfg ++ ) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ ++ if (bWIFICfg) { /* WMM */ ++ ++ /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */ ++ /* 0, 1, 0, 1, 0, 0, 0, 0, 0 }; */ ++ /* 0:ep_0 num, 1:ep_1 num */ ++ ++ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[1];/* VO */ ++ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */ ++ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1];/* BE */ ++ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];/* BK */ ++ ++ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ ++ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ ++ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ ++ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ ++ ++ } ++ else {/* typical setting */ ++ ++ ++ /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */ ++ /* 1, 1, 0, 0, 0, 0, 0, 0, 0 }; */ ++ /* 0:ep_0 num, 1:ep_1 num */ ++ ++ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ ++ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */ ++ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1];/* BE */ ++ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];/* BK */ ++ ++ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ ++ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ ++ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ ++ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ ++ ++ } ++ ++} ++ ++static void _ThreeOutPipeMapping( ++struct adapter *padapter, ++bool bWIFICfg ++ ) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ ++ if (bWIFICfg) {/* for WMM */ ++ ++ /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */ ++ /* 1, 2, 1, 0, 0, 0, 0, 0, 0 }; */ ++ /* 0:H, 1:N, 2:L */ ++ ++ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ ++ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */ ++ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */ ++ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];/* BK */ ++ ++ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ ++ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ ++ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ ++ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ ++ ++ } ++ else {/* typical setting */ ++ ++ ++ /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */ ++ /* 2, 2, 1, 0, 0, 0, 0, 0, 0 }; */ ++ /* 0:H, 1:N, 2:L */ ++ ++ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ ++ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */ ++ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */ ++ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[2];/* BK */ ++ ++ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ ++ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ ++ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ ++ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ ++ } ++ ++} ++ ++bool ++Hal_MappingOutPipe( ++struct adapter *padapter, ++u8 NumOutPipe ++ ) ++{ ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ ++ bool bWIFICfg = (pregistrypriv->wifi_spec) ?true:false; ++ ++ bool result = true; ++ ++ switch (NumOutPipe) ++ { ++ case 2: ++ _TwoOutPipeMapping(padapter, bWIFICfg); ++ break; ++ case 3: ++ case 4: ++ _ThreeOutPipeMapping(padapter, bWIFICfg); ++ break; ++ case 1: ++ _OneOutPipeMapping(padapter); ++ break; ++ default: ++ result = false; ++ break; ++ } ++ ++ return result; ++ ++} ++ ++void hal_init_macaddr(struct adapter *adapter) ++{ ++ rtw_hal_set_hwreg(adapter, HW_VAR_MAC_ADDR, adapter->eeprompriv.mac_addr); ++} ++ ++void rtw_init_hal_com_default_value(struct adapter * Adapter) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++ pHalData->AntDetection = 1; ++} ++ ++/* ++* C2H event format: ++* Field TRIGGER CONTENT CMD_SEQ CMD_LEN CMD_ID ++* BITS [127:120] [119:16] [15:8] [7:4] [3:0] ++*/ ++ ++void c2h_evt_clear(struct adapter *adapter) ++{ ++ rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE); ++} ++ ++/* ++* C2H event format: ++* Field TRIGGER CMD_LEN CONTENT CMD_SEQ CMD_ID ++* BITS [127:120] [119:112] [111:16] [15:8] [7:0] ++*/ ++s32 c2h_evt_read_88xx(struct adapter *adapter, u8 *buf) ++{ ++ s32 ret = _FAIL; ++ struct c2h_evt_hdr_88xx *c2h_evt; ++ int i; ++ u8 trigger; ++ ++ if (buf == NULL) ++ goto exit; ++ ++ trigger = rtw_read8(adapter, REG_C2HEVT_CLEAR); ++ ++ if (trigger == C2H_EVT_HOST_CLOSE) { ++ goto exit; /* Not ready */ ++ } else if (trigger != C2H_EVT_FW_CLOSE) { ++ goto clear_evt; /* Not a valid value */ ++ } ++ ++ c2h_evt = (struct c2h_evt_hdr_88xx *)buf; ++ ++ memset(c2h_evt, 0, 16); ++ ++ c2h_evt->id = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL); ++ c2h_evt->seq = rtw_read8(adapter, REG_C2HEVT_CMD_SEQ_88XX); ++ c2h_evt->plen = rtw_read8(adapter, REG_C2HEVT_CMD_LEN_88XX); ++ ++ RT_PRINT_DATA(_module_hal_init_c_, _drv_info_, "c2h_evt_read(): ", ++ &c2h_evt , sizeof(c2h_evt)); ++ ++ DBG_871X("%s id:%u, len:%u, seq:%u, trigger:0x%02x\n", __func__ ++ , c2h_evt->id, c2h_evt->plen, c2h_evt->seq, trigger); ++ ++ /* Read the content */ ++ for (i = 0; i < c2h_evt->plen; i++) ++ c2h_evt->payload[i] = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + 2 + i); ++ ++ RT_PRINT_DATA(_module_hal_init_c_, _drv_info_, "c2h_evt_read(): Command Content:\n", ++ c2h_evt->payload, c2h_evt->plen); ++ ++ ret = _SUCCESS; ++ ++clear_evt: ++ /* ++ * Clear event to notify FW we have read the command. ++ * If this field isn't clear, the FW won't update the next command message. ++ */ ++ c2h_evt_clear(adapter); ++exit: ++ return ret; ++} ++ ++ ++u8 rtw_hal_networktype_to_raid(struct adapter *adapter, struct sta_info *psta) ++{ ++ return networktype_to_raid_ex(adapter, psta); ++} ++u8 rtw_get_mgntframe_raid(struct adapter *adapter, unsigned char network_type) ++{ ++ ++ u8 raid; ++ raid = (network_type & WIRELESS_11B) ?RATEID_IDX_B ++ :RATEID_IDX_G; ++ return raid; ++} ++ ++void rtw_hal_update_sta_rate_mask(struct adapter *padapter, struct sta_info *psta) ++{ ++ u8 i, rf_type, limit; ++ u32 tx_ra_bitmap; ++ ++ if (psta == NULL) ++ { ++ return; ++ } ++ ++ tx_ra_bitmap = 0; ++ ++ /* b/g mode ra_bitmap */ ++ for (i = 0; ibssrateset); i++) ++ { ++ if (psta->bssrateset[i]) ++ tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i]&0x7f); ++ } ++ ++ /* n mode ra_bitmap */ ++ if (psta->htpriv.ht_option) ++ { ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ if (rf_type == RF_2T2R) ++ limit = 16;/* 2R */ ++ else ++ limit =8;/* 1R */ ++ ++ for (i = 0; ihtpriv.ht_cap.supp_mcs_set[i/8] & BIT(i%8)) ++ tx_ra_bitmap |= BIT(i+12); ++ } ++ } ++ ++ psta->ra_mask = tx_ra_bitmap; ++ psta->init_rate = get_highest_rate_idx(tx_ra_bitmap)&0x3f; ++} ++ ++void hw_var_port_switch (struct adapter *adapter) ++{ ++} ++ ++void SetHwReg(struct adapter *adapter, u8 variable, u8 *val) ++{ ++ struct hal_com_data *hal_data = GET_HAL_DATA(adapter); ++ DM_ODM_T *odm = &(hal_data->odmpriv); ++ ++ switch (variable) { ++ case HW_VAR_PORT_SWITCH: ++ hw_var_port_switch (adapter); ++ break; ++ case HW_VAR_INIT_RTS_RATE: ++ rtw_warn_on(1); ++ break; ++ case HW_VAR_SEC_CFG: ++ { ++ u16 reg_scr; ++ ++ reg_scr = rtw_read16(adapter, REG_SECCFG); ++ rtw_write16(adapter, REG_SECCFG, reg_scr|SCR_CHK_KEYID|SCR_RxDecEnable|SCR_TxEncEnable); ++ } ++ break; ++ case HW_VAR_SEC_DK_CFG: ++ { ++ struct security_priv *sec = &adapter->securitypriv; ++ u8 reg_scr = rtw_read8(adapter, REG_SECCFG); ++ ++ if (val) /* Enable default key related setting */ ++ { ++ reg_scr |= SCR_TXBCUSEDK; ++ if (sec->dot11AuthAlgrthm != dot11AuthAlgrthm_8021X) ++ reg_scr |= (SCR_RxUseDK|SCR_TxUseDK); ++ } ++ else /* Disable default key related setting */ ++ { ++ reg_scr &= ~(SCR_RXBCUSEDK|SCR_TXBCUSEDK|SCR_RxUseDK|SCR_TxUseDK); ++ } ++ ++ rtw_write8(adapter, REG_SECCFG, reg_scr); ++ } ++ break; ++ case HW_VAR_DM_FLAG: ++ odm->SupportAbility = *((u32*)val); ++ break; ++ case HW_VAR_DM_FUNC_OP: ++ if (*((u8 *)val) == true) { ++ /* save dm flag */ ++ odm->BK_SupportAbility = odm->SupportAbility; ++ } else { ++ /* restore dm flag */ ++ odm->SupportAbility = odm->BK_SupportAbility; ++ } ++ break; ++ case HW_VAR_DM_FUNC_SET: ++ if (*((u32*)val) == DYNAMIC_ALL_FUNC_ENABLE) { ++ struct dm_priv *dm = &hal_data->dmpriv; ++ dm->DMFlag = dm->InitDMFlag; ++ odm->SupportAbility = dm->InitODMFlag; ++ } else { ++ odm->SupportAbility |= *((u32 *)val); ++ } ++ break; ++ case HW_VAR_DM_FUNC_CLR: ++ /* ++ * input is already a mask to clear function ++ * don't invert it again! George, Lucas@20130513 ++ */ ++ odm->SupportAbility &= *((u32 *)val); ++ break; ++ case HW_VAR_AMPDU_MIN_SPACE: ++ /* TODO - Is something needed here? */ ++ break; ++ case HW_VAR_WIRELESS_MODE: ++ /* TODO - Is something needed here? */ ++ break; ++ default: ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" variable(%d) not defined!\n", ++ FUNC_ADPT_ARG(adapter), variable); ++ break; ++ } ++} ++ ++void GetHwReg(struct adapter *adapter, u8 variable, u8 *val) ++{ ++ struct hal_com_data *hal_data = GET_HAL_DATA(adapter); ++ DM_ODM_T *odm = &(hal_data->odmpriv); ++ ++ switch (variable) { ++ case HW_VAR_BASIC_RATE: ++ *((u16*)val) = hal_data->BasicRateSet; ++ break; ++ case HW_VAR_DM_FLAG: ++ *((u32*)val) = odm->SupportAbility; ++ break; ++ case HW_VAR_RF_TYPE: ++ *((u8 *)val) = hal_data->rf_type; ++ break; ++ default: ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" variable(%d) not defined!\n", ++ FUNC_ADPT_ARG(adapter), variable); ++ break; ++ } ++} ++ ++ ++ ++ ++u8 ++SetHalDefVar(struct adapter *adapter, enum HAL_DEF_VARIABLE variable, void *value) ++{ ++ struct hal_com_data *hal_data = GET_HAL_DATA(adapter); ++ DM_ODM_T *odm = &(hal_data->odmpriv); ++ u8 bResult = _SUCCESS; ++ ++ switch (variable) { ++ case HW_DEF_FA_CNT_DUMP: ++ /* ODM_COMP_COMMON */ ++ if (*((u8 *)value)) ++ odm->DebugComponents |= (ODM_COMP_DIG |ODM_COMP_FA_CNT); ++ else ++ odm->DebugComponents &= ~(ODM_COMP_DIG |ODM_COMP_FA_CNT); ++ break; ++ case HAL_DEF_DBG_RX_INFO_DUMP: ++ DBG_871X("============ Rx Info dump ===================\n"); ++ DBG_871X("bLinked = %d, RSSI_Min = %d(%%)\n", ++ odm->bLinked, odm->RSSI_Min); ++ ++ if (odm->bLinked) { ++ DBG_871X("RxRate = %s, RSSI_A = %d(%%), RSSI_B = %d(%%)\n", ++ HDATA_RATE(odm->RxRate), odm->RSSI_A, odm->RSSI_B); ++ ++ #ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA ++ rtw_dump_raw_rssi_info(adapter); ++ #endif ++ } ++ break; ++ case HW_DEF_ODM_DBG_FLAG: ++ ODM_CmnInfoUpdate(odm, ODM_CMNINFO_DBG_COMP, *((u64*)value)); ++ break; ++ case HW_DEF_ODM_DBG_LEVEL: ++ ODM_CmnInfoUpdate(odm, ODM_CMNINFO_DBG_LEVEL, *((u32*)value)); ++ break; ++ case HAL_DEF_DBG_DM_FUNC: ++ { ++ u8 dm_func = *((u8 *)value); ++ struct dm_priv *dm = &hal_data->dmpriv; ++ ++ if (dm_func == 0) { /* disable all dynamic func */ ++ odm->SupportAbility = DYNAMIC_FUNC_DISABLE; ++ DBG_8192C("==> Disable all dynamic function...\n"); ++ } ++ else if (dm_func == 1) {/* disable DIG */ ++ odm->SupportAbility &= (~DYNAMIC_BB_DIG); ++ DBG_8192C("==> Disable DIG...\n"); ++ } ++ else if (dm_func == 2) {/* disable High power */ ++ odm->SupportAbility &= (~DYNAMIC_BB_DYNAMIC_TXPWR); ++ } ++ else if (dm_func == 3) {/* disable tx power tracking */ ++ odm->SupportAbility &= (~DYNAMIC_RF_CALIBRATION); ++ DBG_8192C("==> Disable tx power tracking...\n"); ++ } ++ else if (dm_func == 4) {/* disable BT coexistence */ ++ dm->DMFlag &= (~DYNAMIC_FUNC_BT); ++ } ++ else if (dm_func == 5) {/* disable antenna diversity */ ++ odm->SupportAbility &= (~DYNAMIC_BB_ANT_DIV); ++ } ++ else if (dm_func == 6) {/* turn on all dynamic func */ ++ if (!(odm->SupportAbility & DYNAMIC_BB_DIG)) { ++ DIG_T *pDigTable = &odm->DM_DigTable; ++ pDigTable->CurIGValue = rtw_read8(adapter, 0xc50); ++ } ++ dm->DMFlag |= DYNAMIC_FUNC_BT; ++ odm->SupportAbility = DYNAMIC_ALL_FUNC_ENABLE; ++ DBG_8192C("==> Turn on all dynamic function...\n"); ++ } ++ } ++ break; ++ case HAL_DEF_DBG_DUMP_RXPKT: ++ hal_data->bDumpRxPkt = *((u8 *)value); ++ break; ++ case HAL_DEF_DBG_DUMP_TXPKT: ++ hal_data->bDumpTxPkt = *((u8 *)value); ++ break; ++ case HAL_DEF_ANT_DETECT: ++ hal_data->AntDetection = *((u8 *)value); ++ break; ++ default: ++ DBG_871X_LEVEL(_drv_always_, "%s: [WARNING] HAL_DEF_VARIABLE(%d) not defined!\n", __func__, variable); ++ bResult = _FAIL; ++ break; ++ } ++ ++ return bResult; ++} ++ ++u8 ++GetHalDefVar(struct adapter *adapter, enum HAL_DEF_VARIABLE variable, void *value) ++{ ++ struct hal_com_data *hal_data = GET_HAL_DATA(adapter); ++ DM_ODM_T *odm = &(hal_data->odmpriv); ++ u8 bResult = _SUCCESS; ++ ++ switch (variable) { ++ case HAL_DEF_UNDERCORATEDSMOOTHEDPWDB: ++ { ++ struct mlme_priv *pmlmepriv; ++ struct sta_priv *pstapriv; ++ struct sta_info *psta; ++ ++ pmlmepriv = &adapter->mlmepriv; ++ pstapriv = &adapter->stapriv; ++ psta = rtw_get_stainfo(pstapriv, pmlmepriv->cur_network.network.MacAddress); ++ if (psta) ++ { ++ *((int*)value) = psta->rssi_stat.UndecoratedSmoothedPWDB; ++ } ++ } ++ break; ++ case HW_DEF_ODM_DBG_FLAG: ++ *((u64*)value) = odm->DebugComponents; ++ break; ++ case HW_DEF_ODM_DBG_LEVEL: ++ *((u32*)value) = odm->DebugLevel; ++ break; ++ case HAL_DEF_DBG_DM_FUNC: ++ *((u32*)value) =hal_data->odmpriv.SupportAbility; ++ break; ++ case HAL_DEF_DBG_DUMP_RXPKT: ++ *((u8 *)value) = hal_data->bDumpRxPkt; ++ break; ++ case HAL_DEF_DBG_DUMP_TXPKT: ++ *((u8 *)value) = hal_data->bDumpTxPkt; ++ break; ++ case HAL_DEF_ANT_DETECT: ++ *((u8 *)value) = hal_data->AntDetection; ++ break; ++ case HAL_DEF_MACID_SLEEP: ++ *(u8 *)value = false; ++ break; ++ case HAL_DEF_TX_PAGE_SIZE: ++ *((u32*)value) = PAGE_SIZE_128; ++ break; ++ default: ++ DBG_871X_LEVEL(_drv_always_, "%s: [WARNING] HAL_DEF_VARIABLE(%d) not defined!\n", __func__, variable); ++ bResult = _FAIL; ++ break; ++ } ++ ++ return bResult; ++} ++ ++void GetHalODMVar( ++ struct adapter * Adapter, ++ enum HAL_ODM_VARIABLE eVariable, ++ void *pValue1, ++ void *pValue2) ++{ ++ switch (eVariable) { ++#if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) ++ case HAL_ODM_NOISE_MONITOR: ++ { ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ u8 chan = *(u8 *)pValue1; ++ *(s16 *)pValue2 = pHalData->noise[chan]; ++ #ifdef DBG_NOISE_MONITOR ++ DBG_8192C("### Noise monitor chan(%d)-noise:%d (dBm) ###\n", ++ chan, pHalData->noise[chan]); ++ #endif ++ ++ } ++ break; ++#endif/* ifdef CONFIG_BACKGROUND_NOISE_MONITOR */ ++ default: ++ break; ++ } ++} ++ ++void SetHalODMVar( ++ struct adapter * Adapter, ++ enum HAL_ODM_VARIABLE eVariable, ++ void * pValue1, ++ bool bSet) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T podmpriv = &pHalData->odmpriv; ++ /* _irqL irqL; */ ++ switch (eVariable) { ++ case HAL_ODM_STA_INFO: ++ { ++ struct sta_info *psta = (struct sta_info *)pValue1; ++ if (bSet) { ++ DBG_8192C("### Set STA_(%d) info ###\n", psta->mac_id); ++ ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, psta); ++ } ++ else { ++ DBG_8192C("### Clean STA_(%d) info ###\n", psta->mac_id); ++ /* spin_lock_bh(&pHalData->odm_stainfo_lock); */ ++ ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, NULL); ++ ++ /* spin_unlock_bh(&pHalData->odm_stainfo_lock); */ ++ } ++ } ++ break; ++ case HAL_ODM_P2P_STATE: ++ ODM_CmnInfoUpdate(podmpriv, ODM_CMNINFO_WIFI_DIRECT, bSet); ++ break; ++ case HAL_ODM_WIFI_DISPLAY_STATE: ++ ODM_CmnInfoUpdate(podmpriv, ODM_CMNINFO_WIFI_DISPLAY, bSet); ++ break; ++ #if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) ++ case HAL_ODM_NOISE_MONITOR: ++ { ++ struct noise_info *pinfo = (struct noise_info *)pValue1; ++ ++ #ifdef DBG_NOISE_MONITOR ++ DBG_8192C("### Noise monitor chan(%d)-bPauseDIG:%d, IGIValue:0x%02x, max_time:%d (ms) ###\n", ++ pinfo->chan, pinfo->bPauseDIG, pinfo->IGIValue, pinfo->max_time); ++ #endif ++ ++ pHalData->noise[pinfo->chan] = ODM_InbandNoise_Monitor(podmpriv, pinfo->bPauseDIG, pinfo->IGIValue, pinfo->max_time); ++ DBG_871X("chan_%d, noise = %d (dBm)\n", pinfo->chan, pHalData->noise[pinfo->chan]); ++ #ifdef DBG_NOISE_MONITOR ++ DBG_871X("noise_a = %d, noise_b = %d noise_all:%d\n", ++ podmpriv->noise_level.noise[ODM_RF_PATH_A], ++ podmpriv->noise_level.noise[ODM_RF_PATH_B], ++ podmpriv->noise_level.noise_all); ++ #endif ++ } ++ break; ++ #endif/* ifdef CONFIG_BACKGROUND_NOISE_MONITOR */ ++ ++ default: ++ break; ++ } ++} ++ ++ ++bool ++eqNByte( ++ u8*str1, ++ u8*str2, ++ u32 num ++ ) ++{ ++ if (num == 0) ++ return false; ++ while (num>0) ++ { ++ num--; ++ if (str1[num]!=str2[num]) ++ return false; ++ } ++ return true; ++} ++ ++/* */ ++/* Description: */ ++/* Return true if chTmp is represent for hex digit and */ ++/* false otherwise. */ ++/* */ ++/* */ ++bool ++IsHexDigit( ++ char chTmp ++) ++{ ++ if ((chTmp >= '0' && chTmp <= '9') || ++ (chTmp >= 'a' && chTmp <= 'f') || ++ (chTmp >= 'A' && chTmp <= 'F')) ++ { ++ return true; ++ } ++ else ++ { ++ return false; ++ } ++} ++ ++ ++/* */ ++/* Description: */ ++/* Translate a character to hex digit. */ ++/* */ ++u32 ++MapCharToHexDigit( ++ char chTmp ++) ++{ ++ if (chTmp >= '0' && chTmp <= '9') ++ return (chTmp - '0'); ++ else if (chTmp >= 'a' && chTmp <= 'f') ++ return (10 + (chTmp - 'a')); ++ else if (chTmp >= 'A' && chTmp <= 'F') ++ return (10 + (chTmp - 'A')); ++ else ++ return 0; ++} ++ ++ ++ ++/* Description: */ ++/* Parse hex number from the string pucStr. */ ++bool GetHexValueFromString(char *szStr, u32 *pu4bVal, u32 *pu4bMove) ++{ ++ char* szScan = szStr; ++ ++ /* Check input parameter. */ ++ if (szStr == NULL || pu4bVal == NULL || pu4bMove == NULL) ++ { ++ DBG_871X("GetHexValueFromString(): Invalid inpur argumetns! szStr: %p, pu4bVal: %p, pu4bMove: %p\n", szStr, pu4bVal, pu4bMove); ++ return false; ++ } ++ ++ /* Initialize output. */ ++ *pu4bMove = 0; ++ *pu4bVal = 0; ++ ++ /* Skip leading space. */ ++ while (*szScan != '\0' && ++ (*szScan == ' ' || *szScan == '\t')) ++ { ++ szScan++; ++ (*pu4bMove)++; ++ } ++ ++ /* Skip leading '0x' or '0X'. */ ++ if (*szScan == '0' && (*(szScan+1) == 'x' || *(szScan+1) == 'X')) ++ { ++ szScan += 2; ++ (*pu4bMove) += 2; ++ } ++ ++ /* Check if szScan is now pointer to a character for hex digit, */ ++ /* if not, it means this is not a valid hex number. */ ++ if (!IsHexDigit(*szScan)) ++ { ++ return false; ++ } ++ ++ /* Parse each digit. */ ++ do ++ { ++ (*pu4bVal) <<= 4; ++ *pu4bVal += MapCharToHexDigit(*szScan); ++ ++ szScan++; ++ (*pu4bMove)++; ++ } while (IsHexDigit(*szScan)); ++ ++ return true; ++} ++ ++bool GetFractionValueFromString(char *szStr, u8 *pInteger, u8 *pFraction, ++ u32 *pu4bMove) ++{ ++ char *szScan = szStr; ++ ++ /* Initialize output. */ ++ *pu4bMove = 0; ++ *pInteger = 0; ++ *pFraction = 0; ++ ++ /* Skip leading space. */ ++ while (*szScan != '\0' && (*szScan == ' ' || *szScan == '\t')) { ++ ++szScan; ++ ++(*pu4bMove); ++ } ++ ++ /* Parse each digit. */ ++ do { ++ (*pInteger) *= 10; ++ *pInteger += (*szScan - '0'); ++ ++ ++szScan; ++ ++(*pu4bMove); ++ ++ if (*szScan == '.') ++ { ++ ++szScan; ++ ++(*pu4bMove); ++ ++ if (*szScan < '0' || *szScan > '9') ++ return false; ++ else { ++ *pFraction = *szScan - '0'; ++ ++szScan; ++ ++(*pu4bMove); ++ return true; ++ } ++ } ++ } while (*szScan >= '0' && *szScan <= '9'); ++ ++ return true; ++} ++ ++/* */ ++/* Description: */ ++/* Return true if szStr is comment out with leading "//". */ ++/* */ ++bool ++IsCommentString( ++ char *szStr ++) ++{ ++ if (*szStr == '/' && *(szStr+1) == '/') ++ { ++ return true; ++ } ++ else ++ { ++ return false; ++ } ++} ++ ++bool ++GetU1ByteIntegerFromStringInDecimal( ++ char*Str, ++ u8* pInt ++ ) ++{ ++ u16 i = 0; ++ *pInt = 0; ++ ++ while (Str[i] != '\0') ++ { ++ if (Str[i] >= '0' && Str[i] <= '9') ++ { ++ *pInt *= 10; ++ *pInt += (Str[i] - '0'); ++ } ++ else ++ { ++ return false; ++ } ++ ++i; ++ } ++ ++ return true; ++} ++ ++/* <20121004, Kordan> For example, ++ * ParseQualifiedString(inString, 0, outString, '[', ']') gets "Kordan" from ++ * a string "Hello [Kordan]". ++ * If RightQualifier does not exist, it will hang in the while loop ++ */ ++bool ParseQualifiedString(char *In, u32 *Start, char *Out, char LeftQualifier, ++ char RightQualifier) ++{ ++ u32 i = 0, j = 0; ++ char c = In[(*Start)++]; ++ ++ if (c != LeftQualifier) ++ return false; ++ ++ i = (*Start); ++ while ((c = In[(*Start)++]) != RightQualifier) ++ ; /* find ']' */ ++ j = (*Start) - 2; ++ strncpy((char *)Out, (const char*)(In+i), j-i+1); ++ ++ return true; ++} ++ ++bool ++isAllSpaceOrTab( ++ u8*data, ++ u8 size ++ ) ++{ ++ u8 cnt = 0, NumOfSpaceAndTab = 0; ++ ++ while (size > cnt) ++ { ++ if (data[cnt] == ' ' || data[cnt] == '\t' || data[cnt] == '\0') ++ ++NumOfSpaceAndTab; ++ ++ ++cnt; ++ } ++ ++ return size == NumOfSpaceAndTab; ++} ++ ++ ++void rtw_hal_check_rxfifo_full(struct adapter *adapter) ++{ ++ struct dvobj_priv *psdpriv = adapter->dvobj; ++ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; ++ int save_cnt =false; ++ ++ /* switch counter to RX fifo */ ++ /* printk("8723b or 8192e , MAC_667 set 0xf0\n"); */ ++ rtw_write8(adapter, REG_RXERR_RPT+3, rtw_read8(adapter, REG_RXERR_RPT+3)|0xf0); ++ save_cnt = true; ++ /* todo: other chips */ ++ ++ if (save_cnt) ++ { ++ /* rtw_write8(adapter, REG_RXERR_RPT+3, rtw_read8(adapter, REG_RXERR_RPT+3)|0xa0); */ ++ pdbgpriv->dbg_rx_fifo_last_overflow = pdbgpriv->dbg_rx_fifo_curr_overflow; ++ pdbgpriv->dbg_rx_fifo_curr_overflow = rtw_read16(adapter, REG_RXERR_RPT); ++ pdbgpriv->dbg_rx_fifo_diff_overflow = pdbgpriv->dbg_rx_fifo_curr_overflow-pdbgpriv->dbg_rx_fifo_last_overflow; ++ } ++} ++ ++void linked_info_dump(struct adapter *padapter, u8 benable) ++{ ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); ++ ++ if (padapter->bLinkInfoDump == benable) ++ return; ++ ++ DBG_871X("%s %s\n", __func__, (benable)?"enable":"disable"); ++ ++ if (benable) { ++ pwrctrlpriv->org_power_mgnt = pwrctrlpriv->power_mgnt;/* keep org value */ ++ rtw_pm_set_lps(padapter, PS_MODE_ACTIVE); ++ ++ pwrctrlpriv->ips_org_mode = pwrctrlpriv->ips_mode;/* keep org value */ ++ rtw_pm_set_ips(padapter, IPS_NONE); ++ } ++ else { ++ rtw_pm_set_ips(padapter, pwrctrlpriv->ips_org_mode); ++ ++ rtw_pm_set_lps(padapter, pwrctrlpriv->ips_org_mode); ++ } ++ padapter->bLinkInfoDump = benable ; ++} ++ ++#ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA ++void rtw_get_raw_rssi_info(void *sel, struct adapter *padapter) ++{ ++ u8 isCCKrate, rf_path; ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ struct rx_raw_rssi *psample_pkt_rssi = &padapter->recvpriv.raw_rssi_info; ++ ++ DBG_871X_SEL_NL(sel,"RxRate = %s, PWDBALL = %d(%%), rx_pwr_all = %d(dBm)\n", ++ HDATA_RATE(psample_pkt_rssi->data_rate), psample_pkt_rssi->pwdball, psample_pkt_rssi->pwr_all); ++ isCCKrate = (psample_pkt_rssi->data_rate <= DESC_RATE11M)?true :false; ++ ++ if (isCCKrate) ++ psample_pkt_rssi->mimo_singal_strength[0] = psample_pkt_rssi->pwdball; ++ ++ for (rf_path = 0;rf_pathNumTotalRFPath;rf_path++) ++ { ++ DBG_871X_SEL_NL(sel,"RF_PATH_%d =>singal_strength:%d(%%), singal_quality:%d(%%)\n" ++ , rf_path, psample_pkt_rssi->mimo_singal_strength[rf_path], psample_pkt_rssi->mimo_singal_quality[rf_path]); ++ ++ if (!isCCKrate) { ++ DBG_871X_SEL_NL(sel,"\trx_ofdm_pwr:%d(dBm), rx_ofdm_snr:%d(dB)\n", ++ psample_pkt_rssi->ofdm_pwr[rf_path], psample_pkt_rssi->ofdm_snr[rf_path]); ++ } ++ } ++} ++ ++void rtw_dump_raw_rssi_info(struct adapter *padapter) ++{ ++ u8 isCCKrate, rf_path; ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ struct rx_raw_rssi *psample_pkt_rssi = &padapter->recvpriv.raw_rssi_info; ++ DBG_871X("============ RAW Rx Info dump ===================\n"); ++ DBG_871X("RxRate = %s, PWDBALL = %d(%%), rx_pwr_all = %d(dBm)\n", ++ HDATA_RATE(psample_pkt_rssi->data_rate), psample_pkt_rssi->pwdball, psample_pkt_rssi->pwr_all); ++ ++ isCCKrate = (psample_pkt_rssi->data_rate <= DESC_RATE11M)?true :false; ++ ++ if (isCCKrate) ++ psample_pkt_rssi->mimo_singal_strength[0] = psample_pkt_rssi->pwdball; ++ ++ for (rf_path = 0;rf_pathNumTotalRFPath;rf_path++) ++ { ++ DBG_871X("RF_PATH_%d =>singal_strength:%d(%%), singal_quality:%d(%%)" ++ , rf_path, psample_pkt_rssi->mimo_singal_strength[rf_path], psample_pkt_rssi->mimo_singal_quality[rf_path]); ++ ++ if (!isCCKrate) { ++ printk(", rx_ofdm_pwr:%d(dBm), rx_ofdm_snr:%d(dB)\n", ++ psample_pkt_rssi->ofdm_pwr[rf_path], psample_pkt_rssi->ofdm_snr[rf_path]); ++ } else { ++ printk("\n"); ++ } ++ } ++} ++ ++void rtw_store_phy_info(struct adapter *padapter, union recv_frame *prframe) ++{ ++ u8 isCCKrate, rf_path; ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; ++ ++ PODM_PHY_INFO_T pPhyInfo = (PODM_PHY_INFO_T)(&pattrib->phy_info); ++ struct rx_raw_rssi *psample_pkt_rssi = &padapter->recvpriv.raw_rssi_info; ++ ++ psample_pkt_rssi->data_rate = pattrib->data_rate; ++ isCCKrate = (pattrib->data_rate <= DESC_RATE11M)?true :false; ++ ++ psample_pkt_rssi->pwdball = pPhyInfo->RxPWDBAll; ++ psample_pkt_rssi->pwr_all = pPhyInfo->RecvSignalPower; ++ ++ for (rf_path = 0;rf_pathNumTotalRFPath;rf_path++) ++ { ++ psample_pkt_rssi->mimo_singal_strength[rf_path] = pPhyInfo->RxMIMOSignalStrength[rf_path]; ++ psample_pkt_rssi->mimo_singal_quality[rf_path] = pPhyInfo->RxMIMOSignalQuality[rf_path]; ++ if (!isCCKrate) { ++ psample_pkt_rssi->ofdm_pwr[rf_path] = pPhyInfo->RxPwr[rf_path]; ++ psample_pkt_rssi->ofdm_snr[rf_path] = pPhyInfo->RxSNR[rf_path]; ++ } ++ } ++} ++#endif ++ ++static u32 Array_kfreemap[] = { ++0xf8, 0xe, ++0xf6, 0xc, ++0xf4, 0xa, ++0xf2, 0x8, ++0xf0, 0x6, ++0xf3, 0x4, ++0xf5, 0x2, ++0xf7, 0x0, ++0xf9, 0x0, ++0xfc, 0x0, ++}; ++ ++void rtw_bb_rf_gain_offset(struct adapter *padapter) ++{ ++ u8 value = padapter->eeprompriv.EEPROMRFGainOffset; ++ u32 res, i = 0; ++ u32 ArrayLen = sizeof(Array_kfreemap)/sizeof(u32); ++ u32 * Array = Array_kfreemap; ++ u32 v1 = 0, v2 = 0, target = 0; ++ /* DBG_871X("+%s value: 0x%02x+\n", __func__, value); */ ++ ++ if (value & BIT4) { ++ DBG_871X("Offset RF Gain.\n"); ++ DBG_871X("Offset RF Gain. padapter->eeprompriv.EEPROMRFGainVal = 0x%x\n", padapter->eeprompriv.EEPROMRFGainVal); ++ if (padapter->eeprompriv.EEPROMRFGainVal != 0xff) { ++ res = rtw_hal_read_rfreg(padapter, RF_PATH_A, 0x7f, 0xffffffff); ++ res &= 0xfff87fff; ++ DBG_871X("Offset RF Gain. before reg 0x7f = 0x%08x\n", res); ++ /* res &= 0xfff87fff; */ ++ for (i = 0; i < ArrayLen; i += 2) ++ { ++ v1 = Array[i]; ++ v2 = Array[i+1]; ++ if (v1 == padapter->eeprompriv.EEPROMRFGainVal) ++ { ++ DBG_871X("Offset RF Gain. got v1 = 0x%x , v2 = 0x%x\n", v1, v2); ++ target =v2; ++ break; ++ } ++ } ++ DBG_871X("padapter->eeprompriv.EEPROMRFGainVal = 0x%x , Gain offset Target Value = 0x%x\n", padapter->eeprompriv.EEPROMRFGainVal, target); ++ PHY_SetRFReg(padapter, RF_PATH_A, REG_RF_BB_GAIN_OFFSET, BIT18|BIT17|BIT16|BIT15, target); ++ ++ /* res |= (padapter->eeprompriv.EEPROMRFGainVal & 0x0f)<< 15; */ ++ /* rtw_hal_write_rfreg(padapter, RF_PATH_A, REG_RF_BB_GAIN_OFFSET, RF_GAIN_OFFSET_MASK, res); */ ++ res = rtw_hal_read_rfreg(padapter, RF_PATH_A, 0x7f, 0xffffffff); ++ DBG_871X("Offset RF Gain. After reg 0x7f = 0x%08x\n", res); ++ } ++ else ++ { ++ DBG_871X("Offset RF Gain. padapter->eeprompriv.EEPROMRFGainVal = 0x%x != 0xff, didn't run Kfree\n", padapter->eeprompriv.EEPROMRFGainVal); ++ } ++ } else { ++ DBG_871X("Using the default RF gain.\n"); ++ } ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/hal_com_phycfg.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/hal_com_phycfg.c +--- linux-4.3/3rdparty/rtl8723bs/hal/hal_com_phycfg.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/hal_com_phycfg.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,3582 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _HAL_COM_PHYCFG_C_ ++ ++#include ++#include ++#include ++ ++u8 PHY_GetTxPowerByRateBase(struct adapter *Adapter, u8 Band, u8 RfPath, ++ u8 TxNum, enum RATE_SECTION RateSection) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ u8 value = 0; ++ ++ if (RfPath > ODM_RF_PATH_D) ++ { ++ DBG_871X("Invalid Rf Path %d in PHY_GetTxPowerByRateBase()\n", RfPath); ++ return 0; ++ } ++ ++ if (Band == BAND_ON_2_4G) ++ { ++ switch (RateSection) { ++ case CCK: ++ value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][0]; ++ break; ++ case OFDM: ++ value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][1]; ++ break; ++ case HT_MCS0_MCS7: ++ value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][2]; ++ break; ++ case HT_MCS8_MCS15: ++ value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][3]; ++ break; ++ case HT_MCS16_MCS23: ++ value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][4]; ++ break; ++ case HT_MCS24_MCS31: ++ value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][5]; ++ break; ++ case VHT_1SSMCS0_1SSMCS9: ++ value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][6]; ++ break; ++ case VHT_2SSMCS0_2SSMCS9: ++ value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][7]; ++ break; ++ case VHT_3SSMCS0_3SSMCS9: ++ value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][8]; ++ break; ++ case VHT_4SSMCS0_4SSMCS9: ++ value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][9]; ++ break; ++ default: ++ DBG_871X("Invalid RateSection %d in Band 2.4G, Rf Path %d, %dTx in PHY_GetTxPowerByRateBase()\n", ++ RateSection, RfPath, TxNum); ++ break; ++ ++ }; ++ } ++ else if (Band == BAND_ON_5G) ++ { ++ switch (RateSection) { ++ case OFDM: ++ value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][0]; ++ break; ++ case HT_MCS0_MCS7: ++ value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][1]; ++ break; ++ case HT_MCS8_MCS15: ++ value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][2]; ++ break; ++ case HT_MCS16_MCS23: ++ value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][3]; ++ break; ++ case HT_MCS24_MCS31: ++ value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][4]; ++ break; ++ case VHT_1SSMCS0_1SSMCS9: ++ value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][5]; ++ break; ++ case VHT_2SSMCS0_2SSMCS9: ++ value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][6]; ++ break; ++ case VHT_3SSMCS0_3SSMCS9: ++ value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][7]; ++ break; ++ case VHT_4SSMCS0_4SSMCS9: ++ value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][8]; ++ break; ++ default: ++ DBG_871X("Invalid RateSection %d in Band 5G, Rf Path %d, %dTx in PHY_GetTxPowerByRateBase()\n", ++ RateSection, RfPath, TxNum); ++ break; ++ }; ++ } ++ else ++ { ++ DBG_871X("Invalid Band %d in PHY_GetTxPowerByRateBase()\n", Band); ++ } ++ ++ return value; ++} ++ ++static void ++phy_SetTxPowerByRateBase( ++struct adapter * Adapter, ++u8 Band, ++u8 RfPath, ++enum RATE_SECTION RateSection, ++u8 TxNum, ++u8 Value ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++ if (RfPath > ODM_RF_PATH_D) ++ { ++ DBG_871X("Invalid Rf Path %d in phy_SetTxPowerByRatBase()\n", RfPath); ++ return; ++ } ++ ++ if (Band == BAND_ON_2_4G) ++ { ++ switch (RateSection) { ++ case CCK: ++ pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][0] = Value; ++ break; ++ case OFDM: ++ pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][1] = Value; ++ break; ++ case HT_MCS0_MCS7: ++ pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][2] = Value; ++ break; ++ case HT_MCS8_MCS15: ++ pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][3] = Value; ++ break; ++ case HT_MCS16_MCS23: ++ pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][4] = Value; ++ break; ++ case HT_MCS24_MCS31: ++ pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][5] = Value; ++ break; ++ case VHT_1SSMCS0_1SSMCS9: ++ pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][6] = Value; ++ break; ++ case VHT_2SSMCS0_2SSMCS9: ++ pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][7] = Value; ++ break; ++ case VHT_3SSMCS0_3SSMCS9: ++ pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][8] = Value; ++ break; ++ case VHT_4SSMCS0_4SSMCS9: ++ pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][9] = Value; ++ break; ++ default: ++ DBG_871X("Invalid RateSection %d in Band 2.4G, Rf Path %d, %dTx in phy_SetTxPowerByRateBase()\n", ++ RateSection, RfPath, TxNum); ++ break; ++ }; ++ } ++ else if (Band == BAND_ON_5G) ++ { ++ switch (RateSection) { ++ case OFDM: ++ pHalData->TxPwrByRateBase5G[RfPath][TxNum][0] = Value; ++ break; ++ case HT_MCS0_MCS7: ++ pHalData->TxPwrByRateBase5G[RfPath][TxNum][1] = Value; ++ break; ++ case HT_MCS8_MCS15: ++ pHalData->TxPwrByRateBase5G[RfPath][TxNum][2] = Value; ++ break; ++ case HT_MCS16_MCS23: ++ pHalData->TxPwrByRateBase5G[RfPath][TxNum][3] = Value; ++ break; ++ case HT_MCS24_MCS31: ++ pHalData->TxPwrByRateBase5G[RfPath][TxNum][4] = Value; ++ break; ++ case VHT_1SSMCS0_1SSMCS9: ++ pHalData->TxPwrByRateBase5G[RfPath][TxNum][5] = Value; ++ break; ++ case VHT_2SSMCS0_2SSMCS9: ++ pHalData->TxPwrByRateBase5G[RfPath][TxNum][6] = Value; ++ break; ++ case VHT_3SSMCS0_3SSMCS9: ++ pHalData->TxPwrByRateBase5G[RfPath][TxNum][7] = Value; ++ break; ++ case VHT_4SSMCS0_4SSMCS9: ++ pHalData->TxPwrByRateBase5G[RfPath][TxNum][8] = Value; ++ break; ++ default: ++ DBG_871X("Invalid RateSection %d in Band 5G, Rf Path %d, %dTx in phy_SetTxPowerByRateBase()\n", ++ RateSection, RfPath, TxNum); ++ break; ++ }; ++ } ++ else ++ { ++ DBG_871X("Invalid Band %d in phy_SetTxPowerByRateBase()\n", Band); ++ } ++} ++ ++static void ++phy_StoreTxPowerByRateBase( ++struct adapter *padapter ++ ) ++{ ++ u8 path, base; ++ ++ /* DBG_871X("===>%s\n", __func__); */ ++ ++ for (path = ODM_RF_PATH_A; path <= ODM_RF_PATH_B; ++path) ++ { ++ base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_1TX, MGN_11M); ++ phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, CCK, RF_1TX, base); ++ /* DBG_871X("Power index base of 2.4G path %d 1Tx CCK = > 0x%x\n", path, base); */ ++ ++ base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_1TX, MGN_54M); ++ phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, OFDM, RF_1TX, base); ++ /* DBG_871X("Power index base of 2.4G path %d 1Tx OFDM = > 0x%x\n", path, base); */ ++ ++ base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_1TX, MGN_MCS7); ++ phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, HT_MCS0_MCS7, RF_1TX, base); ++ /* DBG_871X("Power index base of 2.4G path %d 1Tx MCS0-7 = > 0x%x\n", path, base); */ ++ ++ base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_2TX, MGN_MCS15); ++ phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, HT_MCS8_MCS15, RF_2TX, base); ++ /* DBG_871X("Power index base of 2.4G path %d 2Tx MCS8-15 = > 0x%x\n", path, base); */ ++ ++ base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_3TX, MGN_MCS23); ++ phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, HT_MCS16_MCS23, RF_3TX, base); ++ /* DBG_871X("Power index base of 2.4G path %d 3Tx MCS16-23 = > 0x%x\n", path, base); */ ++ ++ base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_1TX, MGN_VHT1SS_MCS7); ++ phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, VHT_1SSMCS0_1SSMCS9, RF_1TX, base); ++ /* DBG_871X("Power index base of 2.4G path %d 1Tx VHT1SS = > 0x%x\n", path, base); */ ++ ++ base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_2TX, MGN_VHT2SS_MCS7); ++ phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, VHT_2SSMCS0_2SSMCS9, RF_2TX, base); ++ /* DBG_871X("Power index base of 2.4G path %d 2Tx VHT2SS = > 0x%x\n", path, base); */ ++ ++ base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_3TX, MGN_VHT3SS_MCS7); ++ phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, VHT_3SSMCS0_3SSMCS9, RF_3TX, base); ++ /* DBG_871X("Power index base of 2.4G path %d 3Tx VHT3SS = > 0x%x\n", path, base); */ ++ ++ base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_1TX, MGN_54M); ++ phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, OFDM, RF_1TX, base); ++ /* DBG_871X("Power index base of 5G path %d 1Tx OFDM = > 0x%x\n", path, base); */ ++ ++ base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_1TX, MGN_MCS7); ++ phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, HT_MCS0_MCS7, RF_1TX, base); ++ /* DBG_871X("Power index base of 5G path %d 1Tx MCS0~7 = > 0x%x\n", path, base); */ ++ ++ base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_2TX, MGN_MCS15); ++ phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, HT_MCS8_MCS15, RF_2TX, base); ++ /* DBG_871X("Power index base of 5G path %d 2Tx MCS8~15 = > 0x%x\n", path, base); */ ++ ++ base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_3TX, MGN_MCS23); ++ phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, HT_MCS16_MCS23, RF_3TX, base); ++ /* DBG_871X("Power index base of 5G path %d 3Tx MCS16~23 = > 0x%x\n", path, base); */ ++ ++ base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_1TX, MGN_VHT1SS_MCS7); ++ phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, VHT_1SSMCS0_1SSMCS9, RF_1TX, base); ++ /* DBG_871X("Power index base of 5G path %d 1Tx VHT1SS = > 0x%x\n", path, base); */ ++ ++ base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_2TX, MGN_VHT2SS_MCS7); ++ phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, VHT_2SSMCS0_2SSMCS9, RF_2TX, base); ++ /* DBG_871X("Power index base of 5G path %d 2Tx VHT2SS = > 0x%x\n", path, base); */ ++ ++ base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_3TX, MGN_VHT2SS_MCS7); ++ phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, VHT_3SSMCS0_3SSMCS9, RF_3TX, base); ++ /* DBG_871X("Power index base of 5G path %d 3Tx VHT3SS = > 0x%x\n", path, base); */ ++ } ++ ++ /* DBG_871X("<===%s\n", __func__); */ ++} ++ ++u8 ++PHY_GetRateSectionIndexOfTxPowerByRate( ++struct adapter *padapter, ++u32 RegAddr, ++u32 BitMask ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ u8 index = 0; ++ ++ if (pDM_Odm->PhyRegPgVersion == 0) ++ { ++ switch (RegAddr) ++ { ++ case rTxAGC_A_Rate18_06: index = 0; break; ++ case rTxAGC_A_Rate54_24: index = 1; break; ++ case rTxAGC_A_CCK1_Mcs32: index = 6; break; ++ case rTxAGC_B_CCK11_A_CCK2_11: ++ if (BitMask == bMaskH3Bytes) ++ index = 7; ++ else if (BitMask == 0x000000ff) ++ index = 15; ++ break; ++ ++ case rTxAGC_A_Mcs03_Mcs00: index = 2; break; ++ case rTxAGC_A_Mcs07_Mcs04: index = 3; break; ++ case rTxAGC_A_Mcs11_Mcs08: index = 4; break; ++ case rTxAGC_A_Mcs15_Mcs12: index = 5; break; ++ case rTxAGC_B_Rate18_06: index = 8; break; ++ case rTxAGC_B_Rate54_24: index = 9; break; ++ case rTxAGC_B_CCK1_55_Mcs32: index = 14; break; ++ case rTxAGC_B_Mcs03_Mcs00: index = 10; break; ++ case rTxAGC_B_Mcs07_Mcs04: index = 11; break; ++ case rTxAGC_B_Mcs11_Mcs08: index = 12; break; ++ case rTxAGC_B_Mcs15_Mcs12: index = 13; break; ++ default: ++ DBG_871X("Invalid RegAddr 0x3%x in PHY_GetRateSectionIndexOfTxPowerByRate()", RegAddr); ++ break; ++ }; ++ } ++ ++ return index; ++} ++ ++void ++PHY_GetRateValuesOfTxPowerByRate( ++struct adapter *padapter, ++u32 RegAddr, ++u32 BitMask, ++u32 Value, ++ u8 * RateIndex, ++ s8 * PwrByRateVal, ++ u8 * RateNum ++ ) ++{ ++ u8 i = 0; ++ ++ switch (RegAddr) ++ { ++ case rTxAGC_A_Rate18_06: ++ case rTxAGC_B_Rate18_06: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_6M); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_9M); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_12M); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_18M); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case rTxAGC_A_Rate54_24: ++ case rTxAGC_B_Rate54_24: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_24M); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_36M); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_48M); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_54M); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case rTxAGC_A_CCK1_Mcs32: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_1M); ++ PwrByRateVal[0] = (s8) ((((Value >> (8 + 4)) & 0xF)) * 10 + ++ ((Value >> 8) & 0xF)); ++ *RateNum = 1; ++ break; ++ ++ case rTxAGC_B_CCK11_A_CCK2_11: ++ if (BitMask == 0xffffff00) ++ { ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_2M); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_5_5M); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_11M); ++ for (i = 1; i < 4; ++ i) ++ { ++ PwrByRateVal[i - 1] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 3; ++ } ++ else if (BitMask == 0x000000ff) ++ { ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_11M); ++ PwrByRateVal[0] = (s8) ((((Value >> 4) & 0xF)) * 10 + ++ (Value & 0xF)); ++ *RateNum = 1; ++ } ++ break; ++ ++ case rTxAGC_A_Mcs03_Mcs00: ++ case rTxAGC_B_Mcs03_Mcs00: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS0); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS1); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS2); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS3); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case rTxAGC_A_Mcs07_Mcs04: ++ case rTxAGC_B_Mcs07_Mcs04: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS4); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS5); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS6); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS7); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case rTxAGC_A_Mcs11_Mcs08: ++ case rTxAGC_B_Mcs11_Mcs08: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS8); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS9); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS10); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS11); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case rTxAGC_A_Mcs15_Mcs12: ++ case rTxAGC_B_Mcs15_Mcs12: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS12); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS13); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS14); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS15); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ ++ break; ++ ++ case rTxAGC_B_CCK1_55_Mcs32: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_1M); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_2M); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_5_5M); ++ for (i = 1; i < 4; ++ i) ++ { ++ PwrByRateVal[i - 1] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 3; ++ break; ++ ++ case 0xC20: ++ case 0xE20: ++ case 0x1820: ++ case 0x1a20: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_1M); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_2M); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_5_5M); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_11M); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case 0xC24: ++ case 0xE24: ++ case 0x1824: ++ case 0x1a24: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_6M); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_9M); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_12M); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_18M); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case 0xC28: ++ case 0xE28: ++ case 0x1828: ++ case 0x1a28: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_24M); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_36M); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_48M); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_54M); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case 0xC2C: ++ case 0xE2C: ++ case 0x182C: ++ case 0x1a2C: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS0); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS1); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS2); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS3); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case 0xC30: ++ case 0xE30: ++ case 0x1830: ++ case 0x1a30: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS4); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS5); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS6); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS7); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case 0xC34: ++ case 0xE34: ++ case 0x1834: ++ case 0x1a34: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS8); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS9); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS10); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS11); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case 0xC38: ++ case 0xE38: ++ case 0x1838: ++ case 0x1a38: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS12); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS13); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS14); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS15); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case 0xC3C: ++ case 0xE3C: ++ case 0x183C: ++ case 0x1a3C: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS0); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS1); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS2); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS3); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case 0xC40: ++ case 0xE40: ++ case 0x1840: ++ case 0x1a40: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS4); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS5); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS6); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS7); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case 0xC44: ++ case 0xE44: ++ case 0x1844: ++ case 0x1a44: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS8); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS9); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS0); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS1); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case 0xC48: ++ case 0xE48: ++ case 0x1848: ++ case 0x1a48: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS2); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS3); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS4); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS5); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case 0xC4C: ++ case 0xE4C: ++ case 0x184C: ++ case 0x1a4C: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS6); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS7); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS8); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS9); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case 0xCD8: ++ case 0xED8: ++ case 0x18D8: ++ case 0x1aD8: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS16); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS17); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS18); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS19); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case 0xCDC: ++ case 0xEDC: ++ case 0x18DC: ++ case 0x1aDC: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS20); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS21); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS22); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_MCS23); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case 0xCE0: ++ case 0xEE0: ++ case 0x18E0: ++ case 0x1aE0: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS0); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS1); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS2); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS3); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case 0xCE4: ++ case 0xEE4: ++ case 0x18E4: ++ case 0x1aE4: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS4); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS5); ++ RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS6); ++ RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS7); ++ for (i = 0; i < 4; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ case 0xCE8: ++ case 0xEE8: ++ case 0x18E8: ++ case 0x1aE8: ++ RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS8); ++ RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS9); ++ for (i = 0; i < 2; ++ i) ++ { ++ PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 + ++ ((Value >> (i * 8)) & 0xF)); ++ } ++ *RateNum = 4; ++ break; ++ ++ default: ++ DBG_871X("Invalid RegAddr 0x%x in %s()\n", RegAddr, __func__); ++ break; ++ }; ++} ++ ++static void ++PHY_StoreTxPowerByRateNew( ++struct adapter *padapter, ++u32 Band, ++u32 RfPath, ++u32 TxNum, ++u32 RegAddr, ++u32 BitMask, ++u32 Data ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ u8 i = 0, rateIndex[4] = {0}, rateNum = 0; ++ s8 PwrByRateVal[4] = {0}; ++ ++ PHY_GetRateValuesOfTxPowerByRate(padapter, RegAddr, BitMask, Data, rateIndex, PwrByRateVal, &rateNum); ++ ++ if (Band != BAND_ON_2_4G && Band != BAND_ON_5G) ++ { ++ DBG_871X("Invalid Band %d\n", Band); ++ return; ++ } ++ ++ if (RfPath > ODM_RF_PATH_D) ++ { ++ DBG_871X("Invalid RfPath %d\n", RfPath); ++ return; ++ } ++ ++ if (TxNum > ODM_RF_PATH_D) ++ { ++ DBG_871X("Invalid TxNum %d\n", TxNum); ++ return; ++ } ++ ++ for (i = 0; i < rateNum; ++i) ++ { ++ if (rateIndex[i] == PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS0) || ++ rateIndex[i] == PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS1)) ++ { ++ TxNum = RF_2TX; ++ } ++ ++ pHalData->TxPwrByRateOffset[Band][RfPath][TxNum][rateIndex[i]] = PwrByRateVal[i]; ++ } ++} ++ ++static void ++PHY_StoreTxPowerByRateOld( ++struct adapter * padapter, ++u32 RegAddr, ++u32 BitMask, ++u32 Data ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ u8 index = PHY_GetRateSectionIndexOfTxPowerByRate(padapter, RegAddr, BitMask); ++ ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][index] = Data; ++ /* DBG_871X("MCSTxPowerLevelOriginalOffset[%d][0] = 0x%x\n", pHalData->pwrGroupCnt, */ ++ /* pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][0]); */ ++} ++ ++void ++PHY_InitTxPowerByRate( ++struct adapter *padapter ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ u8 band, rfPath, TxNum, rate; ++ ++ for (band = BAND_ON_2_4G; band <= BAND_ON_5G; ++band) ++ for (rfPath = 0; rfPath < TX_PWR_BY_RATE_NUM_RF; ++rfPath) ++ for (TxNum = 0; TxNum < TX_PWR_BY_RATE_NUM_RF; ++TxNum) ++ for (rate = 0; rate < TX_PWR_BY_RATE_NUM_RATE; ++rate) ++ pHalData->TxPwrByRateOffset[band][rfPath][TxNum][rate] = 0; ++} ++ ++void ++PHY_StoreTxPowerByRate( ++struct adapter *padapter, ++u32 Band, ++u32 RfPath, ++u32 TxNum, ++u32 RegAddr, ++u32 BitMask, ++u32 Data ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ ++ if (pDM_Odm->PhyRegPgVersion > 0) ++ { ++ PHY_StoreTxPowerByRateNew(padapter, Band, RfPath, TxNum, RegAddr, BitMask, Data); ++ } ++ else if (pDM_Odm->PhyRegPgVersion == 0) ++ { ++ PHY_StoreTxPowerByRateOld(padapter, RegAddr, BitMask, Data); ++ ++ if (RegAddr == rTxAGC_A_Mcs15_Mcs12 && pHalData->rf_type == RF_1T1R) ++ pHalData->pwrGroupCnt++; ++ else if (RegAddr == rTxAGC_B_Mcs15_Mcs12 && pHalData->rf_type != RF_1T1R) ++ pHalData->pwrGroupCnt++; ++ } ++ else ++ DBG_871X("Invalid PHY_REG_PG.txt version %d\n", pDM_Odm->PhyRegPgVersion); ++ ++} ++ ++static void ++phy_ConvertTxPowerByRateInDbmToRelativeValues( ++struct adapter *padapter ++ ) ++{ ++ u8 base = 0, i = 0, value = 0, ++ band = 0, path = 0, txNum = 0; ++ u8 cckRates[4] = {MGN_1M, MGN_2M, MGN_5_5M, MGN_11M}, ++ ofdmRates[8] = {MGN_6M, MGN_9M, MGN_12M, MGN_18M, MGN_24M, MGN_36M, MGN_48M, MGN_54M}, ++ mcs0_7Rates[8] = {MGN_MCS0, MGN_MCS1, MGN_MCS2, MGN_MCS3, MGN_MCS4, MGN_MCS5, MGN_MCS6, MGN_MCS7}, ++ mcs8_15Rates[8] = {MGN_MCS8, MGN_MCS9, MGN_MCS10, MGN_MCS11, MGN_MCS12, MGN_MCS13, MGN_MCS14, MGN_MCS15}, ++ mcs16_23Rates[8] = {MGN_MCS16, MGN_MCS17, MGN_MCS18, MGN_MCS19, MGN_MCS20, MGN_MCS21, MGN_MCS22, MGN_MCS23}, ++ vht1ssRates[10] = {MGN_VHT1SS_MCS0, MGN_VHT1SS_MCS1, MGN_VHT1SS_MCS2, MGN_VHT1SS_MCS3, MGN_VHT1SS_MCS4, ++ MGN_VHT1SS_MCS5, MGN_VHT1SS_MCS6, MGN_VHT1SS_MCS7, MGN_VHT1SS_MCS8, MGN_VHT1SS_MCS9}, ++ vht2ssRates[10] = {MGN_VHT2SS_MCS0, MGN_VHT2SS_MCS1, MGN_VHT2SS_MCS2, MGN_VHT2SS_MCS3, MGN_VHT2SS_MCS4, ++ MGN_VHT2SS_MCS5, MGN_VHT2SS_MCS6, MGN_VHT2SS_MCS7, MGN_VHT2SS_MCS8, MGN_VHT2SS_MCS9}, ++ vht3ssRates[10] = {MGN_VHT3SS_MCS0, MGN_VHT3SS_MCS1, MGN_VHT3SS_MCS2, MGN_VHT3SS_MCS3, MGN_VHT3SS_MCS4, ++ MGN_VHT3SS_MCS5, MGN_VHT3SS_MCS6, MGN_VHT3SS_MCS7, MGN_VHT3SS_MCS8, MGN_VHT3SS_MCS9}; ++ ++ /* DBG_871X("===>PHY_ConvertTxPowerByRateInDbmToRelativeValues()\n"); */ ++ ++ for (band = BAND_ON_2_4G; band <= BAND_ON_5G; ++band) ++ { ++ for (path = ODM_RF_PATH_A; path <= ODM_RF_PATH_D; ++path) ++ { ++ for (txNum = RF_1TX; txNum < RF_MAX_TX_NUM; ++txNum) ++ { ++ /* CCK */ ++ base = PHY_GetTxPowerByRate(padapter, band, path, txNum, MGN_11M); ++ for (i = 0; i < sizeof(cckRates); ++i) ++ { ++ value = PHY_GetTxPowerByRate(padapter, band, path, txNum, cckRates[i]); ++ PHY_SetTxPowerByRate(padapter, band, path, txNum, cckRates[i], value - base); ++ } ++ ++ /* OFDM */ ++ base = PHY_GetTxPowerByRate(padapter, band, path, txNum, MGN_54M); ++ for (i = 0; i < sizeof(ofdmRates); ++i) ++ { ++ value = PHY_GetTxPowerByRate(padapter, band, path, txNum, ofdmRates[i]); ++ PHY_SetTxPowerByRate(padapter, band, path, txNum, ofdmRates[i], value - base); ++ } ++ ++ /* HT MCS0~7 */ ++ base = PHY_GetTxPowerByRate(padapter, band, path, txNum, MGN_MCS7); ++ for (i = 0; i < sizeof(mcs0_7Rates); ++i) ++ { ++ value = PHY_GetTxPowerByRate(padapter, band, path, txNum, mcs0_7Rates[i]); ++ PHY_SetTxPowerByRate(padapter, band, path, txNum, mcs0_7Rates[i], value - base); ++ } ++ ++ /* HT MCS8~15 */ ++ base = PHY_GetTxPowerByRate(padapter, band, path, txNum, MGN_MCS15); ++ for (i = 0; i < sizeof(mcs8_15Rates); ++i) ++ { ++ value = PHY_GetTxPowerByRate(padapter, band, path, txNum, mcs8_15Rates[i]); ++ PHY_SetTxPowerByRate(padapter, band, path, txNum, mcs8_15Rates[i], value - base); ++ } ++ ++ /* HT MCS16~23 */ ++ base = PHY_GetTxPowerByRate(padapter, band, path, txNum, MGN_MCS23); ++ for (i = 0; i < sizeof(mcs16_23Rates); ++i) ++ { ++ value = PHY_GetTxPowerByRate(padapter, band, path, txNum, mcs16_23Rates[i]); ++ PHY_SetTxPowerByRate(padapter, band, path, txNum, mcs16_23Rates[i], value - base); ++ } ++ ++ /* VHT 1SS */ ++ base = PHY_GetTxPowerByRate(padapter, band, path, txNum, MGN_VHT1SS_MCS7); ++ for (i = 0; i < sizeof(vht1ssRates); ++i) ++ { ++ value = PHY_GetTxPowerByRate(padapter, band, path, txNum, vht1ssRates[i]); ++ PHY_SetTxPowerByRate(padapter, band, path, txNum, vht1ssRates[i], value - base); ++ } ++ ++ /* VHT 2SS */ ++ base = PHY_GetTxPowerByRate(padapter, band, path, txNum, MGN_VHT2SS_MCS7); ++ for (i = 0; i < sizeof(vht2ssRates); ++i) ++ { ++ value = PHY_GetTxPowerByRate(padapter, band, path, txNum, vht2ssRates[i]); ++ PHY_SetTxPowerByRate(padapter, band, path, txNum, vht2ssRates[i], value - base); ++ } ++ ++ /* VHT 3SS */ ++ base = PHY_GetTxPowerByRate(padapter, band, path, txNum, MGN_VHT3SS_MCS7); ++ for (i = 0; i < sizeof(vht3ssRates); ++i) ++ { ++ value = PHY_GetTxPowerByRate(padapter, band, path, txNum, vht3ssRates[i]); ++ PHY_SetTxPowerByRate(padapter, band, path, txNum, vht3ssRates[i], value - base); ++ } ++ } ++ } ++ } ++ ++ /* DBG_871X("<===PHY_ConvertTxPowerByRateInDbmToRelativeValues()\n"); */ ++} ++ ++/* ++ * This function must be called if the value in the PHY_REG_PG.txt(or header) ++ * is exact dBm values ++ */ ++void ++PHY_TxPowerByRateConfiguration( ++ struct adapter * padapter ++ ) ++{ ++ phy_StoreTxPowerByRateBase(padapter); ++ phy_ConvertTxPowerByRateInDbmToRelativeValues(padapter); ++} ++ ++void ++PHY_SetTxPowerIndexByRateSection( ++struct adapter * padapter, ++u8 RFPath, ++u8 Channel, ++u8 RateSection ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ ++ if (RateSection == CCK) ++ { ++ u8 cckRates[] = {MGN_1M, MGN_2M, MGN_5_5M, MGN_11M}; ++ if (pHalData->CurrentBandType == BAND_ON_2_4G) ++ PHY_SetTxPowerIndexByRateArray(padapter, RFPath, pHalData->CurrentChannelBW, Channel, ++ cckRates, sizeof(cckRates)/sizeof(u8)); ++ ++ } ++ else if (RateSection == OFDM) ++ { ++ u8 ofdmRates[] = {MGN_6M, MGN_9M, MGN_12M, MGN_18M, MGN_24M, MGN_36M, MGN_48M, MGN_54M}; ++ PHY_SetTxPowerIndexByRateArray(padapter, RFPath, pHalData->CurrentChannelBW, Channel, ++ ofdmRates, sizeof(ofdmRates)/sizeof(u8)); ++ ++ } ++ else if (RateSection == HT_MCS0_MCS7) ++ { ++ u8 htRates1T[] = {MGN_MCS0, MGN_MCS1, MGN_MCS2, MGN_MCS3, MGN_MCS4, MGN_MCS5, MGN_MCS6, MGN_MCS7}; ++ PHY_SetTxPowerIndexByRateArray(padapter, RFPath, pHalData->CurrentChannelBW, Channel, ++ htRates1T, sizeof(htRates1T)/sizeof(u8)); ++ ++ } ++ else if (RateSection == HT_MCS8_MCS15) ++ { ++ u8 htRates2T[] = {MGN_MCS8, MGN_MCS9, MGN_MCS10, MGN_MCS11, MGN_MCS12, MGN_MCS13, MGN_MCS14, MGN_MCS15}; ++ PHY_SetTxPowerIndexByRateArray(padapter, RFPath, pHalData->CurrentChannelBW, Channel, ++ htRates2T, sizeof(htRates2T)/sizeof(u8)); ++ ++ } ++ else if (RateSection == HT_MCS16_MCS23) ++ { ++ u8 htRates3T[] = {MGN_MCS16, MGN_MCS17, MGN_MCS18, MGN_MCS19, MGN_MCS20, MGN_MCS21, MGN_MCS22, MGN_MCS23}; ++ PHY_SetTxPowerIndexByRateArray(padapter, RFPath, pHalData->CurrentChannelBW, Channel, ++ htRates3T, sizeof(htRates3T)/sizeof(u8)); ++ ++ } ++ else if (RateSection == HT_MCS24_MCS31) ++ { ++ u8 htRates4T[] = {MGN_MCS24, MGN_MCS25, MGN_MCS26, MGN_MCS27, MGN_MCS28, MGN_MCS29, MGN_MCS30, MGN_MCS31}; ++ PHY_SetTxPowerIndexByRateArray(padapter, RFPath, pHalData->CurrentChannelBW, Channel, ++ htRates4T, sizeof(htRates4T)/sizeof(u8)); ++ ++ } ++ else if (RateSection == VHT_1SSMCS0_1SSMCS9) ++ { ++ u8 vhtRates1T[] = {MGN_VHT1SS_MCS0, MGN_VHT1SS_MCS1, MGN_VHT1SS_MCS2, MGN_VHT1SS_MCS3, MGN_VHT1SS_MCS4, ++ MGN_VHT1SS_MCS5, MGN_VHT1SS_MCS6, MGN_VHT1SS_MCS7, MGN_VHT1SS_MCS8, MGN_VHT1SS_MCS9}; ++ PHY_SetTxPowerIndexByRateArray(padapter, RFPath, pHalData->CurrentChannelBW, Channel, ++ vhtRates1T, sizeof(vhtRates1T)/sizeof(u8)); ++ ++ } ++ else if (RateSection == VHT_2SSMCS0_2SSMCS9) ++ { ++ u8 vhtRates2T[] = {MGN_VHT2SS_MCS0, MGN_VHT2SS_MCS1, MGN_VHT2SS_MCS2, MGN_VHT2SS_MCS3, MGN_VHT2SS_MCS4, ++ MGN_VHT2SS_MCS5, MGN_VHT2SS_MCS6, MGN_VHT2SS_MCS7, MGN_VHT2SS_MCS8, MGN_VHT2SS_MCS9}; ++ ++ PHY_SetTxPowerIndexByRateArray(padapter, RFPath, pHalData->CurrentChannelBW, Channel, ++ vhtRates2T, sizeof(vhtRates2T)/sizeof(u8)); ++ } ++ else if (RateSection == VHT_3SSMCS0_3SSMCS9) ++ { ++ u8 vhtRates3T[] = {MGN_VHT3SS_MCS0, MGN_VHT3SS_MCS1, MGN_VHT3SS_MCS2, MGN_VHT3SS_MCS3, MGN_VHT3SS_MCS4, ++ MGN_VHT3SS_MCS5, MGN_VHT3SS_MCS6, MGN_VHT3SS_MCS7, MGN_VHT3SS_MCS8, MGN_VHT3SS_MCS9}; ++ ++ PHY_SetTxPowerIndexByRateArray(padapter, RFPath, pHalData->CurrentChannelBW, Channel, ++ vhtRates3T, sizeof(vhtRates3T)/sizeof(u8)); ++ } ++ else if (RateSection == VHT_4SSMCS0_4SSMCS9) ++ { ++ u8 vhtRates4T[] = {MGN_VHT4SS_MCS0, MGN_VHT4SS_MCS1, MGN_VHT4SS_MCS2, MGN_VHT4SS_MCS3, MGN_VHT4SS_MCS4, ++ MGN_VHT4SS_MCS5, MGN_VHT4SS_MCS6, MGN_VHT4SS_MCS7, MGN_VHT4SS_MCS8, MGN_VHT4SS_MCS9}; ++ ++ PHY_SetTxPowerIndexByRateArray(padapter, RFPath, pHalData->CurrentChannelBW, Channel, ++ vhtRates4T, sizeof(vhtRates4T)/sizeof(u8)); ++ } ++ else ++ { ++ DBG_871X("Invalid RateSection %d in %s", RateSection, __func__); ++ } ++} ++ ++static bool ++phy_GetChnlIndex( ++u8 Channel, ++ u8 *ChannelIdx ++ ) ++{ ++ u8 channel5G[CHANNEL_MAX_NUMBER_5G] = ++ {36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 100, 102, 104, 106, 108, 110, 112, ++ 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 149, 151, ++ 153, 155, 157, 159, 161, 163, 165, 167, 168, 169, 171, 173, 175, 177}; ++ u8 i = 0; ++ bool bIn24G =true; ++ ++ if (Channel <= 14) ++ { ++ bIn24G =true; ++ *ChannelIdx = Channel -1; ++ } ++ else ++ { ++ bIn24G = false; ++ ++ for (i = 0; i < sizeof(channel5G)/sizeof(u8); ++i) ++ { ++ if (channel5G[i] == Channel) { ++ *ChannelIdx = i; ++ return bIn24G; ++ } ++ } ++ } ++ ++ return bIn24G; ++} ++ ++u8 ++PHY_GetTxPowerIndexBase( ++struct adapter * padapter, ++u8 RFPath, ++u8 Rate, ++enum CHANNEL_WIDTH BandWidth, ++u8 Channel, ++ bool *bIn24G ++ ) ++{ ++ struct hal_com_data * pHalData = GET_HAL_DATA(padapter); ++ u8 i = 0; /* default set to 1S */ ++ u8 txPower = 0; ++ u8 chnlIdx = (Channel-1); ++ ++ if (HAL_IsLegalChannel(padapter, Channel) == false) ++ { ++ chnlIdx = 0; ++ DBG_871X("Illegal channel!!\n"); ++ } ++ ++ *bIn24G = phy_GetChnlIndex(Channel, &chnlIdx); ++ ++ /* DBG_871X("[%s] Channel Index: %d\n", (*bIn24G?"2.4G":"5G"), chnlIdx); */ ++ ++ if (*bIn24G) /* 3 ============================== 2.4 G ============================== */ ++ { ++ if (IS_CCK_RATE(Rate)) ++ { ++ txPower = pHalData->Index24G_CCK_Base[RFPath][chnlIdx]; ++ } ++ else if (MGN_6M <= Rate) ++ { ++ txPower = pHalData->Index24G_BW40_Base[RFPath][chnlIdx]; ++ } ++ else ++ { ++ DBG_871X("PHY_GetTxPowerIndexBase: INVALID Rate.\n"); ++ } ++ ++ /* DBG_871X("Base Tx power(RF-%c, Rate #%d, Channel Index %d) = 0x%X\n", */ ++ /* ((RFPath == 0)?'A':'B'), Rate, chnlIdx, txPower); */ ++ ++ /* OFDM-1T */ ++ if ((MGN_6M <= Rate && Rate <= MGN_54M) && ! IS_CCK_RATE(Rate)) ++ { ++ txPower += pHalData->OFDM_24G_Diff[RFPath][TX_1S]; ++ /* DBG_871X("+PowerDiff 2.4G (RF-%c): (OFDM-1T) = (%d)\n", ((RFPath == 0)?'A':'B'), pHalData->OFDM_24G_Diff[RFPath][TX_1S]); */ ++ } ++ /* BW20-1S, BW20-2S */ ++ if (BandWidth == CHANNEL_WIDTH_20) ++ { ++ if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW20_24G_Diff[RFPath][TX_1S]; ++ if ((MGN_MCS8 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT2SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW20_24G_Diff[RFPath][TX_2S]; ++ if ((MGN_MCS16 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT3SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW20_24G_Diff[RFPath][TX_3S]; ++ if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW20_24G_Diff[RFPath][TX_4S]; ++ ++ /* DBG_871X("+PowerDiff 2.4G (RF-%c): (BW20-1S, BW20-2S, BW20-3S, BW20-4S) = (%d, %d, %d, %d)\n", ((RFPath == 0)?'A':(RFPath == 1)?'B':(RFPath ==2)?'C':'D'), */ ++ /* pHalData->BW20_24G_Diff[RFPath][TX_1S], pHalData->BW20_24G_Diff[RFPath][TX_2S], */ ++ /* pHalData->BW20_24G_Diff[RFPath][TX_3S], pHalData->BW20_24G_Diff[RFPath][TX_4S]); */ ++ } ++ /* BW40-1S, BW40-2S */ ++ else if (BandWidth == CHANNEL_WIDTH_40) ++ { ++ if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW40_24G_Diff[RFPath][TX_1S]; ++ if ((MGN_MCS8 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT2SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW40_24G_Diff[RFPath][TX_2S]; ++ if ((MGN_MCS16 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT3SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW40_24G_Diff[RFPath][TX_3S]; ++ if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW40_24G_Diff[RFPath][TX_4S]; ++ ++ /* DBG_871X("+PowerDiff 2.4G (RF-%c): (BW40-1S, BW40-2S, BW40-3S, BW40-4S) = (%d, %d, %d, %d)\n", ((RFPath == 0)?'A':(RFPath == 1)?'B':(RFPath ==2)?'C':'D'), */ ++ /* pHalData->BW40_24G_Diff[RFPath][TX_1S], pHalData->BW40_24G_Diff[RFPath][TX_2S], */ ++ /* pHalData->BW40_24G_Diff[RFPath][TX_3S], pHalData->BW40_24G_Diff[RFPath][TX_4S]); */ ++ } ++ /* Willis suggest adopt BW 40M power index while in BW 80 mode */ ++ else if (BandWidth == CHANNEL_WIDTH_80) ++ { ++ if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW40_24G_Diff[RFPath][TX_1S]; ++ if ((MGN_MCS8 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT2SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW40_24G_Diff[RFPath][TX_2S]; ++ if ((MGN_MCS16 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT3SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW40_24G_Diff[RFPath][TX_3S]; ++ if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW40_24G_Diff[RFPath][TX_4S]; ++ ++ /* DBG_871X("+PowerDiff 2.4G (RF-%c): (BW40-1S, BW40-2S, BW40-3S, BW40-4T) = (%d, %d, %d, %d) P.S. Current is in BW 80MHz\n", ((RFPath == 0)?'A':(RFPath == 1)?'B':(RFPath ==2)?'C':'D'), */ ++ /* pHalData->BW40_24G_Diff[RFPath][TX_1S], pHalData->BW40_24G_Diff[RFPath][TX_2S], */ ++ /* pHalData->BW40_24G_Diff[RFPath][TX_3S], pHalData->BW40_24G_Diff[RFPath][TX_4S]); */ ++ } ++ } ++ else /* 3 ============================== 5 G ============================== */ ++ { ++ if (MGN_6M <= Rate) ++ { ++ txPower = pHalData->Index5G_BW40_Base[RFPath][chnlIdx]; ++ } ++ else ++ { ++ DBG_871X("===> mpt_ProQueryCalTxPower_Jaguar: INVALID Rate.\n"); ++ } ++ ++ /* DBG_871X("Base Tx power(RF-%c, Rate #%d, Channel Index %d) = 0x%X\n", */ ++ /* ((RFPath == 0)?'A':'B'), Rate, chnlIdx, txPower); */ ++ ++ /* OFDM-1T */ ++ if ((MGN_6M <= Rate && Rate <= MGN_54M) && ! IS_CCK_RATE(Rate)) ++ { ++ txPower += pHalData->OFDM_5G_Diff[RFPath][TX_1S]; ++ /* DBG_871X("+PowerDiff 5G (RF-%c): (OFDM-1T) = (%d)\n", ((RFPath == 0)?'A':'B'), pHalData->OFDM_5G_Diff[RFPath][TX_1S]); */ ++ } ++ ++ /* BW20-1S, BW20-2S */ ++ if (BandWidth == CHANNEL_WIDTH_20) ++ { ++ if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW20_5G_Diff[RFPath][TX_1S]; ++ if ((MGN_MCS8 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT2SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW20_5G_Diff[RFPath][TX_2S]; ++ if ((MGN_MCS16 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT3SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW20_5G_Diff[RFPath][TX_3S]; ++ if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW20_5G_Diff[RFPath][TX_4S]; ++ ++ /* DBG_871X("+PowerDiff 5G (RF-%c): (BW20-1S, BW20-2S, BW20-3S, BW20-4S) = (%d, %d, %d, %d)\n", ((RFPath == 0)?'A':(RFPath == 1)?'B':(RFPath ==2)?'C':'D'), */ ++ /* pHalData->BW20_5G_Diff[RFPath][TX_1S], pHalData->BW20_5G_Diff[RFPath][TX_2S], */ ++ /* pHalData->BW20_5G_Diff[RFPath][TX_3S], pHalData->BW20_5G_Diff[RFPath][TX_4S]); */ ++ } ++ /* BW40-1S, BW40-2S */ ++ else if (BandWidth == CHANNEL_WIDTH_40) ++ { ++ if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW40_5G_Diff[RFPath][TX_1S]; ++ if ((MGN_MCS8 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT2SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW40_5G_Diff[RFPath][TX_2S]; ++ if ((MGN_MCS16 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT3SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW40_5G_Diff[RFPath][TX_3S]; ++ if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW40_5G_Diff[RFPath][TX_4S]; ++ ++ /* DBG_871X("+PowerDiff 5G(RF-%c): (BW40-1S, BW40-2S) = (%d, %d, %d, %d)\n", ((RFPath == 0)?'A':(RFPath == 1)?'B':(RFPath ==2)?'C':'D'), */ ++ /* pHalData->BW40_5G_Diff[RFPath][TX_1S], pHalData->BW40_5G_Diff[RFPath][TX_2S], */ ++ /* pHalData->BW40_5G_Diff[RFPath][TX_3S], pHalData->BW40_5G_Diff[RFPath][TX_4S]); */ ++ } ++ /* BW80-1S, BW80-2S */ ++ else if (BandWidth == CHANNEL_WIDTH_80) ++ { ++ /* <20121220, Kordan> Get the index of array "Index5G_BW80_Base". */ ++ u8 channel5G_80M[CHANNEL_MAX_NUMBER_5G_80M] = {42, 58, 106, 122, 138, 155, 171}; ++ for (i = 0; i < sizeof(channel5G_80M)/sizeof(u8); ++i) ++ if (channel5G_80M[i] == Channel) ++ chnlIdx = i; ++ ++ txPower = pHalData->Index5G_BW80_Base[RFPath][chnlIdx]; ++ ++ if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += + pHalData->BW80_5G_Diff[RFPath][TX_1S]; ++ if ((MGN_MCS8 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT2SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW80_5G_Diff[RFPath][TX_2S]; ++ if ((MGN_MCS16 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT3SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW80_5G_Diff[RFPath][TX_3S]; ++ if ((MGN_MCS23 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) ++ txPower += pHalData->BW80_5G_Diff[RFPath][TX_4S]; ++ ++ /* DBG_871X("+PowerDiff 5G(RF-%c): (BW80-1S, BW80-2S, BW80-3S, BW80-4S) = (%d, %d, %d, %d)\n", ((RFPath == 0)?'A':(RFPath == 1)?'B':(RFPath ==2)?'C':'D'), */ ++ /* pHalData->BW80_5G_Diff[RFPath][TX_1S], pHalData->BW80_5G_Diff[RFPath][TX_2S], */ ++ /* pHalData->BW80_5G_Diff[RFPath][TX_3S], pHalData->BW80_5G_Diff[RFPath][TX_4S]); */ ++ } ++ } ++ ++ return txPower; ++} ++ ++s8 ++PHY_GetTxPowerTrackingOffset( ++ struct adapter *padapter, ++ u8 RFPath, ++ u8 Rate ++ ) ++{ ++ struct hal_com_data * pHalData = GET_HAL_DATA(padapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ s8 offset = 0; ++ ++ if (pDM_Odm->RFCalibrateInfo.TxPowerTrackControl == false) ++ return offset; ++ ++ if ((Rate == MGN_1M) ||(Rate == MGN_2M)||(Rate == MGN_5_5M)||(Rate == MGN_11M)) ++ { ++ offset = pDM_Odm->Remnant_CCKSwingIdx; ++ /* DBG_871X("+Remnant_CCKSwingIdx = 0x%x\n", RFPath, Rate, pDM_Odm->Remnant_CCKSwingIdx); */ ++ } ++ else ++ { ++ offset = pDM_Odm->Remnant_OFDMSwingIdx[RFPath]; ++ /* DBG_871X("+Remanant_OFDMSwingIdx[RFPath %u][Rate 0x%x] = 0x%x\n", RFPath, Rate, pDM_Odm->Remnant_OFDMSwingIdx[RFPath]); */ ++ ++ } ++ ++ return offset; ++} ++ ++u8 ++PHY_GetRateIndexOfTxPowerByRate( ++u8 Rate ++ ) ++{ ++ u8 index = 0; ++ switch (Rate) ++ { ++ case MGN_1M: index = 0; break; ++ case MGN_2M: index = 1; break; ++ case MGN_5_5M: index = 2; break; ++ case MGN_11M: index = 3; break; ++ case MGN_6M: index = 4; break; ++ case MGN_9M: index = 5; break; ++ case MGN_12M: index = 6; break; ++ case MGN_18M: index = 7; break; ++ case MGN_24M: index = 8; break; ++ case MGN_36M: index = 9; break; ++ case MGN_48M: index = 10; break; ++ case MGN_54M: index = 11; break; ++ case MGN_MCS0: index = 12; break; ++ case MGN_MCS1: index = 13; break; ++ case MGN_MCS2: index = 14; break; ++ case MGN_MCS3: index = 15; break; ++ case MGN_MCS4: index = 16; break; ++ case MGN_MCS5: index = 17; break; ++ case MGN_MCS6: index = 18; break; ++ case MGN_MCS7: index = 19; break; ++ case MGN_MCS8: index = 20; break; ++ case MGN_MCS9: index = 21; break; ++ case MGN_MCS10: index = 22; break; ++ case MGN_MCS11: index = 23; break; ++ case MGN_MCS12: index = 24; break; ++ case MGN_MCS13: index = 25; break; ++ case MGN_MCS14: index = 26; break; ++ case MGN_MCS15: index = 27; break; ++ case MGN_MCS16: index = 28; break; ++ case MGN_MCS17: index = 29; break; ++ case MGN_MCS18: index = 30; break; ++ case MGN_MCS19: index = 31; break; ++ case MGN_MCS20: index = 32; break; ++ case MGN_MCS21: index = 33; break; ++ case MGN_MCS22: index = 34; break; ++ case MGN_MCS23: index = 35; break; ++ case MGN_MCS24: index = 36; break; ++ case MGN_MCS25: index = 37; break; ++ case MGN_MCS26: index = 38; break; ++ case MGN_MCS27: index = 39; break; ++ case MGN_MCS28: index = 40; break; ++ case MGN_MCS29: index = 41; break; ++ case MGN_MCS30: index = 42; break; ++ case MGN_MCS31: index = 43; break; ++ case MGN_VHT1SS_MCS0: index = 44; break; ++ case MGN_VHT1SS_MCS1: index = 45; break; ++ case MGN_VHT1SS_MCS2: index = 46; break; ++ case MGN_VHT1SS_MCS3: index = 47; break; ++ case MGN_VHT1SS_MCS4: index = 48; break; ++ case MGN_VHT1SS_MCS5: index = 49; break; ++ case MGN_VHT1SS_MCS6: index = 50; break; ++ case MGN_VHT1SS_MCS7: index = 51; break; ++ case MGN_VHT1SS_MCS8: index = 52; break; ++ case MGN_VHT1SS_MCS9: index = 53; break; ++ case MGN_VHT2SS_MCS0: index = 54; break; ++ case MGN_VHT2SS_MCS1: index = 55; break; ++ case MGN_VHT2SS_MCS2: index = 56; break; ++ case MGN_VHT2SS_MCS3: index = 57; break; ++ case MGN_VHT2SS_MCS4: index = 58; break; ++ case MGN_VHT2SS_MCS5: index = 59; break; ++ case MGN_VHT2SS_MCS6: index = 60; break; ++ case MGN_VHT2SS_MCS7: index = 61; break; ++ case MGN_VHT2SS_MCS8: index = 62; break; ++ case MGN_VHT2SS_MCS9: index = 63; break; ++ case MGN_VHT3SS_MCS0: index = 64; break; ++ case MGN_VHT3SS_MCS1: index = 65; break; ++ case MGN_VHT3SS_MCS2: index = 66; break; ++ case MGN_VHT3SS_MCS3: index = 67; break; ++ case MGN_VHT3SS_MCS4: index = 68; break; ++ case MGN_VHT3SS_MCS5: index = 69; break; ++ case MGN_VHT3SS_MCS6: index = 70; break; ++ case MGN_VHT3SS_MCS7: index = 71; break; ++ case MGN_VHT3SS_MCS8: index = 72; break; ++ case MGN_VHT3SS_MCS9: index = 73; break; ++ case MGN_VHT4SS_MCS0: index = 74; break; ++ case MGN_VHT4SS_MCS1: index = 75; break; ++ case MGN_VHT4SS_MCS2: index = 76; break; ++ case MGN_VHT4SS_MCS3: index = 77; break; ++ case MGN_VHT4SS_MCS4: index = 78; break; ++ case MGN_VHT4SS_MCS5: index = 79; break; ++ case MGN_VHT4SS_MCS6: index = 80; break; ++ case MGN_VHT4SS_MCS7: index = 81; break; ++ case MGN_VHT4SS_MCS8: index = 82; break; ++ case MGN_VHT4SS_MCS9: index = 83; break; ++ default: ++ DBG_871X("Invalid rate 0x%x in %s\n", Rate, __func__); ++ break; ++ }; ++ ++ return index; ++} ++ ++s8 ++PHY_GetTxPowerByRate( ++struct adapter *padapter, ++u8 Band, ++u8 RFPath, ++u8 TxNum, ++u8 Rate ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ s8 value = 0; ++ u8 rateIndex = PHY_GetRateIndexOfTxPowerByRate(Rate); ++ ++ if ((padapter->registrypriv.RegEnableTxPowerByRate == 2 && pHalData->EEPROMRegulatory == 2) || ++ padapter->registrypriv.RegEnableTxPowerByRate == 0) ++ return 0; ++ ++ if (Band != BAND_ON_2_4G && Band != BAND_ON_5G) ++ { ++ DBG_871X("Invalid band %d in %s\n", Band, __func__); ++ return value; ++ } ++ if (RFPath > ODM_RF_PATH_D) ++ { ++ DBG_871X("Invalid RfPath %d in %s\n", RFPath, __func__); ++ return value; ++ } ++ if (TxNum >= RF_MAX_TX_NUM) ++ { ++ DBG_871X("Invalid TxNum %d in %s\n", TxNum, __func__); ++ return value; ++ } ++ if (rateIndex >= TX_PWR_BY_RATE_NUM_RATE) ++ { ++ DBG_871X("Invalid RateIndex %d in %s\n", rateIndex, __func__); ++ return value; ++ } ++ ++ value = pHalData->TxPwrByRateOffset[Band][RFPath][TxNum][rateIndex]; ++ ++ return value; ++ ++} ++ ++void ++PHY_SetTxPowerByRate( ++struct adapter *padapter, ++u8 Band, ++u8 RFPath, ++u8 TxNum, ++u8 Rate, ++s8 Value ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ u8 rateIndex = PHY_GetRateIndexOfTxPowerByRate(Rate); ++ ++ if (Band != BAND_ON_2_4G && Band != BAND_ON_5G) ++ { ++ DBG_871X("Invalid band %d in %s\n", Band, __func__); ++ return; ++ } ++ if (RFPath > ODM_RF_PATH_D) ++ { ++ DBG_871X("Invalid RfPath %d in %s\n", RFPath, __func__); ++ return; ++ } ++ if (TxNum >= RF_MAX_TX_NUM) ++ { ++ DBG_871X("Invalid TxNum %d in %s\n", TxNum, __func__); ++ return; ++ } ++ if (rateIndex >= TX_PWR_BY_RATE_NUM_RATE) ++ { ++ DBG_871X("Invalid RateIndex %d in %s\n", rateIndex, __func__); ++ return; ++ } ++ ++ pHalData->TxPwrByRateOffset[Band][RFPath][TxNum][rateIndex] = Value; ++} ++ ++void ++PHY_SetTxPowerLevelByPath( ++struct adapter *Adapter, ++u8 channel, ++u8 path ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ bool bIsIn24G = (pHalData->CurrentBandType == BAND_ON_2_4G); ++ ++ /* if (pMgntInfo->RegNByteAccess == 0) */ ++ { ++ if (bIsIn24G) ++ PHY_SetTxPowerIndexByRateSection(Adapter, path, channel, CCK); ++ ++ PHY_SetTxPowerIndexByRateSection(Adapter, path, channel, OFDM); ++ PHY_SetTxPowerIndexByRateSection(Adapter, path, channel, HT_MCS0_MCS7); ++ ++ if (pHalData->NumTotalRFPath >= 2) ++ { ++ PHY_SetTxPowerIndexByRateSection(Adapter, path, channel, HT_MCS8_MCS15); ++ } ++ } ++} ++ ++void ++PHY_SetTxPowerIndexByRateArray( ++struct adapter * padapter, ++u8 RFPath, ++enum CHANNEL_WIDTH BandWidth, ++u8 Channel, ++u8 * Rates, ++u8 RateArraySize ++ ) ++{ ++ u32 powerIndex = 0; ++ int i = 0; ++ ++ for (i = 0; i < RateArraySize; ++i) ++ { ++ powerIndex = PHY_GetTxPowerIndex(padapter, RFPath, Rates[i], BandWidth, Channel); ++ PHY_SetTxPowerIndex(padapter, powerIndex, RFPath, Rates[i]); ++ } ++} ++ ++static s8 ++phy_GetWorldWideLimit( ++ s8 * LimitTable ++) ++{ ++ s8 min = LimitTable[0]; ++ u8 i = 0; ++ ++ for (i = 0; i < MAX_REGULATION_NUM; ++i) { ++ if (LimitTable[i] < min) ++ min = LimitTable[i]; ++ } ++ ++ return min; ++} ++ ++static s8 ++phy_GetChannelIndexOfTxPowerLimit( ++u8 Band, ++u8 Channel ++ ) ++{ ++ s8 channelIndex = -1; ++ u8 channel5G[CHANNEL_MAX_NUMBER_5G] = ++ {36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 100, 102, 104, 106, 108, 110, 112, ++ 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 149, 151, ++ 153, 155, 157, 159, 161, 163, 165, 167, 168, 169, 171, 173, 175, 177}; ++ u8 i = 0; ++ if (Band == BAND_ON_2_4G) ++ { ++ channelIndex = Channel - 1; ++ } ++ else if (Band == BAND_ON_5G) ++ { ++ for (i = 0; i < sizeof(channel5G)/sizeof(u8); ++i) ++ { ++ if (channel5G[i] == Channel) ++ channelIndex = i; ++ } ++ } ++ else ++ { ++ DBG_871X("Invalid Band %d in %s", Band, __func__); ++ } ++ ++ if (channelIndex == -1) ++ DBG_871X("Invalid Channel %d of Band %d in %s", Channel, Band, __func__); ++ ++ return channelIndex; ++} ++ ++s8 ++PHY_GetTxPowerLimit( ++struct adapter * Adapter, ++u32 RegPwrTblSel, ++enum BAND_TYPE Band, ++enum CHANNEL_WIDTH Bandwidth, ++u8 RfPath, ++u8 DataRate, ++u8 Channel ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ s16 band = -1, regulation = -1, bandwidth = -1, ++ rateSection = -1, channel = -1; ++ s8 powerLimit = MAX_POWER_INDEX; ++ ++ if ((Adapter->registrypriv.RegEnableTxPowerLimit == 2 && pHalData->EEPROMRegulatory != 1) || ++ Adapter->registrypriv.RegEnableTxPowerLimit == 0) ++ return MAX_POWER_INDEX; ++ ++ switch (Adapter->registrypriv.RegPwrTblSel) ++ { ++ case 1: ++ regulation = TXPWR_LMT_ETSI; ++ break; ++ case 2: ++ regulation = TXPWR_LMT_MKK; ++ break; ++ case 3: ++ regulation = TXPWR_LMT_FCC; ++ break; ++ ++ case 4: ++ regulation = TXPWR_LMT_WW; ++ break; ++ ++ default: ++ regulation = (Band == BAND_ON_2_4G) ? pHalData->Regulation2_4G ++ : pHalData->Regulation5G; ++ break; ++ } ++ ++ /* DBG_871X("pMgntInfo->RegPwrTblSel %d, final regulation %d\n", Adapter->registrypriv.RegPwrTblSel, regulation); */ ++ ++ ++ if (Band == BAND_ON_2_4G) band = 0; ++ else if (Band == BAND_ON_5G) band = 1; ++ ++ if (Bandwidth == CHANNEL_WIDTH_20) bandwidth = 0; ++ else if (Bandwidth == CHANNEL_WIDTH_40) bandwidth = 1; ++ else if (Bandwidth == CHANNEL_WIDTH_80) bandwidth = 2; ++ else if (Bandwidth == CHANNEL_WIDTH_160) bandwidth = 3; ++ ++ switch (DataRate) ++ { ++ case MGN_1M: case MGN_2M: case MGN_5_5M: case MGN_11M: ++ rateSection = 0; ++ break; ++ ++ case MGN_6M: case MGN_9M: case MGN_12M: case MGN_18M: ++ case MGN_24M: case MGN_36M: case MGN_48M: case MGN_54M: ++ rateSection = 1; ++ break; ++ ++ case MGN_MCS0: case MGN_MCS1: case MGN_MCS2: case MGN_MCS3: ++ case MGN_MCS4: case MGN_MCS5: case MGN_MCS6: case MGN_MCS7: ++ rateSection = 2; ++ break; ++ ++ case MGN_MCS8: case MGN_MCS9: case MGN_MCS10: case MGN_MCS11: ++ case MGN_MCS12: case MGN_MCS13: case MGN_MCS14: case MGN_MCS15: ++ rateSection = 3; ++ break; ++ ++ case MGN_MCS16: case MGN_MCS17: case MGN_MCS18: case MGN_MCS19: ++ case MGN_MCS20: case MGN_MCS21: case MGN_MCS22: case MGN_MCS23: ++ rateSection = 4; ++ break; ++ ++ case MGN_MCS24: case MGN_MCS25: case MGN_MCS26: case MGN_MCS27: ++ case MGN_MCS28: case MGN_MCS29: case MGN_MCS30: case MGN_MCS31: ++ rateSection = 5; ++ break; ++ ++ case MGN_VHT1SS_MCS0: case MGN_VHT1SS_MCS1: case MGN_VHT1SS_MCS2: ++ case MGN_VHT1SS_MCS3: case MGN_VHT1SS_MCS4: case MGN_VHT1SS_MCS5: ++ case MGN_VHT1SS_MCS6: case MGN_VHT1SS_MCS7: case MGN_VHT1SS_MCS8: ++ case MGN_VHT1SS_MCS9: ++ rateSection = 6; ++ break; ++ ++ case MGN_VHT2SS_MCS0: case MGN_VHT2SS_MCS1: case MGN_VHT2SS_MCS2: ++ case MGN_VHT2SS_MCS3: case MGN_VHT2SS_MCS4: case MGN_VHT2SS_MCS5: ++ case MGN_VHT2SS_MCS6: case MGN_VHT2SS_MCS7: case MGN_VHT2SS_MCS8: ++ case MGN_VHT2SS_MCS9: ++ rateSection = 7; ++ break; ++ ++ case MGN_VHT3SS_MCS0: case MGN_VHT3SS_MCS1: case MGN_VHT3SS_MCS2: ++ case MGN_VHT3SS_MCS3: case MGN_VHT3SS_MCS4: case MGN_VHT3SS_MCS5: ++ case MGN_VHT3SS_MCS6: case MGN_VHT3SS_MCS7: case MGN_VHT3SS_MCS8: ++ case MGN_VHT3SS_MCS9: ++ rateSection = 8; ++ break; ++ ++ case MGN_VHT4SS_MCS0: case MGN_VHT4SS_MCS1: case MGN_VHT4SS_MCS2: ++ case MGN_VHT4SS_MCS3: case MGN_VHT4SS_MCS4: case MGN_VHT4SS_MCS5: ++ case MGN_VHT4SS_MCS6: case MGN_VHT4SS_MCS7: case MGN_VHT4SS_MCS8: ++ case MGN_VHT4SS_MCS9: ++ rateSection = 9; ++ break; ++ ++ default: ++ DBG_871X("Wrong rate 0x%x\n", DataRate); ++ break; ++ } ++ ++ if (Band == BAND_ON_5G && rateSection == 0) ++ DBG_871X("Wrong rate 0x%x: No CCK in 5G Band\n", DataRate); ++ ++ /* workaround for wrong index combination to obtain tx power limit, */ ++ /* OFDM only exists in BW 20M */ ++ if (rateSection == 1) ++ bandwidth = 0; ++ ++ /* workaround for wrong index combination to obtain tx power limit, */ ++ /* CCK table will only be given in BW 20M */ ++ if (rateSection == 0) ++ bandwidth = 0; ++ ++ /* workaround for wrong indxe combination to obtain tx power limit, */ ++ /* HT on 80M will reference to HT on 40M */ ++ if ((rateSection == 2 || rateSection == 3) && Band == BAND_ON_5G && bandwidth == 2) { ++ bandwidth = 1; ++ } ++ ++ if (Band == BAND_ON_2_4G) ++ channel = phy_GetChannelIndexOfTxPowerLimit(BAND_ON_2_4G, Channel); ++ else if (Band == BAND_ON_5G) ++ channel = phy_GetChannelIndexOfTxPowerLimit(BAND_ON_5G, Channel); ++ else if (Band == BAND_ON_BOTH) ++ { ++ /* BAND_ON_BOTH don't care temporarily */ ++ } ++ ++ if (band == -1 || regulation == -1 || bandwidth == -1 || ++ rateSection == -1 || channel == -1) ++ { ++ /* DBG_871X("Wrong index value to access power limit table [band %d][regulation %d][bandwidth %d][rf_path %d][rate_section %d][chnlGroup %d]\n", */ ++ /* band, regulation, bandwidth, RfPath, rateSection, channelGroup); */ ++ ++ return MAX_POWER_INDEX; ++ } ++ ++ if (Band == BAND_ON_2_4G) { ++ s8 limits[10] = {0}; u8 i = 0; ++ for (i = 0; i < MAX_REGULATION_NUM; i++) ++ limits[i] = pHalData->TxPwrLimit_2_4G[i][bandwidth][rateSection][channel][RfPath]; ++ ++ powerLimit = (regulation == TXPWR_LMT_WW) ? phy_GetWorldWideLimit(limits) : ++ pHalData->TxPwrLimit_2_4G[regulation][bandwidth][rateSection][channel][RfPath]; ++ ++ } else if (Band == BAND_ON_5G) { ++ s8 limits[10] = {0}; u8 i = 0; ++ for (i = 0; i < MAX_REGULATION_NUM; ++i) ++ limits[i] = pHalData->TxPwrLimit_5G[i][bandwidth][rateSection][channel][RfPath]; ++ ++ powerLimit = (regulation == TXPWR_LMT_WW) ? phy_GetWorldWideLimit(limits) : ++ pHalData->TxPwrLimit_5G[regulation][bandwidth][rateSection][channel][RfPath]; ++ } else ++ DBG_871X("No power limit table of the specified band\n"); ++ ++ /* combine 5G VHT & HT rate */ ++ /* 5G 20M and 40M HT and VHT can cross reference */ ++ /* ++ if (Band == BAND_ON_5G && powerLimit == MAX_POWER_INDEX) { ++ if (bandwidth == 0 || bandwidth == 1) { ++ RT_TRACE(COMP_INIT, DBG_LOUD, ("No power limit table of the specified band %d, bandwidth %d, ratesection %d, rf path %d\n", ++ band, bandwidth, rateSection, RfPath)); ++ if (rateSection == 2) ++ powerLimit = pHalData->TxPwrLimit_5G[regulation] ++ [bandwidth][4][channelGroup][RfPath]; ++ else if (rateSection == 4) ++ powerLimit = pHalData->TxPwrLimit_5G[regulation] ++ [bandwidth][2][channelGroup][RfPath]; ++ else if (rateSection == 3) ++ powerLimit = pHalData->TxPwrLimit_5G[regulation] ++ [bandwidth][5][channelGroup][RfPath]; ++ else if (rateSection == 5) ++ powerLimit = pHalData->TxPwrLimit_5G[regulation] ++ [bandwidth][3][channelGroup][RfPath]; ++ } ++ } ++ */ ++ /* DBG_871X("TxPwrLmt[Regulation %d][Band %d][BW %d][RFPath %d][Rate 0x%x][Chnl %d] = %d\n", */ ++ /* regulation, pHalData->CurrentBandType, Bandwidth, RfPath, DataRate, Channel, powerLimit); */ ++ return powerLimit; ++} ++ ++static void ++phy_CrossReferenceHTAndVHTTxPowerLimit( ++struct adapter * padapter ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ u8 regulation, bw, channel, rateSection; ++ s8 tempPwrLmt = 0; ++ ++ for (regulation = 0; regulation < MAX_REGULATION_NUM; ++regulation) ++ { ++ for (bw = 0; bw < MAX_5G_BANDWITH_NUM; ++bw) ++ { ++ for (channel = 0; channel < CHANNEL_MAX_NUMBER_5G; ++channel) ++ { ++ for (rateSection = 0; rateSection < MAX_RATE_SECTION_NUM; ++rateSection) ++ { ++ tempPwrLmt = pHalData->TxPwrLimit_5G[regulation][bw][rateSection][channel][ODM_RF_PATH_A]; ++ if (tempPwrLmt == MAX_POWER_INDEX) ++ { ++ u8 baseSection = 2, refSection = 6; ++ if (bw == 0 || bw == 1) { /* 5G 20M 40M VHT and HT can cross reference */ ++ /* DBG_871X("No power limit table of the specified band %d, bandwidth %d, ratesection %d, channel %d, rf path %d\n", */ ++ /* 1, bw, rateSection, channel, ODM_RF_PATH_A); */ ++ if (rateSection >= 2 && rateSection <= 9) { ++ if (rateSection == 2) ++ { ++ baseSection = 2; ++ refSection = 6; ++ } ++ else if (rateSection == 3) ++ { ++ baseSection = 3; ++ refSection = 7; ++ } ++ else if (rateSection == 4) ++ { ++ baseSection = 4; ++ refSection = 8; ++ } ++ else if (rateSection == 5) ++ { ++ baseSection = 5; ++ refSection = 9; ++ } ++ else if (rateSection == 6) ++ { ++ baseSection = 6; ++ refSection = 2; ++ } ++ else if (rateSection == 7) ++ { ++ baseSection = 7; ++ refSection = 3; ++ } ++ else if (rateSection == 8) ++ { ++ baseSection = 8; ++ refSection = 4; ++ } ++ else if (rateSection == 9) ++ { ++ baseSection = 9; ++ refSection = 5; ++ } ++ pHalData->TxPwrLimit_5G[regulation][bw][baseSection][channel][ODM_RF_PATH_A] = ++ pHalData->TxPwrLimit_5G[regulation][bw][refSection][channel][ODM_RF_PATH_A]; ++ } ++ ++ /* DBG_871X("use other value %d", tempPwrLmt); */ ++ } ++ } ++ } ++ } ++ } ++ } ++} ++ ++void ++PHY_ConvertTxPowerLimitToPowerIndex( ++struct adapter * Adapter ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ u8 BW40PwrBasedBm2_4G = 0x2E; ++ u8 regulation, bw, channel, rateSection; ++ s8 tempValue = 0, tempPwrLmt = 0; ++ u8 rfPath = 0; ++ ++ /* DBG_871X("=====> PHY_ConvertTxPowerLimitToPowerIndex()\n"); */ ++ ++ phy_CrossReferenceHTAndVHTTxPowerLimit(Adapter); ++ ++ for (regulation = 0; regulation < MAX_REGULATION_NUM; ++regulation) ++ { ++ for (bw = 0; bw < MAX_2_4G_BANDWITH_NUM; ++bw) ++ { ++ for (channel = 0; channel < CHANNEL_MAX_NUMBER_2G; ++channel) ++ { ++ for (rateSection = 0; rateSection < MAX_RATE_SECTION_NUM; ++rateSection) ++ { ++ tempPwrLmt = pHalData->TxPwrLimit_2_4G[regulation][bw][rateSection][channel][ODM_RF_PATH_A]; ++ ++ for (rfPath = ODM_RF_PATH_A; rfPath < MAX_RF_PATH_NUM; ++rfPath) ++ { ++ if (pHalData->odmpriv.PhyRegPgValueType == PHY_REG_PG_EXACT_VALUE) ++ { ++ if (rateSection == 5) /* HT 4T */ ++ BW40PwrBasedBm2_4G = PHY_GetTxPowerByRateBase(Adapter, BAND_ON_2_4G, rfPath, RF_4TX, HT_MCS24_MCS31); ++ else if (rateSection == 4) /* HT 3T */ ++ BW40PwrBasedBm2_4G = PHY_GetTxPowerByRateBase(Adapter, BAND_ON_2_4G, rfPath, RF_3TX, HT_MCS16_MCS23); ++ else if (rateSection == 3) /* HT 2T */ ++ BW40PwrBasedBm2_4G = PHY_GetTxPowerByRateBase(Adapter, BAND_ON_2_4G, rfPath, RF_2TX, HT_MCS8_MCS15); ++ else if (rateSection == 2) /* HT 1T */ ++ BW40PwrBasedBm2_4G = PHY_GetTxPowerByRateBase(Adapter, BAND_ON_2_4G, rfPath, RF_1TX, HT_MCS0_MCS7); ++ else if (rateSection == 1) /* OFDM */ ++ BW40PwrBasedBm2_4G = PHY_GetTxPowerByRateBase(Adapter, BAND_ON_2_4G, rfPath, RF_1TX, OFDM); ++ else if (rateSection == 0) /* CCK */ ++ BW40PwrBasedBm2_4G = PHY_GetTxPowerByRateBase(Adapter, BAND_ON_2_4G, rfPath, RF_1TX, CCK); ++ } ++ else ++ BW40PwrBasedBm2_4G = Adapter->registrypriv.RegPowerBase * 2; ++ ++ if (tempPwrLmt != MAX_POWER_INDEX) { ++ tempValue = tempPwrLmt - BW40PwrBasedBm2_4G; ++ pHalData->TxPwrLimit_2_4G[regulation][bw][rateSection][channel][rfPath] = tempValue; ++ } ++ } ++ } ++ } ++ } ++ } ++ ++ /* DBG_871X("<===== PHY_ConvertTxPowerLimitToPowerIndex()\n"); */ ++} ++ ++void ++PHY_InitTxPowerLimit( ++struct adapter * Adapter ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ u8 i, j, k, l, m; ++ ++ /* DBG_871X("=====> PHY_InitTxPowerLimit()!\n"); */ ++ ++ for (i = 0; i < MAX_REGULATION_NUM; ++i) ++ { ++ for (j = 0; j < MAX_2_4G_BANDWITH_NUM; ++j) ++ for (k = 0; k < MAX_RATE_SECTION_NUM; ++k) ++ for (m = 0; m < CHANNEL_MAX_NUMBER_2G; ++m) ++ for (l = 0; l < MAX_RF_PATH_NUM; ++l) ++ pHalData->TxPwrLimit_2_4G[i][j][k][m][l] = MAX_POWER_INDEX; ++ } ++ ++ for (i = 0; i < MAX_REGULATION_NUM; ++i) ++ { ++ for (j = 0; j < MAX_5G_BANDWITH_NUM; ++j) ++ for (k = 0; k < MAX_RATE_SECTION_NUM; ++k) ++ for (m = 0; m < CHANNEL_MAX_NUMBER_5G; ++m) ++ for (l = 0; l < MAX_RF_PATH_NUM; ++l) ++ pHalData->TxPwrLimit_5G[i][j][k][m][l] = MAX_POWER_INDEX; ++ } ++ ++ /* DBG_871X("<===== PHY_InitTxPowerLimit()!\n"); */ ++} ++ ++void ++PHY_SetTxPowerLimit( ++struct adapter * Adapter, ++u8 *Regulation, ++u8 *Band, ++u8 *Bandwidth, ++u8 *RateSection, ++u8 *RfPath, ++u8 *Channel, ++u8 *PowerLimit ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ u8 regulation = 0, bandwidth = 0, rateSection = 0, ++ channel; ++ s8 powerLimit = 0, prevPowerLimit, channelIndex; ++ ++ /* DBG_871X("Index of power limit table [band %s][regulation %s][bw %s][rate section %s][rf path %s][chnl %s][val %s]\n", */ ++ /* Band, Regulation, Bandwidth, RateSection, RfPath, Channel, PowerLimit); */ ++ ++ if (!GetU1ByteIntegerFromStringInDecimal((s8 *)Channel, &channel) || ++ !GetU1ByteIntegerFromStringInDecimal((s8 *)PowerLimit, &powerLimit)) ++ { ++ DBG_871X("Illegal index of power limit table [chnl %s][val %s]\n", Channel, PowerLimit); ++ } ++ ++ powerLimit = powerLimit > MAX_POWER_INDEX ? MAX_POWER_INDEX : powerLimit; ++ ++ if (eqNByte(Regulation, (u8 *)("FCC"), 3)) regulation = 0; ++ else if (eqNByte(Regulation, (u8 *)("MKK"), 3)) regulation = 1; ++ else if (eqNByte(Regulation, (u8 *)("ETSI"), 4)) regulation = 2; ++ else if (eqNByte(Regulation, (u8 *)("WW13"), 4)) regulation = 3; ++ ++ if (eqNByte(RateSection, (u8 *)("CCK"), 3) && eqNByte(RfPath, (u8 *)("1T"), 2)) ++ rateSection = 0; ++ else if (eqNByte(RateSection, (u8 *)("OFDM"), 4) && eqNByte(RfPath, (u8 *)("1T"), 2)) ++ rateSection = 1; ++ else if (eqNByte(RateSection, (u8 *)("HT"), 2) && eqNByte(RfPath, (u8 *)("1T"), 2)) ++ rateSection = 2; ++ else if (eqNByte(RateSection, (u8 *)("HT"), 2) && eqNByte(RfPath, (u8 *)("2T"), 2)) ++ rateSection = 3; ++ else if (eqNByte(RateSection, (u8 *)("HT"), 2) && eqNByte(RfPath, (u8 *)("3T"), 2)) ++ rateSection = 4; ++ else if (eqNByte(RateSection, (u8 *)("HT"), 2) && eqNByte(RfPath, (u8 *)("4T"), 2)) ++ rateSection = 5; ++ else if (eqNByte(RateSection, (u8 *)("VHT"), 3) && eqNByte(RfPath, (u8 *)("1T"), 2)) ++ rateSection = 6; ++ else if (eqNByte(RateSection, (u8 *)("VHT"), 3) && eqNByte(RfPath, (u8 *)("2T"), 2)) ++ rateSection = 7; ++ else if (eqNByte(RateSection, (u8 *)("VHT"), 3) && eqNByte(RfPath, (u8 *)("3T"), 2)) ++ rateSection = 8; ++ else if (eqNByte(RateSection, (u8 *)("VHT"), 3) && eqNByte(RfPath, (u8 *)("4T"), 2)) ++ rateSection = 9; ++ else ++ { ++ DBG_871X("Wrong rate section!\n"); ++ return; ++ } ++ ++ ++ if (eqNByte(Bandwidth, (u8 *)("20M"), 3)) bandwidth = 0; ++ else if (eqNByte(Bandwidth, (u8 *)("40M"), 3)) bandwidth = 1; ++ else if (eqNByte(Bandwidth, (u8 *)("80M"), 3)) bandwidth = 2; ++ else if (eqNByte(Bandwidth, (u8 *)("160M"), 4)) bandwidth = 3; ++ ++ if (eqNByte(Band, (u8 *)("2.4G"), 4)) ++ { ++ channelIndex = phy_GetChannelIndexOfTxPowerLimit(BAND_ON_2_4G, channel); ++ ++ if (channelIndex == -1) ++ return; ++ ++ prevPowerLimit = pHalData->TxPwrLimit_2_4G[regulation][bandwidth][rateSection][channelIndex][ODM_RF_PATH_A]; ++ ++ if (powerLimit < prevPowerLimit) ++ pHalData->TxPwrLimit_2_4G[regulation][bandwidth][rateSection][channelIndex][ODM_RF_PATH_A] = powerLimit; ++ ++ /* DBG_871X("2.4G Band value : [regulation %d][bw %d][rate_section %d][chnl %d][val %d]\n", */ ++ /* regulation, bandwidth, rateSection, channelIndex, pHalData->TxPwrLimit_2_4G[regulation][bandwidth][rateSection][channelIndex][ODM_RF_PATH_A]); */ ++ } ++ else if (eqNByte(Band, (u8 *)("5G"), 2)) ++ { ++ channelIndex = phy_GetChannelIndexOfTxPowerLimit(BAND_ON_5G, channel); ++ ++ if (channelIndex == -1) ++ return; ++ ++ prevPowerLimit = pHalData->TxPwrLimit_5G[regulation][bandwidth][rateSection][channelIndex][ODM_RF_PATH_A]; ++ ++ if (powerLimit < prevPowerLimit) ++ pHalData->TxPwrLimit_5G[regulation][bandwidth][rateSection][channelIndex][ODM_RF_PATH_A] = powerLimit; ++ ++ /* DBG_871X("5G Band value : [regulation %d][bw %d][rate_section %d][chnl %d][val %d]\n", */ ++ /* regulation, bandwidth, rateSection, channel, pHalData->TxPwrLimit_5G[regulation][bandwidth][rateSection][channelIndex][ODM_RF_PATH_A]); */ ++ } ++ else ++ { ++ DBG_871X("Cannot recognize the band info in %s\n", Band); ++ return; ++ } ++} ++ ++u8 ++PHY_GetTxPowerIndex( ++struct adapter * padapter, ++u8 RFPath, ++u8 Rate, ++enum CHANNEL_WIDTH BandWidth, ++u8 Channel ++ ) ++{ ++ return PHY_GetTxPowerIndex_8723B(padapter, RFPath, Rate, BandWidth, Channel); ++} ++ ++void ++PHY_SetTxPowerIndex( ++struct adapter * padapter, ++u32 PowerIndex, ++u8 RFPath, ++u8 Rate ++ ) ++{ ++ PHY_SetTxPowerIndex_8723B(padapter, PowerIndex, RFPath, Rate); ++} ++ ++void ++Hal_ChannelPlanToRegulation( ++struct adapter * Adapter, ++u16 ChannelPlan ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ pHalData->Regulation2_4G = TXPWR_LMT_WW; ++ pHalData->Regulation5G = TXPWR_LMT_WW; ++ ++ switch (ChannelPlan) ++ { ++ case RT_CHANNEL_DOMAIN_WORLD_NULL: ++ pHalData->Regulation2_4G = TXPWR_LMT_WW; ++ break; ++ case RT_CHANNEL_DOMAIN_ETSI1_NULL: ++ pHalData->Regulation2_4G = TXPWR_LMT_ETSI; ++ break; ++ case RT_CHANNEL_DOMAIN_FCC1_NULL: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_MKK1_NULL: ++ pHalData->Regulation2_4G = TXPWR_LMT_MKK; ++ break; ++ case RT_CHANNEL_DOMAIN_ETSI2_NULL: ++ pHalData->Regulation2_4G = TXPWR_LMT_ETSI; ++ break; ++ case RT_CHANNEL_DOMAIN_FCC1_FCC1: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_WORLD_ETSI1: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_ETSI; ++ break; ++ case RT_CHANNEL_DOMAIN_MKK1_MKK1: ++ pHalData->Regulation2_4G = TXPWR_LMT_MKK; ++ pHalData->Regulation5G = TXPWR_LMT_MKK; ++ break; ++ case RT_CHANNEL_DOMAIN_WORLD_KCC1: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_MKK; ++ break; ++ case RT_CHANNEL_DOMAIN_WORLD_FCC2: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_WORLD_FCC3: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_WORLD_FCC4: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_WORLD_FCC5: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_WORLD_FCC6: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_FCC1_FCC7: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_WORLD_ETSI2: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_WORLD_ETSI3: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_MKK1_MKK2: ++ pHalData->Regulation2_4G = TXPWR_LMT_MKK; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_MKK1_MKK3: ++ pHalData->Regulation2_4G = TXPWR_LMT_MKK; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_FCC1_NCC1: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_FCC1_NCC2: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_GLOBAL_NULL: ++ pHalData->Regulation2_4G = TXPWR_LMT_WW; ++ pHalData->Regulation5G = TXPWR_LMT_WW; ++ break; ++ case RT_CHANNEL_DOMAIN_ETSI1_ETSI4: ++ pHalData->Regulation2_4G = TXPWR_LMT_ETSI; ++ pHalData->Regulation5G = TXPWR_LMT_ETSI; ++ break; ++ case RT_CHANNEL_DOMAIN_FCC1_FCC2: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_FCC1_NCC3: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_WORLD_ETSI5: ++ pHalData->Regulation2_4G = TXPWR_LMT_ETSI; ++ pHalData->Regulation5G = TXPWR_LMT_ETSI; ++ break; ++ case RT_CHANNEL_DOMAIN_FCC1_FCC8: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_WORLD_ETSI6: ++ pHalData->Regulation2_4G = TXPWR_LMT_ETSI; ++ pHalData->Regulation5G = TXPWR_LMT_ETSI; ++ break; ++ case RT_CHANNEL_DOMAIN_WORLD_ETSI7: ++ pHalData->Regulation2_4G = TXPWR_LMT_ETSI; ++ pHalData->Regulation5G = TXPWR_LMT_ETSI; ++ break; ++ case RT_CHANNEL_DOMAIN_WORLD_ETSI8: ++ pHalData->Regulation2_4G = TXPWR_LMT_ETSI; ++ pHalData->Regulation5G = TXPWR_LMT_ETSI; ++ break; ++ case RT_CHANNEL_DOMAIN_WORLD_ETSI9: ++ pHalData->Regulation2_4G = TXPWR_LMT_ETSI; ++ pHalData->Regulation5G = TXPWR_LMT_ETSI; ++ break; ++ case RT_CHANNEL_DOMAIN_WORLD_ETSI10: ++ pHalData->Regulation2_4G = TXPWR_LMT_ETSI; ++ pHalData->Regulation5G = TXPWR_LMT_ETSI; ++ break; ++ case RT_CHANNEL_DOMAIN_WORLD_ETSI11: ++ pHalData->Regulation2_4G = TXPWR_LMT_ETSI; ++ pHalData->Regulation5G = TXPWR_LMT_ETSI; ++ break; ++ case RT_CHANNEL_DOMAIN_FCC1_NCC4: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_WORLD_ETSI12: ++ pHalData->Regulation2_4G = TXPWR_LMT_ETSI; ++ pHalData->Regulation5G = TXPWR_LMT_ETSI; ++ break; ++ case RT_CHANNEL_DOMAIN_FCC1_FCC9: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_WORLD_ETSI13: ++ pHalData->Regulation2_4G = TXPWR_LMT_ETSI; ++ pHalData->Regulation5G = TXPWR_LMT_ETSI; ++ break; ++ case RT_CHANNEL_DOMAIN_FCC1_FCC10: ++ pHalData->Regulation2_4G = TXPWR_LMT_FCC; ++ pHalData->Regulation5G = TXPWR_LMT_FCC; ++ break; ++ case RT_CHANNEL_DOMAIN_REALTEK_DEFINE: /* Realtek Reserve */ ++ pHalData->Regulation2_4G = TXPWR_LMT_WW; ++ pHalData->Regulation5G = TXPWR_LMT_WW; ++ break; ++ default: ++ break; ++ } ++} ++ ++#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE ++ ++static char file_path_bs[PATH_MAX]; ++ ++#define GetLineFromBuffer(buffer) strsep(&buffer, "\n") ++ ++int ++phy_ConfigMACWithParaFile( ++struct adapter *Adapter, ++char* pFileName ++) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ int rlen = 0, rtStatus = _FAIL; ++ char *szLine, *ptmp; ++ u32 u4bRegOffset, u4bRegValue, u4bMove; ++ ++ if (!(Adapter->registrypriv.load_phy_file & LOAD_MAC_PARA_FILE)) ++ return rtStatus; ++ ++ memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); ++ ++ if ((pHalData->mac_reg_len == 0) && (pHalData->mac_reg == NULL)) ++ { ++ rtw_merge_string(file_path_bs, PATH_MAX, rtw_phy_file_path, pFileName); ++ ++ if (rtw_is_file_readable(file_path_bs) == true) ++ { ++ rlen = rtw_retrive_from_file(file_path_bs, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); ++ if (rlen > 0) ++ { ++ rtStatus = _SUCCESS; ++ pHalData->mac_reg = vzalloc(rlen); ++ if (pHalData->mac_reg) { ++ memcpy(pHalData->mac_reg, pHalData->para_file_buf, rlen); ++ pHalData->mac_reg_len = rlen; ++ } ++ else { ++ DBG_871X("%s mac_reg alloc fail !\n", __func__); ++ } ++ } ++ } ++ } ++ else ++ { ++ if ((pHalData->mac_reg_len != 0) && (pHalData->mac_reg != NULL)) { ++ memcpy(pHalData->para_file_buf, pHalData->mac_reg, pHalData->mac_reg_len); ++ rtStatus = _SUCCESS; ++ } ++ else { ++ DBG_871X("%s(): Critical Error !!!\n", __func__); ++ } ++ } ++ ++ if (rtStatus == _SUCCESS) ++ { ++ ptmp = pHalData->para_file_buf; ++ for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) ++ { ++ if (!IsCommentString(szLine)) ++ { ++ /* Get 1st hex value as register offset */ ++ if (GetHexValueFromString(szLine, &u4bRegOffset, &u4bMove)) ++ { ++ if (u4bRegOffset == 0xffff) ++ { /* Ending. */ ++ break; ++ } ++ ++ /* Get 2nd hex value as register value. */ ++ szLine += u4bMove; ++ if (GetHexValueFromString(szLine, &u4bRegValue, &u4bMove)) ++ { ++ rtw_write8(Adapter, u4bRegOffset, (u8)u4bRegValue); ++ } ++ } ++ } ++ } ++ } ++ else ++ { ++ DBG_871X("%s(): No File %s, Load from HWImg Array!\n", __func__, pFileName); ++ } ++ ++ return rtStatus; ++} ++ ++int ++phy_ConfigBBWithParaFile( ++struct adapter *Adapter, ++char* pFileName, ++u32 ConfigType ++) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ int rlen = 0, rtStatus = _FAIL; ++ char *szLine, *ptmp; ++ u32 u4bRegOffset, u4bRegValue, u4bMove; ++ char *pBuf = NULL; ++ u32 *pBufLen = NULL; ++ ++ if (!(Adapter->registrypriv.load_phy_file & LOAD_BB_PARA_FILE)) ++ return rtStatus; ++ ++ switch (ConfigType) ++ { ++ case CONFIG_BB_PHY_REG: ++ pBuf = pHalData->bb_phy_reg; ++ pBufLen = &pHalData->bb_phy_reg_len; ++ break; ++ case CONFIG_BB_AGC_TAB: ++ pBuf = pHalData->bb_agc_tab; ++ pBufLen = &pHalData->bb_agc_tab_len; ++ break; ++ default: ++ DBG_871X("Unknown ConfigType!! %d\r\n", ConfigType); ++ break; ++ } ++ ++ memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); ++ ++ if ((pBufLen != NULL) && (*pBufLen == 0) && (pBuf == NULL)) ++ { ++ rtw_merge_string(file_path_bs, PATH_MAX, rtw_phy_file_path, pFileName); ++ ++ if (rtw_is_file_readable(file_path_bs) == true) ++ { ++ rlen = rtw_retrive_from_file(file_path_bs, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); ++ if (rlen > 0) ++ { ++ rtStatus = _SUCCESS; ++ pBuf = vzalloc(rlen); ++ if (pBuf) { ++ memcpy(pBuf, pHalData->para_file_buf, rlen); ++ *pBufLen = rlen; ++ ++ switch (ConfigType) ++ { ++ case CONFIG_BB_PHY_REG: ++ pHalData->bb_phy_reg = pBuf; ++ break; ++ case CONFIG_BB_AGC_TAB: ++ pHalData->bb_agc_tab = pBuf; ++ break; ++ } ++ } ++ else { ++ DBG_871X("%s(): ConfigType %d alloc fail !\n", __func__, ConfigType); ++ } ++ } ++ } ++ } ++ else ++ { ++ if ((pBufLen != NULL) && (*pBufLen == 0) && (pBuf == NULL)) { ++ memcpy(pHalData->para_file_buf, pBuf, *pBufLen); ++ rtStatus = _SUCCESS; ++ } ++ else { ++ DBG_871X("%s(): Critical Error !!!\n", __func__); ++ } ++ } ++ ++ if (rtStatus == _SUCCESS) ++ { ++ ptmp = pHalData->para_file_buf; ++ for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) ++ { ++ if (!IsCommentString(szLine)) ++ { ++ /* Get 1st hex value as register offset. */ ++ if (GetHexValueFromString(szLine, &u4bRegOffset, &u4bMove)) ++ { ++ if (u4bRegOffset == 0xffff) ++ { /* Ending. */ ++ break; ++ } ++ else if (u4bRegOffset == 0xfe || u4bRegOffset == 0xffe) ++ { ++ msleep(50); ++ } ++ else if (u4bRegOffset == 0xfd) ++ { ++ mdelay(5); ++ } ++ else if (u4bRegOffset == 0xfc) ++ { ++ mdelay(1); ++ } ++ else if (u4bRegOffset == 0xfb) ++ { ++ udelay(50); ++ } ++ else if (u4bRegOffset == 0xfa) ++ { ++ udelay(5); ++ } ++ else if (u4bRegOffset == 0xf9) ++ { ++ udelay(1); ++ } ++ ++ /* Get 2nd hex value as register value. */ ++ szLine += u4bMove; ++ if (GetHexValueFromString(szLine, &u4bRegValue, &u4bMove)) ++ { ++ /* DBG_871X("[BB-ADDR]%03lX =%08lX\n", u4bRegOffset, u4bRegValue); */ ++ PHY_SetBBReg(Adapter, u4bRegOffset, bMaskDWord, u4bRegValue); ++ ++ if (u4bRegOffset == 0xa24) ++ pHalData->odmpriv.RFCalibrateInfo.RegA24 = u4bRegValue; ++ ++ /* Add 1us delay between BB/RF register setting. */ ++ udelay(1); ++ } ++ } ++ } ++ } ++ } ++ else ++ { ++ DBG_871X("%s(): No File %s, Load from HWImg Array!\n", __func__, pFileName); ++ } ++ ++ return rtStatus; ++} ++ ++static void ++phy_DecryptBBPgParaFile( ++ struct adapter * Adapter, ++ char* buffer ++ ) ++{ ++ u32 i = 0, j = 0; ++ u8 map[95] = {0}; ++ u8 currentChar; ++ char *BufOfLines, *ptmp; ++ ++ /* DBG_871X("=====>phy_DecryptBBPgParaFile()\n"); */ ++ /* 32 the ascii code of the first visable char, 126 the last one */ ++ for (i = 0; i < 95; ++i) ++ map[i] = (u8) (94 - i); ++ ++ ptmp = buffer; ++ i = 0; ++ for (BufOfLines = GetLineFromBuffer(ptmp); BufOfLines != NULL; BufOfLines = GetLineFromBuffer(ptmp)) ++ { ++ /* DBG_871X("Encrypted Line: %s\n", BufOfLines); */ ++ ++ for (j = 0; j < strlen(BufOfLines); ++j) ++ { ++ currentChar = BufOfLines[j]; ++ ++ if (currentChar == '\0') ++ break; ++ ++ currentChar -= (u8) ((((i + j) * 3) % 128)); ++ ++ BufOfLines[j] = map[currentChar - 32] + 32; ++ } ++ /* DBG_871X("Decrypted Line: %s\n", BufOfLines); */ ++ if (strlen(BufOfLines) != 0) ++ i++; ++ BufOfLines[strlen(BufOfLines)] = '\n'; ++ } ++} ++ ++static int ++phy_ParseBBPgParaFile( ++ struct adapter * Adapter, ++ char* buffer ++ ) ++{ ++ int rtStatus = _SUCCESS; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ char *szLine, *ptmp; ++ u32 u4bRegOffset, u4bRegMask, u4bRegValue; ++ u32 u4bMove; ++ bool firstLine = true; ++ u8 tx_num = 0; ++ u8 band = 0, rf_path = 0; ++ ++ /* DBG_871X("=====>phy_ParseBBPgParaFile()\n"); */ ++ ++ if (Adapter->registrypriv.RegDecryptCustomFile == 1) ++ phy_DecryptBBPgParaFile(Adapter, buffer); ++ ++ ptmp = buffer; ++ for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) ++ { ++ if (!IsCommentString(szLine)) ++ { ++ if (isAllSpaceOrTab(szLine, sizeof(*szLine))) ++ continue; ++ ++ /* Get header info (relative value or exact value) */ ++ if (firstLine) ++ { ++ if (eqNByte(szLine, (u8 *)("#[v1]"), 5)) ++ { ++ ++ pHalData->odmpriv.PhyRegPgVersion = szLine[3] - '0'; ++ /* DBG_871X("This is a new format PHY_REG_PG.txt\n"); */ ++ } ++ else if (eqNByte(szLine, (u8 *)("#[v0]"), 5)) ++ { ++ pHalData->odmpriv.PhyRegPgVersion = szLine[3] - '0'; ++ /* DBG_871X("This is a old format PHY_REG_PG.txt ok\n"); */ ++ } ++ else ++ { ++ DBG_871X("The format in PHY_REG_PG are invalid %s\n", szLine); ++ return _FAIL; ++ } ++ ++ if (eqNByte(szLine + 5, (u8 *)("[Exact]#"), 8)) ++ { ++ pHalData->odmpriv.PhyRegPgValueType = PHY_REG_PG_EXACT_VALUE; ++ /* DBG_871X("The values in PHY_REG_PG are exact values ok\n"); */ ++ firstLine = false; ++ continue; ++ } ++ else if (eqNByte(szLine + 5, (u8 *)("[Relative]#"), 11)) ++ { ++ pHalData->odmpriv.PhyRegPgValueType = PHY_REG_PG_RELATIVE_VALUE; ++ /* DBG_871X("The values in PHY_REG_PG are relative values ok\n"); */ ++ firstLine = false; ++ continue; ++ } ++ else ++ { ++ DBG_871X("The values in PHY_REG_PG are invalid %s\n", szLine); ++ return _FAIL; ++ } ++ } ++ ++ if (pHalData->odmpriv.PhyRegPgVersion == 0) ++ { ++ /* Get 1st hex value as register offset. */ ++ if (GetHexValueFromString(szLine, &u4bRegOffset, &u4bMove)) ++ { ++ szLine += u4bMove; ++ if (u4bRegOffset == 0xffff) ++ { /* Ending. */ ++ break; ++ } ++ ++ /* Get 2nd hex value as register mask. */ ++ if (GetHexValueFromString(szLine, &u4bRegMask, &u4bMove)) ++ szLine += u4bMove; ++ else ++ return _FAIL; ++ ++ if (pHalData->odmpriv.PhyRegPgValueType == PHY_REG_PG_RELATIVE_VALUE) ++ { ++ /* Get 3rd hex value as register value. */ ++ if (GetHexValueFromString(szLine, &u4bRegValue, &u4bMove)) ++ { ++ PHY_StoreTxPowerByRate(Adapter, 0, 0, 1, u4bRegOffset, u4bRegMask, u4bRegValue); ++ /* DBG_871X("[ADDR] %03X =%08X Mask =%08x\n", u4bRegOffset, u4bRegValue, u4bRegMask); */ ++ } ++ else ++ { ++ return _FAIL; ++ } ++ } ++ else if (pHalData->odmpriv.PhyRegPgValueType == PHY_REG_PG_EXACT_VALUE) ++ { ++ u32 combineValue = 0; ++ u8 integer = 0, fraction = 0; ++ ++ if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) ++ szLine += u4bMove; ++ else ++ return _FAIL; ++ ++ integer *= 2; ++ if (fraction == 5) integer += 1; ++ combineValue |= (((integer / 10) << 4) + (integer % 10)); ++ /* DBG_871X(" %d", integer); */ ++ ++ if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) ++ szLine += u4bMove; ++ else ++ return _FAIL; ++ ++ integer *= 2; ++ if (fraction == 5) integer += 1; ++ combineValue <<= 8; ++ combineValue |= (((integer / 10) << 4) + (integer % 10)); ++ /* DBG_871X(" %d", integer); */ ++ ++ if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) ++ szLine += u4bMove; ++ else ++ return _FAIL; ++ ++ integer *= 2; ++ if (fraction == 5) integer += 1; ++ combineValue <<= 8; ++ combineValue |= (((integer / 10) << 4) + (integer % 10)); ++ /* DBG_871X(" %d", integer); */ ++ ++ if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) ++ szLine += u4bMove; ++ else ++ return _FAIL; ++ ++ integer *= 2; ++ if (fraction == 5) integer += 1; ++ combineValue <<= 8; ++ combineValue |= (((integer / 10) << 4) + (integer % 10)); ++ /* DBG_871X(" %d", integer); */ ++ PHY_StoreTxPowerByRate(Adapter, 0, 0, 1, u4bRegOffset, u4bRegMask, combineValue); ++ ++ /* DBG_871X("[ADDR] 0x%3x = 0x%4x\n", u4bRegOffset, combineValue); */ ++ } ++ } ++ } ++ else if (pHalData->odmpriv.PhyRegPgVersion > 0) ++ { ++ u32 index = 0; ++ ++ if (eqNByte(szLine, "0xffff", 6)) ++ break; ++ ++ if (!eqNByte("#[END]#", szLine, 7)) ++ { ++ /* load the table label info */ ++ if (szLine[0] == '#') ++ { ++ index = 0; ++ if (eqNByte(szLine, "#[2.4G]" , 7)) ++ { ++ band = BAND_ON_2_4G; ++ index += 8; ++ } ++ else if (eqNByte(szLine, "#[5G]", 5)) ++ { ++ band = BAND_ON_5G; ++ index += 6; ++ } ++ else ++ { ++ DBG_871X("Invalid band %s in PHY_REG_PG.txt\n", szLine); ++ return _FAIL; ++ } ++ ++ rf_path = szLine[index] - 'A'; ++ /* DBG_871X(" Table label Band %d, RfPath %d\n", band, rf_path); */ ++ } ++ else /* load rows of tables */ ++ { ++ if (szLine[1] == '1') ++ tx_num = RF_1TX; ++ else if (szLine[1] == '2') ++ tx_num = RF_2TX; ++ else if (szLine[1] == '3') ++ tx_num = RF_3TX; ++ else if (szLine[1] == '4') ++ tx_num = RF_4TX; ++ else ++ { ++ DBG_871X("Invalid row in PHY_REG_PG.txt %c\n", szLine[1]); ++ return _FAIL; ++ } ++ ++ while (szLine[index] != ']') ++ ++index; ++ ++index;/* skip ] */ ++ ++ /* Get 2nd hex value as register offset. */ ++ szLine += index; ++ if (GetHexValueFromString(szLine, &u4bRegOffset, &u4bMove)) ++ szLine += u4bMove; ++ else ++ return _FAIL; ++ ++ /* Get 2nd hex value as register mask. */ ++ if (GetHexValueFromString(szLine, &u4bRegMask, &u4bMove)) ++ szLine += u4bMove; ++ else ++ return _FAIL; ++ ++ if (pHalData->odmpriv.PhyRegPgValueType == PHY_REG_PG_RELATIVE_VALUE) ++ { ++ /* Get 3rd hex value as register value. */ ++ if (GetHexValueFromString(szLine, &u4bRegValue, &u4bMove)) ++ { ++ PHY_StoreTxPowerByRate(Adapter, band, rf_path, tx_num, u4bRegOffset, u4bRegMask, u4bRegValue); ++ /* DBG_871X("[ADDR] %03X (tx_num %d) =%08X Mask =%08x\n", u4bRegOffset, tx_num, u4bRegValue, u4bRegMask); */ ++ } ++ else ++ { ++ return _FAIL; ++ } ++ } ++ else if (pHalData->odmpriv.PhyRegPgValueType == PHY_REG_PG_EXACT_VALUE) ++ { ++ u32 combineValue = 0; ++ u8 integer = 0, fraction = 0; ++ ++ if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) ++ szLine += u4bMove; ++ else ++ return _FAIL; ++ ++ integer *= 2; ++ if (fraction == 5) integer += 1; ++ combineValue |= (((integer / 10) << 4) + (integer % 10)); ++ /* DBG_871X(" %d", integer); */ ++ ++ if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) ++ szLine += u4bMove; ++ else ++ return _FAIL; ++ ++ integer *= 2; ++ if (fraction == 5) integer += 1; ++ combineValue <<= 8; ++ combineValue |= (((integer / 10) << 4) + (integer % 10)); ++ /* DBG_871X(" %d", integer); */ ++ ++ if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) ++ szLine += u4bMove; ++ else ++ return _FAIL; ++ ++ integer *= 2; ++ if (fraction == 5) integer += 1; ++ combineValue <<= 8; ++ combineValue |= (((integer / 10) << 4) + (integer % 10)); ++ /* DBG_871X(" %d", integer); */ ++ ++ if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) ++ szLine += u4bMove; ++ else ++ return _FAIL; ++ ++ integer *= 2; ++ if (fraction == 5) integer += 1; ++ combineValue <<= 8; ++ combineValue |= (((integer / 10) << 4) + (integer % 10)); ++ /* DBG_871X(" %d", integer); */ ++ PHY_StoreTxPowerByRate(Adapter, band, rf_path, tx_num, u4bRegOffset, u4bRegMask, combineValue); ++ ++ /* DBG_871X("[ADDR] 0x%3x (tx_num %d) = 0x%4x\n", u4bRegOffset, tx_num, combineValue); */ ++ } ++ } ++ } ++ } ++ } ++ } ++ /* DBG_871X("<=====phy_ParseBBPgParaFile()\n"); */ ++ return rtStatus; ++} ++ ++int ++phy_ConfigBBWithPgParaFile( ++struct adapter *Adapter, ++char* pFileName) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ int rlen = 0, rtStatus = _FAIL; ++ ++ if (!(Adapter->registrypriv.load_phy_file & LOAD_BB_PG_PARA_FILE)) ++ return rtStatus; ++ ++ memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); ++ ++ if ((pHalData->bb_phy_reg_pg_len == 0) && (pHalData->bb_phy_reg_pg == NULL)) ++ { ++ rtw_merge_string(file_path_bs, PATH_MAX, rtw_phy_file_path, pFileName); ++ ++ if (rtw_is_file_readable(file_path_bs) == true) ++ { ++ rlen = rtw_retrive_from_file(file_path_bs, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); ++ if (rlen > 0) ++ { ++ rtStatus = _SUCCESS; ++ pHalData->bb_phy_reg_pg = vzalloc(rlen); ++ if (pHalData->bb_phy_reg_pg) { ++ memcpy(pHalData->bb_phy_reg_pg, pHalData->para_file_buf, rlen); ++ pHalData->bb_phy_reg_pg_len = rlen; ++ } ++ else { ++ DBG_871X("%s bb_phy_reg_pg alloc fail !\n", __func__); ++ } ++ } ++ } ++ } ++ else ++ { ++ if ((pHalData->bb_phy_reg_pg_len != 0) && (pHalData->bb_phy_reg_pg != NULL)) { ++ memcpy(pHalData->para_file_buf, pHalData->bb_phy_reg_pg, pHalData->bb_phy_reg_pg_len); ++ rtStatus = _SUCCESS; ++ } ++ else { ++ DBG_871X("%s(): Critical Error !!!\n", __func__); ++ } ++ } ++ ++ if (rtStatus == _SUCCESS) ++ { ++ /* DBG_871X("phy_ConfigBBWithPgParaFile(): read %s ok\n", pFileName); */ ++ phy_ParseBBPgParaFile(Adapter, pHalData->para_file_buf); ++ } ++ else ++ { ++ DBG_871X("%s(): No File %s, Load from HWImg Array!\n", __func__, pFileName); ++ } ++ ++ return rtStatus; ++} ++ ++int ++PHY_ConfigRFWithParaFile( ++struct adapter *Adapter, ++char* pFileName, ++u8 eRFPath ++) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ int rlen = 0, rtStatus = _FAIL; ++ char *szLine, *ptmp; ++ u32 u4bRegOffset, u4bRegValue, u4bMove; ++ u16 i; ++ char *pBuf = NULL; ++ u32 *pBufLen = NULL; ++ ++ if (!(Adapter->registrypriv.load_phy_file & LOAD_RF_PARA_FILE)) ++ return rtStatus; ++ ++ switch (eRFPath) ++ { ++ case ODM_RF_PATH_A: ++ pBuf = pHalData->rf_radio_a; ++ pBufLen = &pHalData->rf_radio_a_len; ++ break; ++ case ODM_RF_PATH_B: ++ pBuf = pHalData->rf_radio_b; ++ pBufLen = &pHalData->rf_radio_b_len; ++ break; ++ default: ++ DBG_871X("Unknown RF path!! %d\r\n", eRFPath); ++ break; ++ } ++ ++ memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); ++ ++ if ((pBufLen != NULL) && (*pBufLen == 0) && (pBuf == NULL)) ++ { ++ rtw_merge_string(file_path_bs, PATH_MAX, rtw_phy_file_path, pFileName); ++ ++ if (rtw_is_file_readable(file_path_bs) == true) ++ { ++ rlen = rtw_retrive_from_file(file_path_bs, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); ++ if (rlen > 0) ++ { ++ rtStatus = _SUCCESS; ++ pBuf = vzalloc(rlen); ++ if (pBuf) { ++ memcpy(pBuf, pHalData->para_file_buf, rlen); ++ *pBufLen = rlen; ++ ++ switch (eRFPath) ++ { ++ case ODM_RF_PATH_A: ++ pHalData->rf_radio_a = pBuf; ++ break; ++ case ODM_RF_PATH_B: ++ pHalData->rf_radio_b = pBuf; ++ break; ++ } ++ } ++ else { ++ DBG_871X("%s(): eRFPath =%d alloc fail !\n", __func__, eRFPath); ++ } ++ } ++ } ++ } ++ else ++ { ++ if ((pBufLen != NULL) && (*pBufLen == 0) && (pBuf == NULL)) { ++ memcpy(pHalData->para_file_buf, pBuf, *pBufLen); ++ rtStatus = _SUCCESS; ++ } ++ else { ++ DBG_871X("%s(): Critical Error !!!\n", __func__); ++ } ++ } ++ ++ if (rtStatus == _SUCCESS) ++ { ++ /* DBG_871X("%s(): read %s successfully\n", __func__, pFileName); */ ++ ++ ptmp = pHalData->para_file_buf; ++ for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) ++ { ++ if (!IsCommentString(szLine)) ++ { ++ /* Get 1st hex value as register offset. */ ++ if (GetHexValueFromString(szLine, &u4bRegOffset, &u4bMove)) ++ { ++ if (u4bRegOffset == 0xfe || u4bRegOffset == 0xffe) ++ { /* Deay specific ms. Only RF configuration require delay. */ ++ msleep(50); ++ } ++ else if (u4bRegOffset == 0xfd) ++ { ++ /* mdelay(5); */ ++ for (i = 0;i<100;i++) ++ udelay(MAX_STALL_TIME); ++ } ++ else if (u4bRegOffset == 0xfc) ++ { ++ /* mdelay(1); */ ++ for (i = 0;i<20;i++) ++ udelay(MAX_STALL_TIME); ++ } ++ else if (u4bRegOffset == 0xfb) ++ { ++ udelay(50); ++ } ++ else if (u4bRegOffset == 0xfa) ++ { ++ udelay(5); ++ } ++ else if (u4bRegOffset == 0xf9) ++ { ++ udelay(1); ++ } ++ else if (u4bRegOffset == 0xffff) ++ { ++ break; ++ } ++ ++ /* Get 2nd hex value as register value. */ ++ szLine += u4bMove; ++ if (GetHexValueFromString(szLine, &u4bRegValue, &u4bMove)) ++ { ++ PHY_SetRFReg(Adapter, eRFPath, u4bRegOffset, bRFRegOffsetMask, u4bRegValue); ++ ++ /* Temp add, for frequency lock, if no delay, that may cause */ ++ /* frequency shift, ex: 2412MHz => 2417MHz */ ++ /* If frequency shift, the following action may works. */ ++ /* Fractional-N table in radio_a.txt */ ++ /* 0x2a 0x00001 channel 1 */ ++ /* 0x2b 0x00808 frequency divider. */ ++ /* 0x2b 0x53333 */ ++ /* 0x2c 0x0000c */ ++ udelay(1); ++ } ++ } ++ } ++ } ++ } ++ else ++ { ++ DBG_871X("%s(): No File %s, Load from HWImg Array!\n", __func__, pFileName); ++ } ++ ++ return rtStatus; ++} ++ ++static void ++initDeltaSwingIndexTables( ++ struct adapter *Adapter, ++ char* Band, ++ char* Path, ++ char* Sign, ++ char* Channel, ++ char* Rate, ++ char* Data ++) ++{ ++ #define STR_EQUAL_5G(_band, _path, _sign, _rate, _chnl) \ ++ ((strcmp(Band, _band) == 0) && (strcmp(Path, _path) == 0) && (strcmp(Sign, _sign) == 0) &&\ ++ (strcmp(Rate, _rate) == 0) && (strcmp(Channel, _chnl) == 0)\ ++ ) ++ #define STR_EQUAL_2G(_band, _path, _sign, _rate) \ ++ ((strcmp(Band, _band) == 0) && (strcmp(Path, _path) == 0) && (strcmp(Sign, _sign) == 0) &&\ ++ (strcmp(Rate, _rate) == 0)\ ++ ) ++ ++ #define STORE_SWING_TABLE(_array, _iteratedIdx) \ ++ for (token = strsep(&Data, delim); token != NULL; token = strsep(&Data, delim))\ ++ {\ ++ sscanf(token, "%d", &idx);\ ++ _array[_iteratedIdx++] = (u8)idx;\ ++ }\ ++ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ PODM_RF_CAL_T pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo); ++ u32 j = 0; ++ char *token; ++ char delim[] = ","; ++ u32 idx = 0; ++ ++ /* DBG_871X("===>initDeltaSwingIndexTables(): Band: %s;\nPath: %s;\nSign: %s;\nChannel: %s;\nRate: %s;\n, Data: %s;\n", */ ++ /* Band, Path, Sign, Channel, Rate, Data); */ ++ ++ if (STR_EQUAL_2G("2G", "A", "+", "CCK")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKA_P, j); ++ } ++ else if (STR_EQUAL_2G("2G", "A", "-", "CCK")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKA_N, j); ++ } ++ else if (STR_EQUAL_2G("2G", "B", "+", "CCK")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKB_P, j); ++ } ++ else if (STR_EQUAL_2G("2G", "B", "-", "CCK")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKB_N, j); ++ } ++ else if (STR_EQUAL_2G("2G", "A", "+", "ALL")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_2GA_P, j); ++ } ++ else if (STR_EQUAL_2G("2G", "A", "-", "ALL")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_2GA_N, j); ++ } ++ else if (STR_EQUAL_2G("2G", "B", "+", "ALL")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_2GB_P, j); ++ } ++ else if (STR_EQUAL_2G("2G", "B", "-", "ALL")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_2GB_N, j); ++ } ++ else if (STR_EQUAL_5G("5G", "A", "+", "ALL", "0")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P[0], j); ++ } ++ else if (STR_EQUAL_5G("5G", "A", "-", "ALL", "0")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N[0], j); ++ } ++ else if (STR_EQUAL_5G("5G", "B", "+", "ALL", "0")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P[0], j); ++ } ++ else if (STR_EQUAL_5G("5G", "B", "-", "ALL", "0")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N[0], j); ++ } ++ else if (STR_EQUAL_5G("5G", "A", "+", "ALL", "1")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P[1], j); ++ } ++ else if (STR_EQUAL_5G("5G", "A", "-", "ALL", "1")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N[1], j); ++ } ++ else if (STR_EQUAL_5G("5G", "B", "+", "ALL", "1")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P[1], j); ++ } ++ else if (STR_EQUAL_5G("5G", "B", "-", "ALL", "1")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N[1], j); ++ } ++ else if (STR_EQUAL_5G("5G", "A", "+", "ALL", "2")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P[2], j); ++ } ++ else if (STR_EQUAL_5G("5G", "A", "-", "ALL", "2")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N[2], j); ++ } ++ else if (STR_EQUAL_5G("5G", "B", "+", "ALL", "2")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P[2], j); ++ } ++ else if (STR_EQUAL_5G("5G", "B", "-", "ALL", "2")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N[2], j); ++ } ++ else if (STR_EQUAL_5G("5G", "A", "+", "ALL", "3")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P[3], j); ++ } ++ else if (STR_EQUAL_5G("5G", "A", "-", "ALL", "3")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N[3], j); ++ } ++ else if (STR_EQUAL_5G("5G", "B", "+", "ALL", "3")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P[3], j); ++ } ++ else if (STR_EQUAL_5G("5G", "B", "-", "ALL", "3")) ++ { ++ STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N[3], j); ++ } ++ else ++ { ++ DBG_871X("===>initDeltaSwingIndexTables(): The input is invalid!!\n"); ++ } ++} ++ ++int ++PHY_ConfigRFWithTxPwrTrackParaFile( ++struct adapter * Adapter, ++char* pFileName ++) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ int rlen = 0, rtStatus = _FAIL; ++ char *szLine, *ptmp; ++ u32 i = 0; ++ ++ if (!(Adapter->registrypriv.load_phy_file & LOAD_RF_TXPWR_TRACK_PARA_FILE)) ++ return rtStatus; ++ ++ memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); ++ ++ if ((pHalData->rf_tx_pwr_track_len == 0) && (pHalData->rf_tx_pwr_track == NULL)) ++ { ++ rtw_merge_string(file_path_bs, PATH_MAX, rtw_phy_file_path, pFileName); ++ ++ if (rtw_is_file_readable(file_path_bs) == true) ++ { ++ rlen = rtw_retrive_from_file(file_path_bs, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); ++ if (rlen > 0) ++ { ++ rtStatus = _SUCCESS; ++ pHalData->rf_tx_pwr_track = vzalloc(rlen); ++ if (pHalData->rf_tx_pwr_track) { ++ memcpy(pHalData->rf_tx_pwr_track, pHalData->para_file_buf, rlen); ++ pHalData->rf_tx_pwr_track_len = rlen; ++ } ++ else { ++ DBG_871X("%s rf_tx_pwr_track alloc fail !\n", __func__); ++ } ++ } ++ } ++ } ++ else ++ { ++ if ((pHalData->rf_tx_pwr_track_len != 0) && (pHalData->rf_tx_pwr_track != NULL)) { ++ memcpy(pHalData->para_file_buf, pHalData->rf_tx_pwr_track, pHalData->rf_tx_pwr_track_len); ++ rtStatus = _SUCCESS; ++ } ++ else { ++ DBG_871X("%s(): Critical Error !!!\n", __func__); ++ } ++ } ++ ++ if (rtStatus == _SUCCESS) ++ { ++ /* DBG_871X("%s(): read %s successfully\n", __func__, pFileName); */ ++ ++ ptmp = pHalData->para_file_buf; ++ for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) ++ { ++ if (! IsCommentString(szLine)) ++ { ++ char band[5]="", path[5]="", sign[5] = ""; ++ char chnl[5]="", rate[10]=""; ++ char data[300]=""; /* 100 is too small */ ++ ++ if (strlen(szLine) < 10 || szLine[0] != '[') ++ continue; ++ ++ strncpy(band, szLine+1, 2); ++ strncpy(path, szLine+5, 1); ++ strncpy(sign, szLine+8, 1); ++ ++ i = 10; /* szLine+10 */ ++ if (! ParseQualifiedString(szLine, &i, rate, '[', ']')) { ++ /* DBG_871X("Fail to parse rate!\n"); */ ++ } ++ if (! ParseQualifiedString(szLine, &i, chnl, '[', ']')) { ++ /* DBG_871X("Fail to parse channel group!\n"); */ ++ } ++ while (szLine[i] != '{' && i < strlen(szLine)) ++ i++; ++ if (! ParseQualifiedString(szLine, &i, data, '{', '}')) { ++ /* DBG_871X("Fail to parse data!\n"); */ ++ } ++ ++ initDeltaSwingIndexTables(Adapter, band, path, sign, chnl, rate, data); ++ } ++ } ++ } ++ else ++ { ++ DBG_871X("%s(): No File %s, Load from HWImg Array!\n", __func__, pFileName); ++ } ++ ++ return rtStatus; ++} ++ ++static int ++phy_ParsePowerLimitTableFile( ++ struct adapter * Adapter, ++ char* buffer ++) ++{ ++ u32 i = 0, forCnt = 0; ++ u8 loadingStage = 0, limitValue = 0, fraction = 0; ++ char *szLine, *ptmp; ++ int rtStatus = _SUCCESS; ++ char band[10], bandwidth[10], rateSection[10], ++ regulation[TXPWR_LMT_MAX_REGULATION_NUM][10], rfPath[10], colNumBuf[10]; ++ u8 colNum = 0; ++ ++ DBG_871X("===>phy_ParsePowerLimitTableFile()\n"); ++ ++ if (Adapter->registrypriv.RegDecryptCustomFile == 1) ++ phy_DecryptBBPgParaFile(Adapter, buffer); ++ ++ ptmp = buffer; ++ for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) ++ { ++ /* skip comment */ ++ if (IsCommentString(szLine)) { ++ continue; ++ } ++ ++ if (loadingStage == 0) { ++ for (forCnt = 0; forCnt < TXPWR_LMT_MAX_REGULATION_NUM; ++forCnt) ++ memset((void *) regulation[forCnt], 0, 10); ++ memset((void *) band, 0, 10); ++ memset((void *) bandwidth, 0, 10); ++ memset((void *) rateSection, 0, 10); ++ memset((void *) rfPath, 0, 10); ++ memset((void *) colNumBuf, 0, 10); ++ ++ if (szLine[0] != '#' || szLine[1] != '#') ++ continue; ++ ++ /* skip the space */ ++ i = 2; ++ while (szLine[i] == ' ' || szLine[i] == '\t') ++ ++i; ++ ++ szLine[--i] = ' '; /* return the space in front of the regulation info */ ++ ++ /* Parse the label of the table */ ++ if (! ParseQualifiedString(szLine, &i, band, ' ', ',')) { ++ DBG_871X("Fail to parse band!\n"); ++ return _FAIL; ++ } ++ if (! ParseQualifiedString(szLine, &i, bandwidth, ' ', ',')) { ++ DBG_871X("Fail to parse bandwidth!\n"); ++ return _FAIL; ++ } ++ if (! ParseQualifiedString(szLine, &i, rfPath, ' ', ',')) { ++ DBG_871X("Fail to parse rf path!\n"); ++ return _FAIL; ++ } ++ if (! ParseQualifiedString(szLine, &i, rateSection, ' ', ',')) { ++ DBG_871X("Fail to parse rate!\n"); ++ return _FAIL; ++ } ++ ++ loadingStage = 1; ++ } ++ else if (loadingStage == 1) ++ { ++ if (szLine[0] != '#' || szLine[1] != '#') ++ continue; ++ ++ /* skip the space */ ++ i = 2; ++ while (szLine[i] == ' ' || szLine[i] == '\t') ++ ++i; ++ ++ if (!eqNByte((u8 *)(szLine + i), (u8 *)("START"), 5)) { ++ DBG_871X("Lost \"## START\" label\n"); ++ return _FAIL; ++ } ++ ++ loadingStage = 2; ++ } ++ else if (loadingStage == 2) ++ { ++ if (szLine[0] != '#' || szLine[1] != '#') ++ continue; ++ ++ /* skip the space */ ++ i = 2; ++ while (szLine[i] == ' ' || szLine[i] == '\t') ++ ++i; ++ ++ if (! ParseQualifiedString(szLine, &i, colNumBuf, '#', '#')) { ++ DBG_871X("Fail to parse column number!\n"); ++ return _FAIL; ++ } ++ ++ if (!GetU1ByteIntegerFromStringInDecimal(colNumBuf, &colNum)) ++ return _FAIL; ++ ++ if (colNum > TXPWR_LMT_MAX_REGULATION_NUM) { ++ DBG_871X("unvalid col number %d (greater than max %d)\n", ++ colNum, TXPWR_LMT_MAX_REGULATION_NUM); ++ return _FAIL; ++ } ++ ++ for (forCnt = 0; forCnt < colNum; ++forCnt) ++ { ++ u8 regulation_name_cnt = 0; ++ ++ /* skip the space */ ++ while (szLine[i] == ' ' || szLine[i] == '\t') ++ ++i; ++ ++ while (szLine[i] != ' ' && szLine[i] != '\t' && szLine[i] != '\0') ++ regulation[forCnt][regulation_name_cnt++] = szLine[i++]; ++ /* DBG_871X("regulation %s!\n", regulation[forCnt]); */ ++ ++ if (regulation_name_cnt == 0) { ++ DBG_871X("unvalid number of regulation!\n"); ++ return _FAIL; ++ } ++ } ++ ++ loadingStage = 3; ++ } ++ else if (loadingStage == 3) ++ { ++ char channel[10] = {0}, powerLimit[10] = {0}; ++ u8 cnt = 0; ++ ++ /* the table ends */ ++ if (szLine[0] == '#' && szLine[1] == '#') { ++ i = 2; ++ while (szLine[i] == ' ' || szLine[i] == '\t') ++ ++i; ++ ++ if (eqNByte((u8 *)(szLine + i), (u8 *)("END"), 3)) { ++ loadingStage = 0; ++ continue; ++ } ++ else { ++ DBG_871X("Wrong format\n"); ++ DBG_871X("<===== phy_ParsePowerLimitTableFile()\n"); ++ return _FAIL; ++ } ++ } ++ ++ if ((szLine[0] != 'c' && szLine[0] != 'C') || ++ (szLine[1] != 'h' && szLine[1] != 'H')) { ++ DBG_871X("Meet wrong channel => power limt pair\n"); ++ continue; ++ } ++ i = 2;/* move to the location behind 'h' */ ++ ++ /* load the channel number */ ++ cnt = 0; ++ while (szLine[i] >= '0' && szLine[i] <= '9') { ++ channel[cnt] = szLine[i]; ++ ++cnt; ++ ++i; ++ } ++ /* DBG_871X("chnl %s!\n", channel); */ ++ ++ for (forCnt = 0; forCnt < colNum; ++forCnt) ++ { ++ /* skip the space between channel number and the power limit value */ ++ while (szLine[i] == ' ' || szLine[i] == '\t') ++ ++i; ++ ++ /* load the power limit value */ ++ cnt = 0; ++ fraction = 0; ++ memset((void *) powerLimit, 0, 10); ++ while ((szLine[i] >= '0' && szLine[i] <= '9') || szLine[i] == '.') ++ { ++ if (szLine[i] == '.') { ++ if ((szLine[i+1] >= '0' && szLine[i+1] <= '9')) { ++ fraction = szLine[i+1]; ++ i += 2; ++ } ++ else { ++ DBG_871X("Wrong fraction in TXPWR_LMT.txt\n"); ++ return _FAIL; ++ } ++ ++ break; ++ } ++ ++ powerLimit[cnt] = szLine[i]; ++ ++cnt; ++ ++i; ++ } ++ ++ if (powerLimit[0] == '\0') { ++ powerLimit[0] = '6'; ++ powerLimit[1] = '3'; ++ i += 2; ++ } ++ else { ++ if (!GetU1ByteIntegerFromStringInDecimal(powerLimit, &limitValue)) ++ return _FAIL; ++ ++ limitValue *= 2; ++ cnt = 0; ++ if (fraction == '5') ++ ++limitValue; ++ ++ /* the value is greater or equal to 100 */ ++ if (limitValue >= 100) { ++ powerLimit[cnt++] = limitValue/100 + '0'; ++ limitValue %= 100; ++ ++ if (limitValue >= 10) { ++ powerLimit[cnt++] = limitValue/10 + '0'; ++ limitValue %= 10; ++ } ++ else { ++ powerLimit[cnt++] = '0'; ++ } ++ ++ powerLimit[cnt++] = limitValue + '0'; ++ } ++ /* the value is greater or equal to 10 */ ++ else if (limitValue >= 10) { ++ powerLimit[cnt++] = limitValue/10 + '0'; ++ limitValue %= 10; ++ powerLimit[cnt++] = limitValue + '0'; ++ } ++ /* the value is less than 10 */ ++ else ++ powerLimit[cnt++] = limitValue + '0'; ++ ++ powerLimit[cnt] = '\0'; ++ } ++ ++ /* DBG_871X("ch%s => %s\n", channel, powerLimit); */ ++ ++ /* store the power limit value */ ++ PHY_SetTxPowerLimit(Adapter, (u8 *)regulation[forCnt], (u8 *)band, ++ (u8 *)bandwidth, (u8 *)rateSection, (u8 *)rfPath, (u8 *)channel, (u8 *)powerLimit); ++ ++ } ++ } ++ else ++ { ++ DBG_871X("Abnormal loading stage in phy_ParsePowerLimitTableFile()!\n"); ++ rtStatus = _FAIL; ++ break; ++ } ++ } ++ ++ DBG_871X("<===phy_ParsePowerLimitTableFile()\n"); ++ return rtStatus; ++} ++ ++int ++PHY_ConfigRFWithPowerLimitTableParaFile( ++struct adapter *Adapter, ++char* pFileName ++) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ int rlen = 0, rtStatus = _FAIL; ++ ++ if (!(Adapter->registrypriv.load_phy_file & LOAD_RF_TXPWR_LMT_PARA_FILE)) ++ return rtStatus; ++ ++ memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); ++ ++ if ((pHalData->rf_tx_pwr_lmt_len == 0) && (pHalData->rf_tx_pwr_lmt == NULL)) ++ { ++ rtw_merge_string(file_path_bs, PATH_MAX, rtw_phy_file_path, pFileName); ++ ++ if (rtw_is_file_readable(file_path_bs) == true) ++ { ++ rlen = rtw_retrive_from_file(file_path_bs, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); ++ if (rlen > 0) ++ { ++ rtStatus = _SUCCESS; ++ pHalData->rf_tx_pwr_lmt = vzalloc(rlen); ++ if (pHalData->rf_tx_pwr_lmt) { ++ memcpy(pHalData->rf_tx_pwr_lmt, pHalData->para_file_buf, rlen); ++ pHalData->rf_tx_pwr_lmt_len = rlen; ++ } ++ else { ++ DBG_871X("%s rf_tx_pwr_lmt alloc fail !\n", __func__); ++ } ++ } ++ } ++ } ++ else ++ { ++ if ((pHalData->rf_tx_pwr_lmt_len != 0) && (pHalData->rf_tx_pwr_lmt != NULL)) { ++ memcpy(pHalData->para_file_buf, pHalData->rf_tx_pwr_lmt, pHalData->rf_tx_pwr_lmt_len); ++ rtStatus = _SUCCESS; ++ } ++ else { ++ DBG_871X("%s(): Critical Error !!!\n", __func__); ++ } ++ } ++ ++ if (rtStatus == _SUCCESS) ++ { ++ /* DBG_871X("%s(): read %s ok\n", __func__, pFileName); */ ++ rtStatus = phy_ParsePowerLimitTableFile(Adapter, pHalData->para_file_buf); ++ } ++ else ++ { ++ DBG_871X("%s(): No File %s, Load from HWImg Array!\n", __func__, pFileName); ++ } ++ ++ return rtStatus; ++} ++ ++void phy_free_filebuf(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ ++ if (pHalData->mac_reg) ++ vfree(pHalData->mac_reg); ++ if (pHalData->bb_phy_reg) ++ vfree(pHalData->bb_phy_reg); ++ if (pHalData->bb_agc_tab) ++ vfree(pHalData->bb_agc_tab); ++ if (pHalData->bb_phy_reg_pg) ++ vfree(pHalData->bb_phy_reg_pg); ++ if (pHalData->bb_phy_reg_mp) ++ vfree(pHalData->bb_phy_reg_mp); ++ if (pHalData->rf_radio_a) ++ vfree(pHalData->rf_radio_a); ++ if (pHalData->rf_radio_b) ++ vfree(pHalData->rf_radio_b); ++ if (pHalData->rf_tx_pwr_track) ++ vfree(pHalData->rf_tx_pwr_track); ++ if (pHalData->rf_tx_pwr_lmt) ++ vfree(pHalData->rf_tx_pwr_lmt); ++ ++} ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/HalHWImg8723B_BB.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalHWImg8723B_BB.c +--- linux-4.3/3rdparty/rtl8723bs/hal/HalHWImg8723B_BB.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalHWImg8723B_BB.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,612 @@ ++/****************************************************************************** ++* ++* Copyright(c) 2007 - 2011 Realtek 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. ++* ++******************************************************************************/ ++ ++ ++#include "odm_precomp.h" ++ ++static bool ++CheckPositive( ++ PDM_ODM_T pDM_Odm, ++ const u32 Condition1, ++ const u32 Condition2 ++ ) ++{ ++ u8 _BoardType = ((pDM_Odm->BoardType & BIT4) >> 4) << 0 | /* _GLNA */ ++ ((pDM_Odm->BoardType & BIT3) >> 3) << 1 | /* _GPA */ ++ ((pDM_Odm->BoardType & BIT7) >> 7) << 2 | /* _ALNA */ ++ ((pDM_Odm->BoardType & BIT6) >> 6) << 3 | /* _APA */ ++ ((pDM_Odm->BoardType & BIT2) >> 2) << 4; /* _BT */ ++ ++ u32 cond1 = Condition1, cond2 = Condition2; ++ u32 driver1 = pDM_Odm->CutVersion << 24 | ++ pDM_Odm->SupportPlatform << 16 | ++ pDM_Odm->PackageType << 12 | ++ pDM_Odm->SupportInterface << 8 | ++ _BoardType; ++ ++ u32 driver2 = pDM_Odm->TypeGLNA << 0 | ++ pDM_Odm->TypeGPA << 8 | ++ pDM_Odm->TypeALNA << 16 | ++ pDM_Odm->TypeAPA << 24; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ++ ("===> [8812A] CheckPositive (cond1, cond2) = (0x%X 0x%X)\n", cond1, cond2)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ++ ("===> [8812A] CheckPositive (driver1, driver2) = (0x%X 0x%X)\n", driver1, driver2)); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ++ (" (Platform, Interface) = (0x%X, 0x%X)\n", pDM_Odm->SupportPlatform, pDM_Odm->SupportInterface)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ++ (" (Board, Package) = (0x%X, 0x%X)\n", pDM_Odm->BoardType, pDM_Odm->PackageType)); ++ ++ ++ /* Value Defined Check =============== */ ++ /* QFN Type [15:12] and Cut Version [27:24] need to do value check */ ++ ++ if (((cond1 & 0x0000F000) != 0) && ((cond1 & 0x0000F000) != (driver1 & 0x0000F000))) ++ return false; ++ if (((cond1 & 0x0F000000) != 0) && ((cond1 & 0x0F000000) != (driver1 & 0x0F000000))) ++ return false; ++ ++ /* Bit Defined Check ================ */ ++ /* We don't care [31:28] and [23:20] */ ++ /* */ ++ cond1 &= 0x000F0FFF; ++ driver1 &= 0x000F0FFF; ++ ++ if ((cond1 & driver1) == cond1) { ++ u32 bitMask = 0; ++ if ((cond1 & 0x0F) == 0) /* BoardType is DONTCARE */ ++ return true; ++ ++ if ((cond1 & BIT0) != 0) /* GLNA */ ++ bitMask |= 0x000000FF; ++ if ((cond1 & BIT1) != 0) /* GPA */ ++ bitMask |= 0x0000FF00; ++ if ((cond1 & BIT2) != 0) /* ALNA */ ++ bitMask |= 0x00FF0000; ++ if ((cond1 & BIT3) != 0) /* APA */ ++ bitMask |= 0xFF000000; ++ ++ if ((cond2 & bitMask) == (driver2 & bitMask)) /* BoardType of each RF path is matched */ ++ return true; ++ } ++ return false; ++} ++static bool ++CheckNegative( ++ PDM_ODM_T pDM_Odm, ++ const u32 Condition1, ++ const u32 Condition2 ++ ) ++{ ++ return true; ++} ++ ++/****************************************************************************** ++* AGC_TAB.TXT ++******************************************************************************/ ++ ++static u32 Array_MP_8723B_AGC_TAB[] = { ++ 0xC78, 0xFD000001, ++ 0xC78, 0xFC010001, ++ 0xC78, 0xFB020001, ++ 0xC78, 0xFA030001, ++ 0xC78, 0xF9040001, ++ 0xC78, 0xF8050001, ++ 0xC78, 0xF7060001, ++ 0xC78, 0xF6070001, ++ 0xC78, 0xF5080001, ++ 0xC78, 0xF4090001, ++ 0xC78, 0xF30A0001, ++ 0xC78, 0xF20B0001, ++ 0xC78, 0xF10C0001, ++ 0xC78, 0xF00D0001, ++ 0xC78, 0xEF0E0001, ++ 0xC78, 0xEE0F0001, ++ 0xC78, 0xED100001, ++ 0xC78, 0xEC110001, ++ 0xC78, 0xEB120001, ++ 0xC78, 0xEA130001, ++ 0xC78, 0xE9140001, ++ 0xC78, 0xE8150001, ++ 0xC78, 0xE7160001, ++ 0xC78, 0xE6170001, ++ 0xC78, 0xE5180001, ++ 0xC78, 0xE4190001, ++ 0xC78, 0xE31A0001, ++ 0xC78, 0xA51B0001, ++ 0xC78, 0xA41C0001, ++ 0xC78, 0xA31D0001, ++ 0xC78, 0x671E0001, ++ 0xC78, 0x661F0001, ++ 0xC78, 0x65200001, ++ 0xC78, 0x64210001, ++ 0xC78, 0x63220001, ++ 0xC78, 0x4A230001, ++ 0xC78, 0x49240001, ++ 0xC78, 0x48250001, ++ 0xC78, 0x47260001, ++ 0xC78, 0x46270001, ++ 0xC78, 0x45280001, ++ 0xC78, 0x44290001, ++ 0xC78, 0x432A0001, ++ 0xC78, 0x422B0001, ++ 0xC78, 0x292C0001, ++ 0xC78, 0x282D0001, ++ 0xC78, 0x272E0001, ++ 0xC78, 0x262F0001, ++ 0xC78, 0x0A300001, ++ 0xC78, 0x09310001, ++ 0xC78, 0x08320001, ++ 0xC78, 0x07330001, ++ 0xC78, 0x06340001, ++ 0xC78, 0x05350001, ++ 0xC78, 0x04360001, ++ 0xC78, 0x03370001, ++ 0xC78, 0x02380001, ++ 0xC78, 0x01390001, ++ 0xC78, 0x013A0001, ++ 0xC78, 0x013B0001, ++ 0xC78, 0x013C0001, ++ 0xC78, 0x013D0001, ++ 0xC78, 0x013E0001, ++ 0xC78, 0x013F0001, ++ 0xC78, 0xFC400001, ++ 0xC78, 0xFB410001, ++ 0xC78, 0xFA420001, ++ 0xC78, 0xF9430001, ++ 0xC78, 0xF8440001, ++ 0xC78, 0xF7450001, ++ 0xC78, 0xF6460001, ++ 0xC78, 0xF5470001, ++ 0xC78, 0xF4480001, ++ 0xC78, 0xF3490001, ++ 0xC78, 0xF24A0001, ++ 0xC78, 0xF14B0001, ++ 0xC78, 0xF04C0001, ++ 0xC78, 0xEF4D0001, ++ 0xC78, 0xEE4E0001, ++ 0xC78, 0xED4F0001, ++ 0xC78, 0xEC500001, ++ 0xC78, 0xEB510001, ++ 0xC78, 0xEA520001, ++ 0xC78, 0xE9530001, ++ 0xC78, 0xE8540001, ++ 0xC78, 0xE7550001, ++ 0xC78, 0xE6560001, ++ 0xC78, 0xE5570001, ++ 0xC78, 0xE4580001, ++ 0xC78, 0xE3590001, ++ 0xC78, 0xA65A0001, ++ 0xC78, 0xA55B0001, ++ 0xC78, 0xA45C0001, ++ 0xC78, 0xA35D0001, ++ 0xC78, 0x675E0001, ++ 0xC78, 0x665F0001, ++ 0xC78, 0x65600001, ++ 0xC78, 0x64610001, ++ 0xC78, 0x63620001, ++ 0xC78, 0x62630001, ++ 0xC78, 0x61640001, ++ 0xC78, 0x48650001, ++ 0xC78, 0x47660001, ++ 0xC78, 0x46670001, ++ 0xC78, 0x45680001, ++ 0xC78, 0x44690001, ++ 0xC78, 0x436A0001, ++ 0xC78, 0x426B0001, ++ 0xC78, 0x286C0001, ++ 0xC78, 0x276D0001, ++ 0xC78, 0x266E0001, ++ 0xC78, 0x256F0001, ++ 0xC78, 0x24700001, ++ 0xC78, 0x09710001, ++ 0xC78, 0x08720001, ++ 0xC78, 0x07730001, ++ 0xC78, 0x06740001, ++ 0xC78, 0x05750001, ++ 0xC78, 0x04760001, ++ 0xC78, 0x03770001, ++ 0xC78, 0x02780001, ++ 0xC78, 0x01790001, ++ 0xC78, 0x017A0001, ++ 0xC78, 0x017B0001, ++ 0xC78, 0x017C0001, ++ 0xC78, 0x017D0001, ++ 0xC78, 0x017E0001, ++ 0xC78, 0x017F0001, ++ 0xC50, 0x69553422, ++ 0xC50, 0x69553420, ++ 0x824, 0x00390204, ++ ++}; ++ ++void ++ODM_ReadAndConfig_MP_8723B_AGC_TAB( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ u32 i = 0; ++ u32 ArrayLen = sizeof(Array_MP_8723B_AGC_TAB)/sizeof(u32); ++ u32 * Array = Array_MP_8723B_AGC_TAB; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("===> ODM_ReadAndConfig_MP_8723B_AGC_TAB\n")); ++ ++ for (i = 0; i < ArrayLen; i += 2) ++ { ++ u32 v1 = Array[i]; ++ u32 v2 = Array[i+1]; ++ ++ /* This (offset, data) pair doesn't care the condition. */ ++ if (v1 < 0x40000000) ++ { ++ odm_ConfigBB_AGC_8723B(pDM_Odm, v1, bMaskDWord, v2); ++ continue; ++ } ++ else ++ { /* This line is the beginning of branch. */ ++ bool bMatched = true; ++ u8 cCond = (u8)((v1 & (BIT29|BIT28)) >> 28); ++ ++ if (cCond == COND_ELSE) { /* ELSE, ENDIF */ ++ bMatched = true; ++ READ_NEXT_PAIR(v1, v2, i); ++ } else if (! CheckPositive(pDM_Odm, v1, v2)) { ++ bMatched = false; ++ READ_NEXT_PAIR(v1, v2, i); ++ READ_NEXT_PAIR(v1, v2, i); ++ } else { ++ READ_NEXT_PAIR(v1, v2, i); ++ if (! CheckNegative(pDM_Odm, v1, v2)) ++ bMatched = false; ++ else ++ bMatched = true; ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ if (bMatched == false) ++ { /* Condition isn't matched. Discard the following (offset, data) pairs. */ ++ while (v1 < 0x40000000 && i < ArrayLen -2) ++ READ_NEXT_PAIR(v1, v2, i); ++ ++ i -= 2; /* prevent from for-loop += 2 */ ++ } ++ else /* Configure matched pairs and skip to end of if-else. */ ++ { ++ while (v1 < 0x40000000 && i < ArrayLen-2) { ++ odm_ConfigBB_AGC_8723B(pDM_Odm, v1, bMaskDWord, v2); ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ /* Keeps reading until ENDIF. */ ++ cCond = (u8)((v1 & (BIT29|BIT28)) >> 28); ++ while (cCond != COND_ENDIF && i < ArrayLen-2) { ++ READ_NEXT_PAIR(v1, v2, i); ++ cCond = (u8)((v1 & (BIT29|BIT28)) >> 28); ++ } ++ } ++ } ++ } ++} ++ ++/****************************************************************************** ++* PHY_REG.TXT ++******************************************************************************/ ++ ++static u32 Array_MP_8723B_PHY_REG[] = { ++ 0x800, 0x80040000, ++ 0x804, 0x00000003, ++ 0x808, 0x0000FC00, ++ 0x80C, 0x0000000A, ++ 0x810, 0x10001331, ++ 0x814, 0x020C3D10, ++ 0x818, 0x02200385, ++ 0x81C, 0x00000000, ++ 0x820, 0x01000100, ++ 0x824, 0x00190204, ++ 0x828, 0x00000000, ++ 0x82C, 0x00000000, ++ 0x830, 0x00000000, ++ 0x834, 0x00000000, ++ 0x838, 0x00000000, ++ 0x83C, 0x00000000, ++ 0x840, 0x00010000, ++ 0x844, 0x00000000, ++ 0x848, 0x00000000, ++ 0x84C, 0x00000000, ++ 0x850, 0x00000000, ++ 0x854, 0x00000000, ++ 0x858, 0x569A11A9, ++ 0x85C, 0x01000014, ++ 0x860, 0x66F60110, ++ 0x864, 0x061F0649, ++ 0x868, 0x00000000, ++ 0x86C, 0x27272700, ++ 0x870, 0x07000760, ++ 0x874, 0x25004000, ++ 0x878, 0x00000808, ++ 0x87C, 0x00000000, ++ 0x880, 0xB0000C1C, ++ 0x884, 0x00000001, ++ 0x888, 0x00000000, ++ 0x88C, 0xCCC000C0, ++ 0x890, 0x00000800, ++ 0x894, 0xFFFFFFFE, ++ 0x898, 0x40302010, ++ 0x89C, 0x00706050, ++ 0x900, 0x00000000, ++ 0x904, 0x00000023, ++ 0x908, 0x00000000, ++ 0x90C, 0x81121111, ++ 0x910, 0x00000002, ++ 0x914, 0x00000201, ++ 0xA00, 0x00D047C8, ++ 0xA04, 0x80FF800C, ++ 0xA08, 0x8C838300, ++ 0xA0C, 0x2E7F120F, ++ 0xA10, 0x9500BB78, ++ 0xA14, 0x1114D028, ++ 0xA18, 0x00881117, ++ 0xA1C, 0x89140F00, ++ 0xA20, 0x1A1B0000, ++ 0xA24, 0x090E1317, ++ 0xA28, 0x00000204, ++ 0xA2C, 0x00D30000, ++ 0xA70, 0x101FBF00, ++ 0xA74, 0x00000007, ++ 0xA78, 0x00000900, ++ 0xA7C, 0x225B0606, ++ 0xA80, 0x21806490, ++ 0xB2C, 0x00000000, ++ 0xC00, 0x48071D40, ++ 0xC04, 0x03A05611, ++ 0xC08, 0x000000E4, ++ 0xC0C, 0x6C6C6C6C, ++ 0xC10, 0x08800000, ++ 0xC14, 0x40000100, ++ 0xC18, 0x08800000, ++ 0xC1C, 0x40000100, ++ 0xC20, 0x00000000, ++ 0xC24, 0x00000000, ++ 0xC28, 0x00000000, ++ 0xC2C, 0x00000000, ++ 0xC30, 0x69E9AC44, ++ 0xC34, 0x469652AF, ++ 0xC38, 0x49795994, ++ 0xC3C, 0x0A97971C, ++ 0xC40, 0x1F7C403F, ++ 0xC44, 0x000100B7, ++ 0xC48, 0xEC020107, ++ 0xC4C, 0x007F037F, ++ 0xC50, 0x69553420, ++ 0xC54, 0x43BC0094, ++ 0xC58, 0x00013149, ++ 0xC5C, 0x00250492, ++ 0xC60, 0x00000000, ++ 0xC64, 0x7112848B, ++ 0xC68, 0x47C00BFF, ++ 0xC6C, 0x00000036, ++ 0xC70, 0x2C7F000D, ++ 0xC74, 0x020610DB, ++ 0xC78, 0x0000001F, ++ 0xC7C, 0x00B91612, ++ 0xC80, 0x390000E4, ++ 0xC84, 0x20F60000, ++ 0xC88, 0x40000100, ++ 0xC8C, 0x20200000, ++ 0xC90, 0x00020E1A, ++ 0xC94, 0x00000000, ++ 0xC98, 0x00020E1A, ++ 0xC9C, 0x00007F7F, ++ 0xCA0, 0x00000000, ++ 0xCA4, 0x000300A0, ++ 0xCA8, 0x00000000, ++ 0xCAC, 0x00000000, ++ 0xCB0, 0x00000000, ++ 0xCB4, 0x00000000, ++ 0xCB8, 0x00000000, ++ 0xCBC, 0x28000000, ++ 0xCC0, 0x00000000, ++ 0xCC4, 0x00000000, ++ 0xCC8, 0x00000000, ++ 0xCCC, 0x00000000, ++ 0xCD0, 0x00000000, ++ 0xCD4, 0x00000000, ++ 0xCD8, 0x64B22427, ++ 0xCDC, 0x00766932, ++ 0xCE0, 0x00222222, ++ 0xCE4, 0x00000000, ++ 0xCE8, 0x37644302, ++ 0xCEC, 0x2F97D40C, ++ 0xD00, 0x00000740, ++ 0xD04, 0x40020401, ++ 0xD08, 0x0000907F, ++ 0xD0C, 0x20010201, ++ 0xD10, 0xA0633333, ++ 0xD14, 0x3333BC53, ++ 0xD18, 0x7A8F5B6F, ++ 0xD2C, 0xCC979975, ++ 0xD30, 0x00000000, ++ 0xD34, 0x80608000, ++ 0xD38, 0x00000000, ++ 0xD3C, 0x00127353, ++ 0xD40, 0x00000000, ++ 0xD44, 0x00000000, ++ 0xD48, 0x00000000, ++ 0xD4C, 0x00000000, ++ 0xD50, 0x6437140A, ++ 0xD54, 0x00000000, ++ 0xD58, 0x00000282, ++ 0xD5C, 0x30032064, ++ 0xD60, 0x4653DE68, ++ 0xD64, 0x04518A3C, ++ 0xD68, 0x00002101, ++ 0xD6C, 0x2A201C16, ++ 0xD70, 0x1812362E, ++ 0xD74, 0x322C2220, ++ 0xD78, 0x000E3C24, ++ 0xE00, 0x2D2D2D2D, ++ 0xE04, 0x2D2D2D2D, ++ 0xE08, 0x0390272D, ++ 0xE10, 0x2D2D2D2D, ++ 0xE14, 0x2D2D2D2D, ++ 0xE18, 0x2D2D2D2D, ++ 0xE1C, 0x2D2D2D2D, ++ 0xE28, 0x00000000, ++ 0xE30, 0x1000DC1F, ++ 0xE34, 0x10008C1F, ++ 0xE38, 0x02140102, ++ 0xE3C, 0x681604C2, ++ 0xE40, 0x01007C00, ++ 0xE44, 0x01004800, ++ 0xE48, 0xFB000000, ++ 0xE4C, 0x000028D1, ++ 0xE50, 0x1000DC1F, ++ 0xE54, 0x10008C1F, ++ 0xE58, 0x02140102, ++ 0xE5C, 0x28160D05, ++ 0xE60, 0x00000008, ++ 0xE68, 0x001B2556, ++ 0xE6C, 0x00C00096, ++ 0xE70, 0x00C00096, ++ 0xE74, 0x01000056, ++ 0xE78, 0x01000014, ++ 0xE7C, 0x01000056, ++ 0xE80, 0x01000014, ++ 0xE84, 0x00C00096, ++ 0xE88, 0x01000056, ++ 0xE8C, 0x00C00096, ++ 0xED0, 0x00C00096, ++ 0xED4, 0x00C00096, ++ 0xED8, 0x00C00096, ++ 0xEDC, 0x000000D6, ++ 0xEE0, 0x000000D6, ++ 0xEEC, 0x01C00016, ++ 0xF14, 0x00000003, ++ 0xF4C, 0x00000000, ++ 0xF00, 0x00000300, ++ 0x820, 0x01000100, ++ 0x800, 0x83040000, ++ ++}; ++ ++void ++ODM_ReadAndConfig_MP_8723B_PHY_REG( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ u32 i = 0; ++ u32 ArrayLen = sizeof(Array_MP_8723B_PHY_REG)/sizeof(u32); ++ u32 * Array = Array_MP_8723B_PHY_REG; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("===> ODM_ReadAndConfig_MP_8723B_PHY_REG\n")); ++ ++ for (i = 0; i < ArrayLen; i += 2) ++ { ++ u32 v1 = Array[i]; ++ u32 v2 = Array[i+1]; ++ ++ /* This (offset, data) pair doesn't care the condition. */ ++ if (v1 < 0x40000000) ++ { ++ odm_ConfigBB_PHY_8723B(pDM_Odm, v1, bMaskDWord, v2); ++ continue; ++ } ++ else ++ { /* This line is the beginning of branch. */ ++ bool bMatched = true; ++ u8 cCond = (u8)((v1 & (BIT29|BIT28)) >> 28); ++ ++ if (cCond == COND_ELSE) { /* ELSE, ENDIF */ ++ bMatched = true; ++ READ_NEXT_PAIR(v1, v2, i); ++ } else if (! CheckPositive(pDM_Odm, v1, v2)) { ++ bMatched = false; ++ READ_NEXT_PAIR(v1, v2, i); ++ READ_NEXT_PAIR(v1, v2, i); ++ } else { ++ READ_NEXT_PAIR(v1, v2, i); ++ if (! CheckNegative(pDM_Odm, v1, v2)) ++ bMatched = false; ++ else ++ bMatched = true; ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ if (bMatched == false) ++ { /* Condition isn't matched. Discard the following (offset, data) pairs. */ ++ while (v1 < 0x40000000 && i < ArrayLen -2) ++ READ_NEXT_PAIR(v1, v2, i); ++ ++ i -= 2; /* prevent from for-loop += 2 */ ++ } ++ else /* Configure matched pairs and skip to end of if-else. */ ++ { ++ while (v1 < 0x40000000 && i < ArrayLen-2) { ++ odm_ConfigBB_PHY_8723B(pDM_Odm, v1, bMaskDWord, v2); ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ /* Keeps reading until ENDIF. */ ++ cCond = (u8)((v1 & (BIT29|BIT28)) >> 28); ++ while (cCond != COND_ENDIF && i < ArrayLen-2) { ++ READ_NEXT_PAIR(v1, v2, i); ++ cCond = (u8)((v1 & (BIT29|BIT28)) >> 28); ++ } ++ } ++ } ++ } ++} ++ ++/****************************************************************************** ++* PHY_REG_PG.TXT ++******************************************************************************/ ++ ++static u32 Array_MP_8723B_PHY_REG_PG[] = { ++ 0, 0, 0, 0x00000e08, 0x0000ff00, 0x00003800, ++ 0, 0, 0, 0x0000086c, 0xffffff00, 0x32343600, ++ 0, 0, 0, 0x00000e00, 0xffffffff, 0x40424444, ++ 0, 0, 0, 0x00000e04, 0xffffffff, 0x28323638, ++ 0, 0, 0, 0x00000e10, 0xffffffff, 0x38404244, ++ 0, 0, 0, 0x00000e14, 0xffffffff, 0x26303436 ++}; ++ ++void ++ODM_ReadAndConfig_MP_8723B_PHY_REG_PG( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ u32 i = 0; ++ u32 ArrayLen = sizeof(Array_MP_8723B_PHY_REG_PG)/sizeof(u32); ++ u32 * Array = Array_MP_8723B_PHY_REG_PG; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("===> ODM_ReadAndConfig_MP_8723B_PHY_REG_PG\n")); ++ ++ pDM_Odm->PhyRegPgVersion = 1; ++ pDM_Odm->PhyRegPgValueType = PHY_REG_PG_EXACT_VALUE; ++ ++ for (i = 0; i < ArrayLen; i += 6) ++ { ++ u32 v1 = Array[i]; ++ u32 v2 = Array[i+1]; ++ u32 v3 = Array[i+2]; ++ u32 v4 = Array[i+3]; ++ u32 v5 = Array[i+4]; ++ u32 v6 = Array[i+5]; ++ ++ odm_ConfigBB_PHY_REG_PG_8723B(pDM_Odm, v1, v2, v3, v4, v5, v6); ++ } ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/HalHWImg8723B_BB.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalHWImg8723B_BB.h +--- linux-4.3/3rdparty/rtl8723bs/hal/HalHWImg8723B_BB.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalHWImg8723B_BB.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,48 @@ ++/****************************************************************************** ++* ++* Copyright(c) 2007 - 2011 Realtek 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. ++* ++******************************************************************************/ ++ ++#ifndef __INC_MP_BB_HW_IMG_8723B_H ++#define __INC_MP_BB_HW_IMG_8723B_H ++ ++ ++/****************************************************************************** ++* AGC_TAB.TXT ++******************************************************************************/ ++ ++void ++ODM_ReadAndConfig_MP_8723B_AGC_TAB(/* TC: Test Chip, MP: MP Chip */ ++ PDM_ODM_T pDM_Odm ++); ++ ++/****************************************************************************** ++* PHY_REG.TXT ++******************************************************************************/ ++ ++void ++ODM_ReadAndConfig_MP_8723B_PHY_REG(/* TC: Test Chip, MP: MP Chip */ ++ PDM_ODM_T pDM_Odm ++); ++ ++/****************************************************************************** ++* PHY_REG_PG.TXT ++******************************************************************************/ ++ ++void ++ODM_ReadAndConfig_MP_8723B_PHY_REG_PG(/* TC: Test Chip, MP: MP Chip */ ++ PDM_ODM_T pDM_Odm ++); ++u32 ODM_GetVersion_MP_8723B_PHY_REG_PG(void); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/HalHWImg8723B_MAC.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalHWImg8723B_MAC.c +--- linux-4.3/3rdparty/rtl8723bs/hal/HalHWImg8723B_MAC.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalHWImg8723B_MAC.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,275 @@ ++/****************************************************************************** ++* ++* Copyright(c) 2007 - 2011 Realtek 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. ++* ++******************************************************************************/ ++ ++ ++#include "odm_precomp.h" ++ ++static bool ++CheckPositive( ++ PDM_ODM_T pDM_Odm, ++ const u32 Condition1, ++ const u32 Condition2 ++ ) ++{ ++ u8 _BoardType = ((pDM_Odm->BoardType & BIT4) >> 4) << 0 | /* _GLNA */ ++ ((pDM_Odm->BoardType & BIT3) >> 3) << 1 | /* _GPA */ ++ ((pDM_Odm->BoardType & BIT7) >> 7) << 2 | /* _ALNA */ ++ ((pDM_Odm->BoardType & BIT6) >> 6) << 3 | /* _APA */ ++ ((pDM_Odm->BoardType & BIT2) >> 2) << 4; /* _BT */ ++ ++ u32 cond1 = Condition1, cond2 = Condition2; ++ u32 driver1 = pDM_Odm->CutVersion << 24 | ++ pDM_Odm->SupportPlatform << 16 | ++ pDM_Odm->PackageType << 12 | ++ pDM_Odm->SupportInterface << 8 | ++ _BoardType; ++ ++ u32 driver2 = pDM_Odm->TypeGLNA << 0 | ++ pDM_Odm->TypeGPA << 8 | ++ pDM_Odm->TypeALNA << 16 | ++ pDM_Odm->TypeAPA << 24; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ++ ("===> [8812A] CheckPositive (cond1, cond2) = (0x%X 0x%X)\n", cond1, cond2)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ++ ("===> [8812A] CheckPositive (driver1, driver2) = (0x%X 0x%X)\n", driver1, driver2)); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ++ (" (Platform, Interface) = (0x%X, 0x%X)\n", pDM_Odm->SupportPlatform, pDM_Odm->SupportInterface)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ++ (" (Board, Package) = (0x%X, 0x%X)\n", pDM_Odm->BoardType, pDM_Odm->PackageType)); ++ ++ ++ /* Value Defined Check =============== */ ++ /* QFN Type [15:12] and Cut Version [27:24] need to do value check */ ++ ++ if (((cond1 & 0x0000F000) != 0) && ((cond1 & 0x0000F000) != (driver1 & 0x0000F000))) ++ return false; ++ if (((cond1 & 0x0F000000) != 0) && ((cond1 & 0x0F000000) != (driver1 & 0x0F000000))) ++ return false; ++ ++ /* Bit Defined Check ================ */ ++ /* We don't care [31:28] and [23:20] */ ++ /* */ ++ cond1 &= 0x000F0FFF; ++ driver1 &= 0x000F0FFF; ++ ++ if ((cond1 & driver1) == cond1) { ++ u32 bitMask = 0; ++ if ((cond1 & 0x0F) == 0) /* BoardType is DONTCARE */ ++ return true; ++ ++ if ((cond1 & BIT0) != 0) /* GLNA */ ++ bitMask |= 0x000000FF; ++ if ((cond1 & BIT1) != 0) /* GPA */ ++ bitMask |= 0x0000FF00; ++ if ((cond1 & BIT2) != 0) /* ALNA */ ++ bitMask |= 0x00FF0000; ++ if ((cond1 & BIT3) != 0) /* APA */ ++ bitMask |= 0xFF000000; ++ ++ if ((cond2 & bitMask) == (driver2 & bitMask)) /* BoardType of each RF path is matched */ ++ return true; ++ } ++ return false; ++} ++static bool ++CheckNegative( ++ PDM_ODM_T pDM_Odm, ++ const u32 Condition1, ++ const u32 Condition2 ++ ) ++{ ++ return true; ++} ++ ++/****************************************************************************** ++* MAC_REG.TXT ++******************************************************************************/ ++ ++static u32 Array_MP_8723B_MAC_REG[] = { ++ 0x02F, 0x00000030, ++ 0x035, 0x00000000, ++ 0x039, 0x00000008, ++ 0x04E, 0x000000E0, ++ 0x064, 0x00000000, ++ 0x067, 0x00000020, ++ 0x428, 0x0000000A, ++ 0x429, 0x00000010, ++ 0x430, 0x00000000, ++ 0x431, 0x00000000, ++ 0x432, 0x00000000, ++ 0x433, 0x00000001, ++ 0x434, 0x00000004, ++ 0x435, 0x00000005, ++ 0x436, 0x00000007, ++ 0x437, 0x00000008, ++ 0x43C, 0x00000004, ++ 0x43D, 0x00000005, ++ 0x43E, 0x00000007, ++ 0x43F, 0x00000008, ++ 0x440, 0x0000005D, ++ 0x441, 0x00000001, ++ 0x442, 0x00000000, ++ 0x444, 0x00000010, ++ 0x445, 0x00000000, ++ 0x446, 0x00000000, ++ 0x447, 0x00000000, ++ 0x448, 0x00000000, ++ 0x449, 0x000000F0, ++ 0x44A, 0x0000000F, ++ 0x44B, 0x0000003E, ++ 0x44C, 0x00000010, ++ 0x44D, 0x00000000, ++ 0x44E, 0x00000000, ++ 0x44F, 0x00000000, ++ 0x450, 0x00000000, ++ 0x451, 0x000000F0, ++ 0x452, 0x0000000F, ++ 0x453, 0x00000000, ++ 0x456, 0x0000005E, ++ 0x460, 0x00000066, ++ 0x461, 0x00000066, ++ 0x4C8, 0x000000FF, ++ 0x4C9, 0x00000008, ++ 0x4CC, 0x000000FF, ++ 0x4CD, 0x000000FF, ++ 0x4CE, 0x00000001, ++ 0x500, 0x00000026, ++ 0x501, 0x000000A2, ++ 0x502, 0x0000002F, ++ 0x503, 0x00000000, ++ 0x504, 0x00000028, ++ 0x505, 0x000000A3, ++ 0x506, 0x0000005E, ++ 0x507, 0x00000000, ++ 0x508, 0x0000002B, ++ 0x509, 0x000000A4, ++ 0x50A, 0x0000005E, ++ 0x50B, 0x00000000, ++ 0x50C, 0x0000004F, ++ 0x50D, 0x000000A4, ++ 0x50E, 0x00000000, ++ 0x50F, 0x00000000, ++ 0x512, 0x0000001C, ++ 0x514, 0x0000000A, ++ 0x516, 0x0000000A, ++ 0x525, 0x0000004F, ++ 0x550, 0x00000010, ++ 0x551, 0x00000010, ++ 0x559, 0x00000002, ++ 0x55C, 0x00000050, ++ 0x55D, 0x000000FF, ++ 0x605, 0x00000030, ++ 0x608, 0x0000000E, ++ 0x609, 0x0000002A, ++ 0x620, 0x000000FF, ++ 0x621, 0x000000FF, ++ 0x622, 0x000000FF, ++ 0x623, 0x000000FF, ++ 0x624, 0x000000FF, ++ 0x625, 0x000000FF, ++ 0x626, 0x000000FF, ++ 0x627, 0x000000FF, ++ 0x638, 0x00000050, ++ 0x63C, 0x0000000A, ++ 0x63D, 0x0000000A, ++ 0x63E, 0x0000000E, ++ 0x63F, 0x0000000E, ++ 0x640, 0x00000040, ++ 0x642, 0x00000040, ++ 0x643, 0x00000000, ++ 0x652, 0x000000C8, ++ 0x66E, 0x00000005, ++ 0x700, 0x00000021, ++ 0x701, 0x00000043, ++ 0x702, 0x00000065, ++ 0x703, 0x00000087, ++ 0x708, 0x00000021, ++ 0x709, 0x00000043, ++ 0x70A, 0x00000065, ++ 0x70B, 0x00000087, ++ 0x765, 0x00000018, ++ 0x76E, 0x00000004, ++ ++}; ++ ++void ++ODM_ReadAndConfig_MP_8723B_MAC_REG( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ u32 i = 0; ++ u32 ArrayLen = sizeof(Array_MP_8723B_MAC_REG)/sizeof(u32); ++ u32 * Array = Array_MP_8723B_MAC_REG; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("===> ODM_ReadAndConfig_MP_8723B_MAC_REG\n")); ++ ++ for (i = 0; i < ArrayLen; i += 2) ++ { ++ u32 v1 = Array[i]; ++ u32 v2 = Array[i+1]; ++ ++ /* This (offset, data) pair doesn't care the condition. */ ++ if (v1 < 0x40000000) ++ { ++ odm_ConfigMAC_8723B(pDM_Odm, v1, (u8)v2); ++ continue; ++ } ++ else ++ { /* This line is the beginning of branch. */ ++ bool bMatched = true; ++ u8 cCond = (u8)((v1 & (BIT29|BIT28)) >> 28); ++ ++ if (cCond == COND_ELSE) { /* ELSE, ENDIF */ ++ bMatched = true; ++ READ_NEXT_PAIR(v1, v2, i); ++ } else if (! CheckPositive(pDM_Odm, v1, v2)) { ++ bMatched = false; ++ READ_NEXT_PAIR(v1, v2, i); ++ READ_NEXT_PAIR(v1, v2, i); ++ } else { ++ READ_NEXT_PAIR(v1, v2, i); ++ if (! CheckNegative(pDM_Odm, v1, v2)) ++ bMatched = false; ++ else ++ bMatched = true; ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ if (bMatched == false) ++ { /* Condition isn't matched. Discard the following (offset, data) pairs. */ ++ while (v1 < 0x40000000 && i < ArrayLen -2) ++ READ_NEXT_PAIR(v1, v2, i); ++ ++ i -= 2; /* prevent from for-loop += 2 */ ++ } ++ else /* Configure matched pairs and skip to end of if-else. */ ++ { ++ while (v1 < 0x40000000 && i < ArrayLen-2) { ++ odm_ConfigMAC_8723B(pDM_Odm, v1, (u8)v2); ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ /* Keeps reading until ENDIF. */ ++ cCond = (u8)((v1 & (BIT29|BIT28)) >> 28); ++ while (cCond != COND_ENDIF && i < ArrayLen-2) { ++ READ_NEXT_PAIR(v1, v2, i); ++ cCond = (u8)((v1 & (BIT29|BIT28)) >> 28); ++ } ++ } ++ } ++ } ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/HalHWImg8723B_MAC.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalHWImg8723B_MAC.h +--- linux-4.3/3rdparty/rtl8723bs/hal/HalHWImg8723B_MAC.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalHWImg8723B_MAC.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,28 @@ ++/****************************************************************************** ++* ++* Copyright(c) 2007 - 2011 Realtek 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. ++* ++******************************************************************************/ ++ ++#ifndef __INC_MP_MAC_HW_IMG_8723B_H ++#define __INC_MP_MAC_HW_IMG_8723B_H ++ ++ ++/****************************************************************************** ++* MAC_REG.TXT ++******************************************************************************/ ++ ++void ++ODM_ReadAndConfig_MP_8723B_MAC_REG(/* TC: Test Chip, MP: MP Chip */ ++ PDM_ODM_T pDM_Odm ++); ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/HalHWImg8723B_RF.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalHWImg8723B_RF.c +--- linux-4.3/3rdparty/rtl8723bs/hal/HalHWImg8723B_RF.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalHWImg8723B_RF.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,638 @@ ++/****************************************************************************** ++* ++* Copyright(c) 2007 - 2011 Realtek 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. ++* ++******************************************************************************/ ++ ++ ++#include "odm_precomp.h" ++ ++static bool ++CheckPositive( ++ PDM_ODM_T pDM_Odm, ++ const u32 Condition1, ++ const u32 Condition2 ++ ) ++{ ++ u8 _BoardType = ((pDM_Odm->BoardType & BIT4) >> 4) << 0 | /* _GLNA */ ++ ((pDM_Odm->BoardType & BIT3) >> 3) << 1 | /* _GPA */ ++ ((pDM_Odm->BoardType & BIT7) >> 7) << 2 | /* _ALNA */ ++ ((pDM_Odm->BoardType & BIT6) >> 6) << 3 | /* _APA */ ++ ((pDM_Odm->BoardType & BIT2) >> 2) << 4; /* _BT */ ++ ++ u32 cond1 = Condition1, cond2 = Condition2; ++ u32 driver1 = pDM_Odm->CutVersion << 24 | ++ pDM_Odm->SupportPlatform << 16 | ++ pDM_Odm->PackageType << 12 | ++ pDM_Odm->SupportInterface << 8 | ++ _BoardType; ++ ++ u32 driver2 = pDM_Odm->TypeGLNA << 0 | ++ pDM_Odm->TypeGPA << 8 | ++ pDM_Odm->TypeALNA << 16 | ++ pDM_Odm->TypeAPA << 24; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ++ ("===> [8812A] CheckPositive (cond1, cond2) = (0x%X 0x%X)\n", cond1, cond2)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ++ ("===> [8812A] CheckPositive (driver1, driver2) = (0x%X 0x%X)\n", driver1, driver2)); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ++ (" (Platform, Interface) = (0x%X, 0x%X)\n", pDM_Odm->SupportPlatform, pDM_Odm->SupportInterface)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ++ (" (Board, Package) = (0x%X, 0x%X)\n", pDM_Odm->BoardType, pDM_Odm->PackageType)); ++ ++ /* Value Defined Check =============== */ ++ /* QFN Type [15:12] and Cut Version [27:24] need to do value check */ ++ ++ if (((cond1 & 0x0000F000) != 0) && ((cond1 & 0x0000F000) != (driver1 & 0x0000F000))) ++ return false; ++ if (((cond1 & 0x0F000000) != 0) && ((cond1 & 0x0F000000) != (driver1 & 0x0F000000))) ++ return false; ++ ++ /* Bit Defined Check ================ */ ++ /* We don't care [31:28] and [23:20] */ ++ cond1 &= 0x000F0FFF; ++ driver1 &= 0x000F0FFF; ++ ++ if ((cond1 & driver1) == cond1) { ++ u32 bitMask = 0; ++ if ((cond1 & 0x0F) == 0) /* BoardType is DONTCARE */ ++ return true; ++ ++ if ((cond1 & BIT0) != 0) /* GLNA */ ++ bitMask |= 0x000000FF; ++ if ((cond1 & BIT1) != 0) /* GPA */ ++ bitMask |= 0x0000FF00; ++ if ((cond1 & BIT2) != 0) /* ALNA */ ++ bitMask |= 0x00FF0000; ++ if ((cond1 & BIT3) != 0) /* APA */ ++ bitMask |= 0xFF000000; ++ ++ if ((cond2 & bitMask) == (driver2 & bitMask)) /* BoardType of each RF path is matched */ ++ return true; ++ return false; ++ } ++ return false; ++} ++ ++static bool ++CheckNegative( ++ PDM_ODM_T pDM_Odm, ++ const u32 Condition1, ++ const u32 Condition2 ++ ) ++{ ++ return true; ++} ++ ++/****************************************************************************** ++* RadioA.TXT ++******************************************************************************/ ++ ++static u32 Array_MP_8723B_RadioA[] = { ++ 0x000, 0x00010000, ++ 0x0B0, 0x000DFFE0, ++ 0x0FE, 0x00000000, ++ 0x0FE, 0x00000000, ++ 0x0FE, 0x00000000, ++ 0x0B1, 0x00000018, ++ 0x0FE, 0x00000000, ++ 0x0FE, 0x00000000, ++ 0x0FE, 0x00000000, ++ 0x0B2, 0x00084C00, ++ 0x0B5, 0x0000D2CC, ++ 0x0B6, 0x000925AA, ++ 0x0B7, 0x00000010, ++ 0x0B8, 0x0000907F, ++ 0x05C, 0x00000002, ++ 0x07C, 0x00000002, ++ 0x07E, 0x00000005, ++ 0x08B, 0x0006FC00, ++ 0x0B0, 0x000FF9F0, ++ 0x01C, 0x000739D2, ++ 0x01E, 0x00000000, ++ 0x0DF, 0x00000780, ++ 0x050, 0x00067435, ++ 0x80002000, 0x00000000, 0x40000000, 0x00000000, ++ 0x051, 0x0006B10E, ++ 0x90003000, 0x00000000, 0x40000000, 0x00000000, ++ 0x051, 0x0006B10E, ++ 0x90004000, 0x00000000, 0x40000000, 0x00000000, ++ 0x051, 0x0006B10E, ++ 0xA0000000, 0x00000000, ++ 0x051, 0x0006B04E, ++ 0xB0000000, 0x00000000, ++ 0x052, 0x000007D2, ++ 0x053, 0x00000000, ++ 0x054, 0x00050400, ++ 0x055, 0x0004026E, ++ 0x0DD, 0x0000004C, ++ 0x070, 0x00067435, ++ 0x80002000, 0x00000000, 0x40000000, 0x00000000, ++ 0x071, 0x0006B10E, ++ 0x90003000, 0x00000000, 0x40000000, 0x00000000, ++ 0x071, 0x0006B10E, ++ 0x90004000, 0x00000000, 0x40000000, 0x00000000, ++ 0x071, 0x0006B10E, ++ 0xA0000000, 0x00000000, ++ 0x071, 0x0006B04E, ++ 0xB0000000, 0x00000000, ++ 0x072, 0x000007D2, ++ 0x073, 0x00000000, ++ 0x074, 0x00050400, ++ 0x075, 0x0004026E, ++ 0x0EF, 0x00000100, ++ 0x034, 0x0000ADD7, ++ 0x035, 0x00005C00, ++ 0x034, 0x00009DD4, ++ 0x035, 0x00005000, ++ 0x034, 0x00008DD1, ++ 0x035, 0x00004400, ++ 0x034, 0x00007DCE, ++ 0x035, 0x00003800, ++ 0x034, 0x00006CD1, ++ 0x035, 0x00004400, ++ 0x034, 0x00005CCE, ++ 0x035, 0x00003800, ++ 0x034, 0x000048CE, ++ 0x035, 0x00004400, ++ 0x034, 0x000034CE, ++ 0x035, 0x00003800, ++ 0x034, 0x00002451, ++ 0x035, 0x00004400, ++ 0x034, 0x0000144E, ++ 0x035, 0x00003800, ++ 0x034, 0x00000051, ++ 0x035, 0x00004400, ++ 0x0EF, 0x00000000, ++ 0x0EF, 0x00000100, ++ 0x0ED, 0x00000010, ++ 0x044, 0x0000ADD7, ++ 0x044, 0x00009DD4, ++ 0x044, 0x00008DD1, ++ 0x044, 0x00007DCE, ++ 0x044, 0x00006CC1, ++ 0x044, 0x00005CCE, ++ 0x044, 0x000044D1, ++ 0x044, 0x000034CE, ++ 0x044, 0x00002451, ++ 0x044, 0x0000144E, ++ 0x044, 0x00000051, ++ 0x0EF, 0x00000000, ++ 0x0ED, 0x00000000, ++ 0x07F, 0x00020080, ++ 0x0EF, 0x00002000, ++ 0x03B, 0x000380EF, ++ 0x03B, 0x000302FE, ++ 0x03B, 0x00028CE6, ++ 0x03B, 0x000200BC, ++ 0x03B, 0x000188A5, ++ 0x03B, 0x00010FBC, ++ 0x03B, 0x00008F71, ++ 0x03B, 0x00000900, ++ 0x0EF, 0x00000000, ++ 0x0ED, 0x00000001, ++ 0x040, 0x000380EF, ++ 0x040, 0x000302FE, ++ 0x040, 0x00028CE6, ++ 0x040, 0x000200BC, ++ 0x040, 0x000188A5, ++ 0x040, 0x00010FBC, ++ 0x040, 0x00008F71, ++ 0x040, 0x00000900, ++ 0x0ED, 0x00000000, ++ 0x082, 0x00080000, ++ 0x083, 0x00008000, ++ 0x084, 0x00048D80, ++ 0x085, 0x00068000, ++ 0x0A2, 0x00080000, ++ 0x0A3, 0x00008000, ++ 0x0A4, 0x00048D80, ++ 0x0A5, 0x00068000, ++ 0x0ED, 0x00000002, ++ 0x0EF, 0x00000002, ++ 0x056, 0x00000032, ++ 0x076, 0x00000032, ++ 0x001, 0x00000780, ++ ++}; ++ ++void ++ODM_ReadAndConfig_MP_8723B_RadioA( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ u32 i = 0; ++ u32 ArrayLen = sizeof(Array_MP_8723B_RadioA)/sizeof(u32); ++ u32 * Array = Array_MP_8723B_RadioA; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("===> ODM_ReadAndConfig_MP_8723B_RadioA\n")); ++ ++ for (i = 0; i < ArrayLen; i += 2) ++ { ++ u32 v1 = Array[i]; ++ u32 v2 = Array[i+1]; ++ ++ /* This (offset, data) pair doesn't care the condition. */ ++ if (v1 < 0x40000000) ++ { ++ odm_ConfigRF_RadioA_8723B(pDM_Odm, v1, v2); ++ continue; ++ } ++ else ++ { /* This line is the beginning of branch. */ ++ bool bMatched = true; ++ u8 cCond = (u8)((v1 & (BIT29|BIT28)) >> 28); ++ ++ if (cCond == COND_ELSE) { /* ELSE, ENDIF */ ++ bMatched = true; ++ READ_NEXT_PAIR(v1, v2, i); ++ } else if (! CheckPositive(pDM_Odm, v1, v2)) { ++ bMatched = false; ++ READ_NEXT_PAIR(v1, v2, i); ++ READ_NEXT_PAIR(v1, v2, i); ++ } else { ++ READ_NEXT_PAIR(v1, v2, i); ++ if (! CheckNegative(pDM_Odm, v1, v2)) ++ bMatched = false; ++ else ++ bMatched = true; ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ if (bMatched == false) ++ { /* Condition isn't matched. Discard the following (offset, data) pairs. */ ++ while (v1 < 0x40000000 && i < ArrayLen -2) ++ READ_NEXT_PAIR(v1, v2, i); ++ ++ i -= 2; /* prevent from for-loop += 2 */ ++ } ++ else /* Configure matched pairs and skip to end of if-else. */ ++ { ++ while (v1 < 0x40000000 && i < ArrayLen-2) { ++ odm_ConfigRF_RadioA_8723B(pDM_Odm, v1, v2); ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ /* Keeps reading until ENDIF. */ ++ cCond = (u8)((v1 & (BIT29|BIT28)) >> 28); ++ while (cCond != COND_ENDIF && i < ArrayLen-2) { ++ READ_NEXT_PAIR(v1, v2, i); ++ cCond = (u8)((v1 & (BIT29|BIT28)) >> 28); ++ } ++ } ++ } ++ } ++} ++ ++/****************************************************************************** ++* TxPowerTrack_SDIO.TXT ++******************************************************************************/ ++ ++static u8 gDeltaSwingTableIdx_MP_5GB_N_TxPowerTrack_SDIO_8723B[][DELTA_SWINGIDX_SIZE] = { ++ {0, 1, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11, 12, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14}, ++ {0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14}, ++ {0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14}, ++}; ++static u8 gDeltaSwingTableIdx_MP_5GB_P_TxPowerTrack_SDIO_8723B[][DELTA_SWINGIDX_SIZE] = { ++ {0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 16, 17, 17, 18, 19, 20, 20, 20}, ++ {0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 19, 20, 20, 20}, ++ {0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 20, 21, 21, 21}, ++}; ++static u8 gDeltaSwingTableIdx_MP_5GA_N_TxPowerTrack_SDIO_8723B[][DELTA_SWINGIDX_SIZE] = { ++ {0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14}, ++ {0, 1, 2, 3, 3, 4, 5, 6, 6, 6, 7, 7, 8, 8, 9, 10, 11, 11, 12, 13, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16}, ++ {0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 10, 11, 11, 12, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16}, ++}; ++static u8 gDeltaSwingTableIdx_MP_5GA_P_TxPowerTrack_SDIO_8723B[][DELTA_SWINGIDX_SIZE] = { ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 20, 21, 21, 21}, ++ {0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 20, 21, 21, 21}, ++}; ++static u8 gDeltaSwingTableIdx_MP_2GB_N_TxPowerTrack_SDIO_8723B[] = {0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 13, 14, 15}; ++static u8 gDeltaSwingTableIdx_MP_2GB_P_TxPowerTrack_SDIO_8723B[] = {0, 0, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 12, 12, 13, 13, 14, 15, 15}; ++static u8 gDeltaSwingTableIdx_MP_2GA_N_TxPowerTrack_SDIO_8723B[] = {0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 13, 14, 15}; ++static u8 gDeltaSwingTableIdx_MP_2GA_P_TxPowerTrack_SDIO_8723B[] = {0, 0, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 12, 12, 13, 13, 14, 15, 15}; ++static u8 gDeltaSwingTableIdx_MP_2GCCKB_N_TxPowerTrack_SDIO_8723B[] = {0, 0, 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 15}; ++static u8 gDeltaSwingTableIdx_MP_2GCCKB_P_TxPowerTrack_SDIO_8723B[] = {0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 15}; ++static u8 gDeltaSwingTableIdx_MP_2GCCKA_N_TxPowerTrack_SDIO_8723B[] = {0, 0, 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 15}; ++static u8 gDeltaSwingTableIdx_MP_2GCCKA_P_TxPowerTrack_SDIO_8723B[] = {0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 15}; ++ ++void ++ODM_ReadAndConfig_MP_8723B_TxPowerTrack_SDIO( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ PODM_RF_CAL_T pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("===> ODM_ReadAndConfig_MP_MP_8723B\n")); ++ ++ ++ memcpy(pRFCalibrateInfo->DeltaSwingTableIdx_2GA_P, gDeltaSwingTableIdx_MP_2GA_P_TxPowerTrack_SDIO_8723B, DELTA_SWINGIDX_SIZE); ++ memcpy(pRFCalibrateInfo->DeltaSwingTableIdx_2GA_N, gDeltaSwingTableIdx_MP_2GA_N_TxPowerTrack_SDIO_8723B, DELTA_SWINGIDX_SIZE); ++ memcpy(pRFCalibrateInfo->DeltaSwingTableIdx_2GB_P, gDeltaSwingTableIdx_MP_2GB_P_TxPowerTrack_SDIO_8723B, DELTA_SWINGIDX_SIZE); ++ memcpy(pRFCalibrateInfo->DeltaSwingTableIdx_2GB_N, gDeltaSwingTableIdx_MP_2GB_N_TxPowerTrack_SDIO_8723B, DELTA_SWINGIDX_SIZE); ++ ++ memcpy(pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKA_P, gDeltaSwingTableIdx_MP_2GCCKA_P_TxPowerTrack_SDIO_8723B, DELTA_SWINGIDX_SIZE); ++ memcpy(pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKA_N, gDeltaSwingTableIdx_MP_2GCCKA_N_TxPowerTrack_SDIO_8723B, DELTA_SWINGIDX_SIZE); ++ memcpy(pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKB_P, gDeltaSwingTableIdx_MP_2GCCKB_P_TxPowerTrack_SDIO_8723B, DELTA_SWINGIDX_SIZE); ++ memcpy(pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKB_N, gDeltaSwingTableIdx_MP_2GCCKB_N_TxPowerTrack_SDIO_8723B, DELTA_SWINGIDX_SIZE); ++ ++ memcpy(pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P, gDeltaSwingTableIdx_MP_5GA_P_TxPowerTrack_SDIO_8723B, DELTA_SWINGIDX_SIZE*3); ++ memcpy(pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N, gDeltaSwingTableIdx_MP_5GA_N_TxPowerTrack_SDIO_8723B, DELTA_SWINGIDX_SIZE*3); ++ memcpy(pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P, gDeltaSwingTableIdx_MP_5GB_P_TxPowerTrack_SDIO_8723B, DELTA_SWINGIDX_SIZE*3); ++ memcpy(pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N, gDeltaSwingTableIdx_MP_5GB_N_TxPowerTrack_SDIO_8723B, DELTA_SWINGIDX_SIZE*3); ++} ++ ++/****************************************************************************** ++* TXPWR_LMT.TXT ++******************************************************************************/ ++ ++static u8 * Array_MP_8723B_TXPWR_LMT[] = { ++ "FCC", "2.4G", "20M", "CCK", "1T", "01", "32", ++ "ETSI", "2.4G", "20M", "CCK", "1T", "01", "32", ++ "MKK", "2.4G", "20M", "CCK", "1T", "01", "32", ++ "FCC", "2.4G", "20M", "CCK", "1T", "02", "32", ++ "ETSI", "2.4G", "20M", "CCK", "1T", "02", "32", ++ "MKK", "2.4G", "20M", "CCK", "1T", "02", "32", ++ "FCC", "2.4G", "20M", "CCK", "1T", "03", "32", ++ "ETSI", "2.4G", "20M", "CCK", "1T", "03", "32", ++ "MKK", "2.4G", "20M", "CCK", "1T", "03", "32", ++ "FCC", "2.4G", "20M", "CCK", "1T", "04", "32", ++ "ETSI", "2.4G", "20M", "CCK", "1T", "04", "32", ++ "MKK", "2.4G", "20M", "CCK", "1T", "04", "32", ++ "FCC", "2.4G", "20M", "CCK", "1T", "05", "32", ++ "ETSI", "2.4G", "20M", "CCK", "1T", "05", "32", ++ "MKK", "2.4G", "20M", "CCK", "1T", "05", "32", ++ "FCC", "2.4G", "20M", "CCK", "1T", "06", "32", ++ "ETSI", "2.4G", "20M", "CCK", "1T", "06", "32", ++ "MKK", "2.4G", "20M", "CCK", "1T", "06", "32", ++ "FCC", "2.4G", "20M", "CCK", "1T", "07", "32", ++ "ETSI", "2.4G", "20M", "CCK", "1T", "07", "32", ++ "MKK", "2.4G", "20M", "CCK", "1T", "07", "32", ++ "FCC", "2.4G", "20M", "CCK", "1T", "08", "32", ++ "ETSI", "2.4G", "20M", "CCK", "1T", "08", "32", ++ "MKK", "2.4G", "20M", "CCK", "1T", "08", "32", ++ "FCC", "2.4G", "20M", "CCK", "1T", "09", "32", ++ "ETSI", "2.4G", "20M", "CCK", "1T", "09", "32", ++ "MKK", "2.4G", "20M", "CCK", "1T", "09", "32", ++ "FCC", "2.4G", "20M", "CCK", "1T", "10", "32", ++ "ETSI", "2.4G", "20M", "CCK", "1T", "10", "32", ++ "MKK", "2.4G", "20M", "CCK", "1T", "10", "32", ++ "FCC", "2.4G", "20M", "CCK", "1T", "11", "32", ++ "ETSI", "2.4G", "20M", "CCK", "1T", "11", "32", ++ "MKK", "2.4G", "20M", "CCK", "1T", "11", "32", ++ "FCC", "2.4G", "20M", "CCK", "1T", "12", "63", ++ "ETSI", "2.4G", "20M", "CCK", "1T", "12", "32", ++ "MKK", "2.4G", "20M", "CCK", "1T", "12", "32", ++ "FCC", "2.4G", "20M", "CCK", "1T", "13", "63", ++ "ETSI", "2.4G", "20M", "CCK", "1T", "13", "32", ++ "MKK", "2.4G", "20M", "CCK", "1T", "13", "32", ++ "FCC", "2.4G", "20M", "CCK", "1T", "14", "63", ++ "ETSI", "2.4G", "20M", "CCK", "1T", "14", "63", ++ "MKK", "2.4G", "20M", "CCK", "1T", "14", "32", ++ "FCC", "2.4G", "20M", "OFDM", "1T", "01", "28", ++ "ETSI", "2.4G", "20M", "OFDM", "1T", "01", "32", ++ "MKK", "2.4G", "20M", "OFDM", "1T", "01", "32", ++ "FCC", "2.4G", "20M", "OFDM", "1T", "02", "28", ++ "ETSI", "2.4G", "20M", "OFDM", "1T", "02", "32", ++ "MKK", "2.4G", "20M", "OFDM", "1T", "02", "32", ++ "FCC", "2.4G", "20M", "OFDM", "1T", "03", "32", ++ "ETSI", "2.4G", "20M", "OFDM", "1T", "03", "32", ++ "MKK", "2.4G", "20M", "OFDM", "1T", "03", "32", ++ "FCC", "2.4G", "20M", "OFDM", "1T", "04", "32", ++ "ETSI", "2.4G", "20M", "OFDM", "1T", "04", "32", ++ "MKK", "2.4G", "20M", "OFDM", "1T", "04", "32", ++ "FCC", "2.4G", "20M", "OFDM", "1T", "05", "32", ++ "ETSI", "2.4G", "20M", "OFDM", "1T", "05", "32", ++ "MKK", "2.4G", "20M", "OFDM", "1T", "05", "32", ++ "FCC", "2.4G", "20M", "OFDM", "1T", "06", "32", ++ "ETSI", "2.4G", "20M", "OFDM", "1T", "06", "32", ++ "MKK", "2.4G", "20M", "OFDM", "1T", "06", "32", ++ "FCC", "2.4G", "20M", "OFDM", "1T", "07", "32", ++ "ETSI", "2.4G", "20M", "OFDM", "1T", "07", "32", ++ "MKK", "2.4G", "20M", "OFDM", "1T", "07", "32", ++ "FCC", "2.4G", "20M", "OFDM", "1T", "08", "32", ++ "ETSI", "2.4G", "20M", "OFDM", "1T", "08", "32", ++ "MKK", "2.4G", "20M", "OFDM", "1T", "08", "32", ++ "FCC", "2.4G", "20M", "OFDM", "1T", "09", "32", ++ "ETSI", "2.4G", "20M", "OFDM", "1T", "09", "32", ++ "MKK", "2.4G", "20M", "OFDM", "1T", "09", "32", ++ "FCC", "2.4G", "20M", "OFDM", "1T", "10", "28", ++ "ETSI", "2.4G", "20M", "OFDM", "1T", "10", "32", ++ "MKK", "2.4G", "20M", "OFDM", "1T", "10", "32", ++ "FCC", "2.4G", "20M", "OFDM", "1T", "11", "28", ++ "ETSI", "2.4G", "20M", "OFDM", "1T", "11", "32", ++ "MKK", "2.4G", "20M", "OFDM", "1T", "11", "32", ++ "FCC", "2.4G", "20M", "OFDM", "1T", "12", "63", ++ "ETSI", "2.4G", "20M", "OFDM", "1T", "12", "32", ++ "MKK", "2.4G", "20M", "OFDM", "1T", "12", "32", ++ "FCC", "2.4G", "20M", "OFDM", "1T", "13", "63", ++ "ETSI", "2.4G", "20M", "OFDM", "1T", "13", "32", ++ "MKK", "2.4G", "20M", "OFDM", "1T", "13", "32", ++ "FCC", "2.4G", "20M", "OFDM", "1T", "14", "63", ++ "ETSI", "2.4G", "20M", "OFDM", "1T", "14", "63", ++ "MKK", "2.4G", "20M", "OFDM", "1T", "14", "63", ++ "FCC", "2.4G", "20M", "HT", "1T", "01", "26", ++ "ETSI", "2.4G", "20M", "HT", "1T", "01", "32", ++ "MKK", "2.4G", "20M", "HT", "1T", "01", "32", ++ "FCC", "2.4G", "20M", "HT", "1T", "02", "26", ++ "ETSI", "2.4G", "20M", "HT", "1T", "02", "32", ++ "MKK", "2.4G", "20M", "HT", "1T", "02", "32", ++ "FCC", "2.4G", "20M", "HT", "1T", "03", "32", ++ "ETSI", "2.4G", "20M", "HT", "1T", "03", "32", ++ "MKK", "2.4G", "20M", "HT", "1T", "03", "32", ++ "FCC", "2.4G", "20M", "HT", "1T", "04", "32", ++ "ETSI", "2.4G", "20M", "HT", "1T", "04", "32", ++ "MKK", "2.4G", "20M", "HT", "1T", "04", "32", ++ "FCC", "2.4G", "20M", "HT", "1T", "05", "32", ++ "ETSI", "2.4G", "20M", "HT", "1T", "05", "32", ++ "MKK", "2.4G", "20M", "HT", "1T", "05", "32", ++ "FCC", "2.4G", "20M", "HT", "1T", "06", "32", ++ "ETSI", "2.4G", "20M", "HT", "1T", "06", "32", ++ "MKK", "2.4G", "20M", "HT", "1T", "06", "32", ++ "FCC", "2.4G", "20M", "HT", "1T", "07", "32", ++ "ETSI", "2.4G", "20M", "HT", "1T", "07", "32", ++ "MKK", "2.4G", "20M", "HT", "1T", "07", "32", ++ "FCC", "2.4G", "20M", "HT", "1T", "08", "32", ++ "ETSI", "2.4G", "20M", "HT", "1T", "08", "32", ++ "MKK", "2.4G", "20M", "HT", "1T", "08", "32", ++ "FCC", "2.4G", "20M", "HT", "1T", "09", "32", ++ "ETSI", "2.4G", "20M", "HT", "1T", "09", "32", ++ "MKK", "2.4G", "20M", "HT", "1T", "09", "32", ++ "FCC", "2.4G", "20M", "HT", "1T", "10", "26", ++ "ETSI", "2.4G", "20M", "HT", "1T", "10", "32", ++ "MKK", "2.4G", "20M", "HT", "1T", "10", "32", ++ "FCC", "2.4G", "20M", "HT", "1T", "11", "26", ++ "ETSI", "2.4G", "20M", "HT", "1T", "11", "32", ++ "MKK", "2.4G", "20M", "HT", "1T", "11", "32", ++ "FCC", "2.4G", "20M", "HT", "1T", "12", "63", ++ "ETSI", "2.4G", "20M", "HT", "1T", "12", "32", ++ "MKK", "2.4G", "20M", "HT", "1T", "12", "32", ++ "FCC", "2.4G", "20M", "HT", "1T", "13", "63", ++ "ETSI", "2.4G", "20M", "HT", "1T", "13", "32", ++ "MKK", "2.4G", "20M", "HT", "1T", "13", "32", ++ "FCC", "2.4G", "20M", "HT", "1T", "14", "63", ++ "ETSI", "2.4G", "20M", "HT", "1T", "14", "63", ++ "MKK", "2.4G", "20M", "HT", "1T", "14", "63", ++ "FCC", "2.4G", "20M", "HT", "2T", "01", "30", ++ "ETSI", "2.4G", "20M", "HT", "2T", "01", "32", ++ "MKK", "2.4G", "20M", "HT", "2T", "01", "32", ++ "FCC", "2.4G", "20M", "HT", "2T", "02", "32", ++ "ETSI", "2.4G", "20M", "HT", "2T", "02", "32", ++ "MKK", "2.4G", "20M", "HT", "2T", "02", "32", ++ "FCC", "2.4G", "20M", "HT", "2T", "03", "32", ++ "ETSI", "2.4G", "20M", "HT", "2T", "03", "32", ++ "MKK", "2.4G", "20M", "HT", "2T", "03", "32", ++ "FCC", "2.4G", "20M", "HT", "2T", "04", "32", ++ "ETSI", "2.4G", "20M", "HT", "2T", "04", "32", ++ "MKK", "2.4G", "20M", "HT", "2T", "04", "32", ++ "FCC", "2.4G", "20M", "HT", "2T", "05", "32", ++ "ETSI", "2.4G", "20M", "HT", "2T", "05", "32", ++ "MKK", "2.4G", "20M", "HT", "2T", "05", "32", ++ "FCC", "2.4G", "20M", "HT", "2T", "06", "32", ++ "ETSI", "2.4G", "20M", "HT", "2T", "06", "32", ++ "MKK", "2.4G", "20M", "HT", "2T", "06", "32", ++ "FCC", "2.4G", "20M", "HT", "2T", "07", "32", ++ "ETSI", "2.4G", "20M", "HT", "2T", "07", "32", ++ "MKK", "2.4G", "20M", "HT", "2T", "07", "32", ++ "FCC", "2.4G", "20M", "HT", "2T", "08", "32", ++ "ETSI", "2.4G", "20M", "HT", "2T", "08", "32", ++ "MKK", "2.4G", "20M", "HT", "2T", "08", "32", ++ "FCC", "2.4G", "20M", "HT", "2T", "09", "32", ++ "ETSI", "2.4G", "20M", "HT", "2T", "09", "32", ++ "MKK", "2.4G", "20M", "HT", "2T", "09", "32", ++ "FCC", "2.4G", "20M", "HT", "2T", "10", "32", ++ "ETSI", "2.4G", "20M", "HT", "2T", "10", "32", ++ "MKK", "2.4G", "20M", "HT", "2T", "10", "32", ++ "FCC", "2.4G", "20M", "HT", "2T", "11", "30", ++ "ETSI", "2.4G", "20M", "HT", "2T", "11", "32", ++ "MKK", "2.4G", "20M", "HT", "2T", "11", "32", ++ "FCC", "2.4G", "20M", "HT", "2T", "12", "63", ++ "ETSI", "2.4G", "20M", "HT", "2T", "12", "32", ++ "MKK", "2.4G", "20M", "HT", "2T", "12", "32", ++ "FCC", "2.4G", "20M", "HT", "2T", "13", "63", ++ "ETSI", "2.4G", "20M", "HT", "2T", "13", "32", ++ "MKK", "2.4G", "20M", "HT", "2T", "13", "32", ++ "FCC", "2.4G", "20M", "HT", "2T", "14", "63", ++ "ETSI", "2.4G", "20M", "HT", "2T", "14", "63", ++ "MKK", "2.4G", "20M", "HT", "2T", "14", "63", ++ "FCC", "2.4G", "40M", "HT", "1T", "01", "63", ++ "ETSI", "2.4G", "40M", "HT", "1T", "01", "63", ++ "MKK", "2.4G", "40M", "HT", "1T", "01", "63", ++ "FCC", "2.4G", "40M", "HT", "1T", "02", "63", ++ "ETSI", "2.4G", "40M", "HT", "1T", "02", "63", ++ "MKK", "2.4G", "40M", "HT", "1T", "02", "63", ++ "FCC", "2.4G", "40M", "HT", "1T", "03", "26", ++ "ETSI", "2.4G", "40M", "HT", "1T", "03", "32", ++ "MKK", "2.4G", "40M", "HT", "1T", "03", "32", ++ "FCC", "2.4G", "40M", "HT", "1T", "04", "26", ++ "ETSI", "2.4G", "40M", "HT", "1T", "04", "32", ++ "MKK", "2.4G", "40M", "HT", "1T", "04", "32", ++ "FCC", "2.4G", "40M", "HT", "1T", "05", "32", ++ "ETSI", "2.4G", "40M", "HT", "1T", "05", "32", ++ "MKK", "2.4G", "40M", "HT", "1T", "05", "32", ++ "FCC", "2.4G", "40M", "HT", "1T", "06", "32", ++ "ETSI", "2.4G", "40M", "HT", "1T", "06", "32", ++ "MKK", "2.4G", "40M", "HT", "1T", "06", "32", ++ "FCC", "2.4G", "40M", "HT", "1T", "07", "32", ++ "ETSI", "2.4G", "40M", "HT", "1T", "07", "32", ++ "MKK", "2.4G", "40M", "HT", "1T", "07", "32", ++ "FCC", "2.4G", "40M", "HT", "1T", "08", "26", ++ "ETSI", "2.4G", "40M", "HT", "1T", "08", "32", ++ "MKK", "2.4G", "40M", "HT", "1T", "08", "32", ++ "FCC", "2.4G", "40M", "HT", "1T", "09", "26", ++ "ETSI", "2.4G", "40M", "HT", "1T", "09", "32", ++ "MKK", "2.4G", "40M", "HT", "1T", "09", "32", ++ "FCC", "2.4G", "40M", "HT", "1T", "10", "26", ++ "ETSI", "2.4G", "40M", "HT", "1T", "10", "32", ++ "MKK", "2.4G", "40M", "HT", "1T", "10", "32", ++ "FCC", "2.4G", "40M", "HT", "1T", "11", "26", ++ "ETSI", "2.4G", "40M", "HT", "1T", "11", "32", ++ "MKK", "2.4G", "40M", "HT", "1T", "11", "32", ++ "FCC", "2.4G", "40M", "HT", "1T", "12", "63", ++ "ETSI", "2.4G", "40M", "HT", "1T", "12", "32", ++ "MKK", "2.4G", "40M", "HT", "1T", "12", "32", ++ "FCC", "2.4G", "40M", "HT", "1T", "13", "63", ++ "ETSI", "2.4G", "40M", "HT", "1T", "13", "32", ++ "MKK", "2.4G", "40M", "HT", "1T", "13", "32", ++ "FCC", "2.4G", "40M", "HT", "1T", "14", "63", ++ "ETSI", "2.4G", "40M", "HT", "1T", "14", "63", ++ "MKK", "2.4G", "40M", "HT", "1T", "14", "63", ++ "FCC", "2.4G", "40M", "HT", "2T", "01", "63", ++ "ETSI", "2.4G", "40M", "HT", "2T", "01", "63", ++ "MKK", "2.4G", "40M", "HT", "2T", "01", "63", ++ "FCC", "2.4G", "40M", "HT", "2T", "02", "63", ++ "ETSI", "2.4G", "40M", "HT", "2T", "02", "63", ++ "MKK", "2.4G", "40M", "HT", "2T", "02", "63", ++ "FCC", "2.4G", "40M", "HT", "2T", "03", "30", ++ "ETSI", "2.4G", "40M", "HT", "2T", "03", "30", ++ "MKK", "2.4G", "40M", "HT", "2T", "03", "30", ++ "FCC", "2.4G", "40M", "HT", "2T", "04", "32", ++ "ETSI", "2.4G", "40M", "HT", "2T", "04", "30", ++ "MKK", "2.4G", "40M", "HT", "2T", "04", "30", ++ "FCC", "2.4G", "40M", "HT", "2T", "05", "32", ++ "ETSI", "2.4G", "40M", "HT", "2T", "05", "30", ++ "MKK", "2.4G", "40M", "HT", "2T", "05", "30", ++ "FCC", "2.4G", "40M", "HT", "2T", "06", "32", ++ "ETSI", "2.4G", "40M", "HT", "2T", "06", "30", ++ "MKK", "2.4G", "40M", "HT", "2T", "06", "30", ++ "FCC", "2.4G", "40M", "HT", "2T", "07", "32", ++ "ETSI", "2.4G", "40M", "HT", "2T", "07", "30", ++ "MKK", "2.4G", "40M", "HT", "2T", "07", "30", ++ "FCC", "2.4G", "40M", "HT", "2T", "08", "32", ++ "ETSI", "2.4G", "40M", "HT", "2T", "08", "30", ++ "MKK", "2.4G", "40M", "HT", "2T", "08", "30", ++ "FCC", "2.4G", "40M", "HT", "2T", "09", "32", ++ "ETSI", "2.4G", "40M", "HT", "2T", "09", "30", ++ "MKK", "2.4G", "40M", "HT", "2T", "09", "30", ++ "FCC", "2.4G", "40M", "HT", "2T", "10", "32", ++ "ETSI", "2.4G", "40M", "HT", "2T", "10", "30", ++ "MKK", "2.4G", "40M", "HT", "2T", "10", "30", ++ "FCC", "2.4G", "40M", "HT", "2T", "11", "30", ++ "ETSI", "2.4G", "40M", "HT", "2T", "11", "30", ++ "MKK", "2.4G", "40M", "HT", "2T", "11", "30", ++ "FCC", "2.4G", "40M", "HT", "2T", "12", "63", ++ "ETSI", "2.4G", "40M", "HT", "2T", "12", "32", ++ "MKK", "2.4G", "40M", "HT", "2T", "12", "32", ++ "FCC", "2.4G", "40M", "HT", "2T", "13", "63", ++ "ETSI", "2.4G", "40M", "HT", "2T", "13", "32", ++ "MKK", "2.4G", "40M", "HT", "2T", "13", "32", ++ "FCC", "2.4G", "40M", "HT", "2T", "14", "63", ++ "ETSI", "2.4G", "40M", "HT", "2T", "14", "63", ++ "MKK", "2.4G", "40M", "HT", "2T", "14", "63" ++}; ++ ++void ++ODM_ReadAndConfig_MP_8723B_TXPWR_LMT( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ u32 i = 0; ++ u32 ArrayLen = sizeof(Array_MP_8723B_TXPWR_LMT)/sizeof(u8 *); ++ u8 * *Array = Array_MP_8723B_TXPWR_LMT; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("===> ODM_ReadAndConfig_MP_8723B_TXPWR_LMT\n")); ++ ++ for (i = 0; i < ArrayLen; i += 7) { ++ u8 * regulation = Array[i]; ++ u8 * band = Array[i+1]; ++ u8 * bandwidth = Array[i+2]; ++ u8 * rate = Array[i+3]; ++ u8 * rfPath = Array[i+4]; ++ u8 * chnl = Array[i+5]; ++ u8 * val = Array[i+6]; ++ ++ odm_ConfigBB_TXPWR_LMT_8723B(pDM_Odm, regulation, band, bandwidth, rate, rfPath, chnl, val); ++ } ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/HalHWImg8723B_RF.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalHWImg8723B_RF.h +--- linux-4.3/3rdparty/rtl8723bs/hal/HalHWImg8723B_RF.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalHWImg8723B_RF.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,49 @@ ++/****************************************************************************** ++* ++* Copyright(c) 2007 - 2011 Realtek 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. ++* ++******************************************************************************/ ++ ++#ifndef __INC_MP_RF_HW_IMG_8723B_H ++#define __INC_MP_RF_HW_IMG_8723B_H ++ ++ ++/****************************************************************************** ++* RadioA.TXT ++******************************************************************************/ ++ ++void ++ODM_ReadAndConfig_MP_8723B_RadioA(/* TC: Test Chip, MP: MP Chip */ ++ PDM_ODM_T pDM_Odm ++); ++ ++/****************************************************************************** ++* TxPowerTrack_SDIO.TXT ++******************************************************************************/ ++ ++void ++ODM_ReadAndConfig_MP_8723B_TxPowerTrack_SDIO(/* TC: Test Chip, MP: MP Chip */ ++ PDM_ODM_T pDM_Odm ++); ++u32 ODM_GetVersion_MP_8723B_TxPowerTrack_SDIO(void); ++ ++/****************************************************************************** ++* TXPWR_LMT.TXT ++******************************************************************************/ ++ ++void ++ODM_ReadAndConfig_MP_8723B_TXPWR_LMT(/* TC: Test Chip, MP: MP Chip */ ++ PDM_ODM_T pDM_Odm ++); ++u32 ODM_GetVersion_MP_8723B_TXPWR_LMT(void); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/hal_intf.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/hal_intf.c +--- linux-4.3/3rdparty/rtl8723bs/hal/hal_intf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/hal_intf.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,478 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#define _HAL_INTF_C_ ++ ++#include ++#include ++#include ++ ++void rtw_hal_chip_configure(struct adapter *padapter) ++{ ++ if (padapter->HalFunc.intf_chip_configure) ++ padapter->HalFunc.intf_chip_configure(padapter); ++} ++ ++void rtw_hal_read_chip_info(struct adapter *padapter) ++{ ++ if (padapter->HalFunc.read_adapter_info) ++ padapter->HalFunc.read_adapter_info(padapter); ++} ++ ++void rtw_hal_read_chip_version(struct adapter *padapter) ++{ ++ if (padapter->HalFunc.read_chip_version) ++ padapter->HalFunc.read_chip_version(padapter); ++} ++ ++void rtw_hal_def_value_init(struct adapter *padapter) ++{ ++ if (is_primary_adapter(padapter)) ++ if (padapter->HalFunc.init_default_value) ++ padapter->HalFunc.init_default_value(padapter); ++} ++void rtw_hal_free_data(struct adapter *padapter) ++{ ++ /* free HAL Data */ ++ rtw_hal_data_deinit(padapter); ++ ++ if (is_primary_adapter(padapter)) ++ if (padapter->HalFunc.free_hal_data) ++ padapter->HalFunc.free_hal_data(padapter); ++} ++void rtw_hal_dm_init(struct adapter *padapter) ++{ ++ if (is_primary_adapter(padapter)) ++ if (padapter->HalFunc.dm_init) ++ padapter->HalFunc.dm_init(padapter); ++} ++void rtw_hal_dm_deinit(struct adapter *padapter) ++{ ++ /* cancel dm timer */ ++ if (is_primary_adapter(padapter)) ++ if (padapter->HalFunc.dm_deinit) ++ padapter->HalFunc.dm_deinit(padapter); ++} ++ ++static void rtw_hal_init_opmode(struct adapter *padapter) ++{ ++ enum NDIS_802_11_NETWORK_INFRASTRUCTURE networkType = Ndis802_11InfrastructureMax; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ sint fw_state; ++ ++ fw_state = get_fwstate(pmlmepriv); ++ ++ if (fw_state & WIFI_ADHOC_STATE) ++ networkType = Ndis802_11IBSS; ++ else if (fw_state & WIFI_STATION_STATE) ++ networkType = Ndis802_11Infrastructure; ++ else if (fw_state & WIFI_AP_STATE) ++ networkType = Ndis802_11APMode; ++ else ++ return; ++ ++ rtw_setopmode_cmd(padapter, networkType, false); ++} ++ ++uint rtw_hal_init(struct adapter *padapter) ++{ ++ uint status; ++ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); ++ ++ status = padapter->HalFunc.hal_init(padapter); ++ ++ if (status == _SUCCESS) { ++ rtw_hal_init_opmode(padapter); ++ ++ dvobj->padapters->hw_init_completed = true; ++ ++ if (padapter->registrypriv.notch_filter == 1) ++ rtw_hal_notch_filter(padapter, 1); ++ ++ rtw_hal_reset_security_engine(padapter); ++ ++ rtw_sec_restore_wep_key(dvobj->padapters); ++ ++ init_hw_mlme_ext(padapter); ++ ++ rtw_bb_rf_gain_offset(padapter); ++ } else { ++ dvobj->padapters->hw_init_completed = false; ++ DBG_871X("rtw_hal_init: hal__init fail\n"); ++ } ++ ++ RT_TRACE(_module_hal_init_c_, _drv_err_, ("-rtl871x_hal_init:status = 0x%x\n", status)); ++ ++ return status; ++ ++} ++ ++uint rtw_hal_deinit(struct adapter *padapter) ++{ ++ uint status = _SUCCESS; ++ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); ++ ++ status = padapter->HalFunc.hal_deinit(padapter); ++ ++ if (status == _SUCCESS) { ++ padapter = dvobj->padapters; ++ padapter->hw_init_completed = false; ++ } else { ++ DBG_871X("\n rtw_hal_deinit: hal_init fail\n"); ++ } ++ return status; ++} ++ ++void rtw_hal_set_hwreg(struct adapter *padapter, u8 variable, u8 *val) ++{ ++ if (padapter->HalFunc.SetHwRegHandler) ++ padapter->HalFunc.SetHwRegHandler(padapter, variable, val); ++} ++ ++void rtw_hal_get_hwreg(struct adapter *padapter, u8 variable, u8 *val) ++{ ++ if (padapter->HalFunc.GetHwRegHandler) ++ padapter->HalFunc.GetHwRegHandler(padapter, variable, val); ++} ++ ++void rtw_hal_set_hwreg_with_buf(struct adapter *padapter, u8 variable, u8 *pbuf, int len) ++{ ++ if (padapter->HalFunc.SetHwRegHandlerWithBuf) ++ padapter->HalFunc.SetHwRegHandlerWithBuf(padapter, variable, pbuf, len); ++} ++ ++u8 rtw_hal_set_def_var(struct adapter *padapter, enum HAL_DEF_VARIABLE eVariable, void *pValue) ++{ ++ if (padapter->HalFunc.SetHalDefVarHandler) ++ return padapter->HalFunc.SetHalDefVarHandler(padapter, eVariable, pValue); ++ return _FAIL; ++} ++u8 rtw_hal_get_def_var(struct adapter *padapter, enum HAL_DEF_VARIABLE eVariable, void *pValue) ++{ ++ if (padapter->HalFunc.GetHalDefVarHandler) ++ return padapter->HalFunc.GetHalDefVarHandler(padapter, eVariable, pValue); ++ return _FAIL; ++} ++ ++void rtw_hal_set_odm_var(struct adapter *padapter, enum HAL_ODM_VARIABLE eVariable, void *pValue1, bool bSet) ++{ ++ if (padapter->HalFunc.SetHalODMVarHandler) ++ padapter->HalFunc.SetHalODMVarHandler(padapter, eVariable, pValue1, bSet); ++} ++void rtw_hal_get_odm_var(struct adapter *padapter, enum HAL_ODM_VARIABLE eVariable, void *pValue1, void *pValue2) ++{ ++ if (padapter->HalFunc.GetHalODMVarHandler) ++ padapter->HalFunc.GetHalODMVarHandler(padapter, eVariable, pValue1, pValue2); ++} ++ ++void rtw_hal_enable_interrupt(struct adapter *padapter) ++{ ++ if (padapter->HalFunc.enable_interrupt) ++ padapter->HalFunc.enable_interrupt(padapter); ++ else ++ DBG_871X("%s: HalFunc.enable_interrupt is NULL!\n", __func__); ++ ++} ++void rtw_hal_disable_interrupt(struct adapter *padapter) ++{ ++ if (padapter->HalFunc.disable_interrupt) ++ padapter->HalFunc.disable_interrupt(padapter); ++ else ++ DBG_871X("%s: HalFunc.disable_interrupt is NULL!\n", __func__); ++ ++} ++ ++u8 rtw_hal_check_ips_status(struct adapter *padapter) ++{ ++ u8 val = false; ++ if (padapter->HalFunc.check_ips_status) ++ val = padapter->HalFunc.check_ips_status(padapter); ++ else ++ DBG_871X("%s: HalFunc.check_ips_status is NULL!\n", __func__); ++ ++ return val; ++} ++ ++s32 rtw_hal_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ if (padapter->HalFunc.hal_xmitframe_enqueue) ++ return padapter->HalFunc.hal_xmitframe_enqueue(padapter, pxmitframe); ++ ++ return false; ++} ++ ++s32 rtw_hal_xmit(struct adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ if (padapter->HalFunc.hal_xmit) ++ return padapter->HalFunc.hal_xmit(padapter, pxmitframe); ++ ++ return false; ++} ++ ++/* ++ * [IMPORTANT] This function would be run in interrupt context. ++ */ ++s32 rtw_hal_mgnt_xmit(struct adapter *padapter, struct xmit_frame *pmgntframe) ++{ ++ s32 ret = _FAIL; ++ update_mgntframe_attrib_addr(padapter, pmgntframe); ++ /* pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; */ ++ /* pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; */ ++ /* memcpy(pmgntframe->attrib.ra, pwlanhdr->addr1, ETH_ALEN); */ ++ ++ if (padapter->securitypriv.binstallBIPkey == true) ++ { ++ if (IS_MCAST(pmgntframe->attrib.ra)) ++ { ++ pmgntframe->attrib.encrypt = _BIP_; ++ /* pmgntframe->attrib.bswenc = true; */ ++ } ++ else ++ { ++ pmgntframe->attrib.encrypt = _AES_; ++ pmgntframe->attrib.bswenc = true; ++ } ++ rtw_mgmt_xmitframe_coalesce(padapter, pmgntframe->pkt, pmgntframe); ++ } ++ ++ if (padapter->HalFunc.mgnt_xmit) ++ ret = padapter->HalFunc.mgnt_xmit(padapter, pmgntframe); ++ return ret; ++} ++ ++s32 rtw_hal_init_xmit_priv(struct adapter *padapter) ++{ ++ if (padapter->HalFunc.init_xmit_priv != NULL) ++ return padapter->HalFunc.init_xmit_priv(padapter); ++ return _FAIL; ++} ++void rtw_hal_free_xmit_priv(struct adapter *padapter) ++{ ++ if (padapter->HalFunc.free_xmit_priv != NULL) ++ padapter->HalFunc.free_xmit_priv(padapter); ++} ++ ++s32 rtw_hal_init_recv_priv(struct adapter *padapter) ++{ ++ if (padapter->HalFunc.init_recv_priv) ++ return padapter->HalFunc.init_recv_priv(padapter); ++ ++ return _FAIL; ++} ++void rtw_hal_free_recv_priv(struct adapter *padapter) ++{ ++ ++ if (padapter->HalFunc.free_recv_priv) ++ padapter->HalFunc.free_recv_priv(padapter); ++} ++ ++void rtw_hal_update_ra_mask(struct sta_info *psta, u8 rssi_level) ++{ ++ struct adapter *padapter; ++ struct mlme_priv *pmlmepriv; ++ ++ if (!psta) ++ return; ++ ++ padapter = psta->padapter; ++ ++ pmlmepriv = &(padapter->mlmepriv); ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ++ { ++ add_RATid(padapter, psta, rssi_level); ++ } ++ else ++ { ++ if (padapter->HalFunc.UpdateRAMaskHandler) ++ padapter->HalFunc.UpdateRAMaskHandler(padapter, psta->mac_id, rssi_level); ++ } ++} ++ ++void rtw_hal_add_ra_tid(struct adapter *padapter, u32 bitmap, u8 *arg, u8 rssi_level) ++{ ++ if (padapter->HalFunc.Add_RateATid) ++ padapter->HalFunc.Add_RateATid(padapter, bitmap, arg, rssi_level); ++} ++ ++/*Start specifical interface thread */ ++void rtw_hal_start_thread(struct adapter *padapter) ++{ ++ if (padapter->HalFunc.run_thread) ++ padapter->HalFunc.run_thread(padapter); ++} ++/*Start specifical interface thread */ ++void rtw_hal_stop_thread(struct adapter *padapter) ++{ ++ if (padapter->HalFunc.cancel_thread) ++ padapter->HalFunc.cancel_thread(padapter); ++} ++ ++u32 rtw_hal_read_bbreg(struct adapter *padapter, u32 RegAddr, u32 BitMask) ++{ ++ u32 data = 0; ++ if (padapter->HalFunc.read_bbreg) ++ data = padapter->HalFunc.read_bbreg(padapter, RegAddr, BitMask); ++ return data; ++} ++void rtw_hal_write_bbreg(struct adapter *padapter, u32 RegAddr, u32 BitMask, u32 Data) ++{ ++ if (padapter->HalFunc.write_bbreg) ++ padapter->HalFunc.write_bbreg(padapter, RegAddr, BitMask, Data); ++} ++ ++u32 rtw_hal_read_rfreg(struct adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask) ++{ ++ u32 data = 0; ++ if (padapter->HalFunc.read_rfreg) ++ data = padapter->HalFunc.read_rfreg(padapter, eRFPath, RegAddr, BitMask); ++ return data; ++} ++void rtw_hal_write_rfreg(struct adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask, u32 Data) ++{ ++ if (padapter->HalFunc.write_rfreg) ++ padapter->HalFunc.write_rfreg(padapter, eRFPath, RegAddr, BitMask, Data); ++} ++ ++void rtw_hal_set_chan(struct adapter *padapter, u8 channel) ++{ ++ if (padapter->HalFunc.set_channel_handler) ++ padapter->HalFunc.set_channel_handler(padapter, channel); ++} ++ ++void rtw_hal_set_chnl_bw(struct adapter *padapter, u8 channel, ++ enum CHANNEL_WIDTH Bandwidth, u8 Offset40, u8 Offset80) ++{ ++ if (padapter->HalFunc.set_chnl_bw_handler) ++ padapter->HalFunc.set_chnl_bw_handler(padapter, channel, ++ Bandwidth, Offset40, ++ Offset80); ++} ++ ++void rtw_hal_dm_watchdog(struct adapter *padapter) ++{ ++ if (padapter->HalFunc.hal_dm_watchdog) ++ padapter->HalFunc.hal_dm_watchdog(padapter); ++ ++} ++ ++void rtw_hal_dm_watchdog_in_lps(struct adapter *padapter) ++{ ++ if (adapter_to_pwrctl(padapter)->bFwCurrentInPSMode ==true) ++ { ++ if (padapter->HalFunc.hal_dm_watchdog_in_lps) ++ { ++ padapter->HalFunc.hal_dm_watchdog_in_lps(padapter);/* this fuction caller is in interrupt context */ ++ } ++ } ++} ++ ++void rtw_hal_bcn_related_reg_setting(struct adapter *padapter) ++{ ++ if (padapter->HalFunc.SetBeaconRelatedRegistersHandler) ++ padapter->HalFunc.SetBeaconRelatedRegistersHandler(padapter); ++} ++ ++ ++s32 rtw_hal_xmit_thread_handler(struct adapter *padapter) ++{ ++ if (padapter->HalFunc.xmit_thread_handler) ++ return padapter->HalFunc.xmit_thread_handler(padapter); ++ return _FAIL; ++} ++ ++void rtw_hal_notch_filter(struct adapter *adapter, bool enable) ++{ ++ if (adapter->HalFunc.hal_notch_filter) ++ adapter->HalFunc.hal_notch_filter(adapter, enable); ++} ++ ++void rtw_hal_reset_security_engine(struct adapter * adapter) ++{ ++ if (adapter->HalFunc.hal_reset_security_engine) ++ adapter->HalFunc.hal_reset_security_engine(adapter); ++} ++ ++bool rtw_hal_c2h_valid(struct adapter *adapter, u8 *buf) ++{ ++ return c2h_evt_valid((struct c2h_evt_hdr_88xx*)buf); ++} ++ ++s32 rtw_hal_c2h_evt_read(struct adapter *adapter, u8 *buf) ++{ ++ return c2h_evt_read_88xx(adapter, buf); ++} ++ ++s32 rtw_hal_c2h_handler(struct adapter *adapter, u8 *c2h_evt) ++{ ++ s32 ret = _FAIL; ++ if (adapter->HalFunc.c2h_handler) ++ ret = adapter->HalFunc.c2h_handler(adapter, c2h_evt); ++ return ret; ++} ++ ++c2h_id_filter rtw_hal_c2h_id_filter_ccx(struct adapter *adapter) ++{ ++ return adapter->HalFunc.c2h_id_filter_ccx; ++} ++ ++s32 rtw_hal_is_disable_sw_channel_plan(struct adapter *padapter) ++{ ++ return GET_HAL_DATA(padapter)->bDisableSWChannelPlan; ++} ++ ++s32 rtw_hal_macid_sleep(struct adapter *padapter, u32 macid) ++{ ++ u8 support; ++ ++ ++ support = false; ++ rtw_hal_get_def_var(padapter, HAL_DEF_MACID_SLEEP, &support); ++ if (false == support) ++ return _FAIL; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_MACID_SLEEP, (u8 *)&macid); ++ ++ return _SUCCESS; ++} ++ ++s32 rtw_hal_macid_wakeup(struct adapter *padapter, u32 macid) ++{ ++ u8 support; ++ ++ ++ support = false; ++ rtw_hal_get_def_var(padapter, HAL_DEF_MACID_SLEEP, &support); ++ if (false == support) ++ return _FAIL; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_MACID_WAKEUP, (u8 *)&macid); ++ ++ return _SUCCESS; ++} ++ ++s32 rtw_hal_fill_h2c_cmd(struct adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer) ++{ ++ s32 ret = _FAIL; ++ ++ if (padapter->HalFunc.fill_h2c_cmd) ++ ret = padapter->HalFunc.fill_h2c_cmd(padapter, ElementID, CmdLen, pCmdBuffer); ++ else ++ { ++ DBG_871X("%s: func[fill_h2c_cmd] not defined!\n", __func__); ++ } ++ ++ return ret; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/hal_phy.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/hal_phy.c +--- linux-4.3/3rdparty/rtl8723bs/hal/hal_phy.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/hal_phy.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,272 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _HAL_PHY_C_ ++ ++#include ++ ++/** ++* Function: PHY_CalculateBitShift ++* ++* OverView: Get shifted position of the BitMask ++* ++* Input: ++* u32 BitMask, ++* ++* Output: none ++* Return: u32 Return the shift bit bit position of the mask ++*/ ++u32 ++PHY_CalculateBitShift( ++ u32 BitMask ++ ) ++{ ++ u32 i; ++ ++ for(i=0; i<=31; i++) ++ { ++ if (((BitMask>>i) & 0x1 ) == 1) ++ break; ++ } ++ ++ return (i); ++} ++ ++ ++/* */ ++/* ==> RF shadow Operation API Code Section!!! */ ++/* */ ++/*----------------------------------------------------------------------------- ++ * Function: PHY_RFShadowRead ++ * PHY_RFShadowWrite ++ * PHY_RFShadowCompare ++ * PHY_RFShadowRecorver ++ * PHY_RFShadowCompareAll ++ * PHY_RFShadowRecorverAll ++ * PHY_RFShadowCompareFlagSet ++ * PHY_RFShadowRecorverFlagSet ++ * ++ * Overview: When we set RF register, we must write shadow at first. ++ * When we are running, we must compare shadow abd locate error addr. ++ * Decide to recorver or not. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/20/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++u32 ++PHY_RFShadowRead( ++ IN PADAPTER Adapter, ++ IN u8 eRFPath, ++ IN u32 Offset) ++{ ++ return RF_Shadow[eRFPath][Offset].Value; ++ ++} /* PHY_RFShadowRead */ ++ ++ ++void ++PHY_RFShadowWrite( ++ IN PADAPTER Adapter, ++ IN u8 eRFPath, ++ IN u32 Offset, ++ IN u32 Data) ++{ ++ RF_Shadow[eRFPath][Offset].Value = (Data & bRFRegOffsetMask); ++ RF_Shadow[eRFPath][Offset].Driver_Write = true; ++ ++} /* PHY_RFShadowWrite */ ++ ++ ++bool ++PHY_RFShadowCompare( ++ IN PADAPTER Adapter, ++ IN u8 eRFPath, ++ IN u32 Offset) ++{ ++ u32 reg; ++ /* Check if we need to check the register */ ++ if (RF_Shadow[eRFPath][Offset].Compare == true) ++ { ++ reg = rtw_hal_read_rfreg(Adapter, eRFPath, Offset, bRFRegOffsetMask); ++ /* Compare shadow and real rf register for 20bits!! */ ++ if (RF_Shadow[eRFPath][Offset].Value != reg) ++ { ++ /* Locate error position. */ ++ RF_Shadow[eRFPath][Offset].ErrorOrNot = true; ++ /* RT_TRACE(COMP_INIT, DBG_LOUD, */ ++ /* PHY_RFShadowCompare RF-%d Addr%02lx Err = %05lx\n", */ ++ /* eRFPath, Offset, reg)); */ ++ } ++ return RF_Shadow[eRFPath][Offset].ErrorOrNot ; ++ } ++ return false; ++} /* PHY_RFShadowCompare */ ++ ++ ++void ++PHY_RFShadowRecorver( ++ IN PADAPTER Adapter, ++ IN u8 eRFPath, ++ IN u32 Offset) ++{ ++ /* Check if the address is error */ ++ if (RF_Shadow[eRFPath][Offset].ErrorOrNot == true) ++ { ++ /* Check if we need to recorver the register. */ ++ if (RF_Shadow[eRFPath][Offset].Recorver == true) ++ { ++ rtw_hal_write_rfreg(Adapter, eRFPath, Offset, bRFRegOffsetMask, ++ RF_Shadow[eRFPath][Offset].Value); ++ /* RT_TRACE(COMP_INIT, DBG_LOUD, */ ++ /* PHY_RFShadowRecorver RF-%d Addr%02lx=%05lx", */ ++ /* eRFPath, Offset, RF_Shadow[eRFPath][Offset].Value)); */ ++ } ++ } ++ ++} /* PHY_RFShadowRecorver */ ++ ++ ++void ++PHY_RFShadowCompareAll( ++ IN PADAPTER Adapter) ++{ ++ u8 eRFPath = 0 ; ++ u32 Offset = 0, maxReg= GET_RF6052_REAL_MAX_REG(Adapter); ++ ++ for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) ++ { ++ for (Offset = 0; Offset < maxReg; Offset++) ++ { ++ PHY_RFShadowCompare(Adapter, eRFPath, Offset); ++ } ++ } ++ ++} /* PHY_RFShadowCompareAll */ ++ ++ ++void ++PHY_RFShadowRecorverAll( ++ IN PADAPTER Adapter) ++{ ++ u8 eRFPath =0; ++ u32 Offset = 0, maxReg= GET_RF6052_REAL_MAX_REG(Adapter); ++ ++ for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) ++ { ++ for (Offset = 0; Offset < maxReg; Offset++) ++ { ++ PHY_RFShadowRecorver(Adapter, eRFPath, Offset); ++ } ++ } ++ ++} /* PHY_RFShadowRecorverAll */ ++ ++ ++void ++PHY_RFShadowCompareFlagSet( ++ IN PADAPTER Adapter, ++ IN u8 eRFPath, ++ IN u32 Offset, ++ IN u8 Type) ++{ ++ /* Set True or False!!! */ ++ RF_Shadow[eRFPath][Offset].Compare = Type; ++ ++} /* PHY_RFShadowCompareFlagSet */ ++ ++ ++void ++PHY_RFShadowRecorverFlagSet( ++ IN PADAPTER Adapter, ++ IN u8 eRFPath, ++ IN u32 Offset, ++ IN u8 Type) ++{ ++ /* Set True or False!!! */ ++ RF_Shadow[eRFPath][Offset].Recorver= Type; ++ ++} /* PHY_RFShadowRecorverFlagSet */ ++ ++ ++void ++PHY_RFShadowCompareFlagSetAll( ++ IN PADAPTER Adapter) ++{ ++ u8 eRFPath = 0; ++ u32 Offset = 0, maxReg= GET_RF6052_REAL_MAX_REG(Adapter); ++ ++ for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) ++ { ++ for (Offset = 0; Offset < maxReg; Offset++) ++ { ++ /* 2008/11/20 MH For S3S4 test, we only check reg 26/27 now!!!! */ ++ if (Offset != 0x26 && Offset != 0x27) ++ PHY_RFShadowCompareFlagSet(Adapter, eRFPath, Offset, false); ++ else ++ PHY_RFShadowCompareFlagSet(Adapter, eRFPath, Offset, true); ++ } ++ } ++ ++} /* PHY_RFShadowCompareFlagSetAll */ ++ ++ ++void ++PHY_RFShadowRecorverFlagSetAll( ++ IN PADAPTER Adapter) ++{ ++ u8 eRFPath = 0; ++ u32 Offset = 0, maxReg= GET_RF6052_REAL_MAX_REG(Adapter); ++ ++ for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) ++ { ++ for (Offset = 0; Offset < maxReg; Offset++) ++ { ++ /* 2008/11/20 MH For S3S4 test, we only check reg 26/27 now!!!! */ ++ if (Offset != 0x26 && Offset != 0x27) ++ PHY_RFShadowRecorverFlagSet(Adapter, eRFPath, Offset, false); ++ else ++ PHY_RFShadowRecorverFlagSet(Adapter, eRFPath, Offset, true); ++ } ++ } ++ ++} /* PHY_RFShadowCompareFlagSetAll */ ++ ++void ++PHY_RFShadowRefresh( ++ IN PADAPTER Adapter) ++{ ++ u8 eRFPath = 0; ++ u32 Offset = 0, maxReg= GET_RF6052_REAL_MAX_REG(Adapter); ++ ++ for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) ++ { ++ for (Offset = 0; Offset < maxReg; Offset++) ++ { ++ RF_Shadow[eRFPath][Offset].Value = 0; ++ RF_Shadow[eRFPath][Offset].Compare = false; ++ RF_Shadow[eRFPath][Offset].Recorver = false; ++ RF_Shadow[eRFPath][Offset].ErrorOrNot = false; ++ RF_Shadow[eRFPath][Offset].Driver_Write = false; ++ } ++ } ++ ++} /* PHY_RFShadowRead */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/HalPhyRf_8723B.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalPhyRf_8723B.c +--- linux-4.3/3rdparty/rtl8723bs/hal/HalPhyRf_8723B.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalPhyRf_8723B.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,2171 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#include ++#include ++#include "odm_precomp.h" ++ ++ ++ ++/*---------------------------Define Local Constant---------------------------*/ ++/* 2010/04/25 MH Define the max tx power tracking tx agc power. */ ++#define ODM_TXPWRTRACK_MAX_IDX8723B 6 ++ ++/* MACRO definition for pRFCalibrateInfo->TxIQC_8723B[0] */ ++#define PATH_S0 1 /* RF_PATH_B */ ++#define IDX_0xC94 0 ++#define IDX_0xC80 1 ++#define IDX_0xC4C 2 ++#define IDX_0xC14 0 ++#define IDX_0xCA0 1 ++#define KEY 0 ++#define VAL 1 ++ ++/* MACRO definition for pRFCalibrateInfo->TxIQC_8723B[1] */ ++#define PATH_S1 0 /* RF_PATH_A */ ++#define IDX_0xC9C 0 ++#define IDX_0xC88 1 ++#define IDX_0xC4C 2 ++#define IDX_0xC1C 0 ++#define IDX_0xC78 1 ++ ++ ++/*---------------------------Define Local Constant---------------------------*/ ++ ++/* In the case that we fail to read TxPowerTrack.txt, we use the table for ++ * 88E as the default table. ++ */ ++static u8 DeltaSwingTableIdx_2GA_N_8188E[] = { ++ 0, 0, 0, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, ++ 9, 9, 10, 10, 10, 11, 11, 11, 11}; ++static u8 DeltaSwingTableIdx_2GA_P_8188E[] = { ++ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 7, ++ 7, 8, 8, 8, 9, 9, 9, 9, 9}; ++ ++/* 3 ============================================================ */ ++/* 3 Tx Power Tracking */ ++/* 3 ============================================================ */ ++ ++ ++static void setIqkMatrix_8723B( ++ PDM_ODM_T pDM_Odm, ++ u8 OFDM_index, ++ u8 RFPath, ++ s32 IqkResult_X, ++ s32 IqkResult_Y ++ ) ++{ ++ s32 ele_A = 0, ele_D, ele_C = 0, value32; ++ ++ if (OFDM_index >= OFDM_TABLE_SIZE) ++ OFDM_index = OFDM_TABLE_SIZE-1; ++ ++ ele_D = (OFDMSwingTable_New[OFDM_index] & 0xFFC00000)>>22; ++ ++ /* new element A = element D x X */ ++ if ((IqkResult_X != 0) && (*(pDM_Odm->pBandType) == ODM_BAND_2_4G)) ++ { ++ if ((IqkResult_X & 0x00000200) != 0) /* consider minus */ ++ IqkResult_X = IqkResult_X | 0xFFFFFC00; ++ ele_A = ((IqkResult_X * ele_D)>>8)&0x000003FF; ++ ++ /* new element C = element D x Y */ ++ if ((IqkResult_Y & 0x00000200) != 0) ++ IqkResult_Y = IqkResult_Y | 0xFFFFFC00; ++ ele_C = ((IqkResult_Y * ele_D)>>8)&0x000003FF; ++ ++ /* if (RFPath == ODM_RF_PATH_A) */ ++ switch (RFPath) ++ { ++ case ODM_RF_PATH_A: ++ /* wirte new elements A, C, D to regC80 and regC94, element B is always 0 */ ++ value32 = (ele_D<<22)|((ele_C&0x3F)<<16)|ele_A; ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XATxIQImbalance, bMaskDWord, value32); ++ ++ value32 = (ele_C&0x000003C0)>>6; ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XCTxAFE, bMaskH4Bits, value32); ++ ++ value32 = ((IqkResult_X * ele_D)>>7)&0x01; ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, BIT24, value32); ++ break; ++ case ODM_RF_PATH_B: ++ /* wirte new elements A, C, D to regC88 and regC9C, element B is always 0 */ ++ value32 =(ele_D<<22)|((ele_C&0x3F)<<16) |ele_A; ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XBTxIQImbalance, bMaskDWord, value32); ++ ++ value32 = (ele_C&0x000003C0)>>6; ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XDTxAFE, bMaskH4Bits, value32); ++ ++ value32 = ((IqkResult_X * ele_D)>>7)&0x01; ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, BIT28, value32); ++ ++ break; ++ default: ++ break; ++ } ++ } ++ else ++ { ++ switch (RFPath) ++ { ++ case ODM_RF_PATH_A: ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XATxIQImbalance, bMaskDWord, OFDMSwingTable_New[OFDM_index]); ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XCTxAFE, bMaskH4Bits, 0x00); ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, BIT24, 0x00); ++ break; ++ ++ case ODM_RF_PATH_B: ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XBTxIQImbalance, bMaskDWord, OFDMSwingTable_New[OFDM_index]); ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XDTxAFE, bMaskH4Bits, 0x00); ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, BIT28, 0x00); ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("TxPwrTracking path B: X = 0x%x, Y = 0x%x ele_A = 0x%x ele_C = 0x%x ele_D = 0x%x 0xeb4 = 0x%x 0xebc = 0x%x\n", ++ (u32)IqkResult_X, (u32)IqkResult_Y, (u32)ele_A, (u32)ele_C, (u32)ele_D, (u32)IqkResult_X, (u32)IqkResult_Y)); ++} ++ ++ ++static void ++setCCKFilterCoefficient( ++ PDM_ODM_T pDM_Odm, ++ u8 CCKSwingIndex ++) ++{ ++ if (!pDM_Odm->RFCalibrateInfo.bCCKinCH14) ++ { ++ rtw_write8(pDM_Odm->Adapter, 0xa22, CCKSwingTable_Ch1_Ch13_New[CCKSwingIndex][0]); ++ rtw_write8(pDM_Odm->Adapter, 0xa23, CCKSwingTable_Ch1_Ch13_New[CCKSwingIndex][1]); ++ rtw_write8(pDM_Odm->Adapter, 0xa24, CCKSwingTable_Ch1_Ch13_New[CCKSwingIndex][2]); ++ rtw_write8(pDM_Odm->Adapter, 0xa25, CCKSwingTable_Ch1_Ch13_New[CCKSwingIndex][3]); ++ rtw_write8(pDM_Odm->Adapter, 0xa26, CCKSwingTable_Ch1_Ch13_New[CCKSwingIndex][4]); ++ rtw_write8(pDM_Odm->Adapter, 0xa27, CCKSwingTable_Ch1_Ch13_New[CCKSwingIndex][5]); ++ rtw_write8(pDM_Odm->Adapter, 0xa28, CCKSwingTable_Ch1_Ch13_New[CCKSwingIndex][6]); ++ rtw_write8(pDM_Odm->Adapter, 0xa29, CCKSwingTable_Ch1_Ch13_New[CCKSwingIndex][7]); ++ } ++ else ++ { ++ rtw_write8(pDM_Odm->Adapter, 0xa22, CCKSwingTable_Ch14_New[CCKSwingIndex][0]); ++ rtw_write8(pDM_Odm->Adapter, 0xa23, CCKSwingTable_Ch14_New[CCKSwingIndex][1]); ++ rtw_write8(pDM_Odm->Adapter, 0xa24, CCKSwingTable_Ch14_New[CCKSwingIndex][2]); ++ rtw_write8(pDM_Odm->Adapter, 0xa25, CCKSwingTable_Ch14_New[CCKSwingIndex][3]); ++ rtw_write8(pDM_Odm->Adapter, 0xa26, CCKSwingTable_Ch14_New[CCKSwingIndex][4]); ++ rtw_write8(pDM_Odm->Adapter, 0xa27, CCKSwingTable_Ch14_New[CCKSwingIndex][5]); ++ rtw_write8(pDM_Odm->Adapter, 0xa28, CCKSwingTable_Ch14_New[CCKSwingIndex][6]); ++ rtw_write8(pDM_Odm->Adapter, 0xa29, CCKSwingTable_Ch14_New[CCKSwingIndex][7]); ++ } ++} ++ ++void DoIQK_8723B( ++ PDM_ODM_T pDM_Odm, ++ u8 DeltaThermalIndex, ++ u8 ThermalValue, ++ u8 Threshold ++ ) ++{ ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: odm_TxPwrTrackSetPwr88E() ++ * ++ * Overview: 88E change all channel tx power accordign to flag. ++ * OFDM & CCK are all different. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ *When Who Remark ++ *04/23/2012 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++void ++ODM_TxPwrTrackSetPwr_8723B( ++ PDM_ODM_T pDM_Odm, ++ PWRTRACK_METHOD Method, ++ u8 RFPath, ++ u8 ChannelMappedIndex ++ ) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ u8 PwrTrackingLimit_OFDM = 34; /* 0dB */ ++ u8 PwrTrackingLimit_CCK = 28; /* 2dB */ ++ u8 TxRate = 0xFF; ++ u8 Final_OFDM_Swing_Index = 0; ++ u8 Final_CCK_Swing_Index = 0; ++ ++ { ++ u16 rate = *(pDM_Odm->pForcedDataRate); ++ ++ if (!rate) /* auto rate */ ++ { ++ if (pDM_Odm->TxRate != 0xFF) ++ TxRate = HwRateToMRate(pDM_Odm->TxRate); ++ } ++ else /* force rate */ ++ { ++ TxRate = (u8)rate; ++ } ++ } ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("===>ODM_TxPwrTrackSetPwr8723B\n")); ++ ++ if (TxRate != 0xFF) ++ { ++ /* 2 CCK */ ++ if ((TxRate >= MGN_1M) && (TxRate <= MGN_11M)) ++ PwrTrackingLimit_CCK = 28; /* 2dB */ ++ /* 2 OFDM */ ++ else if ((TxRate >= MGN_6M) && (TxRate <= MGN_48M)) ++ PwrTrackingLimit_OFDM = 36; /* 3dB */ ++ else if (TxRate == MGN_54M) ++ PwrTrackingLimit_OFDM = 34; /* 2dB */ ++ ++ /* 2 HT */ ++ else if ((TxRate >= MGN_MCS0) && (TxRate <= MGN_MCS2)) /* QPSK/BPSK */ ++ PwrTrackingLimit_OFDM = 38; /* 4dB */ ++ else if ((TxRate >= MGN_MCS3) && (TxRate <= MGN_MCS4)) /* 16QAM */ ++ PwrTrackingLimit_OFDM = 36; /* 3dB */ ++ else if ((TxRate >= MGN_MCS5) && (TxRate <= MGN_MCS7)) /* 64QAM */ ++ PwrTrackingLimit_OFDM = 34; /* 2dB */ ++ ++ else ++ PwrTrackingLimit_OFDM = pDM_Odm->DefaultOfdmIndex; /* Default OFDM index = 30 */ ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("TxRate = 0x%x, PwrTrackingLimit =%d\n", TxRate, PwrTrackingLimit_OFDM)); ++ ++ if (Method == TXAGC) { ++ struct adapter * Adapter = pDM_Odm->Adapter; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("odm_TxPwrTrackSetPwr8723B CH =%d\n", *(pDM_Odm->pChannel))); ++ ++ pDM_Odm->Remnant_OFDMSwingIdx[RFPath] = pDM_Odm->Absolute_OFDMSwingIdx[RFPath]; ++ ++ pDM_Odm->Modify_TxAGC_Flag_PathA = true; ++ pDM_Odm->Modify_TxAGC_Flag_PathA_CCK = true; ++ ++ PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, CCK); ++ PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, OFDM); ++ PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, HT_MCS0_MCS7); ++ } else if (Method == BBSWING) { ++ Final_OFDM_Swing_Index = pDM_Odm->DefaultOfdmIndex + pDM_Odm->Absolute_OFDMSwingIdx[RFPath]; ++ Final_CCK_Swing_Index = pDM_Odm->DefaultCckIndex + pDM_Odm->Absolute_OFDMSwingIdx[RFPath]; ++ ++ /* Adjust BB swing by OFDM IQ matrix */ ++ if (Final_OFDM_Swing_Index >= PwrTrackingLimit_OFDM) ++ Final_OFDM_Swing_Index = PwrTrackingLimit_OFDM; ++ else if (Final_OFDM_Swing_Index <= 0) ++ Final_OFDM_Swing_Index = 0; ++ ++ if (Final_CCK_Swing_Index >= CCK_TABLE_SIZE) ++ Final_CCK_Swing_Index = CCK_TABLE_SIZE-1; ++ else if (pDM_Odm->BbSwingIdxCck <= 0) ++ Final_CCK_Swing_Index = 0; ++ ++ setIqkMatrix_8723B(pDM_Odm, Final_OFDM_Swing_Index, RFPath, ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][0], ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][1]); ++ ++ setCCKFilterCoefficient(pDM_Odm, Final_CCK_Swing_Index); ++ ++ } ++ else if (Method == MIX_MODE) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("pDM_Odm->DefaultOfdmIndex =%d, pDM_Odm->DefaultCCKIndex =%d, pDM_Odm->Absolute_OFDMSwingIdx[RFPath]=%d, RF_Path = %d\n", ++ pDM_Odm->DefaultOfdmIndex, pDM_Odm->DefaultCckIndex, pDM_Odm->Absolute_OFDMSwingIdx[RFPath], RFPath)); ++ ++ Final_OFDM_Swing_Index = pDM_Odm->DefaultOfdmIndex + pDM_Odm->Absolute_OFDMSwingIdx[RFPath]; ++ Final_CCK_Swing_Index = pDM_Odm->DefaultCckIndex + pDM_Odm->Absolute_OFDMSwingIdx[RFPath]; ++ ++ if (Final_OFDM_Swing_Index > PwrTrackingLimit_OFDM) /* BBSwing higher then Limit */ ++ { ++ pDM_Odm->Remnant_OFDMSwingIdx[RFPath] = Final_OFDM_Swing_Index - PwrTrackingLimit_OFDM; ++ ++ setIqkMatrix_8723B(pDM_Odm, PwrTrackingLimit_OFDM, RFPath, ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][0], ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][1]); ++ ++ pDM_Odm->Modify_TxAGC_Flag_PathA = true; ++ PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, OFDM); ++ PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, HT_MCS0_MCS7); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("******Path_A Over BBSwing Limit , PwrTrackingLimit = %d , Remnant TxAGC Value = %d\n", ++ PwrTrackingLimit_OFDM, pDM_Odm->Remnant_OFDMSwingIdx[RFPath])); ++ } ++ else if (Final_OFDM_Swing_Index <= 0) ++ { ++ pDM_Odm->Remnant_OFDMSwingIdx[RFPath] = Final_OFDM_Swing_Index; ++ ++ setIqkMatrix_8723B(pDM_Odm, 0, RFPath, ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][0], ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][1]); ++ ++ pDM_Odm->Modify_TxAGC_Flag_PathA = true; ++ PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, OFDM); ++ PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, HT_MCS0_MCS7); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("******Path_A Lower then BBSwing lower bound 0 , Remnant TxAGC Value = %d\n", ++ pDM_Odm->Remnant_OFDMSwingIdx[RFPath])); ++ } ++ else ++ { ++ setIqkMatrix_8723B(pDM_Odm, Final_OFDM_Swing_Index, RFPath, ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][0], ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][1]); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("******Path_A Compensate with BBSwing , Final_OFDM_Swing_Index = %d\n", Final_OFDM_Swing_Index)); ++ ++ if (pDM_Odm->Modify_TxAGC_Flag_PathA) /* If TxAGC has changed, reset TxAGC again */ ++ { ++ pDM_Odm->Remnant_OFDMSwingIdx[RFPath] = 0; ++ PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, OFDM); ++ PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, HT_MCS0_MCS7); ++ pDM_Odm->Modify_TxAGC_Flag_PathA = false; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("******Path_A pDM_Odm->Modify_TxAGC_Flag = false\n")); ++ } ++ } ++ ++ if (Final_CCK_Swing_Index > PwrTrackingLimit_CCK) ++ { ++ pDM_Odm->Remnant_CCKSwingIdx = Final_CCK_Swing_Index - PwrTrackingLimit_CCK; ++ setCCKFilterCoefficient(pDM_Odm, PwrTrackingLimit_CCK); ++ pDM_Odm->Modify_TxAGC_Flag_PathA_CCK = true; ++ PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, CCK); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("******Path_A CCK Over Limit , PwrTrackingLimit_CCK = %d , pDM_Odm->Remnant_CCKSwingIdx = %d\n", PwrTrackingLimit_CCK, pDM_Odm->Remnant_CCKSwingIdx)); ++ } ++ else if (Final_CCK_Swing_Index <= 0) /* Lowest CCK Index = 0 */ ++ { ++ pDM_Odm->Remnant_CCKSwingIdx = Final_CCK_Swing_Index; ++ setCCKFilterCoefficient(pDM_Odm, 0); ++ pDM_Odm->Modify_TxAGC_Flag_PathA_CCK = true; ++ PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, CCK); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("******Path_A CCK Under Limit , PwrTrackingLimit_CCK = %d , pDM_Odm->Remnant_CCKSwingIdx = %d\n", 0, pDM_Odm->Remnant_CCKSwingIdx)); ++ } ++ else ++ { ++ setCCKFilterCoefficient(pDM_Odm, Final_CCK_Swing_Index); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("******Path_A CCK Compensate with BBSwing , Final_CCK_Swing_Index = %d\n", Final_CCK_Swing_Index)); ++ ++ if (pDM_Odm->Modify_TxAGC_Flag_PathA_CCK) /* If TxAGC has changed, reset TxAGC again */ ++ { ++ pDM_Odm->Remnant_CCKSwingIdx = 0; ++ PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, CCK); ++ pDM_Odm->Modify_TxAGC_Flag_PathA_CCK = false; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("******Path_A pDM_Odm->Modify_TxAGC_Flag_CCK = false\n")); ++ } ++ } ++ } ++ else ++ { ++ return; /* This method is not supported. */ ++ } ++} ++ ++static void ++GetDeltaSwingTable_8723B( ++PDM_ODM_T pDM_Odm, ++ u8 * *TemperatureUP_A, ++ u8 * *TemperatureDOWN_A, ++ u8 * *TemperatureUP_B, ++ u8 * *TemperatureDOWN_B ++ ) ++{ ++ struct adapter * Adapter = pDM_Odm->Adapter; ++ PODM_RF_CAL_T pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo); ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ u16 rate = *(pDM_Odm->pForcedDataRate); ++ u8 channel = pHalData->CurrentChannel; ++ ++ if (1 <= channel && channel <= 14) { ++ if (IS_CCK_RATE(rate)) { ++ *TemperatureUP_A = pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKA_P; ++ *TemperatureDOWN_A = pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKA_N; ++ *TemperatureUP_B = pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKB_P; ++ *TemperatureDOWN_B = pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKB_N; ++ } else { ++ *TemperatureUP_A = pRFCalibrateInfo->DeltaSwingTableIdx_2GA_P; ++ *TemperatureDOWN_A = pRFCalibrateInfo->DeltaSwingTableIdx_2GA_N; ++ *TemperatureUP_B = pRFCalibrateInfo->DeltaSwingTableIdx_2GB_P; ++ *TemperatureDOWN_B = pRFCalibrateInfo->DeltaSwingTableIdx_2GB_N; ++ } ++ }/*else if (36 <= channel && channel <= 64) { ++ *TemperatureUP_A = pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P[0]; ++ *TemperatureDOWN_A = pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N[0]; ++ *TemperatureUP_B = pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P[0]; ++ *TemperatureDOWN_B = pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N[0]; ++ } else if (100 <= channel && channel <= 140) { ++ *TemperatureUP_A = pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P[1]; ++ *TemperatureDOWN_A = pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N[1]; ++ *TemperatureUP_B = pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P[1]; ++ *TemperatureDOWN_B = pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N[1]; ++ } else if (149 <= channel && channel <= 173) { ++ *TemperatureUP_A = pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P[2]; ++ *TemperatureDOWN_A = pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N[2]; ++ *TemperatureUP_B = pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P[2]; ++ *TemperatureDOWN_B = pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N[2]; ++ }*/else { ++ *TemperatureUP_A = (u8 *)DeltaSwingTableIdx_2GA_P_8188E; ++ *TemperatureDOWN_A = (u8 *)DeltaSwingTableIdx_2GA_N_8188E; ++ *TemperatureUP_B = (u8 *)DeltaSwingTableIdx_2GA_P_8188E; ++ *TemperatureDOWN_B = (u8 *)DeltaSwingTableIdx_2GA_N_8188E; ++ } ++ ++ return; ++} ++ ++ ++void ConfigureTxpowerTrack_8723B( ++ PTXPWRTRACK_CFG pConfig ++ ) ++{ ++ pConfig->SwingTableSize_CCK = CCK_TABLE_SIZE; ++ pConfig->SwingTableSize_OFDM = OFDM_TABLE_SIZE; ++ pConfig->Threshold_IQK = IQK_THRESHOLD; ++ pConfig->AverageThermalNum = AVG_THERMAL_NUM_8723B; ++ pConfig->RfPathCount = MAX_PATH_NUM_8723B; ++ pConfig->ThermalRegAddr = RF_T_METER_8723B; ++ ++ pConfig->ODM_TxPwrTrackSetPwr = ODM_TxPwrTrackSetPwr_8723B; ++ pConfig->DoIQK = DoIQK_8723B; ++ pConfig->PHY_LCCalibrate = PHY_LCCalibrate_8723B; ++ pConfig->GetDeltaSwingTable = GetDeltaSwingTable_8723B; ++} ++ ++/* 1 7. IQK */ ++#define MAX_TOLERANCE 5 ++#define IQK_DELAY_TIME 1 /* ms */ ++ ++static u8 /* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ ++phy_PathA_IQK_8723B( ++struct adapter *padapter, ++bool configPathB, ++u8 RF_Path ++ ) ++{ ++ u32 regEAC, regE94, regE9C, tmp, Path_SEL_BB /*, regEA4*/; ++ u8 result = 0x00; ++ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ ++ /* Save RF Path */ ++ Path_SEL_BB = PHY_QueryBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQK!\n")); ++ ++ /* leave IQK mode */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000); ++ ++ /* enable path A PA in TXIQK mode */ ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_WE_LUT, 0x80000, 0x1); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x18000); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0003f); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xc7f87); ++ /* disable path B PA in TXIQK mode */ ++/* PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0xed, bRFRegOffsetMask, 0x00020); */ ++/* PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0x43, bRFRegOffsetMask, 0x40ec1); */ ++ ++ /* 1 Tx IQK */ ++ /* IQK setting */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK, bMaskDWord, 0x01007c00); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK, bMaskDWord, 0x01004800); ++ /* path-A IQK setting */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A IQK setting!\n")); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_Tone_A, bMaskDWord, 0x18008c1c); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_Tone_A, bMaskDWord, 0x38008c1c); ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_Tone_B, bMaskDWord, 0x38008c1c); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_Tone_B, bMaskDWord, 0x38008c1c); ++/* PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_PI_A, bMaskDWord, 0x8214010a); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_PI_A, bMaskDWord, 0x821303ea); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_A, bMaskDWord, 0x28110000); ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_PI_B, bMaskDWord, 0x82110000); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_B, bMaskDWord, 0x28110000); ++ ++ /* LO calibration setting */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Rsp, bMaskDWord, 0x00462911); ++ ++ /* enter IQK mode */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x808000); ++ ++ /* Ant switch */ ++ if (configPathB || (RF_Path == 0)) ++ /* wifi switch to S1 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, 0x00000000); ++ else ++ /* wifi switch to S0 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, 0x00000280); ++ ++ /* GNT_BT = 0 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, 0x00000800); ++ ++ /* One shot, path A LOK & IQK */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n")); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); ++ PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); ++ ++ /* delay x ms */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_8723B)); */ ++ /* PlatformStallExecution(IQK_DELAY_TIME_8723B*1000); */ ++ mdelay(IQK_DELAY_TIME_8723B); ++ ++ /* restore Ant Path */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, Path_SEL_BB); ++ /* GNT_BT = 1 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, 0x00001800); ++ ++ /* leave IQK mode */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000); ++ ++ ++ /* Check failed */ ++ regEAC = PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_After_IQK_A_2, bMaskDWord); ++ regE94 = PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_Before_IQK_A, bMaskDWord); ++ regE9C = PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_After_IQK_A, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x, 0xe9c = 0x%x\n", regE94, regE9C)); ++ /* monitor image power before & after IQK */ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe90(before IQK) = 0x%x, 0xe98(afer IQK) = 0x%x\n", ++ PHY_QueryBBReg(pDM_Odm->Adapter, 0xe90, bMaskDWord), PHY_QueryBBReg(pDM_Odm->Adapter, 0xe98, bMaskDWord))); ++ ++ ++ /* Allen 20131125 */ ++ tmp =(regE9C & 0x03FF0000)>>16; ++ if ((tmp & 0x200)> 0) ++ tmp = 0x400 - tmp; ++ ++ if (!(regEAC & BIT28) && ++ (((regE94 & 0x03FF0000)>>16) != 0x142) && ++ (((regE9C & 0x03FF0000)>>16) != 0x42) && ++ (((regE94 & 0x03FF0000)>>16) <0x110) && ++ (((regE94 & 0x03FF0000)>>16) >0xf0) && ++ (tmp <0xf)) ++ result |= 0x01; ++ else /* if Tx not OK, ignore Rx */ ++ return result; ++ ++ return result; ++} ++ ++static u8 /* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ ++phy_PathA_RxIQK8723B( ++struct adapter *padapter, ++bool configPathB, ++u8 RF_Path ++ ) ++{ ++ u32 regEAC, regE94, regE9C, regEA4, u4tmp, tmp, Path_SEL_BB; ++ u8 result = 0x00; ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK!\n")); */ ++ ++ /* Save RF Path */ ++ Path_SEL_BB = PHY_QueryBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord); ++ ++ /* leave IQK mode */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A RX IQK:Get TXIMR setting\n")); ++ /* 1 Get TXIMR setting */ ++ /* modify RXIQK mode table */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A Rx IQK modify RXIQK mode table!\n")); */ ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_WE_LUT, 0x80000, 0x1); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x18000); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0001f); ++ /* LNA2 off, PA on for Dcut */ ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xf7fb7); ++/* PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_WE_LUT, 0x80000, 0x0); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x808000); ++ ++ /* IQK setting */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK, bMaskDWord, 0x01007c00); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK, bMaskDWord, 0x01004800); ++ ++ /* path-A IQK setting */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_Tone_A, bMaskDWord, 0x18008c1c); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_Tone_A, bMaskDWord, 0x38008c1c); ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_Tone_B, bMaskDWord, 0x38008c1c); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_Tone_B, bMaskDWord, 0x38008c1c); ++ ++/* PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_PI_A, bMaskDWord, 0x82160c1f); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_PI_A, bMaskDWord, 0x82130ff0); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_A, bMaskDWord, 0x28110000); ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_PI_B, bMaskDWord, 0x82110000); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_B, bMaskDWord, 0x28110000); ++ ++ /* LO calibration setting */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Rsp, bMaskDWord, 0x0046a911); ++ ++ /* enter IQK mode */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x808000); ++ ++ /* Ant switch */ ++ if (configPathB || (RF_Path == 0)) ++ /* wifi switch to S1 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, 0x00000000); ++ else ++ /* wifi switch to S0 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, 0x00000280); ++ ++ /* GNT_BT = 0 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, 0x00000800); ++ ++ /* One shot, path A LOK & IQK */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n")); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); ++ PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); ++ ++ /* delay x ms */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_8723B)); */ ++ /* PlatformStallExecution(IQK_DELAY_TIME_8723B*1000); */ ++ mdelay(IQK_DELAY_TIME_8723B); ++ ++ /* restore Ant Path */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, Path_SEL_BB); ++ /* GNT_BT = 1 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, 0x00001800); ++ ++ /* leave IQK mode */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000); ++ ++ /* Check failed */ ++ regEAC = PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_After_IQK_A_2, bMaskDWord); ++ regE94 = PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_Before_IQK_A, bMaskDWord); ++ regE9C = PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_After_IQK_A, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x, 0xe9c = 0x%x\n", regE94, regE9C)); ++ /* monitor image power before & after IQK */ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe90(before IQK) = 0x%x, 0xe98(afer IQK) = 0x%x\n", ++ PHY_QueryBBReg(pDM_Odm->Adapter, 0xe90, bMaskDWord), PHY_QueryBBReg(pDM_Odm->Adapter, 0xe98, bMaskDWord))); ++ ++ /* Allen 20131125 */ ++ tmp =(regE9C & 0x03FF0000)>>16; ++ if ((tmp & 0x200)> 0) ++ tmp = 0x400 - tmp; ++ ++ if (!(regEAC & BIT28) && ++ (((regE94 & 0x03FF0000)>>16) != 0x142) && ++ (((regE9C & 0x03FF0000)>>16) != 0x42) && ++ (((regE94 & 0x03FF0000)>>16) <0x110) && ++ (((regE94 & 0x03FF0000)>>16) >0xf0) && ++ (tmp <0xf)) ++ result |= 0x01; ++ else /* if Tx not OK, ignore Rx */ ++ return result; ++ ++ u4tmp = 0x80007C00 | (regE94&0x3FF0000) | ((regE9C&0x3FF0000) >> 16); ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK, bMaskDWord, u4tmp); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe40 = 0x%x u4tmp = 0x%x\n", PHY_QueryBBReg(pDM_Odm->Adapter, rTx_IQK, bMaskDWord), u4tmp)); ++ ++ ++ /* 1 RX IQK */ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A RX IQK\n")); ++ ++ /* modify RXIQK mode table */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A Rx IQK modify RXIQK mode table 2!\n")); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_WE_LUT, 0x80000, 0x1); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x18000); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0001f); ++ /* LAN2 on, PA off for Dcut */ ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xf7d77); ++/* PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_WE_LUT, 0x80000, 0x0); */ ++ ++ /* PA, PAD setting */ ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0xdf, bRFRegOffsetMask, 0xf80); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0x55, bRFRegOffsetMask, 0x4021f); ++ ++ ++ /* IQK setting */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK, bMaskDWord, 0x01004800); ++ ++ /* path-A IQK setting */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_Tone_A, bMaskDWord, 0x38008c1c); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_Tone_A, bMaskDWord, 0x18008c1c); ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_Tone_B, bMaskDWord, 0x38008c1c); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_Tone_B, bMaskDWord, 0x38008c1c); ++ ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_PI_A, bMaskDWord, 0x82110000); ++/* PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_A, bMaskDWord, 0x281604c2); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_A, bMaskDWord, 0x2813001f); ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_PI_B, bMaskDWord, 0x82110000); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_B, bMaskDWord, 0x28110000); ++ ++ /* LO calibration setting */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Rsp, bMaskDWord, 0x0046a8d1); ++ ++ /* enter IQK mode */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x808000); ++ ++ /* Ant switch */ ++ if (configPathB || (RF_Path == 0)) ++ /* wifi switch to S1 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, 0x00000000); ++ else ++ /* wifi switch to S0 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, 0x00000280); ++ ++ /* GNT_BT = 0 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, 0x00000800); ++ ++ /* One shot, path A LOK & IQK */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n")); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); ++ PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); ++ ++ /* delay x ms */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_88E)); */ ++ /* PlatformStallExecution(IQK_DELAY_TIME_8723B*1000); */ ++ mdelay(IQK_DELAY_TIME_8723B); ++ ++ /* restore Ant Path */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, Path_SEL_BB); ++ /* GNT_BT = 1 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, 0x00001800); ++ ++ /* leave IQK mode */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000); ++ ++ /* Check failed */ ++ regEAC = PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_After_IQK_A_2, bMaskDWord); ++ regEA4 = PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_Before_IQK_A_2, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xea4 = 0x%x, 0xeac = 0x%x\n", regEA4, regEAC)); ++ /* monitor image power before & after IQK */ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xea0(before IQK) = 0x%x, 0xea8(afer IQK) = 0x%x\n", ++ PHY_QueryBBReg(pDM_Odm->Adapter, 0xea0, bMaskDWord), PHY_QueryBBReg(pDM_Odm->Adapter, 0xea8, bMaskDWord))); ++ ++ /* PA/PAD controlled by 0x0 */ ++ /* leave IQK mode */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0xdf, bRFRegOffsetMask, 0x780); ++ ++ /* Allen 20131125 */ ++ tmp =(regEAC & 0x03FF0000)>>16; ++ if ((tmp & 0x200)> 0) ++ tmp = 0x400 - tmp; ++ ++ if (!(regEAC & BIT27) && /* if Tx is OK, check whether Rx is OK */ ++ (((regEA4 & 0x03FF0000)>>16) != 0x132) && ++ (((regEAC & 0x03FF0000)>>16) != 0x36) && ++ (((regEA4 & 0x03FF0000)>>16) < 0x110) && ++ (((regEA4 & 0x03FF0000)>>16) > 0xf0) && ++ (tmp <0xf)) ++ result |= 0x02; ++ else /* if Tx not OK, ignore Rx */ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK fail!!\n")); ++ return result; ++} ++ ++static u8 /* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ ++phy_PathB_IQK_8723B( ++struct adapter *padapter ++ ) ++{ ++ u32 regEAC, regE94, regE9C, tmp, Path_SEL_BB/*, regEC4, regECC, Path_SEL_BB*/; ++ u8 result = 0x00; ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK!\n")); ++ ++ /* Save RF Path */ ++ Path_SEL_BB = PHY_QueryBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord); ++ ++ /* leave IQK mode */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000); ++ ++ /* in TXIQK mode */ ++/* PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_WE_LUT, 0x80000, 0x1); */ ++/* PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x20000); */ ++/* PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0003f); */ ++/* PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xc7f87); */ ++ /* enable path B PA in TXIQK mode */ ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0xed, 0x20, 0x1); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0x43, bRFRegOffsetMask, 0x30fc1); ++ ++ ++ ++ /* 1 Tx IQK */ ++ /* IQK setting */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK, bMaskDWord, 0x01007c00); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK, bMaskDWord, 0x01004800); ++ /* path-A IQK setting */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-B IQK setting!\n")); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_Tone_A, bMaskDWord, 0x18008c1c); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_Tone_A, bMaskDWord, 0x38008c1c); ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_Tone_B, bMaskDWord, 0x38008c1c); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_Tone_B, bMaskDWord, 0x38008c1c); ++ ++/* PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_PI_A, bMaskDWord, 0x82140114); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_PI_A, bMaskDWord, 0x821303ea); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_A, bMaskDWord, 0x28110000); ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_PI_B, bMaskDWord, 0x82110000); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_B, bMaskDWord, 0x28110000); ++ ++ /* LO calibration setting */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Rsp, bMaskDWord, 0x00462911); ++ ++ /* enter IQK mode */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x808000); ++ ++ /* switch to path B */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, 0x00000280); ++/* PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0xb0, bRFRegOffsetMask, 0xeffe0); */ ++ ++ /* GNT_BT = 0 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, 0x00000800); ++ ++ /* One shot, path B LOK & IQK */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path B LOK & IQK!\n")); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); ++ PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); ++ ++ /* delay x ms */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path B LOK & IQK.\n", IQK_DELAY_TIME_88E)); */ ++ /* PlatformStallExecution(IQK_DELAY_TIME_88E*1000); */ ++ mdelay(IQK_DELAY_TIME_8723B); ++ ++ /* restore Ant Path */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, Path_SEL_BB); ++ /* GNT_BT = 1 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, 0x00001800); ++ ++ /* leave IQK mode */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000); ++ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0x948 = 0x%x\n", PHY_QueryBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord))); */ ++ ++ ++ /* Check failed */ ++ regEAC = PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_After_IQK_A_2, bMaskDWord); ++ regE94 = PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_Before_IQK_A, bMaskDWord); ++ regE9C = PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_After_IQK_A, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x, 0xe9c = 0x%x\n", regE94, regE9C)); ++ /* monitor image power before & after IQK */ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe90(before IQK) = 0x%x, 0xe98(afer IQK) = 0x%x\n", ++ PHY_QueryBBReg(pDM_Odm->Adapter, 0xe90, bMaskDWord), PHY_QueryBBReg(pDM_Odm->Adapter, 0xe98, bMaskDWord))); ++ ++ /* Allen 20131125 */ ++ tmp =(regE9C & 0x03FF0000)>>16; ++ if ((tmp & 0x200)> 0) ++ tmp = 0x400 - tmp; ++ ++ if (!(regEAC & BIT28) && ++ (((regE94 & 0x03FF0000)>>16) != 0x142) && ++ (((regE9C & 0x03FF0000)>>16) != 0x42) && ++ (((regE94 & 0x03FF0000)>>16) <0x110) && ++ (((regE94 & 0x03FF0000)>>16) >0xf0) && ++ (tmp <0xf)) ++ result |= 0x01; ++ ++ return result; ++} ++ ++static u8 /* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ ++phy_PathB_RxIQK8723B( ++struct adapter *padapter, ++bool configPathB ++ ) ++{ ++ u32 regE94, regE9C, regEA4, regEAC, u4tmp, tmp, Path_SEL_BB; ++ u8 result = 0x00; ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Rx IQK!\n")); */ ++ ++ /* Save RF Path */ ++ Path_SEL_BB = PHY_QueryBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord); ++ /* leave IQK mode */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000); ++ ++ /* switch to path B */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, 0x00000280); ++ ++ /* 1 Get TXIMR setting */ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B RX IQK:Get TXIMR setting!\n")); ++ /* modify RXIQK mode table */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A Rx IQK modify RXIQK mode table!\n")); */ ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_WE_LUT, 0x80000, 0x1); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x18000); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0001f); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xf7fb7); ++ /* open PA S1 & SMIXER */ ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0xed, 0x20, 0x1); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0x43, bRFRegOffsetMask, 0x30fcd); ++ ++ ++ /* IQK setting */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK, bMaskDWord, 0x01007c00); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK, bMaskDWord, 0x01004800); ++ ++ ++ /* path-B IQK setting */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_Tone_A, bMaskDWord, 0x18008c1c); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_Tone_A, bMaskDWord, 0x38008c1c); ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_Tone_B, bMaskDWord, 0x38008c1c); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_Tone_B, bMaskDWord, 0x38008c1c); ++ ++/* PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_PI_A, bMaskDWord, 0x82160c1f); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_PI_A, bMaskDWord, 0x82130ff0); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_A, bMaskDWord, 0x28110000); ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_PI_B, bMaskDWord, 0x82110000); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_B, bMaskDWord, 0x28110000); ++ ++ /* LO calibration setting */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Rsp, bMaskDWord, 0x0046a911); ++ ++ /* enter IQK mode */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x808000); ++ ++ /* switch to path B */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, 0x00000280); ++/* PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0xb0, bRFRegOffsetMask, 0xeffe0); */ ++ ++ /* GNT_BT = 0 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, 0x00000800); ++ ++ /* One shot, path B TXIQK @ RXIQK */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path B LOK & IQK!\n")); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); ++ PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); ++ ++ ++ /* delay x ms */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_88E)); */ ++ /* PlatformStallExecution(IQK_DELAY_TIME_88E*1000); */ ++ mdelay(IQK_DELAY_TIME_8723B); ++ ++ /* restore Ant Path */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, Path_SEL_BB); ++ /* GNT_BT = 1 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, 0x00001800); ++ ++ /* leave IQK mode */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000); ++ ++ /* Check failed */ ++ regEAC = PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_After_IQK_A_2, bMaskDWord); ++ regE94 = PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_Before_IQK_A, bMaskDWord); ++ regE9C = PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_After_IQK_A, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x, 0xe9c = 0x%x\n", regE94, regE9C)); ++ /* monitor image power before & after IQK */ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe90(before IQK) = 0x%x, 0xe98(afer IQK) = 0x%x\n", ++ PHY_QueryBBReg(pDM_Odm->Adapter, 0xe90, bMaskDWord), PHY_QueryBBReg(pDM_Odm->Adapter, 0xe98, bMaskDWord))); ++ ++ /* Allen 20131125 */ ++ tmp =(regE9C & 0x03FF0000)>>16; ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("tmp1 = 0x%x\n", tmp)); */ ++ if ((tmp & 0x200)> 0) ++ tmp = 0x400 - tmp; ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("tmp2 = 0x%x\n", tmp)); */ ++ ++ if (!(regEAC & BIT28) && ++ (((regE94 & 0x03FF0000)>>16) != 0x142) && ++ (((regE9C & 0x03FF0000)>>16) != 0x42) && ++ (((regE94 & 0x03FF0000)>>16) <0x110) && ++ (((regE94 & 0x03FF0000)>>16) >0xf0) && ++ (tmp <0xf)) ++ result |= 0x01; ++ else /* if Tx not OK, ignore Rx */ ++ return result; ++ ++ u4tmp = 0x80007C00 | (regE94&0x3FF0000) | ((regE9C&0x3FF0000) >> 16); ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK, bMaskDWord, u4tmp); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe40 = 0x%x u4tmp = 0x%x\n", PHY_QueryBBReg(pDM_Odm->Adapter, rTx_IQK, bMaskDWord), u4tmp)); ++ ++ /* 1 RX IQK */ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B RX IQK\n")); ++ ++ /* modify RXIQK mode table */ ++ /* 20121009, Kordan> RF Mode = 3 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_WE_LUT, 0x80000, 0x1); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x18000); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0001f); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xf7d77); ++/* PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_WE_LUT, 0x80000, 0x0); */ ++ ++ /* open PA S1 & close SMIXER */ ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0xed, 0x20, 0x1); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0x43, bRFRegOffsetMask, 0x30ebd); ++ ++ /* PA, PAD setting */ ++/* PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0xdf, bRFRegOffsetMask, 0xf80); */ ++/* PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0x56, bRFRegOffsetMask, 0x51000); */ ++ ++ /* IQK setting */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK, bMaskDWord, 0x01004800); ++ ++ /* path-B IQK setting */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_Tone_A, bMaskDWord, 0x38008c1c); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_Tone_A, bMaskDWord, 0x18008c1c); ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_Tone_B, bMaskDWord, 0x38008c1c); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_Tone_B, bMaskDWord, 0x38008c1c); ++ ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_PI_A, bMaskDWord, 0x82110000); ++/* PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_A, bMaskDWord, 0x281604c2); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_A, bMaskDWord, 0x2813001f); ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_PI_B, bMaskDWord, 0x82110000); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_B, bMaskDWord, 0x28110000); ++ ++ /* LO calibration setting */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Rsp, bMaskDWord, 0x0046a8d1); ++ ++ /* enter IQK mode */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x808000); ++ ++ /* switch to path B */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, 0x00000280); ++/* PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0xb0, bRFRegOffsetMask, 0xeffe0); */ ++ ++ /* GNT_BT = 0 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, 0x00000800); ++ ++ /* One shot, path B LOK & IQK */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path B LOK & IQK!\n")); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); ++ PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); ++ ++ /* delay x ms */ ++/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_88E)); */ ++ /* PlatformStallExecution(IQK_DELAY_TIME_88E*1000); */ ++ mdelay(IQK_DELAY_TIME_8723B); ++ ++ /* restore Ant Path */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, Path_SEL_BB); ++ /* GNT_BT = 1 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, 0x00001800); ++ ++ /* leave IQK mode */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000); ++ ++ /* Check failed */ ++ regEAC = PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_After_IQK_A_2, bMaskDWord); ++ regEA4 = PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_Before_IQK_A_2, bMaskDWord);; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xea4 = 0x%x, 0xeac = 0x%x\n", regEA4, regEAC)); ++ /* monitor image power before & after IQK */ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xea0(before IQK) = 0x%x, 0xea8(afer IQK) = 0x%x\n", ++ PHY_QueryBBReg(pDM_Odm->Adapter, 0xea0, bMaskDWord), PHY_QueryBBReg(pDM_Odm->Adapter, 0xea8, bMaskDWord))); ++ ++ /* PA/PAD controlled by 0x0 */ ++ /* leave IQK mode */ ++/* PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, 0xffffff00, 0x00000000); */ ++/* PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_B, 0xdf, bRFRegOffsetMask, 0x180); */ ++ ++ ++ ++ /* Allen 20131125 */ ++ tmp =(regEAC & 0x03FF0000)>>16; ++ if ((tmp & 0x200)> 0) ++ tmp = 0x400 - tmp; ++ ++ if (!(regEAC & BIT27) && /* if Tx is OK, check whether Rx is OK */ ++ (((regEA4 & 0x03FF0000)>>16) != 0x132) && ++ (((regEAC & 0x03FF0000)>>16) != 0x36) && ++ (((regEA4 & 0x03FF0000)>>16) <0x110) && ++ (((regEA4 & 0x03FF0000)>>16) >0xf0) && ++ (tmp <0xf)) ++ result |= 0x02; ++ else ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Rx IQK fail!!\n")); ++ ++ return result; ++} ++ ++static void ++_PHY_PathAFillIQKMatrix8723B( ++struct adapter *padapter, ++bool bIQKOK, ++s32 result[][8], ++u8 final_candidate, ++bool bTxOnly ++ ) ++{ ++ u32 Oldval_0, X, TX0_A, reg; ++ s32 Y, TX0_C; ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ ++ PODM_RF_CAL_T pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQ Calibration %s !\n", (bIQKOK)?"Success":"Failed")); ++ ++ if (final_candidate == 0xFF) ++ return; ++ ++ else if (bIQKOK) ++ { ++ Oldval_0 = (PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_XATxIQImbalance, bMaskDWord) >> 22) & 0x3FF; ++ ++ X = result[final_candidate][0]; ++ if ((X & 0x00000200) != 0) ++ X = X | 0xFFFFFC00; ++ TX0_A = (X * Oldval_0) >> 8; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("X = 0x%x, TX0_A = 0x%x, Oldval_0 0x%x\n", X, TX0_A, Oldval_0)); ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XATxIQImbalance, 0x3FF, TX0_A); ++ ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, BIT(31), ((X* Oldval_0>>7) & 0x1)); ++ ++ Y = result[final_candidate][1]; ++ if ((Y & 0x00000200) != 0) ++ Y = Y | 0xFFFFFC00; ++ ++ /* 2 Tx IQC */ ++ TX0_C = (Y * Oldval_0) >> 8; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Y = 0x%x, TX = 0x%x\n", Y, TX0_C)); ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XCTxAFE, 0xF0000000, ((TX0_C&0x3C0)>>6)); ++ pRFCalibrateInfo->TxIQC_8723B[PATH_S1][IDX_0xC94][KEY] = rOFDM0_XCTxAFE; ++ pRFCalibrateInfo->TxIQC_8723B[PATH_S1][IDX_0xC94][VAL] = PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_XCTxAFE, bMaskDWord); ++ ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XATxIQImbalance, 0x003F0000, (TX0_C&0x3F)); ++ pRFCalibrateInfo->TxIQC_8723B[PATH_S1][IDX_0xC80][KEY] = rOFDM0_XATxIQImbalance; ++ pRFCalibrateInfo->TxIQC_8723B[PATH_S1][IDX_0xC80][VAL] = PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_XATxIQImbalance, bMaskDWord); ++ ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, BIT(29), ((Y* Oldval_0>>7) & 0x1)); ++ pRFCalibrateInfo->TxIQC_8723B[PATH_S1][IDX_0xC4C][KEY] = rOFDM0_ECCAThreshold; ++ pRFCalibrateInfo->TxIQC_8723B[PATH_S1][IDX_0xC4C][VAL] = PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, bMaskDWord); ++ ++ if (bTxOnly) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("_PHY_PathAFillIQKMatrix8723B only Tx OK\n")); ++ ++ /* <20130226, Kordan> Saving RxIQC, otherwise not initialized. */ ++ pRFCalibrateInfo->RxIQC_8723B[PATH_S1][IDX_0xCA0][KEY] = rOFDM0_RxIQExtAnta; ++ pRFCalibrateInfo->RxIQC_8723B[PATH_S1][IDX_0xCA0][VAL] = 0xfffffff & PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_RxIQExtAnta, bMaskDWord); ++ pRFCalibrateInfo->RxIQC_8723B[PATH_S1][IDX_0xC14][KEY] = rOFDM0_XARxIQImbalance; ++/* pRFCalibrateInfo->RxIQC_8723B[PATH_S1][IDX_0xC14][VAL] = PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_XARxIQImbalance, bMaskDWord); */ ++ pRFCalibrateInfo->RxIQC_8723B[PATH_S1][IDX_0xC14][VAL] = 0x40000100; ++ return; ++ } ++ ++ reg = result[final_candidate][2]; ++ ++ /* 2 Rx IQC */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XARxIQImbalance, 0x3FF, reg); ++ reg = result[final_candidate][3] & 0x3F; ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XARxIQImbalance, 0xFC00, reg); ++ pRFCalibrateInfo->RxIQC_8723B[PATH_S1][IDX_0xC14][KEY] = rOFDM0_XARxIQImbalance; ++ pRFCalibrateInfo->RxIQC_8723B[PATH_S1][IDX_0xC14][VAL] = PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_XARxIQImbalance, bMaskDWord); ++ ++ reg = (result[final_candidate][3] >> 6) & 0xF; ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_RxIQExtAnta, 0xF0000000, reg); ++ pRFCalibrateInfo->RxIQC_8723B[PATH_S1][IDX_0xCA0][KEY] = rOFDM0_RxIQExtAnta; ++ pRFCalibrateInfo->RxIQC_8723B[PATH_S1][IDX_0xCA0][VAL] = PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_RxIQExtAnta, bMaskDWord); ++ ++ } ++} ++ ++static void ++_PHY_PathBFillIQKMatrix8723B( ++struct adapter *padapter, ++bool bIQKOK, ++s32 result[][8], ++u8 final_candidate, ++bool bTxOnly /* do Tx only */ ++ ) ++{ ++ u32 Oldval_1, X, TX1_A, reg; ++ s32 Y, TX1_C; ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ ++ PODM_RF_CAL_T pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQ Calibration %s !\n", (bIQKOK)?"Success":"Failed")); ++ ++ if (final_candidate == 0xFF) ++ return; ++ ++ else if (bIQKOK) ++ { ++ Oldval_1 = (PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_XBTxIQImbalance, bMaskDWord) >> 22) & 0x3FF; ++ ++ X = result[final_candidate][4]; ++ if ((X & 0x00000200) != 0) ++ X = X | 0xFFFFFC00; ++ TX1_A = (X * Oldval_1) >> 8; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("X = 0x%x, TX1_A = 0x%x\n", X, TX1_A)); ++ ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XBTxIQImbalance, 0x3FF, TX1_A); ++ ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, BIT(27), ((X* Oldval_1>>7) & 0x1)); ++ ++ Y = result[final_candidate][5]; ++ if ((Y & 0x00000200) != 0) ++ Y = Y | 0xFFFFFC00; ++ ++ TX1_C = (Y * Oldval_1) >> 8; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Y = 0x%x, TX1_C = 0x%x\n", Y, TX1_C)); ++ ++ /* 2 Tx IQC */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XDTxAFE, 0xF0000000, ((TX1_C&0x3C0)>>6)); ++/* pRFCalibrateInfo->TxIQC_8723B[PATH_S0][IDX_0xC9C][KEY] = rOFDM0_XDTxAFE; */ ++/* pRFCalibrateInfo->TxIQC_8723B[PATH_S0][IDX_0xC9C][VAL] = PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_XDTxAFE, bMaskDWord); */ ++ pRFCalibrateInfo->TxIQC_8723B[PATH_S0][IDX_0xC94][KEY] = rOFDM0_XCTxAFE; ++ pRFCalibrateInfo->TxIQC_8723B[PATH_S0][IDX_0xC94][VAL] = PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_XDTxAFE, bMaskDWord); ++ ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XBTxIQImbalance, 0x003F0000, (TX1_C&0x3F)); ++ pRFCalibrateInfo->TxIQC_8723B[PATH_S0][IDX_0xC80][KEY] = rOFDM0_XATxIQImbalance; ++ pRFCalibrateInfo->TxIQC_8723B[PATH_S0][IDX_0xC80][VAL] = PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_XBTxIQImbalance, bMaskDWord); ++ ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, BIT(25), ((Y* Oldval_1>>7) & 0x1)); ++ pRFCalibrateInfo->TxIQC_8723B[PATH_S0][IDX_0xC4C][KEY] = rOFDM0_ECCAThreshold; ++ pRFCalibrateInfo->TxIQC_8723B[PATH_S0][IDX_0xC4C][VAL] = PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, bMaskDWord); ++ ++ if (bTxOnly) { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("_PHY_PathBFillIQKMatrix8723B only Tx OK\n")); ++ ++ pRFCalibrateInfo->RxIQC_8723B[PATH_S0][IDX_0xC14][KEY] = rOFDM0_XARxIQImbalance; ++/* pRFCalibrateInfo->RxIQC_8723B[PATH_S0][IDX_0xC14][VAL] = PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_XARxIQImbalance, bMaskDWord); */ ++ pRFCalibrateInfo->RxIQC_8723B[PATH_S0][IDX_0xC14][VAL] = 0x40000100; ++ pRFCalibrateInfo->RxIQC_8723B[PATH_S0][IDX_0xCA0][KEY] = rOFDM0_RxIQExtAnta; ++ pRFCalibrateInfo->RxIQC_8723B[PATH_S0][IDX_0xCA0][VAL] = 0x0fffffff & PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_RxIQExtAnta, bMaskDWord); ++ return; ++ } ++ ++ /* 2 Rx IQC */ ++ reg = result[final_candidate][6]; ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XBRxIQImbalance, 0x3FF, reg); ++ reg = result[final_candidate][7] & 0x3F; ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XBRxIQImbalance, 0xFC00, reg); ++ pRFCalibrateInfo->RxIQC_8723B[PATH_S0][IDX_0xC14][KEY] = rOFDM0_XARxIQImbalance; ++ pRFCalibrateInfo->RxIQC_8723B[PATH_S0][IDX_0xC14][VAL] = PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_XBRxIQImbalance, bMaskDWord); ++ ++ reg = (result[final_candidate][7] >> 6) & 0xF; ++/* PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_AGCRSSITable, 0x0000F000, reg); */ ++ pRFCalibrateInfo->RxIQC_8723B[PATH_S0][IDX_0xCA0][KEY] = rOFDM0_RxIQExtAnta; ++ pRFCalibrateInfo->RxIQC_8723B[PATH_S0][IDX_0xCA0][VAL] = (reg << 28)|(PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_RxIQExtAnta, bMaskDWord)& 0x0fffffff); ++ } ++} ++ ++/* */ ++/* 2011/07/26 MH Add an API for testing IQK fail case. */ ++/* */ ++/* MP Already declare in odm.c */ ++ ++void ++ODM_SetIQCbyRFpath(PDM_ODM_T pDM_Odm, u32 RFpath) ++{ ++ ++ PODM_RF_CAL_T pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo); ++ ++ if ((pRFCalibrateInfo->TxIQC_8723B[PATH_S0][IDX_0xC80][VAL] != 0x0) && ++ (pRFCalibrateInfo->RxIQC_8723B[PATH_S0][IDX_0xC14][VAL] != 0x0) && ++ (pRFCalibrateInfo->TxIQC_8723B[PATH_S1][IDX_0xC80][VAL] != 0x0) && ++ (pRFCalibrateInfo->RxIQC_8723B[PATH_S1][IDX_0xC14][VAL] != 0x0)) { ++ if (RFpath) /* S1: RFpath = 0, S0:RFpath = 1 */ ++ { ++ /* S0 TX IQC */ ++ PHY_SetBBReg(pDM_Odm->Adapter, pRFCalibrateInfo->TxIQC_8723B[PATH_S0][IDX_0xC94][KEY], bMaskDWord, pRFCalibrateInfo->TxIQC_8723B[PATH_S0][IDX_0xC94][VAL]); ++ PHY_SetBBReg(pDM_Odm->Adapter, pRFCalibrateInfo->TxIQC_8723B[PATH_S0][IDX_0xC80][KEY], bMaskDWord, pRFCalibrateInfo->TxIQC_8723B[PATH_S0][IDX_0xC80][VAL]); ++ PHY_SetBBReg(pDM_Odm->Adapter, pRFCalibrateInfo->TxIQC_8723B[PATH_S0][IDX_0xC4C][KEY], bMaskDWord, pRFCalibrateInfo->TxIQC_8723B[PATH_S0][IDX_0xC4C][VAL]); ++ /* S0 RX IQC */ ++ PHY_SetBBReg(pDM_Odm->Adapter, pRFCalibrateInfo->RxIQC_8723B[PATH_S0][IDX_0xC14][KEY], bMaskDWord, pRFCalibrateInfo->RxIQC_8723B[PATH_S0][IDX_0xC14][VAL]); ++ PHY_SetBBReg(pDM_Odm->Adapter, pRFCalibrateInfo->RxIQC_8723B[PATH_S0][IDX_0xCA0][KEY], bMaskDWord, pRFCalibrateInfo->RxIQC_8723B[PATH_S0][IDX_0xCA0][VAL]); ++ } else { ++ /* S1 TX IQC */ ++ PHY_SetBBReg(pDM_Odm->Adapter, pRFCalibrateInfo->TxIQC_8723B[PATH_S1][IDX_0xC94][KEY], bMaskDWord, pRFCalibrateInfo->TxIQC_8723B[PATH_S1][IDX_0xC94][VAL]); ++ PHY_SetBBReg(pDM_Odm->Adapter, pRFCalibrateInfo->TxIQC_8723B[PATH_S1][IDX_0xC80][KEY], bMaskDWord, pRFCalibrateInfo->TxIQC_8723B[PATH_S1][IDX_0xC80][VAL]); ++ PHY_SetBBReg(pDM_Odm->Adapter, pRFCalibrateInfo->TxIQC_8723B[PATH_S1][IDX_0xC4C][KEY], bMaskDWord, pRFCalibrateInfo->TxIQC_8723B[PATH_S1][IDX_0xC4C][VAL]); ++ /* S1 RX IQC */ ++ PHY_SetBBReg(pDM_Odm->Adapter, pRFCalibrateInfo->RxIQC_8723B[PATH_S1][IDX_0xC14][KEY], bMaskDWord, pRFCalibrateInfo->RxIQC_8723B[PATH_S1][IDX_0xC14][VAL]); ++ PHY_SetBBReg(pDM_Odm->Adapter, pRFCalibrateInfo->RxIQC_8723B[PATH_S1][IDX_0xCA0][KEY], bMaskDWord, pRFCalibrateInfo->RxIQC_8723B[PATH_S1][IDX_0xCA0][VAL]); ++ } ++ } ++} ++ ++static bool ++ODM_CheckPowerStatus( ++ struct adapter * Adapter) ++{ ++ return true; ++} ++ ++static void ++_PHY_SaveADDARegisters8723B( ++struct adapter *padapter, ++u32 * ADDAReg, ++u32 * ADDABackup, ++u32 RegisterNum ++ ) ++{ ++ u32 i; ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ ++ if (ODM_CheckPowerStatus(padapter) == false) ++ return; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Save ADDA parameters.\n")); ++ for (i = 0 ; i < RegisterNum ; i++) { ++ ADDABackup[i] = PHY_QueryBBReg(pDM_Odm->Adapter, ADDAReg[i], bMaskDWord); ++ } ++} ++ ++ ++static void ++_PHY_SaveMACRegisters8723B( ++struct adapter *padapter, ++u32 * MACReg, ++u32 * MACBackup ++ ) ++{ ++ u32 i; ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Save MAC parameters.\n")); ++ for (i = 0 ; i < (IQK_MAC_REG_NUM - 1); i++) { ++ MACBackup[i] = rtw_read8(pDM_Odm->Adapter, MACReg[i]); ++ } ++ MACBackup[i] = rtw_read32(pDM_Odm->Adapter, MACReg[i]); ++ ++} ++ ++ ++static void ++_PHY_ReloadADDARegisters8723B( ++struct adapter *padapter, ++u32 * ADDAReg, ++u32 * ADDABackup, ++u32 RegiesterNum ++ ) ++{ ++ u32 i; ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Reload ADDA power saving parameters !\n")); ++ for (i = 0 ; i < RegiesterNum; i++) ++ { ++ PHY_SetBBReg(pDM_Odm->Adapter, ADDAReg[i], bMaskDWord, ADDABackup[i]); ++ } ++} ++ ++static void ++_PHY_ReloadMACRegisters8723B( ++struct adapter *padapter, ++u32 * MACReg, ++u32 * MACBackup ++ ) ++{ ++ u32 i; ++ ++ for (i = 0 ; i < (IQK_MAC_REG_NUM - 1); i++) { ++ rtw_write8(padapter, MACReg[i], (u8)MACBackup[i]); ++ } ++ rtw_write32(padapter, MACReg[i], MACBackup[i]); ++} ++ ++ ++static void ++_PHY_PathADDAOn8723B( ++struct adapter *padapter, ++u32 * ADDAReg, ++bool isPathAOn, ++bool is2T ++ ) ++{ ++ u32 pathOn; ++ u32 i; ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("ADDA ON.\n")); ++ ++ pathOn = isPathAOn ? 0x01c00014 : 0x01c00014; ++ if (false == is2T) { ++ pathOn = 0x01c00014; ++ PHY_SetBBReg(pDM_Odm->Adapter, ADDAReg[0], bMaskDWord, 0x01c00014); ++ } ++ else { ++ PHY_SetBBReg(pDM_Odm->Adapter, ADDAReg[0], bMaskDWord, pathOn); ++ } ++ ++ for (i = 1 ; i < IQK_ADDA_REG_NUM ; i++) { ++ PHY_SetBBReg(pDM_Odm->Adapter, ADDAReg[i], bMaskDWord, pathOn); ++ } ++ ++} ++ ++static void ++_PHY_MACSettingCalibration8723B( ++struct adapter *padapter, ++u32 * MACReg, ++u32 * MACBackup ++ ) ++{ ++ u32 i = 0; ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("MAC settings for Calibration.\n")); ++ ++ rtw_write8(pDM_Odm->Adapter, MACReg[i], 0x3F); ++ ++ for (i = 1 ; i < (IQK_MAC_REG_NUM - 1); i++) { ++ rtw_write8(pDM_Odm->Adapter, MACReg[i], (u8)(MACBackup[i]&(~BIT3))); ++ } ++ rtw_write8(pDM_Odm->Adapter, MACReg[i], (u8)(MACBackup[i]&(~BIT5))); ++ ++} ++ ++static bool ++phy_SimularityCompare_8723B( ++struct adapter *padapter, ++s32 result[][8], ++u8 c1, ++u8 c2 ++ ) ++{ ++ u32 i, j, diff, SimularityBitMap, bound = 0; ++ u8 final_candidate[2] = {0xFF, 0xFF}; /* for path A and path B */ ++ bool bResult = true; ++ bool is2T = true; ++ s32 tmp1 = 0, tmp2 = 0; ++ ++ if (is2T) ++ bound = 8; ++ else ++ bound = 4; ++ ++ SimularityBitMap = 0; ++ ++ for (i = 0; i < bound; i++) ++ { ++ ++ if ((i == 1) || (i ==3) || (i ==5) || (i ==7)) ++ { ++ if ((result[c1][i]& 0x00000200) != 0) ++ tmp1 = result[c1][i] | 0xFFFFFC00; ++ else ++ tmp1 = result[c1][i]; ++ ++ if ((result[c2][i]& 0x00000200) != 0) ++ tmp2 = result[c2][i] | 0xFFFFFC00; ++ else ++ tmp2 = result[c2][i]; ++ } ++ else ++ { ++ tmp1 = result[c1][i]; ++ tmp2 = result[c2][i]; ++ } ++ ++ diff = (tmp1 > tmp2) ? (tmp1 - tmp2) : (tmp2 - tmp1); ++ ++ if (diff > MAX_TOLERANCE) ++ { ++ if ((i == 2 || i == 6) && !SimularityBitMap) ++ { ++ if (result[c1][i]+result[c1][i+1] == 0) ++ final_candidate[(i/4)] = c2; ++ else if (result[c2][i]+result[c2][i+1] == 0) ++ final_candidate[(i/4)] = c1; ++ else ++ SimularityBitMap = SimularityBitMap|(1<odmpriv; ++ ++ u32 i; ++ u8 PathAOK, PathBOK; ++ u8 tmp0xc50 = (u8)PHY_QueryBBReg(pDM_Odm->Adapter, 0xC50, bMaskByte0); ++ u8 tmp0xc58 = (u8)PHY_QueryBBReg(pDM_Odm->Adapter, 0xC58, bMaskByte0); ++ u32 ADDA_REG[IQK_ADDA_REG_NUM] = { ++ rFPGA0_XCD_SwitchControl, rBlue_Tooth, ++ rRx_Wait_CCA, rTx_CCK_RFON, ++ rTx_CCK_BBON, rTx_OFDM_RFON, ++ rTx_OFDM_BBON, rTx_To_Rx, ++ rTx_To_Tx, rRx_CCK, ++ rRx_OFDM, rRx_Wait_RIFS, ++ rRx_TO_Rx, rStandby, ++ rSleep, rPMPD_ANAEN }; ++ u32 IQK_MAC_REG[IQK_MAC_REG_NUM] = { ++ REG_TXPAUSE, REG_BCN_CTRL, ++ REG_BCN_CTRL_1, REG_GPIO_MUXCFG}; ++ ++ /* since 92C & 92D have the different define in IQK_BB_REG */ ++ u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = { ++ rOFDM0_TRxPathEnable, rOFDM0_TRMuxPar, ++ rFPGA0_XCD_RFInterfaceSW, rConfig_AntA, rConfig_AntB, ++ rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE, ++ rFPGA0_XB_RFInterfaceOE, rCCK0_AFESetting ++ }; ++ const u32 retryCount = 2; ++ ++ /* Note: IQ calibration must be performed after loading */ ++ /* PHY_REG.txt , and radio_a, radio_b.txt */ ++ ++ /* u32 bbvalue; */ ++ ++ if (t == 0) ++ { ++/* bbvalue = PHY_QueryBBReg(pDM_Odm->Adapter, rFPGA0_RFMOD, bMaskDWord); */ ++/* RT_DISP(FINIT, INIT_IQK, ("phy_IQCalibrate_8188E() ==>0x%08x\n", bbvalue)); */ ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQ Calibration for %s for %d times\n", (is2T ? "2T2R" : "1T1R"), t)); ++ ++ /* Save ADDA parameters, turn Path A ADDA on */ ++ _PHY_SaveADDARegisters8723B(padapter, ADDA_REG, pDM_Odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM); ++ _PHY_SaveMACRegisters8723B(padapter, IQK_MAC_REG, pDM_Odm->RFCalibrateInfo.IQK_MAC_backup); ++ _PHY_SaveADDARegisters8723B(padapter, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM); ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQ Calibration for %s for %d times\n", (is2T ? "2T2R" : "1T1R"), t)); ++ ++ _PHY_PathADDAOn8723B(padapter, ADDA_REG, true, is2T); ++ ++/* no serial mode */ ++ ++ /* save RF path for 8723B */ ++/* Path_SEL_BB = PHY_QueryBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord); */ ++/* Path_SEL_RF = PHY_QueryRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0xb0, 0xfffff); */ ++ ++ /* MAC settings */ ++ _PHY_MACSettingCalibration8723B(padapter, IQK_MAC_REG, pDM_Odm->RFCalibrateInfo.IQK_MAC_backup); ++ ++ /* BB setting */ ++ /* PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_RFMOD, BIT24, 0x00); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rCCK0_AFESetting, 0x0f000000, 0xf); ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_TRxPathEnable, bMaskDWord, 0x03a05600); ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_TRMuxPar, bMaskDWord, 0x000800e4); ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, 0x22204000); ++ ++ ++/* PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 0x01); */ ++/* PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 0x01); */ ++/* PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_XA_RFInterfaceOE, BIT10, 0x00); */ ++/* PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_XB_RFInterfaceOE, BIT10, 0x00); */ ++ ++ ++/* RX IQ calibration setting for 8723B D cut large current issue when leaving IPS */ ++ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_WE_LUT, 0x80000, 0x1); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x30000); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0001f); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xf7fb7); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0xed, 0x20, 0x1); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0x43, bRFRegOffsetMask, 0x60fbd); ++ ++/* path A TX IQK */ ++ for (i = 0 ; i < retryCount ; i++) { ++ PathAOK = phy_PathA_IQK_8723B(padapter, is2T, RF_Path); ++/* if (PathAOK == 0x03) { */ ++ if (PathAOK == 0x01) { ++ /* Path A Tx IQK Success */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000); ++ pDM_Odm->RFCalibrateInfo.TxLOK[ODM_RF_PATH_A] = PHY_QueryRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0x8, bRFRegOffsetMask); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Tx IQK Success!!\n")); ++ result[t][0] = (PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16; ++ result[t][1] = (PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16; ++ break; ++ } ++ } ++ ++/* path A RXIQK */ ++ for (i = 0 ; i < retryCount ; i++) { ++ PathAOK = phy_PathA_RxIQK8723B(padapter, is2T, RF_Path); ++ if (PathAOK == 0x03) { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK Success!!\n")); ++/* result[t][0] = (PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16; */ ++/* result[t][1] = (PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16; */ ++ result[t][2] = (PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_Before_IQK_A_2, bMaskDWord)&0x3FF0000)>>16; ++ result[t][3] = (PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_After_IQK_A_2, bMaskDWord)&0x3FF0000)>>16; ++ break; ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK Fail!!\n")); ++ } ++ } ++ ++ if (0x00 == PathAOK) { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQK failed!!\n")); ++ } ++ ++/* path B IQK */ ++ if (is2T) { ++ ++ /* path B TX IQK */ ++ for (i = 0 ; i < retryCount ; i++) { ++ PathBOK = phy_PathB_IQK_8723B(padapter); ++ if (PathBOK == 0x01) { ++ /* Path B Tx IQK Success */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000); ++ pDM_Odm->RFCalibrateInfo.TxLOK[ODM_RF_PATH_B] = PHY_QueryRFReg(pDM_Odm->Adapter, ODM_RF_PATH_B, 0x8, bRFRegOffsetMask); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Tx IQK Success!!\n")); ++ result[t][4] = (PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16; ++ result[t][5] = (PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16; ++ break; ++ } ++ } ++ ++/* path B RX IQK */ ++ for (i = 0 ; i < retryCount ; i++) { ++ PathBOK = phy_PathB_RxIQK8723B(padapter, is2T); ++ if (PathBOK == 0x03) { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Rx IQK Success!!\n")); ++/* result[t][0] = (PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16; */ ++/* result[t][1] = (PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16; */ ++ result[t][6] = (PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_Before_IQK_A_2, bMaskDWord)&0x3FF0000)>>16; ++ result[t][7] = (PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_After_IQK_A_2, bMaskDWord)&0x3FF0000)>>16; ++ break; ++ } else { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Rx IQK Fail!!\n")); ++ } ++ } ++ ++/* Allen end */ ++ if (0x00 == PathBOK) { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK failed!!\n")); ++ } ++ } ++ ++ /* Back to BB mode, load original value */ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK:Back to BB mode, load original value!\n")); ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0); ++ ++ if (t != 0) { ++ /* Reload ADDA power saving parameters */ ++ _PHY_ReloadADDARegisters8723B(padapter, ADDA_REG, pDM_Odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM); ++ ++ /* Reload MAC parameters */ ++ _PHY_ReloadMACRegisters8723B(padapter, IQK_MAC_REG, pDM_Odm->RFCalibrateInfo.IQK_MAC_backup); ++ ++ _PHY_ReloadADDARegisters8723B(padapter, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM); ++ ++ /* Reload RF path */ ++/* PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, Path_SEL_BB); */ ++/* PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0xb0, 0xfffff, Path_SEL_RF); */ ++ ++ /* Allen initial gain 0xc50 */ ++ /* Restore RX initial gain */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0xc50, bMaskByte0, 0x50); ++ PHY_SetBBReg(pDM_Odm->Adapter, 0xc50, bMaskByte0, tmp0xc50); ++ if (is2T) { ++ PHY_SetBBReg(pDM_Odm->Adapter, 0xc58, bMaskByte0, 0x50); ++ PHY_SetBBReg(pDM_Odm->Adapter, 0xc58, bMaskByte0, tmp0xc58); ++ } ++ ++ /* load 0xe30 IQC default value */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_Tone_A, bMaskDWord, 0x01008c00); ++ PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_Tone_A, bMaskDWord, 0x01008c00); ++ ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_IQCalibrate_8723B() <==\n")); ++ ++} ++ ++ ++static void ++phy_LCCalibrate_8723B( ++ PDM_ODM_T pDM_Odm, ++ bool is2T ++ ) ++{ ++ u8 tmpReg; ++ u32 RF_Amode = 0, RF_Bmode = 0, LC_Cal; ++ struct adapter *padapter = pDM_Odm->Adapter; ++ ++ /* Check continuous TX and Packet TX */ ++ tmpReg = rtw_read8(pDM_Odm->Adapter, 0xd03); ++ ++ if ((tmpReg&0x70) != 0) /* Deal with contisuous TX case */ ++ rtw_write8(pDM_Odm->Adapter, 0xd03, tmpReg&0x8F); /* disable all continuous TX */ ++ else /* Deal with Packet TX case */ ++ rtw_write8(pDM_Odm->Adapter, REG_TXPAUSE, 0xFF); /* block all queues */ ++ ++ if ((tmpReg&0x70) != 0) ++ { ++ /* 1. Read original RF mode */ ++ /* Path-A */ ++ RF_Amode = PHY_QueryRFReg(padapter, ODM_RF_PATH_A, RF_AC, bMask12Bits); ++ ++ /* Path-B */ ++ if (is2T) ++ RF_Bmode = PHY_QueryRFReg(padapter, ODM_RF_PATH_B, RF_AC, bMask12Bits); ++ ++ /* 2. Set RF mode = standby mode */ ++ /* Path-A */ ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_AC, bMask12Bits, (RF_Amode&0x8FFFF)|0x10000); ++ ++ /* Path-B */ ++ if (is2T) ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_B, RF_AC, bMask12Bits, (RF_Bmode&0x8FFFF)|0x10000); ++ } ++ ++ /* 3. Read RF reg18 */ ++ LC_Cal = PHY_QueryRFReg(padapter, ODM_RF_PATH_A, RF_CHNLBW, bMask12Bits); ++ ++ /* 4. Set LC calibration begin bit15 */ ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0xB0, bRFRegOffsetMask, 0xDFBE0); /* LDO ON */ ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_CHNLBW, bMask12Bits, LC_Cal|0x08000); ++ ++ mdelay(100); ++ ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0xB0, bRFRegOffsetMask, 0xDFFE0); /* LDO OFF */ ++ ++ /* Channel 10 LC calibration issue for 8723bs with 26M xtal */ ++ if (pDM_Odm->SupportInterface == ODM_ITRF_SDIO && pDM_Odm->PackageType >= 0x2) ++ { ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_CHNLBW, bMask12Bits, LC_Cal); ++ } ++ ++ /* Restore original situation */ ++ if ((tmpReg&0x70) != 0) /* Deal with contisuous TX case */ ++ { ++ /* Path-A */ ++ rtw_write8(pDM_Odm->Adapter, 0xd03, tmpReg); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_AC, bMask12Bits, RF_Amode); ++ ++ /* Path-B */ ++ if (is2T) ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_B, RF_AC, bMask12Bits, RF_Bmode); ++ } ++ else /* Deal with Packet TX case */ ++ { ++ rtw_write8(pDM_Odm->Adapter, REG_TXPAUSE, 0x00); ++ } ++} ++ ++/* Analog Pre-distortion calibration */ ++#define APK_BB_REG_NUM 8 ++#define APK_CURVE_REG_NUM 4 ++#define PATH_NUM 2 ++ ++#define DP_BB_REG_NUM 7 ++#define DP_RF_REG_NUM 1 ++#define DP_RETRY_LIMIT 10 ++#define DP_PATH_NUM 2 ++#define DP_DPK_NUM 3 ++#define DP_DPK_VALUE_NUM 2 ++ ++ ++ ++/* IQK version:V2.5 20140123 */ ++/* IQK is controlled by Is2ant, RF path */ ++void ++PHY_IQCalibrate_8723B( ++ struct adapter *padapter, ++ bool bReCovery, ++ bool bRestore, ++ bool Is2ant, /* false:1ant, true:2-ant */ ++ u8 RF_Path /* 0:S1, 1:S0 */ ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ ++ s32 result[4][8]; /* last is final result */ ++ u8 i, final_candidate, Indexforchannel; ++ bool bPathAOK, bPathBOK; ++ s32 RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC, RegTmp = 0; ++ bool is12simular, is13simular, is23simular; ++ bool bSingleTone = false, bCarrierSuppression = false; ++ u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = { ++ rOFDM0_XARxIQImbalance, rOFDM0_XBRxIQImbalance, ++ rOFDM0_ECCAThreshold, rOFDM0_AGCRSSITable, ++ rOFDM0_XATxIQImbalance, rOFDM0_XBTxIQImbalance, ++ rOFDM0_XCTxAFE, rOFDM0_XDTxAFE, ++ rOFDM0_RxIQExtAnta}; ++/* u32 Path_SEL_BB = 0; */ ++ u32 GNT_BT_default; ++ u32 StartTime; ++ s32 ProgressingTime; ++ ++ if (ODM_CheckPowerStatus(padapter) == false) ++ return; ++ ++ if (!(pDM_Odm->SupportAbility & ODM_RF_CALIBRATION)) ++ { ++ return; ++ } ++ ++ /* 20120213 Turn on when continuous Tx to pass lab testing. (required by Edlu) */ ++ if (bSingleTone || bCarrierSuppression) ++ return; ++ ++#if DISABLE_BB_RF ++ return; ++#endif ++ if (pDM_Odm->RFCalibrateInfo.bIQKInProgress) ++ return; ++ ++ ++ pDM_Odm->RFCalibrateInfo.bIQKInProgress = true; ++ ++ if (bRestore) { ++ u32 offset, data; ++ u8 path, bResult = SUCCESS; ++ PODM_RF_CAL_T pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo); ++ ++ path = (PHY_QueryBBReg(pDM_Odm->Adapter, rS0S1_PathSwitch, bMaskByte0) == 0x00) ? ODM_RF_PATH_A : ODM_RF_PATH_B; ++ ++ /* Restore TX IQK */ ++ for (i = 0; i < 3; ++i) { ++ offset = pRFCalibrateInfo->TxIQC_8723B[path][i][0]; ++ data = pRFCalibrateInfo->TxIQC_8723B[path][i][1]; ++ if ((offset == 0) || (data == 0)) { ++ DBG_871X("%s =>path:%s Restore TX IQK result failed\n", __func__, (path ==ODM_RF_PATH_A)?"A":"B"); ++ bResult = FAIL; ++ break; ++ } ++ /* RT_TRACE(_module_mp_, _drv_notice_, ("Switch to S1 TxIQC(offset, data) = (0x%X, 0x%X)\n", offset, data)); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, offset, bMaskDWord, data); ++ } ++ ++ /* Restore RX IQK */ ++ for (i = 0; i < 2; ++i) { ++ offset = pRFCalibrateInfo->RxIQC_8723B[path][i][0]; ++ data = pRFCalibrateInfo->RxIQC_8723B[path][i][1]; ++ if ((offset == 0) || (data == 0)) { ++ DBG_871X("%s =>path:%s Restore RX IQK result failed\n", __func__, (path ==ODM_RF_PATH_A)?"A":"B"); ++ bResult = FAIL; ++ break; ++ } ++ /* RT_TRACE(_module_mp_, _drv_notice_, ("Switch to S1 RxIQC (offset, data) = (0x%X, 0x%X)\n", offset, data)); */ ++ PHY_SetBBReg(pDM_Odm->Adapter, offset, bMaskDWord, data); ++ } ++ ++ if (pDM_Odm->RFCalibrateInfo.TxLOK[ODM_RF_PATH_A] == 0) { ++ DBG_871X("%s => Restore Path-A TxLOK result failed\n", __func__); ++ bResult = FAIL; ++ } else { ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXM_IDAC, bRFRegOffsetMask, pDM_Odm->RFCalibrateInfo.TxLOK[ODM_RF_PATH_A]); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_B, RF_TXM_IDAC, bRFRegOffsetMask, pDM_Odm->RFCalibrateInfo.TxLOK[ODM_RF_PATH_B]); ++ } ++ ++ if (bResult == SUCCESS) ++ return; ++ } ++ ++ if (bReCovery) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("PHY_IQCalibrate_8723B: Return due to bReCovery!\n")); ++ _PHY_ReloadADDARegisters8723B(padapter, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup_recover, 9); ++ return; ++ } ++ StartTime = jiffies; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK:Start!!!\n")); ++ ++ /* save default GNT_BT */ ++ GNT_BT_default = PHY_QueryBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord); ++ /* Save RF Path */ ++/* Path_SEL_BB = PHY_QueryBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord); */ ++/* Path_SEL_RF = PHY_QueryRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0xb0, 0xfffff); */ ++ ++ /* set GNT_BT = 0, pause BT traffic */ ++/* PHY_SetBBReg(pDM_Odm->Adapter, 0x764, BIT12, 0x0); */ ++/* PHY_SetBBReg(pDM_Odm->Adapter, 0x764, BIT11, 0x1); */ ++ ++ ++ for (i = 0; i < 8; i++) ++ { ++ result[0][i] = 0; ++ result[1][i] = 0; ++ result[2][i] = 0; ++ result[3][i] = 0; ++ } ++ final_candidate = 0xff; ++ bPathAOK = false; ++ bPathBOK = false; ++ is12simular = false; ++ is23simular = false; ++ is13simular = false; ++ ++ ++ for (i = 0; i<3; i++) ++ { ++ phy_IQCalibrate_8723B(padapter, result, i, Is2ant, RF_Path); ++ ++ if (i == 1) ++ { ++ is12simular = phy_SimularityCompare_8723B(padapter, result, 0, 1); ++ if (is12simular) ++ { ++ final_candidate = 0; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is12simular final_candidate is %x\n", final_candidate)); ++ break; ++ } ++ } ++ ++ if (i == 2) ++ { ++ is13simular = phy_SimularityCompare_8723B(padapter, result, 0, 2); ++ if (is13simular) ++ { ++ final_candidate = 0; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is13simular final_candidate is %x\n", final_candidate)); ++ ++ break; ++ } ++ is23simular = phy_SimularityCompare_8723B(padapter, result, 1, 2); ++ if (is23simular) ++ { ++ final_candidate = 1; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is23simular final_candidate is %x\n", final_candidate)); ++ } ++ else ++ { ++ for (i = 0; i < 8; i++) ++ RegTmp += result[3][i]; ++ ++ if (RegTmp != 0) ++ final_candidate = 3; ++ else ++ final_candidate = 0xFF; ++ } ++ } ++ } ++/* RT_TRACE(COMP_INIT, DBG_LOUD, ("Release Mutex in IQCalibrate\n")); */ ++ ++ for (i = 0; i<4; i++) ++ { ++ RegE94 = result[i][0]; ++ RegE9C = result[i][1]; ++ RegEA4 = result[i][2]; ++ RegEAC = result[i][3]; ++ RegEB4 = result[i][4]; ++ RegEBC = result[i][5]; ++ RegEC4 = result[i][6]; ++ RegECC = result[i][7]; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: RegE94 =%x RegE9C =%x RegEA4 =%x RegEAC =%x RegEB4 =%x RegEBC =%x RegEC4 =%x RegECC =%x\n ", RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC)); ++ } ++ ++ if (final_candidate != 0xff) ++ { ++ pDM_Odm->RFCalibrateInfo.RegE94 = RegE94 = result[final_candidate][0]; ++ pDM_Odm->RFCalibrateInfo.RegE9C = RegE9C = result[final_candidate][1]; ++ RegEA4 = result[final_candidate][2]; ++ RegEAC = result[final_candidate][3]; ++ pDM_Odm->RFCalibrateInfo.RegEB4 = RegEB4 = result[final_candidate][4]; ++ pDM_Odm->RFCalibrateInfo.RegEBC = RegEBC = result[final_candidate][5]; ++ RegEC4 = result[final_candidate][6]; ++ RegECC = result[final_candidate][7]; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: final_candidate is %x\n", final_candidate)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: RegE94 =%x RegE9C =%x RegEA4 =%x RegEAC =%x RegEB4 =%x RegEBC =%x RegEC4 =%x RegECC =%x\n ", RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC)); ++ bPathAOK = bPathBOK = true; ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: FAIL use default value\n")); ++ ++ pDM_Odm->RFCalibrateInfo.RegE94 = pDM_Odm->RFCalibrateInfo.RegEB4 = 0x100; /* X default value */ ++ pDM_Odm->RFCalibrateInfo.RegE9C = pDM_Odm->RFCalibrateInfo.RegEBC = 0x0; /* Y default value */ ++ } ++ ++ { ++ if (RegE94 != 0) ++ { ++ _PHY_PathAFillIQKMatrix8723B(padapter, bPathAOK, result, final_candidate, (RegEA4 == 0)); ++ } ++ } ++ { ++ if (RegEB4 != 0) ++ { ++ _PHY_PathBFillIQKMatrix8723B(padapter, bPathBOK, result, final_candidate, (RegEC4 == 0)); ++ } ++ } ++ ++ Indexforchannel = ODM_GetRightChnlPlaceforIQK(pHalData->CurrentChannel); ++ ++/* To Fix BSOD when final_candidate is 0xff */ ++/* by sherry 20120321 */ ++ if (final_candidate < 4) ++ { ++ for (i = 0; i < IQK_Matrix_REG_NUM; i++) ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][i] = result[final_candidate][i]; ++ pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].bIQKDone = true; ++ } ++ /* RT_DISP(FINIT, INIT_IQK, ("\nIQK OK Indexforchannel %d.\n", Indexforchannel)); */ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("\nIQK OK Indexforchannel %d.\n", Indexforchannel)); ++ ++ _PHY_SaveADDARegisters8723B(padapter, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup_recover, 9); ++ ++ /* restore GNT_BT */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, GNT_BT_default); ++ /* Restore RF Path */ ++/* PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, Path_SEL_BB); */ ++/* PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0xb0, 0xfffff, Path_SEL_RF); */ ++ ++ /* Resotr RX mode table parameter */ ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_WE_LUT, 0x80000, 0x1); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x18000); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0001f); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xe6177); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0xed, 0x20, 0x1); ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0x43, bRFRegOffsetMask, 0x300bd); ++ ++ /* set GNT_BT = HW control */ ++/* PHY_SetBBReg(pDM_Odm->Adapter, 0x764, BIT12, 0x0); */ ++/* PHY_SetBBReg(pDM_Odm->Adapter, 0x764, BIT11, 0x0); */ ++ ++ if (Is2ant) { ++ if (RF_Path == 0x0) /* S1 */ ++ ODM_SetIQCbyRFpath(pDM_Odm, 0); ++ else /* S0 */ ++ ODM_SetIQCbyRFpath(pDM_Odm, 1); ++ } ++ ++ pDM_Odm->RFCalibrateInfo.bIQKInProgress = false; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK finished\n")); ++ ProgressingTime = jiffies_to_msecs(jiffies - StartTime); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK ProgressingTime = %d\n", ProgressingTime)); ++ ++ ++} ++ ++ ++void ++PHY_LCCalibrate_8723B( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ bool bSingleTone = false, bCarrierSuppression = false; ++ u32 timeout = 2000, timecount = 0; ++ u32 StartTime; ++ s32 ProgressingTime; ++ ++#if DISABLE_BB_RF ++ return; ++#endif ++ ++ if (!(pDM_Odm->SupportAbility & ODM_RF_CALIBRATION)) ++ { ++ return; ++ } ++ ++ /* 20120213 Turn on when continuous Tx to pass lab testing. (required by Edlu) */ ++ if (bSingleTone || bCarrierSuppression) ++ return; ++ ++ StartTime = jiffies; ++ while (*(pDM_Odm->pbScanInProcess) && timecount < timeout) ++ { ++ mdelay(50); ++ timecount += 50; ++ } ++ ++ pDM_Odm->RFCalibrateInfo.bLCKInProgress = true; ++ ++ ++ phy_LCCalibrate_8723B(pDM_Odm, false); ++ ++ ++ pDM_Odm->RFCalibrateInfo.bLCKInProgress = false; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LCK:Finish!!!interface %d\n", pDM_Odm->InterfaceIndex)); ++ ProgressingTime = jiffies_to_msecs(jiffies - StartTime); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LCK ProgressingTime = %d\n", ProgressingTime)); ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/HalPhyRf_8723B.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalPhyRf_8723B.h +--- linux-4.3/3rdparty/rtl8723bs/hal/HalPhyRf_8723B.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalPhyRf_8723B.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,100 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#ifndef __HAL_PHY_RF_8723B_H__ ++#define __HAL_PHY_RF_8723B_H__ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++#define IQK_DELAY_TIME_8723B 20 /* ms */ ++#define IQK_DEFERRED_TIME_8723B 4 ++#define index_mapping_NUM_8723B 15 ++#define AVG_THERMAL_NUM_8723B 4 ++#define RF_T_METER_8723B 0x42 /* */ ++ ++ ++void ConfigureTxpowerTrack_8723B( ++ PTXPWRTRACK_CFG pConfig ++ ); ++ ++void DoIQK_8723B( ++ PDM_ODM_T pDM_Odm, ++ u8 DeltaThermalIndex, ++ u8 ThermalValue, ++ u8 Threshold ++ ); ++ ++void ++ODM_TxPwrTrackSetPwr_8723B( ++ PDM_ODM_T pDM_Odm, ++ PWRTRACK_METHOD Method, ++ u8 RFPath, ++ u8 ChannelMappedIndex ++ ); ++ ++/* 1 7. IQK */ ++ ++void ++PHY_IQCalibrate_8723B( ++ struct adapter *Adapter, ++ bool bReCovery, ++ bool bRestore, ++ bool Is2ant, ++ u8 RF_Path); ++ ++void ++ODM_SetIQCbyRFpath( ++ PDM_ODM_T pDM_Odm, ++ u32 RFpath ++ ); ++ ++/* */ ++/* LC calibrate */ ++/* */ ++void ++PHY_LCCalibrate_8723B( ++ PDM_ODM_T pDM_Odm ++); ++ ++/* */ ++/* AP calibrate */ ++/* */ ++void ++PHY_DigitalPredistortion_8723B(struct adapter *padapter); ++ ++ ++void ++_PHY_SaveADDARegisters_8723B( ++ struct adapter *padapter, ++ u32 * ADDAReg, ++ u32 * ADDABackup, ++ u32 RegisterNum ++ ); ++ ++void ++_PHY_PathADDAOn_8723B( ++ struct adapter *padapter, ++ u32 * ADDAReg, ++ bool isPathAOn, ++ bool is2T ++ ); ++ ++void ++_PHY_MACSettingCalibration_8723B( ++ struct adapter *padapter, ++ u32 * MACReg, ++ u32 * MACBackup ++ ); ++ ++#endif /* #ifndef __HAL_PHY_RF_8188E_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/HalPhyRf.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalPhyRf.c +--- linux-4.3/3rdparty/rtl8723bs/hal/HalPhyRf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/HalPhyRf.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,394 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++/* include "Mp_Precomp.h" */ ++#include "odm_precomp.h" ++ ++ ++#define CALCULATE_SWINGTALBE_OFFSET(_offset, _direction, _size, _deltaThermal) \ ++ do {\ ++ for (_offset = 0; _offset < _size; _offset++)\ ++ {\ ++ if (_deltaThermal < thermalThreshold[_direction][_offset])\ ++ {\ ++ if (_offset != 0)\ ++ _offset--;\ ++ break;\ ++ }\ ++ } \ ++ if (_offset >= _size)\ ++ _offset = _size-1;\ ++ } while (0) ++ ++ ++void ConfigureTxpowerTrack( ++PDM_ODM_T pDM_Odm, ++ PTXPWRTRACK_CFG pConfig ++ ) ++{ ++ ConfigureTxpowerTrack_8723B(pConfig); ++} ++ ++/* */ ++/* <20121113, Kordan> This function should be called when TxAGC changed. */ ++/* Otherwise the previous compensation is gone, because we record the */ ++/* delta of temperature between two TxPowerTracking watch dogs. */ ++/* */ ++/* NOTE: If Tx BB swing or Tx scaling is varified during run-time, still */ ++/* need to call this function. */ ++/* */ ++void ++ODM_ClearTxPowerTrackingState( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(pDM_Odm->Adapter); ++ u8 p = 0; ++ ++ pDM_Odm->BbSwingIdxCckBase = pDM_Odm->DefaultCckIndex; ++ pDM_Odm->BbSwingIdxCck = pDM_Odm->DefaultCckIndex; ++ pDM_Odm->RFCalibrateInfo.CCK_index = 0; ++ ++ for (p = ODM_RF_PATH_A; p < MAX_RF_PATH; ++p) ++ { ++ pDM_Odm->BbSwingIdxOfdmBase[p] = pDM_Odm->DefaultOfdmIndex; ++ pDM_Odm->BbSwingIdxOfdm[p] = pDM_Odm->DefaultOfdmIndex; ++ pDM_Odm->RFCalibrateInfo.OFDM_index[p] = pDM_Odm->DefaultOfdmIndex; ++ ++ pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0; ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p] = 0; ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p] = 0; ++ pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0; ++ ++ pDM_Odm->Absolute_OFDMSwingIdx[p] = 0; /* Initial Mix mode power tracking */ ++ pDM_Odm->Remnant_OFDMSwingIdx[p] = 0; ++ } ++ ++ pDM_Odm->Modify_TxAGC_Flag_PathA = false; /* Initial at Modify Tx Scaling Mode */ ++ pDM_Odm->Modify_TxAGC_Flag_PathB = false; /* Initial at Modify Tx Scaling Mode */ ++ pDM_Odm->Remnant_CCKSwingIdx = 0; ++ pDM_Odm->RFCalibrateInfo.ThermalValue = pHalData->EEPROMThermalMeter; ++ pDM_Odm->RFCalibrateInfo.ThermalValue_IQK = pHalData->EEPROMThermalMeter; ++ pDM_Odm->RFCalibrateInfo.ThermalValue_LCK = pHalData->EEPROMThermalMeter; ++} ++ ++void ++ODM_TXPowerTrackingCallback_ThermalMeter( ++ struct adapter *Adapter ++ ) ++{ ++ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ ++ u8 ThermalValue = 0, delta, delta_LCK, delta_IQK, p = 0, i = 0; ++ u8 ThermalValue_AVG_count = 0; ++ u32 ThermalValue_AVG = 0; ++ ++ u8 OFDM_min_index = 0; /* OFDM BB Swing should be less than +3.0dB, which is required by Arthur */ ++ u8 Indexforchannel = 0; /* GetRightChnlPlaceforIQK(pHalData->CurrentChannel) */ ++ ++ TXPWRTRACK_CFG c; ++ ++ ++ /* 4 1. The following TWO tables decide the final index of OFDM/CCK swing table. */ ++ u8 * deltaSwingTableIdx_TUP_A; ++ u8 * deltaSwingTableIdx_TDOWN_A; ++ u8 * deltaSwingTableIdx_TUP_B; ++ u8 * deltaSwingTableIdx_TDOWN_B; ++ ++ /* 4 2. Initilization (7 steps in total) */ ++ ++ ConfigureTxpowerTrack(pDM_Odm, &c); ++ ++ (*c.GetDeltaSwingTable)(pDM_Odm, (u8 **)&deltaSwingTableIdx_TUP_A, (u8 **)&deltaSwingTableIdx_TDOWN_A, ++ (u8 **)&deltaSwingTableIdx_TUP_B, (u8 **)&deltaSwingTableIdx_TDOWN_B); ++ ++ pDM_Odm->RFCalibrateInfo.TXPowerTrackingCallbackCnt++; /* cosa add for debug */ ++ pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = true; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("===>ODM_TXPowerTrackingCallback_ThermalMeter, \ ++ \n pDM_Odm->BbSwingIdxCckBase: %d, pDM_Odm->BbSwingIdxOfdmBase[A]: %d, pDM_Odm->DefaultOfdmIndex: %d\n", ++ pDM_Odm->BbSwingIdxCckBase, pDM_Odm->BbSwingIdxOfdmBase[ODM_RF_PATH_A], pDM_Odm->DefaultOfdmIndex)); ++ ++ ThermalValue = (u8)PHY_QueryRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, c.ThermalRegAddr, 0xfc00); /* 0x42: RF Reg[15:10] 88E */ ++ if (! pDM_Odm->RFCalibrateInfo.TxPowerTrackControl || pHalData->EEPROMThermalMeter == 0 || ++ pHalData->EEPROMThermalMeter == 0xFF) ++ return; ++ ++ /* 4 3. Initialize ThermalValues of RFCalibrateInfo */ ++ ++ if (pDM_Odm->RFCalibrateInfo.bReloadtxpowerindex) ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("reload ofdm index for band switch\n")); ++ ++ /* 4 4. Calculate average thermal meter */ ++ ++ pDM_Odm->RFCalibrateInfo.ThermalValue_AVG[pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index] = ThermalValue; ++ pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index++; ++ if (pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index == c.AverageThermalNum) /* Average times = c.AverageThermalNum */ ++ pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index = 0; ++ ++ for (i = 0; i < c.AverageThermalNum; i++) { ++ if (pDM_Odm->RFCalibrateInfo.ThermalValue_AVG[i]) { ++ ThermalValue_AVG += pDM_Odm->RFCalibrateInfo.ThermalValue_AVG[i]; ++ ThermalValue_AVG_count++; ++ } ++ } ++ ++ if (ThermalValue_AVG_count) /* Calculate Average ThermalValue after average enough times */ ++ { ++ ThermalValue = (u8)(ThermalValue_AVG / ThermalValue_AVG_count); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("AVG Thermal Meter = 0x%X, EFUSE Thermal Base = 0x%X\n", ThermalValue, pHalData->EEPROMThermalMeter)); ++ } ++ ++ /* 4 5. Calculate delta, delta_LCK, delta_IQK. */ ++ ++ /* delta" here is used to determine whether thermal value changes or not. */ ++ delta = (ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue)?(ThermalValue - pDM_Odm->RFCalibrateInfo.ThermalValue):(pDM_Odm->RFCalibrateInfo.ThermalValue - ThermalValue); ++ delta_LCK = (ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue_LCK)?(ThermalValue - pDM_Odm->RFCalibrateInfo.ThermalValue_LCK):(pDM_Odm->RFCalibrateInfo.ThermalValue_LCK - ThermalValue); ++ delta_IQK = (ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue_IQK)?(ThermalValue - pDM_Odm->RFCalibrateInfo.ThermalValue_IQK):(pDM_Odm->RFCalibrateInfo.ThermalValue_IQK - ThermalValue); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("(delta, delta_LCK, delta_IQK) = (%d, %d, %d)\n", delta, delta_LCK, delta_IQK)); ++ ++ /* 4 6. If necessary, do LCK. */ ++ ++ if ((delta_LCK >= c.Threshold_IQK)) /* Delta temperature is equal to or larger than 20 centigrade. */ ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("delta_LCK(%d) >= Threshold_IQK(%d)\n", delta_LCK, c.Threshold_IQK)); ++ pDM_Odm->RFCalibrateInfo.ThermalValue_LCK = ThermalValue; ++ if (c.PHY_LCCalibrate) ++ (*c.PHY_LCCalibrate)(pDM_Odm); ++ } ++ ++ /* 3 7. If necessary, move the index of swing table to adjust Tx power. */ ++ ++ if (delta > 0 && pDM_Odm->RFCalibrateInfo.TxPowerTrackControl) { ++ /* delta" here is used to record the absolute value of differrence. */ ++ delta = ThermalValue > pHalData->EEPROMThermalMeter?(ThermalValue - pHalData->EEPROMThermalMeter):(pHalData->EEPROMThermalMeter - ThermalValue); ++ if (delta >= TXPWR_TRACK_TABLE_SIZE) ++ delta = TXPWR_TRACK_TABLE_SIZE - 1; ++ ++ /* 4 7.1 The Final Power Index = BaseIndex + PowerIndexOffset */ ++ ++ if (ThermalValue > pHalData->EEPROMThermalMeter) { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("deltaSwingTableIdx_TUP_A[%d] = %d\n", delta, deltaSwingTableIdx_TUP_A[delta])); ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[ODM_RF_PATH_A] = pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_A]; ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_A] = deltaSwingTableIdx_TUP_A[delta]; ++ ++ pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = deltaSwingTableIdx_TUP_A[delta]; /* Record delta swing for mix mode power tracking */ ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("******Temp is higher and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n", pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A])); ++ ++ if (c.RfPathCount > 1) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("deltaSwingTableIdx_TUP_B[%d] = %d\n", delta, deltaSwingTableIdx_TUP_B[delta])); ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[ODM_RF_PATH_B] = pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_B]; ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_B] = deltaSwingTableIdx_TUP_B[delta]; ++ ++ pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] = deltaSwingTableIdx_TUP_B[delta]; /* Record delta swing for mix mode power tracking */ ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("******Temp is higher and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n", pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B])); ++ } ++ ++ } else { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("deltaSwingTableIdx_TDOWN_A[%d] = %d\n", delta, deltaSwingTableIdx_TDOWN_A[delta])); ++ ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[ODM_RF_PATH_A] = pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_A]; ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_A] = -1 * deltaSwingTableIdx_TDOWN_A[delta]; ++ ++ pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = -1 * deltaSwingTableIdx_TDOWN_A[delta]; /* Record delta swing for mix mode power tracking */ ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("******Temp is lower and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n", pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A])); ++ ++ if (c.RfPathCount > 1) { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("deltaSwingTableIdx_TDOWN_B[%d] = %d\n", delta, deltaSwingTableIdx_TDOWN_B[delta])); ++ ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[ODM_RF_PATH_B] = pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_B]; ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_B] = -1 * deltaSwingTableIdx_TDOWN_B[delta]; ++ ++ pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] = -1 * deltaSwingTableIdx_TDOWN_B[delta]; /* Record delta swing for mix mode power tracking */ ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("******Temp is lower and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n", pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B])); ++ } ++ } ++ ++ for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++) { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("\n\n ================================ [Path-%c] Calculating PowerIndexOffset ================================\n", (p == ODM_RF_PATH_A ? 'A' : 'B'))); ++ ++ if (pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p] == pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p]) /* If Thermal value changes but lookup table value still the same */ ++ pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0; ++ else ++ pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p] - pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p]; /* Power Index Diff between 2 times Power Tracking */ ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("[Path-%c] PowerIndexOffset(%d) = DeltaPowerIndex(%d) - DeltaPowerIndexLast(%d)\n", ++ (p == ODM_RF_PATH_A ? 'A' : 'B'), pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p], pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p], ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p])); ++ ++ pDM_Odm->RFCalibrateInfo.OFDM_index[p] = pDM_Odm->BbSwingIdxOfdmBase[p] + pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p]; ++ pDM_Odm->RFCalibrateInfo.CCK_index = pDM_Odm->BbSwingIdxCckBase + pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p]; ++ ++ pDM_Odm->BbSwingIdxCck = pDM_Odm->RFCalibrateInfo.CCK_index; ++ pDM_Odm->BbSwingIdxOfdm[p] = pDM_Odm->RFCalibrateInfo.OFDM_index[p]; ++ ++ /* *************Print BB Swing Base and Index Offset************* */ ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("The 'CCK' final index(%d) = BaseIndex(%d) + PowerIndexOffset(%d)\n", ++ pDM_Odm->BbSwingIdxCck, pDM_Odm->BbSwingIdxCckBase, pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p])); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("The 'OFDM' final index(%d) = BaseIndex[%c](%d) + PowerIndexOffset(%d)\n", ++ pDM_Odm->BbSwingIdxOfdm[p], (p == ODM_RF_PATH_A ? 'A' : 'B'), pDM_Odm->BbSwingIdxOfdmBase[p], pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p])); ++ ++ /* 4 7.1 Handle boundary conditions of index. */ ++ ++ ++ if (pDM_Odm->RFCalibrateInfo.OFDM_index[p] > c.SwingTableSize_OFDM-1) ++ { ++ pDM_Odm->RFCalibrateInfo.OFDM_index[p] = c.SwingTableSize_OFDM-1; ++ } ++ else if (pDM_Odm->RFCalibrateInfo.OFDM_index[p] < OFDM_min_index) ++ { ++ pDM_Odm->RFCalibrateInfo.OFDM_index[p] = OFDM_min_index; ++ } ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("\n\n ========================================================================================================\n")); ++ if (pDM_Odm->RFCalibrateInfo.CCK_index > c.SwingTableSize_CCK-1) ++ pDM_Odm->RFCalibrateInfo.CCK_index = c.SwingTableSize_CCK-1; ++ /* else if (pDM_Odm->RFCalibrateInfo.CCK_index < 0) */ ++ /* pDM_Odm->RFCalibrateInfo.CCK_index = 0; */ ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("The thermal meter is unchanged or TxPowerTracking OFF(%d): ThermalValue: %d , pDM_Odm->RFCalibrateInfo.ThermalValue: %d\n", ++ pDM_Odm->RFCalibrateInfo.TxPowerTrackControl, ThermalValue, pDM_Odm->RFCalibrateInfo.ThermalValue)); ++ ++ for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++) ++ pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0; ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("TxPowerTracking: [CCK] Swing Current Index: %d, Swing Base Index: %d\n", ++ pDM_Odm->RFCalibrateInfo.CCK_index, pDM_Odm->BbSwingIdxCckBase)); /* Print Swing base & current */ ++ for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("TxPowerTracking: [OFDM] Swing Current Index: %d, Swing Base Index[%c]: %d\n", ++ pDM_Odm->RFCalibrateInfo.OFDM_index[p], (p == ODM_RF_PATH_A ? 'A' : 'B'), pDM_Odm->BbSwingIdxOfdmBase[p])); ++ } ++ ++ if ((pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_A] != 0 || ++ pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_B] != 0) && ++ pDM_Odm->RFCalibrateInfo.TxPowerTrackControl) ++ { ++ /* 4 7.2 Configure the Swing Table to adjust Tx Power. */ ++ ++ pDM_Odm->RFCalibrateInfo.bTxPowerChanged = true; /* Always true after Tx Power is adjusted by power tracking. */ ++ /* */ ++ /* 2012/04/23 MH According to Luke's suggestion, we can not write BB digital */ ++ /* to increase TX power. Otherwise, EVM will be bad. */ ++ /* */ ++ /* 2012/04/25 MH Add for tx power tracking to set tx power in tx agc for 88E. */ ++ if (ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("Temperature Increasing(A): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", ++ pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_A], delta, ThermalValue, pHalData->EEPROMThermalMeter, pDM_Odm->RFCalibrateInfo.ThermalValue)); ++ ++ if (c.RfPathCount > 1) ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("Temperature Increasing(B): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", ++ pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_B], delta, ThermalValue, pHalData->EEPROMThermalMeter, pDM_Odm->RFCalibrateInfo.ThermalValue)); ++ ++ } ++ else if (ThermalValue < pDM_Odm->RFCalibrateInfo.ThermalValue)/* Low temperature */ ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("Temperature Decreasing(A): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", ++ pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_A], delta, ThermalValue, pHalData->EEPROMThermalMeter, pDM_Odm->RFCalibrateInfo.ThermalValue)); ++ ++ if (c.RfPathCount > 1) ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("Temperature Decreasing(B): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", ++ pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_B], delta, ThermalValue, pHalData->EEPROMThermalMeter, pDM_Odm->RFCalibrateInfo.ThermalValue)); ++ ++ } ++ if (ThermalValue > pHalData->EEPROMThermalMeter) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("Temperature(%d) higher than PG value(%d)\n", ThermalValue, pHalData->EEPROMThermalMeter)); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("**********Enter POWER Tracking MIX_MODE**********\n")); ++ for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++) ++ (*c.ODM_TxPwrTrackSetPwr)(pDM_Odm, MIX_MODE, p, 0); ++ } ++ else ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("Temperature(%d) lower than PG value(%d)\n", ThermalValue, pHalData->EEPROMThermalMeter)); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("**********Enter POWER Tracking MIX_MODE**********\n")); ++ for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++) ++ (*c.ODM_TxPwrTrackSetPwr)(pDM_Odm, MIX_MODE, p, Indexforchannel); ++ } ++ ++ pDM_Odm->BbSwingIdxCckBase = pDM_Odm->BbSwingIdxCck; /* Record last time Power Tracking result as base. */ ++ for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++) ++ pDM_Odm->BbSwingIdxOfdmBase[p] = pDM_Odm->BbSwingIdxOfdm[p]; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ++ ("pDM_Odm->RFCalibrateInfo.ThermalValue = %d ThermalValue = %d\n", pDM_Odm->RFCalibrateInfo.ThermalValue, ThermalValue)); ++ ++ pDM_Odm->RFCalibrateInfo.ThermalValue = ThermalValue; /* Record last Power Tracking Thermal Value */ ++ ++ } ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("<===ODM_TXPowerTrackingCallback_ThermalMeter\n")); ++ ++ pDM_Odm->RFCalibrateInfo.TXPowercount = 0; ++} ++ ++ ++ ++ ++/* 3 ============================================================ */ ++/* 3 IQ Calibration */ ++/* 3 ============================================================ */ ++ ++u8 ODM_GetRightChnlPlaceforIQK(u8 chnl) ++{ ++ u8 channel_all[ODM_TARGET_CHNL_NUM_2G_5G] = ++ {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 149, 151, 153, 155, 157, 159, 161, 163, 165}; ++ u8 place = chnl; ++ ++ ++ if (chnl > 14) ++ { ++ for (place = 14; place ++#include ++#include ++ ++ ++/* */ ++/* Description: */ ++/* This routine deal with the Power Configuration CMDs parsing for RTL8723/RTL8188E Series IC. */ ++/* */ ++/* Assumption: */ ++/* We should follow specific format which was released from HW SD. */ ++/* */ ++/* 2011.07.07, added by Roger. */ ++/* */ ++u8 HalPwrSeqCmdParsing( ++ struct adapter * padapter, ++ u8 CutVersion, ++ u8 FabVersion, ++ u8 InterfaceType, ++ WLAN_PWR_CFG PwrSeqCmd[]) ++{ ++ WLAN_PWR_CFG PwrCfgCmd = {0}; ++ u8 bPollingBit = false; ++ u32 AryIdx = 0; ++ u8 value = 0; ++ u32 offset = 0; ++ u32 pollingCount = 0; /* polling autoload done. */ ++ u32 maxPollingCnt = 5000; ++ ++ do { ++ PwrCfgCmd = PwrSeqCmd[AryIdx]; ++ ++ RT_TRACE(_module_hal_init_c_ , _drv_info_, ++ ("HalPwrSeqCmdParsing: offset(%#x) cut_msk(%#x) fab_msk(%#x) interface_msk(%#x) base(%#x) cmd(%#x) msk(%#x) value(%#x)\n", ++ GET_PWR_CFG_OFFSET(PwrCfgCmd), ++ GET_PWR_CFG_CUT_MASK(PwrCfgCmd), ++ GET_PWR_CFG_FAB_MASK(PwrCfgCmd), ++ GET_PWR_CFG_INTF_MASK(PwrCfgCmd), ++ GET_PWR_CFG_BASE(PwrCfgCmd), ++ GET_PWR_CFG_CMD(PwrCfgCmd), ++ GET_PWR_CFG_MASK(PwrCfgCmd), ++ GET_PWR_CFG_VALUE(PwrCfgCmd))); ++ ++ /* 2 Only Handle the command whose FAB, CUT, and Interface are matched */ ++ if ((GET_PWR_CFG_FAB_MASK(PwrCfgCmd) & FabVersion) && ++ (GET_PWR_CFG_CUT_MASK(PwrCfgCmd) & CutVersion) && ++ (GET_PWR_CFG_INTF_MASK(PwrCfgCmd) & InterfaceType)) ++ { ++ switch (GET_PWR_CFG_CMD(PwrCfgCmd)) ++ { ++ case PWR_CMD_READ: ++ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_READ\n")); ++ break; ++ ++ case PWR_CMD_WRITE: ++ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_WRITE\n")); ++ offset = GET_PWR_CFG_OFFSET(PwrCfgCmd); ++ ++ /* */ ++ /* We should deal with interface specific address mapping for some interfaces, e.g., SDIO interface */ ++ /* 2011.07.07. */ ++ /* */ ++ if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO) ++ { ++ /* Read Back SDIO Local value */ ++ value = SdioLocalCmd52Read1Byte(padapter, offset); ++ ++ value &= ~(GET_PWR_CFG_MASK(PwrCfgCmd)); ++ value |= (GET_PWR_CFG_VALUE(PwrCfgCmd) & GET_PWR_CFG_MASK(PwrCfgCmd)); ++ ++ /* Write Back SDIO Local value */ ++ SdioLocalCmd52Write1Byte(padapter, offset, value); ++ } ++ else ++ { ++ /* Read the value from system register */ ++ value = rtw_read8(padapter, offset); ++ ++ value =value&(~(GET_PWR_CFG_MASK(PwrCfgCmd))); ++ value =value|(GET_PWR_CFG_VALUE(PwrCfgCmd)&GET_PWR_CFG_MASK(PwrCfgCmd)); ++ ++ /* Write the value back to sytem register */ ++ rtw_write8(padapter, offset, value); ++ } ++ break; ++ ++ case PWR_CMD_POLLING: ++ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_POLLING\n")); ++ ++ bPollingBit = false; ++ offset = GET_PWR_CFG_OFFSET(PwrCfgCmd); ++ do { ++ if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO) ++ value = SdioLocalCmd52Read1Byte(padapter, offset); ++ else ++ value = rtw_read8(padapter, offset); ++ ++ value =value&GET_PWR_CFG_MASK(PwrCfgCmd); ++ if (value == (GET_PWR_CFG_VALUE(PwrCfgCmd) & GET_PWR_CFG_MASK(PwrCfgCmd))) ++ bPollingBit = true; ++ else ++ udelay(10); ++ ++ if (pollingCount++ > maxPollingCnt) { ++ DBG_871X("Fail to polling Offset[%#x]=%02x\n", offset, value); ++ return false; ++ } ++ } while (!bPollingBit); ++ ++ break; ++ ++ case PWR_CMD_DELAY: ++ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_DELAY\n")); ++ if (GET_PWR_CFG_VALUE(PwrCfgCmd) == PWRSEQ_DELAY_US) ++ udelay(GET_PWR_CFG_OFFSET(PwrCfgCmd)); ++ else ++ udelay(GET_PWR_CFG_OFFSET(PwrCfgCmd)*1000); ++ break; ++ ++ case PWR_CMD_END: ++ /* When this command is parsed, end the process */ ++ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_END\n")); ++ return true; ++ break; ++ ++ default: ++ RT_TRACE(_module_hal_init_c_ , _drv_err_, ("HalPwrSeqCmdParsing: Unknown CMD!!\n")); ++ break; ++ } ++ } ++ ++ AryIdx++;/* Add Array Index */ ++ }while (1); ++ ++ return true; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/hal_sdio.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/hal_sdio.c +--- linux-4.3/3rdparty/rtl8723bs/hal/hal_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/hal_sdio.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,106 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _HAL_SDIO_C_ ++ ++#include ++#include ++#include ++ ++u8 rtw_hal_sdio_max_txoqt_free_space(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ ++ if (pHalData->SdioTxOQTMaxFreeSpace < 8) ++ pHalData->SdioTxOQTMaxFreeSpace = 8; ++ ++ return pHalData->SdioTxOQTMaxFreeSpace; ++} ++ ++u8 rtw_hal_sdio_query_tx_freepage(struct adapter *padapter, u8 PageIdx, u8 RequiredPageNum) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ ++ if ((pHalData->SdioTxFIFOFreePage[PageIdx]+pHalData->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX]) >= (RequiredPageNum)) ++ return true; ++ else ++ return false; ++} ++ ++void rtw_hal_sdio_update_tx_freepage(struct adapter *padapter, u8 PageIdx, u8 RequiredPageNum) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ u8 DedicatedPgNum = 0; ++ u8 RequiredPublicFreePgNum = 0; ++ /* _irqL irql; */ ++ ++ /* spin_lock_bh(&pHalData->SdioTxFIFOFreePageLock); */ ++ ++ DedicatedPgNum = pHalData->SdioTxFIFOFreePage[PageIdx]; ++ if (RequiredPageNum <= DedicatedPgNum) { ++ pHalData->SdioTxFIFOFreePage[PageIdx] -= RequiredPageNum; ++ } else { ++ pHalData->SdioTxFIFOFreePage[PageIdx] = 0; ++ RequiredPublicFreePgNum = RequiredPageNum - DedicatedPgNum; ++ pHalData->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX] -= RequiredPublicFreePgNum; ++ } ++ ++ /* spin_unlock_bh(&pHalData->SdioTxFIFOFreePageLock); */ ++} ++ ++void rtw_hal_set_sdio_tx_max_length(struct adapter *padapter, u8 numHQ, u8 numNQ, u8 numLQ, u8 numPubQ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ u32 page_size; ++ u32 lenHQ, lenNQ, lenLQ; ++ ++ rtw_hal_get_def_var(padapter, HAL_DEF_TX_PAGE_SIZE,&page_size); ++ ++ lenHQ = ((numHQ + numPubQ) >> 1) * page_size; ++ lenNQ = ((numNQ + numPubQ) >> 1) * page_size; ++ lenLQ = ((numLQ + numPubQ) >> 1) * page_size; ++ ++ pHalData->sdio_tx_max_len[HI_QUEUE_IDX] = (lenHQ > MAX_XMITBUF_SZ)? MAX_XMITBUF_SZ:lenHQ; ++ pHalData->sdio_tx_max_len[MID_QUEUE_IDX] = (lenNQ > MAX_XMITBUF_SZ)? MAX_XMITBUF_SZ:lenNQ; ++ pHalData->sdio_tx_max_len[LOW_QUEUE_IDX] = (lenLQ > MAX_XMITBUF_SZ)? MAX_XMITBUF_SZ:lenLQ; ++} ++ ++u32 rtw_hal_get_sdio_tx_max_length(struct adapter *padapter, u8 queue_idx) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ u32 deviceId, max_len; ++ ++ ++ deviceId = ffaddr2deviceId(pdvobjpriv, queue_idx); ++ switch (deviceId) { ++ case WLAN_TX_HIQ_DEVICE_ID: ++ max_len = pHalData->sdio_tx_max_len[HI_QUEUE_IDX]; ++ break; ++ ++ case WLAN_TX_MIQ_DEVICE_ID: ++ max_len = pHalData->sdio_tx_max_len[MID_QUEUE_IDX]; ++ break; ++ ++ case WLAN_TX_LOQ_DEVICE_ID: ++ max_len = pHalData->sdio_tx_max_len[LOW_QUEUE_IDX]; ++ break; ++ ++ default: ++ max_len = pHalData->sdio_tx_max_len[MID_QUEUE_IDX]; ++ break; ++ } ++ ++ return max_len; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/Mp_Precomp.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/Mp_Precomp.h +--- linux-4.3/3rdparty/rtl8723bs/hal/Mp_Precomp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/Mp_Precomp.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,33 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2013 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __MP_PRECOMP_H__ ++#define __MP_PRECOMP_H__ ++ ++#include ++#include ++ ++#define BT_TMP_BUF_SIZE 100 ++ ++#define DCMD_Printf DBG_BT_INFO ++ ++#ifdef bEnable ++#undef bEnable ++#endif ++ ++#include "HalBtcOutSrc.h" ++#include "HalBtc8723b1Ant.h" ++#include "HalBtc8723b2Ant.h" ++ ++#endif /* __MP_PRECOMP_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_AntDiv.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_AntDiv.c +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_AntDiv.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_AntDiv.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,74 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++//============================================================ ++// include files ++//============================================================ ++ ++#include "odm_precomp.h" ++ ++//====================================================== ++// when antenna test utility is on or some testing need to disable antenna diversity ++// call this function to disable all ODM related mechanisms which will switch antenna. ++//====================================================== ++void ++ODM_StopAntennaSwitchDm( ++PDM_ODM_T pDM_Odm ++ ) ++{ ++ // disable ODM antenna diversity ++ pDM_Odm->SupportAbility &= ~ODM_BB_ANT_DIV; ++ ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("STOP Antenna Diversity\n")); ++} ++ ++void ++ODM_SetAntConfig( ++PDM_ODM_T pDM_Odm, ++u8 antSetting // 0=A, 1=B, 2=C, .... ++ ) ++{ ++ if(antSetting == 0) // ant A ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, 0x00000000); ++ else if(antSetting == 1) ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, 0x00000280); ++} ++ ++//====================================================== ++ ++ ++void ++ODM_SwAntDivRestAfterLink( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; ++ u32 i; ++ ++ pDM_Odm->RSSI_test = false; ++ pDM_SWAT_Table->try_flag = 0xff; ++ pDM_SWAT_Table->RSSI_Trying = 0; ++ pDM_SWAT_Table->Double_chk_flag= 0; ++ ++ pDM_FatTable->RxIdleAnt=MAIN_ANT; ++ ++ for (i=0; iMainAnt_Sum[i] = 0; ++ pDM_FatTable->AuxAnt_Sum[i] = 0; ++ pDM_FatTable->MainAnt_Cnt[i] = 0; ++ pDM_FatTable->AuxAnt_Cnt[i] = 0; ++ } ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_AntDiv.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_AntDiv.h +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_AntDiv.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_AntDiv.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,38 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#ifndef __ODMANTDIV_H__ ++#define __ODMANTDIV_H__ ++ ++ ++ ++#define ANT1_2G 0 /* = ANT2_5G */ ++#define ANT2_2G 1 /* = ANT1_5G */ ++ ++/* Antenna Diversty Control Type */ ++#define ODM_AUTO_ANT 0 ++#define ODM_FIX_MAIN_ANT 1 ++#define ODM_FIX_AUX_ANT 2 ++ ++#define TX_BY_REG 0 ++ ++#define ANTDIV_ON 1 ++#define ANTDIV_OFF 0 ++ ++#define INIT_ANTDIV_TIMMER 0 ++#define CANCEL_ANTDIV_TIMMER 1 ++#define RELEASE_ANTDIV_TIMMER 2 ++ ++#endif /* ifndef __ODMANTDIV_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm.c +--- linux-4.3/3rdparty/rtl8723bs/hal/odm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,1630 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#include "odm_precomp.h" ++ ++static const u16 dB_Invert_Table[8][12] = { ++ {1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4}, ++ {4, 5, 6, 6, 7, 8, 9, 10, 11, 13, 14, 16}, ++ {18, 20, 22, 25, 28, 32, 35, 40, 45, 50, 56, 63}, ++ {71, 79, 89, 100, 112, 126, 141, 158, 178, 200, 224, 251}, ++ {282, 316, 355, 398, 447, 501, 562, 631, 708, 794, 891, 1000}, ++ {1122, 1259, 1413, 1585, 1778, 1995, 2239, 2512, 2818, 3162, 3548, 3981}, ++ {4467, 5012, 5623, 6310, 7079, 7943, 8913, 10000, 11220, 12589, 14125, ++ 15849}, ++ {17783, 19953, 22387, 25119, 28184, 31623, 35481, 39811, 44668, 50119, ++ 56234, 65535}}; ++ ++/* Global var */ ++ ++u32 OFDMSwingTable[OFDM_TABLE_SIZE] = { ++ 0x7f8001fe, /* 0, +6.0dB */ ++ 0x788001e2, /* 1, +5.5dB */ ++ 0x71c001c7, /* 2, +5.0dB */ ++ 0x6b8001ae, /* 3, +4.5dB */ ++ 0x65400195, /* 4, +4.0dB */ ++ 0x5fc0017f, /* 5, +3.5dB */ ++ 0x5a400169, /* 6, +3.0dB */ ++ 0x55400155, /* 7, +2.5dB */ ++ 0x50800142, /* 8, +2.0dB */ ++ 0x4c000130, /* 9, +1.5dB */ ++ 0x47c0011f, /* 10, +1.0dB */ ++ 0x43c0010f, /* 11, +0.5dB */ ++ 0x40000100, /* 12, +0dB */ ++ 0x3c8000f2, /* 13, -0.5dB */ ++ 0x390000e4, /* 14, -1.0dB */ ++ 0x35c000d7, /* 15, -1.5dB */ ++ 0x32c000cb, /* 16, -2.0dB */ ++ 0x300000c0, /* 17, -2.5dB */ ++ 0x2d4000b5, /* 18, -3.0dB */ ++ 0x2ac000ab, /* 19, -3.5dB */ ++ 0x288000a2, /* 20, -4.0dB */ ++ 0x26000098, /* 21, -4.5dB */ ++ 0x24000090, /* 22, -5.0dB */ ++ 0x22000088, /* 23, -5.5dB */ ++ 0x20000080, /* 24, -6.0dB */ ++ 0x1e400079, /* 25, -6.5dB */ ++ 0x1c800072, /* 26, -7.0dB */ ++ 0x1b00006c, /* 27. -7.5dB */ ++ 0x19800066, /* 28, -8.0dB */ ++ 0x18000060, /* 29, -8.5dB */ ++ 0x16c0005b, /* 30, -9.0dB */ ++ 0x15800056, /* 31, -9.5dB */ ++ 0x14400051, /* 32, -10.0dB */ ++ 0x1300004c, /* 33, -10.5dB */ ++ 0x12000048, /* 34, -11.0dB */ ++ 0x11000044, /* 35, -11.5dB */ ++ 0x10000040, /* 36, -12.0dB */ ++}; ++ ++u8 CCKSwingTable_Ch1_Ch13[CCK_TABLE_SIZE][8] = { ++ {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, /* 0, +0dB */ ++ {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 1, -0.5dB */ ++ {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 2, -1.0dB */ ++ {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 3, -1.5dB */ ++ {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 4, -2.0dB */ ++ {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 5, -2.5dB */ ++ {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 6, -3.0dB */ ++ {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 7, -3.5dB */ ++ {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 8, -4.0dB */ ++ {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 9, -4.5dB */ ++ {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 10, -5.0dB */ ++ {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 11, -5.5dB */ ++ {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /* 12, -6.0dB <== default */ ++ {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 13, -6.5dB */ ++ {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 14, -7.0dB */ ++ {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 15, -7.5dB */ ++ {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */ ++ {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 17, -8.5dB */ ++ {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 18, -9.0dB */ ++ {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 19, -9.5dB */ ++ {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 20, -10.0dB */ ++ {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 21, -10.5dB */ ++ {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 22, -11.0dB */ ++ {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /* 23, -11.5dB */ ++ {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /* 24, -12.0dB */ ++ {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /* 25, -12.5dB */ ++ {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /* 26, -13.0dB */ ++ {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 27, -13.5dB */ ++ {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 28, -14.0dB */ ++ {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 29, -14.5dB */ ++ {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 30, -15.0dB */ ++ {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /* 31, -15.5dB */ ++ {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01} /* 32, -16.0dB */ ++}; ++ ++u8 CCKSwingTable_Ch14[CCK_TABLE_SIZE][8] = { ++ {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, /* 0, +0dB */ ++ {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 1, -0.5dB */ ++ {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 2, -1.0dB */ ++ {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /* 3, -1.5dB */ ++ {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 4, -2.0dB */ ++ {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /* 5, -2.5dB */ ++ {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 6, -3.0dB */ ++ {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 7, -3.5dB */ ++ {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 8, -4.0dB */ ++ {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /* 9, -4.5dB */ ++ {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 10, -5.0dB */ ++ {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 11, -5.5dB */ ++ {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 12, -6.0dB <== default */ ++ {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 13, -6.5dB */ ++ {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 14, -7.0dB */ ++ {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 15, -7.5dB */ ++ {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */ ++ {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 17, -8.5dB */ ++ {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 18, -9.0dB */ ++ {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 19, -9.5dB */ ++ {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 20, -10.0dB */ ++ {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 21, -10.5dB */ ++ {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 22, -11.0dB */ ++ {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 23, -11.5dB */ ++ {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 24, -12.0dB */ ++ {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 25, -12.5dB */ ++ {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 26, -13.0dB */ ++ {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 27, -13.5dB */ ++ {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 28, -14.0dB */ ++ {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 29, -14.5dB */ ++ {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 30, -15.0dB */ ++ {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 31, -15.5dB */ ++ {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} /* 32, -16.0dB */ ++}; ++ ++u32 OFDMSwingTable_New[OFDM_TABLE_SIZE] = { ++ 0x0b40002d, /* 0, -15.0dB */ ++ 0x0c000030, /* 1, -14.5dB */ ++ 0x0cc00033, /* 2, -14.0dB */ ++ 0x0d800036, /* 3, -13.5dB */ ++ 0x0e400039, /* 4, -13.0dB */ ++ 0x0f00003c, /* 5, -12.5dB */ ++ 0x10000040, /* 6, -12.0dB */ ++ 0x11000044, /* 7, -11.5dB */ ++ 0x12000048, /* 8, -11.0dB */ ++ 0x1300004c, /* 9, -10.5dB */ ++ 0x14400051, /* 10, -10.0dB */ ++ 0x15800056, /* 11, -9.5dB */ ++ 0x16c0005b, /* 12, -9.0dB */ ++ 0x18000060, /* 13, -8.5dB */ ++ 0x19800066, /* 14, -8.0dB */ ++ 0x1b00006c, /* 15, -7.5dB */ ++ 0x1c800072, /* 16, -7.0dB */ ++ 0x1e400079, /* 17, -6.5dB */ ++ 0x20000080, /* 18, -6.0dB */ ++ 0x22000088, /* 19, -5.5dB */ ++ 0x24000090, /* 20, -5.0dB */ ++ 0x26000098, /* 21, -4.5dB */ ++ 0x288000a2, /* 22, -4.0dB */ ++ 0x2ac000ab, /* 23, -3.5dB */ ++ 0x2d4000b5, /* 24, -3.0dB */ ++ 0x300000c0, /* 25, -2.5dB */ ++ 0x32c000cb, /* 26, -2.0dB */ ++ 0x35c000d7, /* 27, -1.5dB */ ++ 0x390000e4, /* 28, -1.0dB */ ++ 0x3c8000f2, /* 29, -0.5dB */ ++ 0x40000100, /* 30, +0dB */ ++ 0x43c0010f, /* 31, +0.5dB */ ++ 0x47c0011f, /* 32, +1.0dB */ ++ 0x4c000130, /* 33, +1.5dB */ ++ 0x50800142, /* 34, +2.0dB */ ++ 0x55400155, /* 35, +2.5dB */ ++ 0x5a400169, /* 36, +3.0dB */ ++ 0x5fc0017f, /* 37, +3.5dB */ ++ 0x65400195, /* 38, +4.0dB */ ++ 0x6b8001ae, /* 39, +4.5dB */ ++ 0x71c001c7, /* 40, +5.0dB */ ++ 0x788001e2, /* 41, +5.5dB */ ++ 0x7f8001fe /* 42, +6.0dB */ ++}; ++ ++u8 CCKSwingTable_Ch1_Ch13_New[CCK_TABLE_SIZE][8] = { ++ {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01}, /* 0, -16.0dB */ ++ {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /* 1, -15.5dB */ ++ {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 2, -15.0dB */ ++ {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 3, -14.5dB */ ++ {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 4, -14.0dB */ ++ {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 5, -13.5dB */ ++ {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /* 6, -13.0dB */ ++ {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /* 7, -12.5dB */ ++ {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /* 8, -12.0dB */ ++ {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /* 9, -11.5dB */ ++ {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 10, -11.0dB */ ++ {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 11, -10.5dB */ ++ {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 12, -10.0dB */ ++ {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 13, -9.5dB */ ++ {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 14, -9.0dB */ ++ {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 15, -8.5dB */ ++ {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */ ++ {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 17, -7.5dB */ ++ {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 18, -7.0dB */ ++ {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 19, -6.5dB */ ++ {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /* 20, -6.0dB */ ++ {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 21, -5.5dB */ ++ {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 22, -5.0dB */ ++ {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 23, -4.5dB */ ++ {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 24, -4.0dB */ ++ {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 25, -3.5dB */ ++ {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 26, -3.0dB */ ++ {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 27, -2.5dB */ ++ {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 28, -2.0dB */ ++ {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 29, -1.5dB */ ++ {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 30, -1.0dB */ ++ {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 31, -0.5dB */ ++ {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04} /* 32, +0dB */ ++}; ++ ++u8 CCKSwingTable_Ch14_New[CCK_TABLE_SIZE][8]= { ++ {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}, /* 0, -16.0dB */ ++ {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 1, -15.5dB */ ++ {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 2, -15.0dB */ ++ {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 3, -14.5dB */ ++ {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 4, -14.0dB */ ++ {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 5, -13.5dB */ ++ {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 6, -13.0dB */ ++ {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 7, -12.5dB */ ++ {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 8, -12.0dB */ ++ {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 9, -11.5dB */ ++ {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 10, -11.0dB */ ++ {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 11, -10.5dB */ ++ {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 12, -10.0dB */ ++ {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 13, -9.5dB */ ++ {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 14, -9.0dB */ ++ {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 15, -8.5dB */ ++ {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */ ++ {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 17, -7.5dB */ ++ {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 18, -7.0dB */ ++ {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 19, -6.5dB */ ++ {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 20, -6.0dB */ ++ {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 21, -5.5dB */ ++ {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 22, -5.0dB */ ++ {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /* 23, -4.5dB */ ++ {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 24, -4.0dB */ ++ {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 25, -3.5dB */ ++ {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 26, -3.0dB */ ++ {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /* 27, -2.5dB */ ++ {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 28, -2.0dB */ ++ {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /* 29, -1.5dB */ ++ {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 30, -1.0dB */ ++ {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 31, -0.5dB */ ++ {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00} /* 32, +0dB */ ++}; ++ ++u32 TxScalingTable_Jaguar[TXSCALE_TABLE_SIZE] = ++{ ++ 0x081, /* 0, -12.0dB */ ++ 0x088, /* 1, -11.5dB */ ++ 0x090, /* 2, -11.0dB */ ++ 0x099, /* 3, -10.5dB */ ++ 0x0A2, /* 4, -10.0dB */ ++ 0x0AC, /* 5, -9.5dB */ ++ 0x0B6, /* 6, -9.0dB */ ++ 0x0C0, /* 7, -8.5dB */ ++ 0x0CC, /* 8, -8.0dB */ ++ 0x0D8, /* 9, -7.5dB */ ++ 0x0E5, /* 10, -7.0dB */ ++ 0x0F2, /* 11, -6.5dB */ ++ 0x101, /* 12, -6.0dB */ ++ 0x110, /* 13, -5.5dB */ ++ 0x120, /* 14, -5.0dB */ ++ 0x131, /* 15, -4.5dB */ ++ 0x143, /* 16, -4.0dB */ ++ 0x156, /* 17, -3.5dB */ ++ 0x16A, /* 18, -3.0dB */ ++ 0x180, /* 19, -2.5dB */ ++ 0x197, /* 20, -2.0dB */ ++ 0x1AF, /* 21, -1.5dB */ ++ 0x1C8, /* 22, -1.0dB */ ++ 0x1E3, /* 23, -0.5dB */ ++ 0x200, /* 24, +0 dB */ ++ 0x21E, /* 25, +0.5dB */ ++ 0x23E, /* 26, +1.0dB */ ++ 0x261, /* 27, +1.5dB */ ++ 0x285, /* 28, +2.0dB */ ++ 0x2AB, /* 29, +2.5dB */ ++ 0x2D3, /* 30, +3.0dB */ ++ 0x2FE, /* 31, +3.5dB */ ++ 0x32B, /* 32, +4.0dB */ ++ 0x35C, /* 33, +4.5dB */ ++ 0x38E, /* 34, +5.0dB */ ++ 0x3C4, /* 35, +5.5dB */ ++ 0x3FE /* 36, +6.0dB */ ++}; ++ ++/* Local Function predefine. */ ++ ++/* START------------COMMON INFO RELATED--------------- */ ++void ++odm_CommonInfoSelfInit( ++ PDM_ODM_T pDM_Odm ++ ); ++ ++void ++odm_CommonInfoSelfUpdate( ++ PDM_ODM_T pDM_Odm ++ ); ++ ++void ++odm_CmnInfoInit_Debug( ++ PDM_ODM_T pDM_Odm ++ ); ++ ++void ++odm_BasicDbgMessage ++( ++ PDM_ODM_T pDM_Odm ++ ); ++ ++/* END------------COMMON INFO RELATED--------------- */ ++ ++/* START---------------DIG--------------------------- */ ++ ++/* Remove by Yuchen */ ++ ++/* END---------------DIG--------------------------- */ ++ ++/* START-------BB POWER SAVE----------------------- */ ++/* Remove BB power Saving by YuChen */ ++/* END---------BB POWER SAVE----------------------- */ ++ ++void ++odm_RefreshRateAdaptiveMaskCE( ++ PDM_ODM_T pDM_Odm ++ ); ++ ++/* Remove by YuChen */ ++ ++void ++odm_RSSIMonitorInit( ++PDM_ODM_T pDM_Odm ++ ); ++ ++void ++odm_RSSIMonitorCheckCE( ++ PDM_ODM_T pDM_Odm ++ ); ++ ++void ++odm_RSSIMonitorCheck( ++ PDM_ODM_T pDM_Odm ++ ); ++ ++void ++odm_SwAntDetectInit( ++ PDM_ODM_T pDM_Odm ++ ); ++ ++void odm_SwAntDivChkAntSwitchCallback(void *FunctionContext); ++ ++ ++ ++void ++odm_GlobalAdapterCheck( ++ void ++ ); ++ ++void ++odm_RefreshRateAdaptiveMask( ++ PDM_ODM_T pDM_Odm ++ ); ++ ++void ++ODM_TXPowerTrackingCheck( ++ PDM_ODM_T pDM_Odm ++ ); ++ ++void ++odm_RateAdaptiveMaskInit( ++PDM_ODM_T pDM_Odm ++ ); ++ ++void ++odm_TXPowerTrackingThermalMeterInit( ++PDM_ODM_T pDM_Odm ++ ); ++ ++ ++void ++odm_TXPowerTrackingInit( ++PDM_ODM_T pDM_Odm ++ ); ++ ++void ++odm_TXPowerTrackingCheckCE( ++PDM_ODM_T pDM_Odm ++ ); ++ ++/* Remove Edca by Yu Chen */ ++ ++ ++#define RxDefaultAnt1 0x65a9 ++#define RxDefaultAnt2 0x569a ++ ++void ++odm_InitHybridAntDiv( ++ PDM_ODM_T pDM_Odm ++ ); ++ ++bool ++odm_StaDefAntSel( ++ PDM_ODM_T pDM_Odm, ++ u32 OFDM_Ant1_Cnt, ++ u32 OFDM_Ant2_Cnt, ++ u32 CCK_Ant1_Cnt, ++ u32 CCK_Ant2_Cnt, ++ u8 *pDefAnt ++ ); ++ ++void ++odm_SetRxIdleAnt( ++PDM_ODM_T pDM_Odm, ++u8 Ant, ++ bool bDualPath ++); ++ ++ ++ ++void ++odm_HwAntDiv( ++PDM_ODM_T pDM_Odm ++); ++ ++ ++/* */ ++/* 3 Export Interface */ ++/* */ ++ ++/* */ ++/* 2011/09/21 MH Add to describe different team necessary resource allocate?? */ ++/* */ ++void ++ODM_DMInit( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ ++ odm_CommonInfoSelfInit(pDM_Odm); ++ odm_CmnInfoInit_Debug(pDM_Odm); ++ odm_DIGInit(pDM_Odm); ++ odm_NHMCounterStatisticsInit(pDM_Odm); ++ odm_AdaptivityInit(pDM_Odm); ++ odm_RateAdaptiveMaskInit(pDM_Odm); ++ ODM_CfoTrackingInit(pDM_Odm); ++ ODM_EdcaTurboInit(pDM_Odm); ++ odm_RSSIMonitorInit(pDM_Odm); ++ odm_TXPowerTrackingInit(pDM_Odm); ++ ++ ODM_ClearTxPowerTrackingState(pDM_Odm); ++ ++ if (*(pDM_Odm->mp_mode) != 1) ++ odm_PathDiversityInit(pDM_Odm); ++ ++ odm_DynamicBBPowerSavingInit(pDM_Odm); ++ odm_DynamicTxPowerInit(pDM_Odm); ++ ++ odm_SwAntDetectInit(pDM_Odm); ++} ++ ++/* */ ++/* 2011/09/20 MH This is the entry pointer for all team to execute HW out source DM. */ ++/* You can not add any dummy function here, be care, you can only use DM structure */ ++/* to perform any new ODM_DM. */ ++/* */ ++void ++ODM_DMWatchdog( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ odm_CommonInfoSelfUpdate(pDM_Odm); ++ odm_BasicDbgMessage(pDM_Odm); ++ odm_FalseAlarmCounterStatistics(pDM_Odm); ++ odm_NHMCounterStatistics(pDM_Odm); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): RSSI = 0x%x\n", pDM_Odm->RSSI_Min)); ++ ++ odm_RSSIMonitorCheck(pDM_Odm); ++ ++ /* For CE Platform(SPRD or Tablet) */ ++ /* 8723A or 8189ES platform */ ++ /* NeilChen--2012--08--24-- */ ++ /* Fix Leave LPS issue */ ++ if ((adapter_to_pwrctl(pDM_Odm->Adapter)->pwr_mode != PS_MODE_ACTIVE) /* in LPS mode */ ++ /* */ ++ /* (pDM_Odm->SupportICType & (ODM_RTL8723A))|| */ ++ /* (pDM_Odm->SupportICType & (ODM_RTL8188E) &&(&&(((pDM_Odm->SupportInterface == ODM_ITRF_SDIO))) */ ++ /* */ ++ ) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("----Step1: odm_DIG is in LPS mode\n")); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("---Step2: 8723AS is in LPS mode\n")); ++ odm_DIGbyRSSI_LPS(pDM_Odm); ++ } ++ else ++ { ++ odm_DIG(pDM_Odm); ++ } ++ ++ { ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ odm_Adaptivity(pDM_Odm, pDM_DigTable->CurIGValue); ++ } ++ odm_CCKPacketDetectionThresh(pDM_Odm); ++ ++ if (*(pDM_Odm->pbPowerSaving) ==true) ++ return; ++ ++ ++ odm_RefreshRateAdaptiveMask(pDM_Odm); ++ odm_EdcaTurboCheck(pDM_Odm); ++ odm_PathDiversity(pDM_Odm); ++ ODM_CfoTracking(pDM_Odm); ++ ++ ODM_TXPowerTrackingCheck(pDM_Odm); ++ ++ /* odm_EdcaTurboCheck(pDM_Odm); */ ++ ++ /* 2010.05.30 LukeLee: For CE platform, files in IC subfolders may not be included to be compiled, */ ++ /* so compile flags must be left here to prevent from compile errors */ ++ pDM_Odm->PhyDbgInfo.NumQryBeaconPkt = 0; ++} ++ ++ ++/* */ ++/* Init /.. Fixed HW value. Only init time. */ ++/* */ ++void ++ODM_CmnInfoInit( ++ PDM_ODM_T pDM_Odm, ++ ODM_CMNINFO_E CmnInfo, ++ u32 Value ++ ) ++{ ++ /* */ ++ /* This section is used for init value */ ++ /* */ ++ switch (CmnInfo) ++ { ++ /* */ ++ /* Fixed ODM value. */ ++ /* */ ++ case ODM_CMNINFO_ABILITY: ++ pDM_Odm->SupportAbility = (u32)Value; ++ break; ++ ++ case ODM_CMNINFO_RF_TYPE: ++ pDM_Odm->RFType = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_PLATFORM: ++ pDM_Odm->SupportPlatform = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_INTERFACE: ++ pDM_Odm->SupportInterface = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_MP_TEST_CHIP: ++ pDM_Odm->bIsMPChip = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_IC_TYPE: ++ pDM_Odm->SupportICType = Value; ++ break; ++ ++ case ODM_CMNINFO_CUT_VER: ++ pDM_Odm->CutVersion = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_FAB_VER: ++ pDM_Odm->FabVersion = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_RFE_TYPE: ++ pDM_Odm->RFEType = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_RF_ANTENNA_TYPE: ++ pDM_Odm->AntDivType = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_BOARD_TYPE: ++ pDM_Odm->BoardType = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_PACKAGE_TYPE: ++ pDM_Odm->PackageType = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_EXT_LNA: ++ pDM_Odm->ExtLNA = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_5G_EXT_LNA: ++ pDM_Odm->ExtLNA5G = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_EXT_PA: ++ pDM_Odm->ExtPA = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_5G_EXT_PA: ++ pDM_Odm->ExtPA5G = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_GPA: ++ pDM_Odm->TypeGPA = (ODM_TYPE_GPA_E)Value; ++ break; ++ case ODM_CMNINFO_APA: ++ pDM_Odm->TypeAPA = (ODM_TYPE_APA_E)Value; ++ break; ++ case ODM_CMNINFO_GLNA: ++ pDM_Odm->TypeGLNA = (ODM_TYPE_GLNA_E)Value; ++ break; ++ case ODM_CMNINFO_ALNA: ++ pDM_Odm->TypeALNA = (ODM_TYPE_ALNA_E)Value; ++ break; ++ ++ case ODM_CMNINFO_EXT_TRSW: ++ pDM_Odm->ExtTRSW = (u8)Value; ++ break; ++ case ODM_CMNINFO_PATCH_ID: ++ pDM_Odm->PatchID = (u8)Value; ++ break; ++ case ODM_CMNINFO_BINHCT_TEST: ++ pDM_Odm->bInHctTest = (bool)Value; ++ break; ++ case ODM_CMNINFO_BWIFI_TEST: ++ pDM_Odm->bWIFITest = (bool)Value; ++ break; ++ ++ case ODM_CMNINFO_SMART_CONCURRENT: ++ pDM_Odm->bDualMacSmartConcurrent = (bool)Value; ++ break; ++ ++ /* To remove the compiler warning, must add an empty default statement to handle the other values. */ ++ default: ++ /* do nothing */ ++ break; ++ ++ } ++ ++} ++ ++ ++void ++ODM_CmnInfoHook( ++ PDM_ODM_T pDM_Odm, ++ ODM_CMNINFO_E CmnInfo, ++ void * pValue ++ ) ++{ ++ /* */ ++ /* Hook call by reference pointer. */ ++ /* */ ++ switch (CmnInfo) ++ { ++ /* */ ++ /* Dynamic call by reference pointer. */ ++ /* */ ++ case ODM_CMNINFO_MAC_PHY_MODE: ++ pDM_Odm->pMacPhyMode = (u8 *)pValue; ++ break; ++ ++ case ODM_CMNINFO_TX_UNI: ++ pDM_Odm->pNumTxBytesUnicast = (u64 *)pValue; ++ break; ++ ++ case ODM_CMNINFO_RX_UNI: ++ pDM_Odm->pNumRxBytesUnicast = (u64 *)pValue; ++ break; ++ ++ case ODM_CMNINFO_WM_MODE: ++ pDM_Odm->pwirelessmode = (u8 *)pValue; ++ break; ++ ++ case ODM_CMNINFO_BAND: ++ pDM_Odm->pBandType = (u8 *)pValue; ++ break; ++ ++ case ODM_CMNINFO_SEC_CHNL_OFFSET: ++ pDM_Odm->pSecChOffset = (u8 *)pValue; ++ break; ++ ++ case ODM_CMNINFO_SEC_MODE: ++ pDM_Odm->pSecurity = (u8 *)pValue; ++ break; ++ ++ case ODM_CMNINFO_BW: ++ pDM_Odm->pBandWidth = (u8 *)pValue; ++ break; ++ ++ case ODM_CMNINFO_CHNL: ++ pDM_Odm->pChannel = (u8 *)pValue; ++ break; ++ ++ case ODM_CMNINFO_DMSP_GET_VALUE: ++ pDM_Odm->pbGetValueFromOtherMac = (bool *)pValue; ++ break; ++ ++ case ODM_CMNINFO_BUDDY_ADAPTOR: ++ pDM_Odm->pBuddyAdapter = (struct adapter * *)pValue; ++ break; ++ ++ case ODM_CMNINFO_DMSP_IS_MASTER: ++ pDM_Odm->pbMasterOfDMSP = (bool *)pValue; ++ break; ++ ++ case ODM_CMNINFO_SCAN: ++ pDM_Odm->pbScanInProcess = (bool *)pValue; ++ break; ++ ++ case ODM_CMNINFO_POWER_SAVING: ++ pDM_Odm->pbPowerSaving = (bool *)pValue; ++ break; ++ ++ case ODM_CMNINFO_ONE_PATH_CCA: ++ pDM_Odm->pOnePathCCA = (u8 *)pValue; ++ break; ++ ++ case ODM_CMNINFO_DRV_STOP: ++ pDM_Odm->pbDriverStopped = (bool *)pValue; ++ break; ++ ++ case ODM_CMNINFO_PNP_IN: ++ pDM_Odm->pbDriverIsGoingToPnpSetPowerSleep = (bool *)pValue; ++ break; ++ ++ case ODM_CMNINFO_INIT_ON: ++ pDM_Odm->pinit_adpt_in_progress = (bool *)pValue; ++ break; ++ ++ case ODM_CMNINFO_ANT_TEST: ++ pDM_Odm->pAntennaTest = (u8 *)pValue; ++ break; ++ ++ case ODM_CMNINFO_NET_CLOSED: ++ pDM_Odm->pbNet_closed = (bool *)pValue; ++ break; ++ ++ case ODM_CMNINFO_FORCED_RATE: ++ pDM_Odm->pForcedDataRate = (u16 *)pValue; ++ break; ++ ++ case ODM_CMNINFO_FORCED_IGI_LB: ++ pDM_Odm->pu1ForcedIgiLb = (u8 *)pValue; ++ break; ++ ++ case ODM_CMNINFO_MP_MODE: ++ pDM_Odm->mp_mode = (u8 *)pValue; ++ break; ++ ++ /* case ODM_CMNINFO_RTSTA_AID: */ ++ /* pDM_Odm->pAidMap = (u8 *)pValue; */ ++ /* break; */ ++ ++ /* case ODM_CMNINFO_BT_COEXIST: */ ++ /* pDM_Odm->BTCoexist = (bool *)pValue; */ ++ ++ /* case ODM_CMNINFO_STA_STATUS: */ ++ /* pDM_Odm->pODM_StaInfo[] = (PSTA_INFO_T)pValue; */ ++ /* break; */ ++ ++ /* case ODM_CMNINFO_PHY_STATUS: */ ++ /* pDM_Odm->pPhyInfo = (ODM_PHY_INFO *)pValue; */ ++ /* break; */ ++ ++ /* case ODM_CMNINFO_MAC_STATUS: */ ++ /* pDM_Odm->pMacInfo = (ODM_MAC_INFO *)pValue; */ ++ /* break; */ ++ /* To remove the compiler warning, must add an empty default statement to handle the other values. */ ++ default: ++ /* do nothing */ ++ break; ++ ++ } ++ ++} ++ ++ ++void ++ODM_CmnInfoPtrArrayHook( ++ PDM_ODM_T pDM_Odm, ++ ODM_CMNINFO_E CmnInfo, ++ u16 Index, ++ void * pValue ++ ) ++{ ++ /* */ ++ /* Hook call by reference pointer. */ ++ /* */ ++ switch (CmnInfo) ++ { ++ /* */ ++ /* Dynamic call by reference pointer. */ ++ /* */ ++ case ODM_CMNINFO_STA_STATUS: ++ pDM_Odm->pODM_StaInfo[Index] = (PSTA_INFO_T)pValue; ++ break; ++ /* To remove the compiler warning, must add an empty default statement to handle the other values. */ ++ default: ++ /* do nothing */ ++ break; ++ } ++ ++} ++ ++ ++/* */ ++/* Update Band/CHannel/.. The values are dynamic but non-per-packet. */ ++/* */ ++void ++ODM_CmnInfoUpdate( ++ PDM_ODM_T pDM_Odm, ++ u32 CmnInfo, ++ u64 Value ++ ) ++{ ++ /* */ ++ /* This init variable may be changed in run time. */ ++ /* */ ++ switch (CmnInfo) ++ { ++ case ODM_CMNINFO_LINK_IN_PROGRESS: ++ pDM_Odm->bLinkInProcess = (bool)Value; ++ break; ++ ++ case ODM_CMNINFO_ABILITY: ++ pDM_Odm->SupportAbility = (u32)Value; ++ break; ++ ++ case ODM_CMNINFO_RF_TYPE: ++ pDM_Odm->RFType = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_WIFI_DIRECT: ++ pDM_Odm->bWIFI_Direct = (bool)Value; ++ break; ++ ++ case ODM_CMNINFO_WIFI_DISPLAY: ++ pDM_Odm->bWIFI_Display = (bool)Value; ++ break; ++ ++ case ODM_CMNINFO_LINK: ++ pDM_Odm->bLinked = (bool)Value; ++ break; ++ ++ case ODM_CMNINFO_STATION_STATE: ++ pDM_Odm->bsta_state = (bool)Value; ++ break; ++ ++ case ODM_CMNINFO_RSSI_MIN: ++ pDM_Odm->RSSI_Min = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_DBG_COMP: ++ pDM_Odm->DebugComponents = Value; ++ break; ++ ++ case ODM_CMNINFO_DBG_LEVEL: ++ pDM_Odm->DebugLevel = (u32)Value; ++ break; ++ case ODM_CMNINFO_RA_THRESHOLD_HIGH: ++ pDM_Odm->RateAdaptive.HighRSSIThresh = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_RA_THRESHOLD_LOW: ++ pDM_Odm->RateAdaptive.LowRSSIThresh = (u8)Value; ++ break; ++ /* The following is for BT HS mode and BT coexist mechanism. */ ++ case ODM_CMNINFO_BT_ENABLED: ++ pDM_Odm->bBtEnabled = (bool)Value; ++ break; ++ ++ case ODM_CMNINFO_BT_HS_CONNECT_PROCESS: ++ pDM_Odm->bBtConnectProcess = (bool)Value; ++ break; ++ ++ case ODM_CMNINFO_BT_HS_RSSI: ++ pDM_Odm->btHsRssi = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_BT_OPERATION: ++ pDM_Odm->bBtHsOperation = (bool)Value; ++ break; ++ ++ case ODM_CMNINFO_BT_LIMITED_DIG: ++ pDM_Odm->bBtLimitedDig = (bool)Value; ++ break; ++ ++ case ODM_CMNINFO_BT_DISABLE_EDCA: ++ pDM_Odm->bBtDisableEdcaTurbo = (bool)Value; ++ break; ++ ++/* ++ case ODM_CMNINFO_OP_MODE: ++ pDM_Odm->OPMode = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_WM_MODE: ++ pDM_Odm->WirelessMode = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_BAND: ++ pDM_Odm->BandType = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_SEC_CHNL_OFFSET: ++ pDM_Odm->SecChOffset = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_SEC_MODE: ++ pDM_Odm->Security = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_BW: ++ pDM_Odm->BandWidth = (u8)Value; ++ break; ++ ++ case ODM_CMNINFO_CHNL: ++ pDM_Odm->Channel = (u8)Value; ++ break; ++*/ ++ default: ++ /* do nothing */ ++ break; ++ } ++ ++ ++} ++ ++void ++odm_CommonInfoSelfInit( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ pDM_Odm->bCckHighPower = (bool) PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG(CCK_RPT_FORMAT, pDM_Odm), ODM_BIT(CCK_RPT_FORMAT, pDM_Odm)); ++ pDM_Odm->RFPathRxEnable = (u8) PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG(BB_RX_PATH, pDM_Odm), ODM_BIT(BB_RX_PATH, pDM_Odm)); ++ ++ ODM_InitDebugSetting(pDM_Odm); ++ ++ pDM_Odm->TxRate = 0xFF; ++} ++ ++void ++odm_CommonInfoSelfUpdate( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ u8 EntryCnt = 0; ++ u8 i; ++ PSTA_INFO_T pEntry; ++ ++ if (*(pDM_Odm->pBandWidth) == ODM_BW40M) ++ { ++ if (*(pDM_Odm->pSecChOffset) == 1) ++ pDM_Odm->ControlChannel = *(pDM_Odm->pChannel) -2; ++ else if (*(pDM_Odm->pSecChOffset) == 2) ++ pDM_Odm->ControlChannel = *(pDM_Odm->pChannel) +2; ++ } ++ else ++ pDM_Odm->ControlChannel = *(pDM_Odm->pChannel); ++ ++ for (i = 0; ipODM_StaInfo[i]; ++ if (IS_STA_VALID(pEntry)) ++ EntryCnt++; ++ } ++ if (EntryCnt == 1) ++ pDM_Odm->bOneEntryOnly = true; ++ else ++ pDM_Odm->bOneEntryOnly = false; ++} ++ ++void ++odm_CmnInfoInit_Debug( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoInit_Debug ==>\n")); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportPlatform =%d\n", pDM_Odm->SupportPlatform)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportAbility = 0x%x\n", pDM_Odm->SupportAbility)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportInterface =%d\n", pDM_Odm->SupportInterface)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportICType = 0x%x\n", pDM_Odm->SupportICType)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("CutVersion =%d\n", pDM_Odm->CutVersion)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("FabVersion =%d\n", pDM_Odm->FabVersion)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RFType =%d\n", pDM_Odm->RFType)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("BoardType =%d\n", pDM_Odm->BoardType)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtLNA =%d\n", pDM_Odm->ExtLNA)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtPA =%d\n", pDM_Odm->ExtPA)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtTRSW =%d\n", pDM_Odm->ExtTRSW)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("PatchID =%d\n", pDM_Odm->PatchID)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bInHctTest =%d\n", pDM_Odm->bInHctTest)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFITest =%d\n", pDM_Odm->bWIFITest)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bDualMacSmartConcurrent =%d\n", pDM_Odm->bDualMacSmartConcurrent)); ++ ++} ++ ++void ++odm_BasicDbgMessage ++( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_BasicDbgMsg ==>\n")); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bLinked = %d, RSSI_Min = %d,\n", ++ pDM_Odm->bLinked, pDM_Odm->RSSI_Min)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RxRate = 0x%x, RSSI_A = %d, RSSI_B = %d\n", ++ pDM_Odm->RxRate, pDM_Odm->RSSI_A, pDM_Odm->RSSI_B)); ++} ++ ++/* 3 ============================================================ */ ++/* 3 DIG */ ++/* 3 ============================================================ */ ++/*----------------------------------------------------------------------------- ++ * Function: odm_DIGInit() ++ * ++ * Overview: Set DIG scheme init value. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ *When Who Remark ++ * ++ *---------------------------------------------------------------------------*/ ++ ++/* Remove DIG by yuchen */ ++ ++/* Remove DIG and FA check by Yu Chen */ ++ ++ ++/* 3 ============================================================ */ ++/* 3 BB Power Save */ ++/* 3 ============================================================ */ ++ ++/* Remove BB power saving by Yuchen */ ++ ++/* 3 ============================================================ */ ++/* 3 RATR MASK */ ++/* 3 ============================================================ */ ++/* 3 ============================================================ */ ++/* 3 Rate Adaptive */ ++/* 3 ============================================================ */ ++ ++void ++odm_RateAdaptiveMaskInit( ++PDM_ODM_T pDM_Odm ++ ) ++{ ++ PODM_RATE_ADAPTIVE pOdmRA = &pDM_Odm->RateAdaptive; ++ ++ pOdmRA->Type = DM_Type_ByDriver; ++ if (pOdmRA->Type == DM_Type_ByDriver) ++ pDM_Odm->bUseRAMask = true; ++ else ++ pDM_Odm->bUseRAMask = false; ++ ++ pOdmRA->RATRState = DM_RATR_STA_INIT; ++ pOdmRA->LdpcThres = 35; ++ pOdmRA->bUseLdpc = false; ++ pOdmRA->HighRSSIThresh = 50; ++ pOdmRA->LowRSSIThresh = 20; ++} ++ ++u32 ODM_Get_Rate_Bitmap( ++PDM_ODM_T pDM_Odm, ++u32 macid, ++u32 ra_mask, ++u8 rssi_level) ++{ ++ PSTA_INFO_T pEntry; ++ u32 rate_bitmap = 0; ++ u8 WirelessMode; ++ ++ pEntry = pDM_Odm->pODM_StaInfo[macid]; ++ if (!IS_STA_VALID(pEntry)) ++ return ra_mask; ++ ++ WirelessMode = pEntry->wireless_mode; ++ ++ switch (WirelessMode) ++ { ++ case ODM_WM_B: ++ if (ra_mask & 0x0000000c) /* 11M or 5.5M enable */ ++ rate_bitmap = 0x0000000d; ++ else ++ rate_bitmap = 0x0000000f; ++ break; ++ ++ case (ODM_WM_G): ++ case (ODM_WM_A): ++ if (rssi_level == DM_RATR_STA_HIGH) ++ rate_bitmap = 0x00000f00; ++ else ++ rate_bitmap = 0x00000ff0; ++ break; ++ ++ case (ODM_WM_B|ODM_WM_G): ++ if (rssi_level == DM_RATR_STA_HIGH) ++ rate_bitmap = 0x00000f00; ++ else if (rssi_level == DM_RATR_STA_MIDDLE) ++ rate_bitmap = 0x00000ff0; ++ else ++ rate_bitmap = 0x00000ff5; ++ break; ++ ++ case (ODM_WM_B|ODM_WM_G|ODM_WM_N24G) : ++ case (ODM_WM_B|ODM_WM_N24G) : ++ case (ODM_WM_G|ODM_WM_N24G) : ++ case (ODM_WM_A|ODM_WM_N5G) : ++ { ++ if (pDM_Odm->RFType == ODM_1T2R ||pDM_Odm->RFType == ODM_1T1R) ++ { ++ if (rssi_level == DM_RATR_STA_HIGH) ++ { ++ rate_bitmap = 0x000f0000; ++ } ++ else if (rssi_level == DM_RATR_STA_MIDDLE) ++ { ++ rate_bitmap = 0x000ff000; ++ } ++ else { ++ if (*(pDM_Odm->pBandWidth) == ODM_BW40M) ++ rate_bitmap = 0x000ff015; ++ else ++ rate_bitmap = 0x000ff005; ++ } ++ } ++ else ++ { ++ if (rssi_level == DM_RATR_STA_HIGH) ++ { ++ rate_bitmap = 0x0f8f0000; ++ } ++ else if (rssi_level == DM_RATR_STA_MIDDLE) ++ { ++ rate_bitmap = 0x0f8ff000; ++ } ++ else ++ { ++ if (*(pDM_Odm->pBandWidth) == ODM_BW40M) ++ rate_bitmap = 0x0f8ff015; ++ else ++ rate_bitmap = 0x0f8ff005; ++ } ++ } ++ } ++ break; ++ ++ case (ODM_WM_AC|ODM_WM_G): ++ if (rssi_level == 1) ++ rate_bitmap = 0xfc3f0000; ++ else if (rssi_level == 2) ++ rate_bitmap = 0xfffff000; ++ else ++ rate_bitmap = 0xffffffff; ++ break; ++ ++ case (ODM_WM_AC|ODM_WM_A): ++ ++ if (pDM_Odm->RFType == RF_1T1R) ++ { ++ if (rssi_level == 1) /* add by Gary for ac-series */ ++ rate_bitmap = 0x003f8000; ++ else if (rssi_level == 2) ++ rate_bitmap = 0x003ff000; ++ else ++ rate_bitmap = 0x003ff010; ++ } ++ else ++ { ++ if (rssi_level == 1) /* add by Gary for ac-series */ ++ rate_bitmap = 0xfe3f8000; /* VHT 2SS MCS3~9 */ ++ else if (rssi_level == 2) ++ rate_bitmap = 0xfffff000; /* VHT 2SS MCS0~9 */ ++ else ++ rate_bitmap = 0xfffff010; /* All */ ++ } ++ break; ++ ++ default: ++ if (pDM_Odm->RFType == RF_1T2R) ++ rate_bitmap = 0x000fffff; ++ else ++ rate_bitmap = 0x0fffffff; ++ break; ++ ++ } ++ ++ /* printk("%s ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x\n", __func__, rssi_level, WirelessMode, rate_bitmap); */ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, (" ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x\n", rssi_level, WirelessMode, rate_bitmap)); ++ ++ return (ra_mask&rate_bitmap); ++ ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: odm_RefreshRateAdaptiveMask() ++ * ++ * Overview: Update rate table mask according to rssi ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ *When Who Remark ++ *05/27/2009 hpfan Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++void ++odm_RefreshRateAdaptiveMask( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("odm_RefreshRateAdaptiveMask()---------->\n")); ++ if (!(pDM_Odm->SupportAbility & ODM_BB_RA_MASK)) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("odm_RefreshRateAdaptiveMask(): Return cos not supported\n")); ++ return; ++ } ++ odm_RefreshRateAdaptiveMaskCE(pDM_Odm); ++} ++ ++void ++odm_RefreshRateAdaptiveMaskCE( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ u8 i; ++ struct adapter *padapter = pDM_Odm->Adapter; ++ ++ if (padapter->bDriverStopped) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("<---- odm_RefreshRateAdaptiveMask(): driver is going to unload\n")); ++ return; ++ } ++ ++ if (!pDM_Odm->bUseRAMask) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("<---- odm_RefreshRateAdaptiveMask(): driver does not control rate adaptive mask\n")); ++ return; ++ } ++ ++ /* printk("==> %s\n", __func__); */ ++ ++ for (i = 0; ipODM_StaInfo[i]; ++ if (IS_STA_VALID(pstat)) { ++ if (IS_MCAST(pstat->hwaddr)) /* if (psta->mac_id == 1) */ ++ continue; ++ if (IS_MCAST(pstat->hwaddr)) ++ continue; ++ ++ if (true == ODM_RAStateCheck(pDM_Odm, pstat->rssi_stat.UndecoratedSmoothedPWDB, false , &pstat->rssi_level)) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI:%d, RSSI_LEVEL:%d\n", pstat->rssi_stat.UndecoratedSmoothedPWDB, pstat->rssi_level)); ++ /* printk("RSSI:%d, RSSI_LEVEL:%d\n", pstat->rssi_stat.UndecoratedSmoothedPWDB, pstat->rssi_level); */ ++ rtw_hal_update_ra_mask(pstat, pstat->rssi_level); ++ } ++ ++ } ++ } ++} ++ ++/* Return Value: bool */ ++/* - true: RATRState is changed. */ ++bool ++ODM_RAStateCheck( ++ PDM_ODM_T pDM_Odm, ++ s32 RSSI, ++ bool bForceUpdate, ++ u8 * pRATRState ++ ) ++{ ++ PODM_RATE_ADAPTIVE pRA = &pDM_Odm->RateAdaptive; ++ const u8 GoUpGap = 5; ++ u8 HighRSSIThreshForRA = pRA->HighRSSIThresh; ++ u8 LowRSSIThreshForRA = pRA->LowRSSIThresh; ++ u8 RATRState; ++ ++ /* Threshold Adjustment: */ ++ /* when RSSI state trends to go up one or two levels, make sure RSSI is high enough. */ ++ /* Here GoUpGap is added to solve the boundary's level alternation issue. */ ++ switch (*pRATRState) ++ { ++ case DM_RATR_STA_INIT: ++ case DM_RATR_STA_HIGH: ++ break; ++ ++ case DM_RATR_STA_MIDDLE: ++ HighRSSIThreshForRA += GoUpGap; ++ break; ++ ++ case DM_RATR_STA_LOW: ++ HighRSSIThreshForRA += GoUpGap; ++ LowRSSIThreshForRA += GoUpGap; ++ break; ++ ++ default: ++ ODM_RT_ASSERT(pDM_Odm, false, ("wrong rssi level setting %d !", *pRATRState)); ++ break; ++ } ++ ++ /* Decide RATRState by RSSI. */ ++ if (RSSI > HighRSSIThreshForRA) ++ RATRState = DM_RATR_STA_HIGH; ++ else if (RSSI > LowRSSIThreshForRA) ++ RATRState = DM_RATR_STA_MIDDLE; ++ else ++ RATRState = DM_RATR_STA_LOW; ++ /* printk("==>%s, RATRState:0x%02x , RSSI:%d\n", __func__, RATRState, RSSI); */ ++ ++ if (*pRATRState!=RATRState || bForceUpdate) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI Level %d -> %d\n", *pRATRState, RATRState)); ++ *pRATRState = RATRState; ++ return true; ++ } ++ ++ return false; ++} ++ ++ ++/* */ ++ ++/* 3 ============================================================ */ ++/* 3 Dynamic Tx Power */ ++/* 3 ============================================================ */ ++ ++/* Remove BY YuChen */ ++ ++/* 3 ============================================================ */ ++/* 3 RSSI Monitor */ ++/* 3 ============================================================ */ ++ ++void ++odm_RSSIMonitorInit( ++PDM_ODM_T pDM_Odm ++ ) ++{ ++ pRA_T pRA_Table = &pDM_Odm->DM_RA_Table; ++ ++ pRA_Table->firstconnect = false; ++ ++} ++ ++void ++odm_RSSIMonitorCheck( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_RSSI_MONITOR)) ++ return; ++ ++ odm_RSSIMonitorCheckCE(pDM_Odm); ++ ++} /* odm_RSSIMonitorCheck */ ++ ++static void FindMinimumRSSI(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); ++ ++ /* 1 1.Determine the minimum RSSI */ ++ ++ if ((pDM_Odm->bLinked != true) && ++ (pdmpriv->EntryMinUndecoratedSmoothedPWDB == 0)) ++ { ++ pdmpriv->MinUndecoratedPWDBForDM = 0; ++ /* ODM_RT_TRACE(pDM_Odm, COMP_BB_POWERSAVING, DBG_LOUD, ("Not connected to any\n")); */ ++ } ++ else ++ { ++ pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB; ++ } ++ ++ /* DBG_8192C("%s =>MinUndecoratedPWDBForDM(%d)\n", __func__, pdmpriv->MinUndecoratedPWDBForDM); */ ++ /* ODM_RT_TRACE(pDM_Odm, COMP_DIG, DBG_LOUD, ("MinUndecoratedPWDBForDM =%d\n", pHalData->MinUndecoratedPWDBForDM)); */ ++} ++ ++void ++odm_RSSIMonitorCheckCE( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ int i; ++ int tmpEntryMaxPWDB = 0, tmpEntryMinPWDB = 0xff; ++ u8 sta_cnt = 0; ++ u32 PWDB_rssi[NUM_STA]={0};/* 0~15]:MACID, [16~31]:PWDB_rssi */ ++ bool FirstConnect = false; ++ pRA_T pRA_Table = &pDM_Odm->DM_RA_Table; ++ ++ if (pDM_Odm->bLinked != true) ++ return; ++ ++ FirstConnect = (pDM_Odm->bLinked) && (pRA_Table->firstconnect == false); ++ pRA_Table->firstconnect = pDM_Odm->bLinked; ++ ++ /* if (check_fwstate(&Adapter->mlmepriv, WIFI_AP_STATE|WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE) == true) */ ++ { ++ struct sta_info *psta; ++ ++ for (i = 0; ipODM_StaInfo[i])) ++ { ++ if (IS_MCAST(psta->hwaddr)) /* if (psta->mac_id == 1) */ ++ continue; ++ ++ if (psta->rssi_stat.UndecoratedSmoothedPWDB == (-1)) ++ continue; ++ ++ if (psta->rssi_stat.UndecoratedSmoothedPWDB < tmpEntryMinPWDB) ++ tmpEntryMinPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; ++ ++ if (psta->rssi_stat.UndecoratedSmoothedPWDB > tmpEntryMaxPWDB) ++ tmpEntryMaxPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; ++ ++ if (psta->rssi_stat.UndecoratedSmoothedPWDB != (-1)) { ++ PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB<<16)); ++ } ++ } ++ } ++ ++ /* printk("%s ==> sta_cnt(%d)\n", __func__, sta_cnt); */ ++ ++ for (i = 0; i< sta_cnt; i++) ++ { ++ if (PWDB_rssi[i] != (0)) { ++ if (pHalData->fw_ractrl == true)/* Report every sta's RSSI to FW */ ++ { ++ rtl8723b_set_rssi_cmd(Adapter, (u8 *)(&PWDB_rssi[i])); ++ } ++ } ++ } ++ } ++ ++ ++ ++ if (tmpEntryMaxPWDB != 0) /* If associated entry is found */ ++ { ++ pdmpriv->EntryMaxUndecoratedSmoothedPWDB = tmpEntryMaxPWDB; ++ } ++ else ++ { ++ pdmpriv->EntryMaxUndecoratedSmoothedPWDB = 0; ++ } ++ ++ if (tmpEntryMinPWDB != 0xff) /* If associated entry is found */ ++ { ++ pdmpriv->EntryMinUndecoratedSmoothedPWDB = tmpEntryMinPWDB; ++ } ++ else ++ { ++ pdmpriv->EntryMinUndecoratedSmoothedPWDB = 0; ++ } ++ ++ FindMinimumRSSI(Adapter);/* get pdmpriv->MinUndecoratedPWDBForDM */ ++ ++ pDM_Odm->RSSI_Min = pdmpriv->MinUndecoratedPWDBForDM; ++ /* ODM_CmnInfoUpdate(&pHalData->odmpriv , ODM_CMNINFO_RSSI_MIN, pdmpriv->MinUndecoratedPWDBForDM); */ ++} ++ ++/* 3 ============================================================ */ ++/* 3 Tx Power Tracking */ ++/* 3 ============================================================ */ ++ ++void ++odm_TXPowerTrackingInit( ++PDM_ODM_T pDM_Odm ++ ) ++{ ++ odm_TXPowerTrackingThermalMeterInit(pDM_Odm); ++} ++ ++static u8 ++getSwingIndex( ++PDM_ODM_T pDM_Odm ++ ) ++{ ++ struct adapter * Adapter = pDM_Odm->Adapter; ++ u8 i = 0; ++ u32 bbSwing; ++ u32 swingTableSize; ++ u32 * pSwingTable; ++ ++ bbSwing = PHY_QueryBBReg(Adapter, rOFDM0_XATxIQImbalance, 0xFFC00000); ++ ++ pSwingTable = OFDMSwingTable_New; ++ swingTableSize = OFDM_TABLE_SIZE; ++ ++ for (i = 0; i < swingTableSize; ++i) { ++ u32 tableValue = pSwingTable[i]; ++ ++ if (tableValue >= 0x100000) ++ tableValue >>= 22; ++ if (bbSwing == tableValue) ++ break; ++ } ++ return i; ++} ++ ++void ++odm_TXPowerTrackingThermalMeterInit( ++PDM_ODM_T pDM_Odm ++ ) ++{ ++ u8 defaultSwingIndex = getSwingIndex(pDM_Odm); ++ u8 p = 0; ++ struct adapter * Adapter = pDM_Odm->Adapter; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++ ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ ++ pdmpriv->bTXPowerTracking = true; ++ pdmpriv->TXPowercount = 0; ++ pdmpriv->bTXPowerTrackingInit = false; ++ ++ if (*(pDM_Odm->mp_mode) != 1) ++ pdmpriv->TxPowerTrackControl = true; ++ else ++ pdmpriv->TxPowerTrackControl = false; ++ ++ ++ /* MSG_8192C("pdmpriv->TxPowerTrackControl = %d\n", pdmpriv->TxPowerTrackControl); */ ++ ++ /* pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = true; */ ++ pDM_Odm->RFCalibrateInfo.ThermalValue = pHalData->EEPROMThermalMeter; ++ pDM_Odm->RFCalibrateInfo.ThermalValue_IQK = pHalData->EEPROMThermalMeter; ++ pDM_Odm->RFCalibrateInfo.ThermalValue_LCK = pHalData->EEPROMThermalMeter; ++ ++ /* The index of "0 dB" in SwingTable. */ ++ pDM_Odm->DefaultOfdmIndex = (defaultSwingIndex >= OFDM_TABLE_SIZE) ? 30 : defaultSwingIndex; ++ pDM_Odm->DefaultCckIndex = 20; ++ ++ pDM_Odm->BbSwingIdxCckBase = pDM_Odm->DefaultCckIndex; ++ pDM_Odm->RFCalibrateInfo.CCK_index = pDM_Odm->DefaultCckIndex; ++ ++ for (p = ODM_RF_PATH_A; p < MAX_RF_PATH; ++p) ++ { ++ pDM_Odm->BbSwingIdxOfdmBase[p] = pDM_Odm->DefaultOfdmIndex; ++ pDM_Odm->RFCalibrateInfo.OFDM_index[p] = pDM_Odm->DefaultOfdmIndex; ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p] = 0; ++ pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p] = 0; ++ pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0; ++ } ++ ++} ++ ++ ++void ++ODM_TXPowerTrackingCheck( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ odm_TXPowerTrackingCheckCE(pDM_Odm); ++} ++ ++void ++odm_TXPowerTrackingCheckCE( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ ++ if (!(pDM_Odm->SupportAbility & ODM_RF_TX_PWR_TRACK)) ++ { ++ return; ++ } ++ ++ if (!pDM_Odm->RFCalibrateInfo.TM_Trigger) /* at least delay 1 sec */ ++ { ++ PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_T_METER_NEW, (BIT17 | BIT16), 0x03); ++ ++ /* DBG_871X("Trigger Thermal Meter!!\n"); */ ++ ++ pDM_Odm->RFCalibrateInfo.TM_Trigger = 1; ++ return; ++ } ++ else ++ { ++ /* DBG_871X("Schedule TxPowerTracking direct call!!\n"); */ ++ ODM_TXPowerTrackingCallback_ThermalMeter(Adapter); ++ pDM_Odm->RFCalibrateInfo.TM_Trigger = 0; ++ } ++} ++ ++/* 3 ============================================================ */ ++/* 3 SW Antenna Diversity */ ++/* 3 ============================================================ */ ++void ++odm_SwAntDetectInit( ++ PDM_ODM_T pDM_Odm ++ ) ++{ ++ pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ pDM_SWAT_Table->SWAS_NoLink_BK_Reg92c = rtw_read32(pDM_Odm->Adapter, rDPDT_control); ++ pDM_SWAT_Table->PreAntenna = MAIN_ANT; ++ pDM_SWAT_Table->CurAntenna = MAIN_ANT; ++ pDM_SWAT_Table->SWAS_NoLink_State = 0; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_CfoTracking.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_CfoTracking.c +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_CfoTracking.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_CfoTracking.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,275 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#include "odm_precomp.h" ++ ++static void ++odm_SetCrystalCap( ++ void * pDM_VOID, ++ u8 CrystalCap ++) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; ++ bool bEEPROMCheck; ++ struct adapter * Adapter = pDM_Odm->Adapter; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++ bEEPROMCheck = (pHalData->EEPROMVersion >= 0x01)?true:false; ++ ++ if (pCfoTrack->CrystalCap == CrystalCap) ++ return; ++ ++ pCfoTrack->CrystalCap = CrystalCap; ++ ++ /* 0x2C[23:18] = 0x2C[17:12] = CrystalCap */ ++ CrystalCap = CrystalCap & 0x3F; ++ PHY_SetBBReg(pDM_Odm->Adapter, REG_MAC_PHY_CTRL, 0x00FFF000, (CrystalCap | (CrystalCap << 6))); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("odm_SetCrystalCap(): CrystalCap = 0x%x\n", CrystalCap)); ++} ++ ++static u8 ++odm_GetDefaultCrytaltalCap( ++ void * pDM_VOID ++) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ u8 CrystalCap = 0x20; ++ ++ struct adapter * Adapter = pDM_Odm->Adapter; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++ CrystalCap = pHalData->CrystalCap; ++ ++ CrystalCap = CrystalCap & 0x3f; ++ ++ return CrystalCap; ++} ++ ++static void ++odm_SetATCStatus( ++ void * pDM_VOID, ++ bool ATCStatus ++) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; ++ ++ if (pCfoTrack->bATCStatus == ATCStatus) ++ return; ++ ++ PHY_SetBBReg(pDM_Odm->Adapter, ODM_REG(BB_ATC, pDM_Odm), ODM_BIT(BB_ATC, pDM_Odm), ATCStatus); ++ pCfoTrack->bATCStatus = ATCStatus; ++} ++ ++static bool ++odm_GetATCStatus( ++ void * pDM_VOID ++) ++{ ++ bool ATCStatus; ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ ++ ATCStatus = (bool)PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG(BB_ATC, pDM_Odm), ODM_BIT(BB_ATC, pDM_Odm)); ++ return ATCStatus; ++} ++ ++void ++ODM_CfoTrackingReset( ++ void * pDM_VOID ++) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; ++ ++ pCfoTrack->DefXCap = odm_GetDefaultCrytaltalCap(pDM_Odm); ++ pCfoTrack->bAdjust = true; ++ ++ odm_SetCrystalCap(pDM_Odm, pCfoTrack->DefXCap); ++ odm_SetATCStatus(pDM_Odm, true); ++} ++ ++void ++ODM_CfoTrackingInit( ++ void * pDM_VOID ++) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; ++ ++ pCfoTrack->DefXCap = pCfoTrack->CrystalCap = odm_GetDefaultCrytaltalCap(pDM_Odm); ++ pCfoTrack->bATCStatus = odm_GetATCStatus(pDM_Odm); ++ pCfoTrack->bAdjust = true; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking_init() =========>\n")); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking_init(): bATCStatus = %d, CrystalCap = 0x%x\n", pCfoTrack->bATCStatus, pCfoTrack->DefXCap)); ++} ++ ++void ++ODM_CfoTracking( ++ void * pDM_VOID ++) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; ++ int CFO_kHz_A, CFO_kHz_B, CFO_ave = 0; ++ int CFO_ave_diff; ++ int CrystalCap = (int)pCfoTrack->CrystalCap; ++ u8 Adjust_Xtal = 1; ++ ++ /* 4 Support ability */ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_CFO_TRACKING)) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking(): Return: SupportAbility ODM_BB_CFO_TRACKING is disabled\n")); ++ return; ++ } ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking() =========>\n")); ++ ++ if (!pDM_Odm->bLinked || !pDM_Odm->bOneEntryOnly) ++ { ++ /* 4 No link or more than one entry */ ++ ODM_CfoTrackingReset(pDM_Odm); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking(): Reset: bLinked = %d, bOneEntryOnly = %d\n", ++ pDM_Odm->bLinked, pDM_Odm->bOneEntryOnly)); ++ } ++ else ++ { ++ /* 3 1. CFO Tracking */ ++ /* 4 1.1 No new packet */ ++ if (pCfoTrack->packetCount == pCfoTrack->packetCount_pre) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking(): packet counter doesn't change\n")); ++ return; ++ } ++ pCfoTrack->packetCount_pre = pCfoTrack->packetCount; ++ ++ /* 4 1.2 Calculate CFO */ ++ CFO_kHz_A = (int)(pCfoTrack->CFO_tail[0] * 3125) / 1280; ++ CFO_kHz_B = (int)(pCfoTrack->CFO_tail[1] * 3125) / 1280; ++ ++ if (pDM_Odm->RFType < ODM_2T2R) ++ CFO_ave = CFO_kHz_A; ++ else ++ CFO_ave = (int)(CFO_kHz_A + CFO_kHz_B) >> 1; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking(): CFO_kHz_A = %dkHz, CFO_kHz_B = %dkHz, CFO_ave = %dkHz\n", ++ CFO_kHz_A, CFO_kHz_B, CFO_ave)); ++ ++ /* 4 1.3 Avoid abnormal large CFO */ ++ CFO_ave_diff = (pCfoTrack->CFO_ave_pre >= CFO_ave)?(pCfoTrack->CFO_ave_pre - CFO_ave):(CFO_ave - pCfoTrack->CFO_ave_pre); ++ if (CFO_ave_diff > 20 && pCfoTrack->largeCFOHit == 0 && !pCfoTrack->bAdjust) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking(): first large CFO hit\n")); ++ pCfoTrack->largeCFOHit = 1; ++ return; ++ } ++ else ++ pCfoTrack->largeCFOHit = 0; ++ pCfoTrack->CFO_ave_pre = CFO_ave; ++ ++ /* 4 1.4 Dynamic Xtal threshold */ ++ if (pCfoTrack->bAdjust == false) ++ { ++ if (CFO_ave > CFO_TH_XTAL_HIGH || CFO_ave < (-CFO_TH_XTAL_HIGH)) ++ pCfoTrack->bAdjust = true; ++ } ++ else ++ { ++ if (CFO_ave < CFO_TH_XTAL_LOW && CFO_ave > (-CFO_TH_XTAL_LOW)) ++ pCfoTrack->bAdjust = false; ++ } ++ ++ /* 4 1.5 BT case: Disable CFO tracking */ ++ if (pDM_Odm->bBtEnabled) ++ { ++ pCfoTrack->bAdjust = false; ++ odm_SetCrystalCap(pDM_Odm, pCfoTrack->DefXCap); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking(): Disable CFO tracking for BT!!\n")); ++ } ++ ++ /* 4 1.6 Big jump */ ++ if (pCfoTrack->bAdjust) ++ { ++ if (CFO_ave > CFO_TH_XTAL_LOW) ++ Adjust_Xtal = Adjust_Xtal + ((CFO_ave - CFO_TH_XTAL_LOW) >> 2); ++ else if (CFO_ave < (-CFO_TH_XTAL_LOW)) ++ Adjust_Xtal = Adjust_Xtal + ((CFO_TH_XTAL_LOW - CFO_ave) >> 2); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking(): Crystal cap offset = %d\n", Adjust_Xtal)); ++ } ++ ++ /* 4 1.7 Adjust Crystal Cap. */ ++ if (pCfoTrack->bAdjust) ++ { ++ if (CFO_ave > CFO_TH_XTAL_LOW) ++ CrystalCap = CrystalCap + Adjust_Xtal; ++ else if (CFO_ave < (-CFO_TH_XTAL_LOW)) ++ CrystalCap = CrystalCap - Adjust_Xtal; ++ ++ if (CrystalCap > 0x3f) ++ CrystalCap = 0x3f; ++ else if (CrystalCap < 0) ++ CrystalCap = 0; ++ ++ odm_SetCrystalCap(pDM_Odm, (u8)CrystalCap); ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking(): Crystal cap = 0x%x, Default Crystal cap = 0x%x\n", ++ pCfoTrack->CrystalCap, pCfoTrack->DefXCap)); ++ ++ /* 3 2. Dynamic ATC switch */ ++ if (CFO_ave < CFO_TH_ATC && CFO_ave > -CFO_TH_ATC) ++ { ++ odm_SetATCStatus(pDM_Odm, false); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking(): Disable ATC!!\n")); ++ } ++ else ++ { ++ odm_SetATCStatus(pDM_Odm, true); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking(): Enable ATC!!\n")); ++ } ++ } ++} ++ ++void ++ODM_ParsingCFO( ++ void * pDM_VOID, ++ void * pPktinfo_VOID, ++ s8 * pcfotail ++ ) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ PODM_PACKET_INFO_T pPktinfo = (PODM_PACKET_INFO_T)pPktinfo_VOID; ++ PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; ++ u8 i; ++ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_CFO_TRACKING)) ++ return; ++ ++ if (pPktinfo->StationID != 0) ++ { ++ /* 3 Update CFO report for path-A & path-B */ ++ /* Only paht-A and path-B have CFO tail and short CFO */ ++ for (i = ODM_RF_PATH_A; i <= ODM_RF_PATH_B; i++) ++ { ++ pCfoTrack->CFO_tail[i] = (int)pcfotail[i]; ++ } ++ ++ /* 3 Update packet counter */ ++ if (pCfoTrack->packetCount == 0xffffffff) ++ pCfoTrack->packetCount = 0; ++ else ++ pCfoTrack->packetCount++; ++ } ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_CfoTracking.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_CfoTracking.h +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_CfoTracking.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_CfoTracking.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,48 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#ifndef __ODMCFOTRACK_H__ ++#define __ODMCFOTRACK_H__ ++ ++#define CFO_TH_XTAL_HIGH 20 /* kHz */ ++#define CFO_TH_XTAL_LOW 10 /* kHz */ ++#define CFO_TH_ATC 80 /* kHz */ ++ ++typedef struct _CFO_TRACKING_ ++{ ++ bool bATCStatus; ++ bool largeCFOHit; ++ bool bAdjust; ++ u8 CrystalCap; ++ u8 DefXCap; ++ int CFO_tail[2]; ++ int CFO_ave_pre; ++ u32 packetCount; ++ u32 packetCount_pre; ++ ++ bool bForceXtalCap; ++ bool bReset; ++} CFO_TRACKING, *PCFO_TRACKING; ++ ++void ODM_CfoTrackingReset(void *pDM_VOID ++); ++ ++void ODM_CfoTrackingInit(void *pDM_VOID); ++ ++void ODM_CfoTracking(void *pDM_VOID); ++ ++void ODM_ParsingCFO(void *pDM_VOID, void *pPktinfo_VOID, s8 *pcfotail); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_debug.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_debug.c +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_debug.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_debug.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,52 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#include "odm_precomp.h" ++ ++void ODM_InitDebugSetting(PDM_ODM_T pDM_Odm) ++{ ++ pDM_Odm->DebugLevel = ODM_DBG_LOUD; ++ ++ pDM_Odm->DebugComponents = ++/* BB Functions */ ++/* ODM_COMP_DIG | */ ++/* ODM_COMP_RA_MASK | */ ++/* ODM_COMP_DYNAMIC_TXPWR | */ ++/* ODM_COMP_FA_CNT | */ ++/* ODM_COMP_RSSI_MONITOR | */ ++/* ODM_COMP_CCK_PD | */ ++/* ODM_COMP_ANT_DIV | */ ++/* ODM_COMP_PWR_SAVE | */ ++/* ODM_COMP_PWR_TRAIN | */ ++/* ODM_COMP_RATE_ADAPTIVE | */ ++/* ODM_COMP_PATH_DIV | */ ++/* ODM_COMP_DYNAMIC_PRICCA | */ ++/* ODM_COMP_RXHP | */ ++/* ODM_COMP_MP | */ ++/* ODM_COMP_CFO_TRACKING | */ ++ ++/* MAC Functions */ ++/* ODM_COMP_EDCA_TURBO | */ ++/* ODM_COMP_EARLY_MODE | */ ++/* RF Functions */ ++/* ODM_COMP_TX_PWR_TRACK | */ ++/* ODM_COMP_RX_GAIN_TRACK | */ ++/* ODM_COMP_CALIBRATION | */ ++/* Common */ ++/* ODM_COMP_COMMON | */ ++/* ODM_COMP_INIT | */ ++/* ODM_COMP_PSD | */ ++0; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_debug.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_debug.h +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_debug.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_debug.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,154 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#ifndef __ODM_DBG_H__ ++#define __ODM_DBG_H__ ++ ++ ++/* */ ++/* Define the debug levels */ ++/* */ ++/* 1. DBG_TRACE and DBG_LOUD are used for normal cases. */ ++/* So that, they can help SW engineer to develope or trace states changed */ ++/* and also help HW enginner to trace every operation to and from HW, */ ++/* e.g IO, Tx, Rx. */ ++/* */ ++/* 2. DBG_WARNNING and DBG_SERIOUS are used for unusual or error cases, */ ++/* which help us to debug SW or HW. */ ++/* */ ++/* */ ++/* */ ++/* Never used in a call to ODM_RT_TRACE()! */ ++/* */ ++#define ODM_DBG_OFF 1 ++ ++/* */ ++/* Fatal bug. */ ++/* For example, Tx/Rx/IO locked up, OS hangs, memory access violation, */ ++/* resource allocation failed, unexpected HW behavior, HW BUG and so on. */ ++/* */ ++#define ODM_DBG_SERIOUS 2 ++ ++/* */ ++/* Abnormal, rare, or unexpeted cases. */ ++/* For example, IRP/Packet/OID canceled, device suprisely unremoved and so on. */ ++/* */ ++#define ODM_DBG_WARNING 3 ++ ++/* */ ++/* Normal case with useful information about current SW or HW state. */ ++/* For example, Tx/Rx descriptor to fill, Tx/Rx descriptor completed status, */ ++/* SW protocol state change, dynamic mechanism state change and so on. */ ++/* */ ++#define ODM_DBG_LOUD 4 ++ ++/* */ ++/* Normal case with detail execution flow or information. */ ++/* */ ++#define ODM_DBG_TRACE 5 ++ ++/* */ ++/* Define the tracing components */ ++/* */ ++/* */ ++/* BB Functions */ ++#define ODM_COMP_DIG BIT0 ++#define ODM_COMP_RA_MASK BIT1 ++#define ODM_COMP_DYNAMIC_TXPWR BIT2 ++#define ODM_COMP_FA_CNT BIT3 ++#define ODM_COMP_RSSI_MONITOR BIT4 ++#define ODM_COMP_CCK_PD BIT5 ++#define ODM_COMP_ANT_DIV BIT6 ++#define ODM_COMP_PWR_SAVE BIT7 ++#define ODM_COMP_PWR_TRAIN BIT8 ++#define ODM_COMP_RATE_ADAPTIVE BIT9 ++#define ODM_COMP_PATH_DIV BIT10 ++#define ODM_COMP_PSD BIT11 ++#define ODM_COMP_DYNAMIC_PRICCA BIT12 ++#define ODM_COMP_RXHP BIT13 ++#define ODM_COMP_MP BIT14 ++#define ODM_COMP_CFO_TRACKING BIT15 ++/* MAC Functions */ ++#define ODM_COMP_EDCA_TURBO BIT16 ++#define ODM_COMP_EARLY_MODE BIT17 ++/* RF Functions */ ++#define ODM_COMP_TX_PWR_TRACK BIT24 ++#define ODM_COMP_RX_GAIN_TRACK BIT25 ++#define ODM_COMP_CALIBRATION BIT26 ++/* Common Functions */ ++#define ODM_COMP_COMMON BIT30 ++#define ODM_COMP_INIT BIT31 ++ ++/*------------------------Export Marco Definition---------------------------*/ ++ #define DbgPrint printk ++ #define RT_PRINTK(fmt, args...) DbgPrint("%s(): " fmt, __func__, ## args); ++ #define RT_DISP(dbgtype, dbgflag, printstr) ++ ++#ifndef ASSERT ++ #define ASSERT(expr) ++#endif ++ ++#if DBG ++#define ODM_RT_TRACE(pDM_Odm, comp, level, fmt) \ ++ if (((comp) & pDM_Odm->DebugComponents) && (level <= pDM_Odm->DebugLevel || level == ODM_DBG_SERIOUS)) \ ++ { \ ++ RT_PRINTK fmt; \ ++ } ++ ++#define ODM_RT_TRACE_F(pDM_Odm, comp, level, fmt) \ ++ if (((comp) & pDM_Odm->DebugComponents) && (level <= pDM_Odm->DebugLevel)) \ ++ { \ ++ RT_PRINTK fmt; \ ++ } ++ ++#define ODM_RT_ASSERT(pDM_Odm, expr, fmt) \ ++ if (!(expr)) { \ ++ DbgPrint("Assertion failed! %s at ......\n", #expr); \ ++ DbgPrint(" ......%s,%s, line =%d\n", __FILE__, __func__, __LINE__); \ ++ RT_PRINTK fmt; \ ++ ASSERT(false); \ ++ } ++#define ODM_dbg_enter() { DbgPrint("==> %s\n", __func__); } ++#define ODM_dbg_exit() { DbgPrint("<== %s\n", __func__); } ++#define ODM_dbg_trace(str) { DbgPrint("%s:%s\n", __func__, str); } ++ ++#define ODM_PRINT_ADDR(pDM_Odm, comp, level, title_str, ptr) \ ++ if (((comp) & pDM_Odm->DebugComponents) && (level <= pDM_Odm->DebugLevel)) \ ++ { \ ++ int __i; \ ++ u8 *__ptr = (u8 *)ptr; \ ++ DbgPrint("[ODM] "); \ ++ DbgPrint(title_str); \ ++ DbgPrint(" "); \ ++ for (__i = 0; __i<6; __i++) \ ++ DbgPrint("%02X%s", __ptr[__i], (__i ==5)?"":"-"); \ ++ DbgPrint("\n"); \ ++ } ++#else ++#define ODM_RT_TRACE(pDM_Odm, comp, level, fmt) ++#define ODM_RT_TRACE_F(pDM_Odm, comp, level, fmt) ++#define ODM_RT_ASSERT(pDM_Odm, expr, fmt) ++#define ODM_dbg_enter() ++#define ODM_dbg_exit() ++#define ODM_dbg_trace(str) ++#define ODM_PRINT_ADDR(pDM_Odm, comp, level, title_str, ptr) ++#endif ++ ++void ++ODM_InitDebugSetting( ++ PDM_ODM_T pDM_Odm ++ ); ++ ++#endif /* __ODM_DBG_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_DIG.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_DIG.c +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_DIG.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_DIG.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,1104 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#include "odm_precomp.h" ++ ++#define ADAPTIVITY_VERSION "5.0" ++ ++void ++odm_NHMCounterStatisticsInit( ++ void * pDM_VOID ++ ) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ ++ /* PHY parameters initialize for n series */ ++ rtw_write16(pDM_Odm->Adapter, ODM_REG_NHM_TIMER_11N+2, 0x2710); /* 0x894[31:16]= 0x2710 Time duration for NHM unit: 4us, 0x2710 =40ms */ ++ /* rtw_write16(pDM_Odm->Adapter, ODM_REG_NHM_TIMER_11N+2, 0x4e20); 0x894[31:16]= 0x4e20 Time duration for NHM unit: 4us, 0x4e20 =80ms */ ++ rtw_write16(pDM_Odm->Adapter, ODM_REG_NHM_TH9_TH10_11N+2, 0xffff); /* 0x890[31:16]= 0xffff th_9, th_10 */ ++ /* rtw_write32(pDM_Odm->Adapter, ODM_REG_NHM_TH3_TO_TH0_11N, 0xffffff5c); 0x898 = 0xffffff5c th_3, th_2, th_1, th_0 */ ++ rtw_write32(pDM_Odm->Adapter, ODM_REG_NHM_TH3_TO_TH0_11N, 0xffffff52); /* 0x898 = 0xffffff52 th_3, th_2, th_1, th_0 */ ++ rtw_write32(pDM_Odm->Adapter, ODM_REG_NHM_TH7_TO_TH4_11N, 0xffffffff); /* 0x89c = 0xffffffff th_7, th_6, th_5, th_4 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, ODM_REG_FPGA0_IQK_11N, bMaskByte0, 0xff); /* 0xe28[7:0]= 0xff th_8 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, ODM_REG_NHM_TH9_TH10_11N, BIT10|BIT9|BIT8, 0x7); /* 0x890[9:8]=3 enable CCX */ ++ PHY_SetBBReg(pDM_Odm->Adapter, ODM_REG_OFDM_FA_RSTC_11N, BIT7, 0x1); /* 0xc0c[7]= 1 max power among all RX ants */ ++} ++ ++void ++odm_NHMCounterStatistics( ++ void * pDM_VOID ++ ) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ ++ /* Get NHM report */ ++ odm_GetNHMCounterStatistics(pDM_Odm); ++ ++ /* Reset NHM counter */ ++ odm_NHMCounterStatisticsReset(pDM_Odm); ++} ++ ++void ++odm_GetNHMCounterStatistics( ++ void * pDM_VOID ++ ) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ u32 value32 = 0; ++ ++ value32 = PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG_NHM_CNT_11N, bMaskDWord); ++ ++ pDM_Odm->NHM_cnt_0 = (u8)(value32 & bMaskByte0); ++} ++ ++void ++odm_NHMCounterStatisticsReset( ++ void * pDM_VOID ++ ) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ ++ PHY_SetBBReg(pDM_Odm->Adapter, ODM_REG_NHM_TH9_TH10_11N, BIT1, 0); ++ PHY_SetBBReg(pDM_Odm->Adapter, ODM_REG_NHM_TH9_TH10_11N, BIT1, 1); ++} ++ ++void ++odm_NHMBBInit( ++ void * pDM_VOID ++) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ ++ pDM_Odm->adaptivity_flag = 0; ++ pDM_Odm->tolerance_cnt = 3; ++ pDM_Odm->NHMLastTxOkcnt = 0; ++ pDM_Odm->NHMLastRxOkcnt = 0; ++ pDM_Odm->NHMCurTxOkcnt = 0; ++ pDM_Odm->NHMCurRxOkcnt = 0; ++} ++ ++/* */ ++void ++odm_NHMBB( ++ void * pDM_VOID ++) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ /* u8 test_status; */ ++ /* Pfalse_ALARM_STATISTICS pFalseAlmCnt = &(pDM_Odm->FalseAlmCnt); */ ++ ++ pDM_Odm->NHMCurTxOkcnt = *(pDM_Odm->pNumTxBytesUnicast) - pDM_Odm->NHMLastTxOkcnt; ++ pDM_Odm->NHMCurRxOkcnt = *(pDM_Odm->pNumRxBytesUnicast) - pDM_Odm->NHMLastRxOkcnt; ++ pDM_Odm->NHMLastTxOkcnt = *(pDM_Odm->pNumTxBytesUnicast); ++ pDM_Odm->NHMLastRxOkcnt = *(pDM_Odm->pNumRxBytesUnicast); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("NHM_cnt_0 =%d, NHMCurTxOkcnt = %llu, NHMCurRxOkcnt = %llu\n", ++ pDM_Odm->NHM_cnt_0, pDM_Odm->NHMCurTxOkcnt, pDM_Odm->NHMCurRxOkcnt)); ++ ++ ++ if ((pDM_Odm->NHMCurTxOkcnt) + 1 > (u64)(pDM_Odm->NHMCurRxOkcnt<<2) + 1) /* Tx > 4*Rx possible for adaptivity test */ ++ { ++ if (pDM_Odm->NHM_cnt_0 >= 190 || pDM_Odm->adaptivity_flag == true) ++ { ++ /* Enable EDCCA since it is possible running Adaptivity testing */ ++ /* test_status = 1; */ ++ pDM_Odm->adaptivity_flag = true; ++ pDM_Odm->tolerance_cnt = 0; ++ } ++ else ++ { ++ if (pDM_Odm->tolerance_cnt<3) ++ pDM_Odm->tolerance_cnt = pDM_Odm->tolerance_cnt + 1; ++ else ++ pDM_Odm->tolerance_cnt = 4; ++ /* test_status = 5; */ ++ if (pDM_Odm->tolerance_cnt > 3) ++ { ++ /* test_status = 3; */ ++ pDM_Odm->adaptivity_flag = false; ++ } ++ } ++ } ++ else /* TXadaptivity_flag == true && pDM_Odm->NHM_cnt_0 <= 200) ++ { ++ /* test_status = 2; */ ++ pDM_Odm->tolerance_cnt = 0; ++ } ++ else ++ { ++ if (pDM_Odm->tolerance_cnt<3) ++ pDM_Odm->tolerance_cnt = pDM_Odm->tolerance_cnt + 1; ++ else ++ pDM_Odm->tolerance_cnt = 4; ++ /* test_status = 5; */ ++ if (pDM_Odm->tolerance_cnt >3) ++ { ++ /* test_status = 4; */ ++ pDM_Odm->adaptivity_flag = false; ++ } ++ } ++ } ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("adaptivity_flag = %d\n ", pDM_Odm->adaptivity_flag)); ++} ++ ++void ++odm_SearchPwdBLowerBound( ++ void * pDM_VOID, ++ u8 IGI_target ++) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ u32 value32 = 0; ++ u8 cnt, IGI; ++ bool bAdjust =true; ++ s8 TH_L2H_dmc, TH_H2L_dmc; ++ s8 Diff; ++ ++ IGI = 0x50; /* find H2L, L2H lower bound */ ++ ODM_Write_DIG(pDM_Odm, IGI); ++ ++ ++ Diff = IGI_target -(s8)IGI; ++ TH_L2H_dmc = pDM_Odm->TH_L2H_ini + Diff; ++ if (TH_L2H_dmc > 10) ++ TH_L2H_dmc = 10; ++ TH_H2L_dmc = TH_L2H_dmc - pDM_Odm->TH_EDCCA_HL_diff; ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, bMaskByte0, (u8)TH_L2H_dmc); ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, bMaskByte2, (u8)TH_H2L_dmc); ++ ++ mdelay(5); ++ ++ while (bAdjust) { ++ for (cnt = 0; cnt<20; cnt ++) { ++ value32 = PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG_RPT_11N, bMaskDWord); ++ ++ if (value32 & BIT30) ++ pDM_Odm->txEdcca1 = pDM_Odm->txEdcca1 + 1; ++ else if (value32 & BIT29) ++ pDM_Odm->txEdcca1 = pDM_Odm->txEdcca1 + 1; ++ else ++ pDM_Odm->txEdcca0 = pDM_Odm->txEdcca0 + 1; ++ } ++ /* DbgPrint("txEdcca1 = %d, txEdcca0 = %d\n", pDM_Odm->txEdcca1, pDM_Odm->txEdcca0); */ ++ ++ if (pDM_Odm->txEdcca1 > 5) { ++ IGI = IGI -1; ++ TH_L2H_dmc = TH_L2H_dmc + 1; ++ if (TH_L2H_dmc > 10) ++ TH_L2H_dmc = 10; ++ TH_H2L_dmc = TH_L2H_dmc - pDM_Odm->TH_EDCCA_HL_diff; ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, bMaskByte0, (u8)TH_L2H_dmc); ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, bMaskByte2, (u8)TH_H2L_dmc); ++ ++ pDM_Odm->TxHangFlg = true; ++ pDM_Odm->txEdcca1 = 0; ++ pDM_Odm->txEdcca0 = 0; ++ ++ if (TH_L2H_dmc == 10) { ++ bAdjust = false; ++ pDM_Odm->TxHangFlg = false; ++ pDM_Odm->txEdcca1 = 0; ++ pDM_Odm->txEdcca0 = 0; ++ pDM_Odm->H2L_lb = TH_H2L_dmc; ++ pDM_Odm->L2H_lb = TH_L2H_dmc; ++ pDM_Odm->Adaptivity_IGI_upper = IGI; ++ } ++ } else { ++ bAdjust = false; ++ pDM_Odm->TxHangFlg = false; ++ pDM_Odm->txEdcca1 = 0; ++ pDM_Odm->txEdcca0 = 0; ++ pDM_Odm->H2L_lb = TH_H2L_dmc; ++ pDM_Odm->L2H_lb = TH_L2H_dmc; ++ pDM_Odm->Adaptivity_IGI_upper = IGI; ++ } ++ } ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("IGI = 0x%x, H2L_lb = 0x%x, L2H_lb = 0x%x\n", IGI, pDM_Odm->H2L_lb , pDM_Odm->L2H_lb)); ++} ++ ++void ++odm_AdaptivityInit( ++void * pDM_VOID ++) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ ++ if (pDM_Odm->Carrier_Sense_enable == false) ++ { ++ pDM_Odm->TH_L2H_ini = 0xf7; /* -7 */ ++ } ++ else ++ pDM_Odm->TH_L2H_ini = 0xa; ++ ++ pDM_Odm->AdapEn_RSSI = 20; ++ pDM_Odm->TH_EDCCA_HL_diff = 7; ++ ++ pDM_Odm->IGI_Base = 0x32; ++ pDM_Odm->IGI_target = 0x1c; ++ pDM_Odm->ForceEDCCA = 0; ++ pDM_Odm->NHM_disable = false; ++ pDM_Odm->TxHangFlg = true; ++ pDM_Odm->txEdcca0 = 0; ++ pDM_Odm->txEdcca1 = 0; ++ pDM_Odm->H2L_lb = 0; ++ pDM_Odm->L2H_lb = 0; ++ pDM_Odm->Adaptivity_IGI_upper = 0; ++ odm_NHMBBInit(pDM_Odm); ++ ++ PHY_SetBBReg(pDM_Odm->Adapter, REG_RD_CTRL, BIT11, 1); /* stop counting if EDCCA is asserted */ ++} ++ ++ ++void ++odm_Adaptivity( ++ void * pDM_VOID, ++ u8 IGI ++) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ s8 TH_L2H_dmc, TH_H2L_dmc; ++ s8 Diff, IGI_target; ++ bool EDCCA_State = false; ++ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_ADAPTIVITY)) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("Go to odm_DynamicEDCCA()\n")); ++ return; ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_Adaptivity() =====>\n")); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("ForceEDCCA =%d, IGI_Base = 0x%x, TH_L2H_ini = %d, TH_EDCCA_HL_diff = %d, AdapEn_RSSI = %d\n", ++ pDM_Odm->ForceEDCCA, pDM_Odm->IGI_Base, pDM_Odm->TH_L2H_ini, pDM_Odm->TH_EDCCA_HL_diff, pDM_Odm->AdapEn_RSSI)); ++ ++ if (*pDM_Odm->pBandWidth == ODM_BW20M) /* CHANNEL_WIDTH_20 */ ++ IGI_target = pDM_Odm->IGI_Base; ++ else if (*pDM_Odm->pBandWidth == ODM_BW40M) ++ IGI_target = pDM_Odm->IGI_Base + 2; ++ else if (*pDM_Odm->pBandWidth == ODM_BW80M) ++ IGI_target = pDM_Odm->IGI_Base + 2; ++ else ++ IGI_target = pDM_Odm->IGI_Base; ++ pDM_Odm->IGI_target = (u8) IGI_target; ++ ++ /* Search pwdB lower bound */ ++ if (pDM_Odm->TxHangFlg == true) ++ { ++ PHY_SetBBReg(pDM_Odm->Adapter, ODM_REG_DBG_RPT_11N, bMaskDWord, 0x208); ++ odm_SearchPwdBLowerBound(pDM_Odm, pDM_Odm->IGI_target); ++ } ++ ++ if ((!pDM_Odm->bLinked)||(*pDM_Odm->pChannel > 149)) /* Band4 doesn't need adaptivity */ ++ { ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, bMaskByte0, 0x7f); ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, bMaskByte2, 0x7f); ++ return; ++ } ++ ++ if (!pDM_Odm->ForceEDCCA) ++ { ++ if (pDM_Odm->RSSI_Min > pDM_Odm->AdapEn_RSSI) ++ EDCCA_State = 1; ++ else if (pDM_Odm->RSSI_Min < (pDM_Odm->AdapEn_RSSI - 5)) ++ EDCCA_State = 0; ++ } ++ else ++ EDCCA_State = 1; ++ ++ if (pDM_Odm->bLinked && pDM_Odm->Carrier_Sense_enable == false && pDM_Odm->NHM_disable == false &&pDM_Odm->TxHangFlg == false) ++ odm_NHMBB(pDM_Odm); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("BandWidth =%s, IGI_target = 0x%x, EDCCA_State =%d\n", ++ (*pDM_Odm->pBandWidth ==ODM_BW80M)?"80M":((*pDM_Odm->pBandWidth ==ODM_BW40M)?"40M":"20M"), IGI_target, EDCCA_State)); ++ ++ if (EDCCA_State == 1) ++ { ++ Diff = IGI_target -(s8)IGI; ++ TH_L2H_dmc = pDM_Odm->TH_L2H_ini + Diff; ++ if (TH_L2H_dmc > 10) ++ TH_L2H_dmc = 10; ++ ++ TH_H2L_dmc = TH_L2H_dmc - pDM_Odm->TH_EDCCA_HL_diff; ++ ++ /* replace lower bound to prevent EDCCA always equal */ ++ if (TH_H2L_dmc < pDM_Odm->H2L_lb) ++ TH_H2L_dmc = pDM_Odm->H2L_lb; ++ if (TH_L2H_dmc < pDM_Odm->L2H_lb) ++ TH_L2H_dmc = pDM_Odm->L2H_lb; ++ } ++ else ++ { ++ TH_L2H_dmc = 0x7f; ++ TH_H2L_dmc = 0x7f; ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("IGI = 0x%x, TH_L2H_dmc = %d, TH_H2L_dmc = %d\n", ++ IGI, TH_L2H_dmc, TH_H2L_dmc)); ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, bMaskByte0, (u8)TH_L2H_dmc); ++ PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, bMaskByte2, (u8)TH_H2L_dmc); ++} ++ ++void ++ODM_Write_DIG( ++void * pDM_VOID, ++u8 CurrentIGI ++ ) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ ++ if (pDM_DigTable->bStopDIG) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("Stop Writing IGI\n")); ++ return; ++ } ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_TRACE, ("ODM_REG(IGI_A, pDM_Odm) = 0x%x, ODM_BIT(IGI, pDM_Odm) = 0x%x\n", ++ ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm))); ++ ++ if (pDM_DigTable->CurIGValue != CurrentIGI) ++ { ++ /* 1 Check initial gain by upper bound */ ++ if (!pDM_DigTable->bPSDInProgress) ++ { ++ if (CurrentIGI > pDM_DigTable->rx_gain_range_max) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_TRACE, ("CurrentIGI(0x%02x) is larger than upper bound !!\n", pDM_DigTable->rx_gain_range_max)); ++ CurrentIGI = pDM_DigTable->rx_gain_range_max; ++ } ++ ++ } ++ ++ /* 1 Set IGI value */ ++ PHY_SetBBReg(pDM_Odm->Adapter, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI); ++ ++ if (pDM_Odm->RFType > ODM_1T1R) ++ PHY_SetBBReg(pDM_Odm->Adapter, ODM_REG(IGI_B, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI); ++ ++ pDM_DigTable->CurIGValue = CurrentIGI; ++ } ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_TRACE, ("CurrentIGI(0x%02x).\n", CurrentIGI)); ++ ++} ++ ++void ++odm_PauseDIG( ++ void * pDM_VOID, ++ ODM_Pause_DIG_TYPE PauseType, ++ u8 IGIValue ++) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ static bool bPaused = false; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_PauseDIG() =========>\n")); ++ ++ if ((pDM_Odm->SupportAbility & ODM_BB_ADAPTIVITY) && pDM_Odm->TxHangFlg == true) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_PauseDIG(): Dynamic adjust threshold in progress !!\n")); ++ return; ++ } ++ ++ if (!bPaused && (!(pDM_Odm->SupportAbility & ODM_BB_DIG) || !(pDM_Odm->SupportAbility & ODM_BB_FA_CNT))) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_PauseDIG(): Return: SupportAbility ODM_BB_DIG or ODM_BB_FA_CNT is disabled\n")); ++ return; ++ } ++ ++ switch (PauseType) ++ { ++ /* 1 Pause DIG */ ++ case ODM_PAUSE_DIG: ++ /* 2 Disable DIG */ ++ ODM_CmnInfoUpdate(pDM_Odm, ODM_CMNINFO_ABILITY, pDM_Odm->SupportAbility & (~ODM_BB_DIG)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_PauseDIG(): Pause DIG !!\n")); ++ ++ /* 2 Backup IGI value */ ++ if (!bPaused) ++ { ++ pDM_DigTable->IGIBackup = pDM_DigTable->CurIGValue; ++ bPaused = true; ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_PauseDIG(): Backup IGI = 0x%x\n", pDM_DigTable->IGIBackup)); ++ ++ /* 2 Write new IGI value */ ++ ODM_Write_DIG(pDM_Odm, IGIValue); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_PauseDIG(): Write new IGI = 0x%x\n", IGIValue)); ++ break; ++ ++ /* 1 Resume DIG */ ++ case ODM_RESUME_DIG: ++ if (bPaused) ++ { ++ /* 2 Write backup IGI value */ ++ ODM_Write_DIG(pDM_Odm, pDM_DigTable->IGIBackup); ++ bPaused = false; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_PauseDIG(): Write original IGI = 0x%x\n", pDM_DigTable->IGIBackup)); ++ ++ /* 2 Enable DIG */ ++ ODM_CmnInfoUpdate(pDM_Odm, ODM_CMNINFO_ABILITY, pDM_Odm->SupportAbility | ODM_BB_DIG); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_PauseDIG(): Resume DIG !!\n")); ++ } ++ break; ++ ++ default: ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_PauseDIG(): Wrong type !!\n")); ++ break; ++ } ++} ++ ++bool ++odm_DigAbort( ++ void * pDM_VOID ++ ) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ ++ /* SupportAbility */ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT)) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Return: SupportAbility ODM_BB_FA_CNT is disabled\n")); ++ return true; ++ } ++ ++ /* SupportAbility */ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_DIG)) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Return: SupportAbility ODM_BB_DIG is disabled\n")); ++ return true; ++ } ++ ++ /* ScanInProcess */ ++ if (*(pDM_Odm->pbScanInProcess)) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Return: In Scan Progress\n")); ++ return true; ++ } ++ ++ /* add by Neil Chen to avoid PSD is processing */ ++ if (pDM_Odm->bDMInitialGainEnable == false) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Return: PSD is Processing\n")); ++ return true; ++ } ++ ++ return false; ++} ++ ++void ++odm_DIGInit( ++ void * pDM_VOID ++ ) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ ++ pDM_DigTable->bStopDIG = false; ++ pDM_DigTable->bPSDInProgress = false; ++ pDM_DigTable->CurIGValue = (u8) PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm)); ++ pDM_DigTable->RssiLowThresh = DM_DIG_THRESH_LOW; ++ pDM_DigTable->RssiHighThresh = DM_DIG_THRESH_HIGH; ++ pDM_DigTable->FALowThresh = DMfalseALARM_THRESH_LOW; ++ pDM_DigTable->FAHighThresh = DMfalseALARM_THRESH_HIGH; ++ pDM_DigTable->BackoffVal = DM_DIG_BACKOFF_DEFAULT; ++ pDM_DigTable->BackoffVal_range_max = DM_DIG_BACKOFF_MAX; ++ pDM_DigTable->BackoffVal_range_min = DM_DIG_BACKOFF_MIN; ++ pDM_DigTable->PreCCK_CCAThres = 0xFF; ++ pDM_DigTable->CurCCK_CCAThres = 0x83; ++ pDM_DigTable->ForbiddenIGI = DM_DIG_MIN_NIC; ++ pDM_DigTable->LargeFAHit = 0; ++ pDM_DigTable->Recover_cnt = 0; ++ pDM_DigTable->bMediaConnect_0 = false; ++ pDM_DigTable->bMediaConnect_1 = false; ++ ++ /* To Initialize pDM_Odm->bDMInitialGainEnable == false to avoid DIG error */ ++ pDM_Odm->bDMInitialGainEnable = true; ++ ++ pDM_DigTable->DIG_Dynamic_MIN_0 = DM_DIG_MIN_NIC; ++ pDM_DigTable->DIG_Dynamic_MIN_1 = DM_DIG_MIN_NIC; ++ ++ /* To Initi BT30 IGI */ ++ pDM_DigTable->BT30_CurIGI = 0x32; ++ ++ if (pDM_Odm->BoardType & (ODM_BOARD_EXT_PA|ODM_BOARD_EXT_LNA)) ++ { ++ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; ++ pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC; ++ } ++ else ++ { ++ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; ++ pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC; ++ } ++ ++} ++ ++ ++void ++odm_DIG( ++ void * pDM_VOID ++ ) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ ++ /* Common parameters */ ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ Pfalse_ALARM_STATISTICS pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; ++ bool FirstConnect, FirstDisConnect; ++ u8 DIG_MaxOfMin, DIG_Dynamic_MIN; ++ u8 dm_dig_max, dm_dig_min; ++ u8 CurrentIGI = pDM_DigTable->CurIGValue; ++ u8 offset; ++ u32 dm_FA_thres[3]; ++ u8 Adap_IGI_Upper = 0; ++ u32 TxTp = 0, RxTp = 0; ++ bool bDFSBand = false; ++ bool bPerformance = true, bFirstTpTarget = false, bFirstCoverage = false; ++ ++ if (odm_DigAbort(pDM_Odm) == true) ++ return; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() ===========================>\n\n")); ++ ++ if (pDM_Odm->adaptivity_flag == true) ++ Adap_IGI_Upper = pDM_Odm->Adaptivity_IGI_upper; ++ ++ ++ /* 1 Update status */ ++ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0; ++ FirstConnect = (pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == false); ++ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == true); ++ ++ /* 1 Boundary Decision */ ++ /* 2 For WIN\CE */ ++ dm_dig_max = 0x5A; ++ dm_dig_min = DM_DIG_MIN_NIC; ++ DIG_MaxOfMin = DM_DIG_MAX_AP; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Absolutly upper bound = 0x%x, lower bound = 0x%x\n", dm_dig_max, dm_dig_min)); ++ ++ /* 1 Adjust boundary by RSSI */ ++ if (pDM_Odm->bLinked && bPerformance) ++ { ++ /* 2 Modify DIG upper bound */ ++ /* 4 Modify DIG upper bound for 92E, 8723A\B, 8821 & 8812 BT */ ++ if (pDM_Odm->bBtLimitedDig == 1) ++ { ++ offset = 10; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Coex. case: Force upper bound to RSSI + %d !!!!!!\n", offset)); ++ } ++ else ++ offset = 15; ++ ++ if ((pDM_Odm->RSSI_Min + offset) > dm_dig_max) ++ pDM_DigTable->rx_gain_range_max = dm_dig_max; ++ else if ((pDM_Odm->RSSI_Min + offset) < dm_dig_min) ++ pDM_DigTable->rx_gain_range_max = dm_dig_min; ++ else ++ pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + offset; ++ ++ /* 2 Modify DIG lower bound */ ++ /* if (pDM_Odm->bOneEntryOnly) */ ++ { ++ if (pDM_Odm->RSSI_Min < dm_dig_min) ++ DIG_Dynamic_MIN = dm_dig_min; ++ else if (pDM_Odm->RSSI_Min > DIG_MaxOfMin) ++ DIG_Dynamic_MIN = DIG_MaxOfMin; ++ else ++ DIG_Dynamic_MIN = pDM_Odm->RSSI_Min; ++ } ++ } ++ else ++ { ++ { ++ pDM_DigTable->rx_gain_range_max = dm_dig_max; ++ } ++ DIG_Dynamic_MIN = dm_dig_min; ++ } ++ ++ /* 1 Force Lower Bound for AntDiv */ ++ if (pDM_Odm->bLinked && !pDM_Odm->bOneEntryOnly) ++ { ++ if (pDM_Odm->SupportAbility & ODM_BB_ANT_DIV) ++ { ++ if (pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV || pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV ||pDM_Odm->AntDivType == S0S1_SW_ANTDIV) ++ { ++ if (pDM_DigTable->AntDiv_RSSI_max > DIG_MaxOfMin) ++ DIG_Dynamic_MIN = DIG_MaxOfMin; ++ else ++ DIG_Dynamic_MIN = (u8) pDM_DigTable->AntDiv_RSSI_max; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_DIG(): Antenna diversity case: Force lower bound to 0x%x !!!!!!\n", DIG_Dynamic_MIN)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_DIG(): Antenna diversity case: RSSI_max = 0x%x !!!!!!\n", pDM_DigTable->AntDiv_RSSI_max)); ++ } ++ } ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Adjust boundary by RSSI Upper bound = 0x%x, Lower bound = 0x%x\n", ++ pDM_DigTable->rx_gain_range_max, DIG_Dynamic_MIN)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Link status: bLinked = %d, RSSI = %d, bFirstConnect = %d, bFirsrDisConnect = %d\n\n", ++ pDM_Odm->bLinked, pDM_Odm->RSSI_Min, FirstConnect, FirstDisConnect)); ++ ++ /* 1 Modify DIG lower bound, deal with abnormal case */ ++ /* 2 Abnormal false alarm case */ ++ { ++ if (FirstDisConnect) ++ { ++ pDM_DigTable->rx_gain_range_min = DIG_Dynamic_MIN; ++ pDM_DigTable->ForbiddenIGI = DIG_Dynamic_MIN; ++ } ++ else ++ pDM_DigTable->rx_gain_range_min = odm_ForbiddenIGICheck(pDM_Odm, DIG_Dynamic_MIN, CurrentIGI); ++ } ++ ++ if (pDM_Odm->bLinked && !FirstConnect) ++ { ++ if ((pDM_Odm->PhyDbgInfo.NumQryBeaconPkt < 5) && (pDM_Odm->bsta_state)) ++ { ++ pDM_DigTable->rx_gain_range_min = dm_dig_min; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Abnrormal #beacon (%d) case in STA mode: Force lower bound to 0x%x !!!!!!\n\n", ++ pDM_Odm->PhyDbgInfo.NumQryBeaconPkt, pDM_DigTable->rx_gain_range_min)); ++ } ++ } ++ ++ /* 2 Abnormal lower bound case */ ++ if (pDM_DigTable->rx_gain_range_min > pDM_DigTable->rx_gain_range_max) ++ { ++ pDM_DigTable->rx_gain_range_min = pDM_DigTable->rx_gain_range_max; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Abnrormal lower bound case: Force lower bound to 0x%x !!!!!!\n\n", pDM_DigTable->rx_gain_range_min)); ++ } ++ ++ ++ /* 1 False alarm threshold decision */ ++ odm_FAThresholdCheck(pDM_Odm, bDFSBand, bPerformance, RxTp, TxTp, dm_FA_thres); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): False alarm threshold = %d, %d, %d\n\n", dm_FA_thres[0], dm_FA_thres[1], dm_FA_thres[2])); ++ ++ /* 1 Adjust initial gain by false alarm */ ++ if (pDM_Odm->bLinked && bPerformance) ++ { ++ /* 2 After link */ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Adjust IGI after link\n")); ++ ++ if (bFirstTpTarget || (FirstConnect && bPerformance)) ++ { ++ pDM_DigTable->LargeFAHit = 0; ++ ++ { ++ if (pDM_Odm->RSSI_Min < DIG_MaxOfMin) ++ { ++ if (CurrentIGI < pDM_Odm->RSSI_Min) ++ CurrentIGI = pDM_Odm->RSSI_Min; ++ } ++ else ++ { ++ if (CurrentIGI < DIG_MaxOfMin) ++ CurrentIGI = DIG_MaxOfMin; ++ } ++ } ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): First connect case: IGI does on-shot to 0x%x\n", CurrentIGI)); ++ ++ } ++ else ++ { ++ if (pFalseAlmCnt->Cnt_all > dm_FA_thres[2]) ++ CurrentIGI = CurrentIGI + 4; ++ else if (pFalseAlmCnt->Cnt_all > dm_FA_thres[1]) ++ CurrentIGI = CurrentIGI + 2; ++ else if (pFalseAlmCnt->Cnt_all < dm_FA_thres[0]) ++ CurrentIGI = CurrentIGI - 2; ++ ++ if ((pDM_Odm->PhyDbgInfo.NumQryBeaconPkt < 5) && (pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH1) && (pDM_Odm->bsta_state)) ++ { ++ CurrentIGI = pDM_DigTable->rx_gain_range_min; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Abnormal #beacon (%d) case: IGI does one-shot to 0x%x\n", ++ pDM_Odm->PhyDbgInfo.NumQryBeaconPkt, CurrentIGI)); ++ } ++ } ++ } ++ else ++ { ++ /* 2 Before link */ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Adjust IGI before link\n")); ++ ++ if (FirstDisConnect || bFirstCoverage) ++ { ++ CurrentIGI = dm_dig_min; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): First disconnect case: IGI does on-shot to lower bound\n")); ++ } ++ else ++ { ++ if (pFalseAlmCnt->Cnt_all > dm_FA_thres[2]) ++ CurrentIGI = CurrentIGI + 4; ++ else if (pFalseAlmCnt->Cnt_all > dm_FA_thres[1]) ++ CurrentIGI = CurrentIGI + 2; ++ else if (pFalseAlmCnt->Cnt_all < dm_FA_thres[0]) ++ CurrentIGI = CurrentIGI - 2; ++ } ++ } ++ ++ /* 1 Check initial gain by upper/lower bound */ ++ if (CurrentIGI < pDM_DigTable->rx_gain_range_min) ++ CurrentIGI = pDM_DigTable->rx_gain_range_min; ++ ++ if (CurrentIGI > pDM_DigTable->rx_gain_range_max) ++ CurrentIGI = pDM_DigTable->rx_gain_range_max; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): CurIGValue = 0x%x, TotalFA = %d\n\n", CurrentIGI, pFalseAlmCnt->Cnt_all)); ++ ++ /* 1 Force upper bound and lower bound for adaptivity */ ++ if (pDM_Odm->SupportAbility & ODM_BB_ADAPTIVITY && pDM_Odm->adaptivity_flag == true) ++ { ++ if (CurrentIGI > Adap_IGI_Upper) ++ CurrentIGI = Adap_IGI_Upper; ++ ++ if (pDM_Odm->IGI_LowerBound != 0) ++ { ++ if (CurrentIGI < pDM_Odm->IGI_LowerBound) ++ CurrentIGI = pDM_Odm->IGI_LowerBound; ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Adaptivity case: Force upper bound to 0x%x !!!!!!\n", Adap_IGI_Upper)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Adaptivity case: Force lower bound to 0x%x !!!!!!\n\n", pDM_Odm->IGI_LowerBound)); ++ } ++ ++ ++ /* 1 Update status */ ++ if (pDM_Odm->bBtHsOperation) ++ { ++ if (pDM_Odm->bLinked) ++ { ++ if (pDM_DigTable->BT30_CurIGI > (CurrentIGI)) ++ ODM_Write_DIG(pDM_Odm, CurrentIGI); ++ else ++ ODM_Write_DIG(pDM_Odm, pDM_DigTable->BT30_CurIGI); ++ ++ pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked; ++ pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN; ++ } ++ else ++ { ++ if (pDM_Odm->bLinkInProcess) ++ ODM_Write_DIG(pDM_Odm, 0x1c); ++ else if (pDM_Odm->bBtConnectProcess) ++ ODM_Write_DIG(pDM_Odm, 0x28); ++ else ++ ODM_Write_DIG(pDM_Odm, pDM_DigTable->BT30_CurIGI);/* ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); */ ++ } ++ } ++ else /* BT is not using */ ++ { ++ ODM_Write_DIG(pDM_Odm, CurrentIGI);/* ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); */ ++ pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked; ++ pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN; ++ } ++} ++ ++void ++odm_DIGbyRSSI_LPS( ++ void * pDM_VOID ++ ) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ Pfalse_ALARM_STATISTICS pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; ++ ++ u8 RSSI_Lower =DM_DIG_MIN_NIC; /* 0x1E or 0x1C */ ++ u8 CurrentIGI =pDM_Odm->RSSI_Min; ++ ++ CurrentIGI =CurrentIGI+RSSI_OFFSET_DIG; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIGbyRSSI_LPS() ==>\n")); ++ ++ /* Using FW PS mode to make IGI */ ++ /* Adjust by FA in LPS MODE */ ++ if (pFalseAlmCnt->Cnt_all> DM_DIG_FA_TH2_LPS) ++ CurrentIGI = CurrentIGI+4; ++ else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1_LPS) ++ CurrentIGI = CurrentIGI+2; ++ else if (pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0_LPS) ++ CurrentIGI = CurrentIGI-2; ++ ++ ++ /* Lower bound checking */ ++ ++ /* RSSI Lower bound check */ ++ if ((pDM_Odm->RSSI_Min-10) > DM_DIG_MIN_NIC) ++ RSSI_Lower =(pDM_Odm->RSSI_Min-10); ++ else ++ RSSI_Lower =DM_DIG_MIN_NIC; ++ ++ /* Upper and Lower Bound checking */ ++ if (CurrentIGI > DM_DIG_MAX_NIC) ++ CurrentIGI =DM_DIG_MAX_NIC; ++ else if (CurrentIGI < RSSI_Lower) ++ CurrentIGI =RSSI_Lower; ++ ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIGbyRSSI_LPS(): pFalseAlmCnt->Cnt_all = %d\n", pFalseAlmCnt->Cnt_all)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIGbyRSSI_LPS(): pDM_Odm->RSSI_Min = %d\n", pDM_Odm->RSSI_Min)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIGbyRSSI_LPS(): CurrentIGI = 0x%x\n", CurrentIGI)); ++ ++ ODM_Write_DIG(pDM_Odm, CurrentIGI);/* ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); */ ++} ++ ++/* 3 ============================================================ */ ++/* 3 FASLE ALARM CHECK */ ++/* 3 ============================================================ */ ++ ++void ++odm_FalseAlarmCounterStatistics( ++ void * pDM_VOID ++ ) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ Pfalse_ALARM_STATISTICS FalseAlmCnt = &(pDM_Odm->FalseAlmCnt); ++ u32 ret_value; ++ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT)) ++ return; ++ ++ /* hold ofdm counter */ ++ PHY_SetBBReg(pDM_Odm->Adapter, ODM_REG_OFDM_FA_HOLDC_11N, BIT31, 1); /* hold page C counter */ ++ PHY_SetBBReg(pDM_Odm->Adapter, ODM_REG_OFDM_FA_RSTD_11N, BIT31, 1); /* hold page D counter */ ++ ++ ret_value = PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG_OFDM_FA_TYPE1_11N, bMaskDWord); ++ FalseAlmCnt->Cnt_Fast_Fsync = (ret_value&0xffff); ++ FalseAlmCnt->Cnt_SB_Search_fail = ((ret_value&0xffff0000)>>16); ++ ++ ret_value = PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG_OFDM_FA_TYPE2_11N, bMaskDWord); ++ FalseAlmCnt->Cnt_OFDM_CCA = (ret_value&0xffff); ++ FalseAlmCnt->Cnt_Parity_Fail = ((ret_value&0xffff0000)>>16); ++ ++ ret_value = PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG_OFDM_FA_TYPE3_11N, bMaskDWord); ++ FalseAlmCnt->Cnt_Rate_Illegal = (ret_value&0xffff); ++ FalseAlmCnt->Cnt_Crc8_fail = ((ret_value&0xffff0000)>>16); ++ ++ ret_value = PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG_OFDM_FA_TYPE4_11N, bMaskDWord); ++ FalseAlmCnt->Cnt_Mcs_fail = (ret_value&0xffff); ++ ++ FalseAlmCnt->Cnt_Ofdm_fail = FalseAlmCnt->Cnt_Parity_Fail + FalseAlmCnt->Cnt_Rate_Illegal + ++ FalseAlmCnt->Cnt_Crc8_fail + FalseAlmCnt->Cnt_Mcs_fail + ++ FalseAlmCnt->Cnt_Fast_Fsync + FalseAlmCnt->Cnt_SB_Search_fail; ++ ++ { ++ /* hold cck counter */ ++ PHY_SetBBReg(pDM_Odm->Adapter, ODM_REG_CCK_FA_RST_11N, BIT12, 1); ++ PHY_SetBBReg(pDM_Odm->Adapter, ODM_REG_CCK_FA_RST_11N, BIT14, 1); ++ ++ ret_value = PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG_CCK_FA_LSB_11N, bMaskByte0); ++ FalseAlmCnt->Cnt_Cck_fail = ret_value; ++ ++ ret_value = PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG_CCK_FA_MSB_11N, bMaskByte3); ++ FalseAlmCnt->Cnt_Cck_fail += (ret_value& 0xff)<<8; ++ ++ ret_value = PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG_CCK_CCA_CNT_11N, bMaskDWord); ++ FalseAlmCnt->Cnt_CCK_CCA = ((ret_value&0xFF)<<8) |((ret_value&0xFF00)>>8); ++ } ++ ++ FalseAlmCnt->Cnt_all = (FalseAlmCnt->Cnt_Fast_Fsync + ++ FalseAlmCnt->Cnt_SB_Search_fail + ++ FalseAlmCnt->Cnt_Parity_Fail + ++ FalseAlmCnt->Cnt_Rate_Illegal + ++ FalseAlmCnt->Cnt_Crc8_fail + ++ FalseAlmCnt->Cnt_Mcs_fail + ++ FalseAlmCnt->Cnt_Cck_fail); ++ ++ FalseAlmCnt->Cnt_CCA_all = FalseAlmCnt->Cnt_OFDM_CCA + FalseAlmCnt->Cnt_CCK_CCA; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Enter odm_FalseAlarmCounterStatistics\n")); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Fast_Fsync =%d, Cnt_SB_Search_fail =%d\n", ++ FalseAlmCnt->Cnt_Fast_Fsync, FalseAlmCnt->Cnt_SB_Search_fail)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Parity_Fail =%d, Cnt_Rate_Illegal =%d\n", ++ FalseAlmCnt->Cnt_Parity_Fail, FalseAlmCnt->Cnt_Rate_Illegal)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Crc8_fail =%d, Cnt_Mcs_fail =%d\n", ++ FalseAlmCnt->Cnt_Crc8_fail, FalseAlmCnt->Cnt_Mcs_fail)); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_OFDM_CCA =%d\n", FalseAlmCnt->Cnt_OFDM_CCA)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_CCK_CCA =%d\n", FalseAlmCnt->Cnt_CCK_CCA)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_CCA_all =%d\n", FalseAlmCnt->Cnt_CCA_all)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Ofdm_fail =%d\n", FalseAlmCnt->Cnt_Ofdm_fail)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Cck_fail =%d\n", FalseAlmCnt->Cnt_Cck_fail)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Ofdm_fail =%d\n", FalseAlmCnt->Cnt_Ofdm_fail)); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Total False Alarm =%d\n", FalseAlmCnt->Cnt_all)); ++} ++ ++ ++void ++odm_FAThresholdCheck( ++ void * pDM_VOID, ++ bool bDFSBand, ++ bool bPerformance, ++ u32 RxTp, ++ u32 TxTp, ++ u32* dm_FA_thres ++ ) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ ++ if (pDM_Odm->bLinked && (bPerformance||bDFSBand)) ++ { ++ /* For NIC */ ++ dm_FA_thres[0] = DM_DIG_FA_TH0; ++ dm_FA_thres[1] = DM_DIG_FA_TH1; ++ dm_FA_thres[2] = DM_DIG_FA_TH2; ++ } ++ else ++ { ++ { ++ dm_FA_thres[0] = 2000; ++ dm_FA_thres[1] = 4000; ++ dm_FA_thres[2] = 5000; ++ } ++ } ++ return; ++} ++ ++u8 ++odm_ForbiddenIGICheck( ++ void * pDM_VOID, ++ u8 DIG_Dynamic_MIN, ++ u8 CurrentIGI ++ ) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ Pfalse_ALARM_STATISTICS pFalseAlmCnt = &(pDM_Odm->FalseAlmCnt); ++ u8 rx_gain_range_min = pDM_DigTable->rx_gain_range_min; ++ ++ if (pFalseAlmCnt->Cnt_all > 10000) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Abnormally false alarm case.\n")); ++ ++ if (pDM_DigTable->LargeFAHit != 3) ++ pDM_DigTable->LargeFAHit++; ++ ++ if (pDM_DigTable->ForbiddenIGI < CurrentIGI)/* if (pDM_DigTable->ForbiddenIGI < pDM_DigTable->CurIGValue) */ ++ { ++ pDM_DigTable->ForbiddenIGI = CurrentIGI;/* pDM_DigTable->ForbiddenIGI = pDM_DigTable->CurIGValue; */ ++ pDM_DigTable->LargeFAHit = 1; ++ } ++ ++ if (pDM_DigTable->LargeFAHit >= 3) ++ { ++ if ((pDM_DigTable->ForbiddenIGI + 2) > pDM_DigTable->rx_gain_range_max) ++ rx_gain_range_min = pDM_DigTable->rx_gain_range_max; ++ else ++ rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 2); ++ pDM_DigTable->Recover_cnt = 1800; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Abnormally false alarm case: Recover_cnt = %d\n", pDM_DigTable->Recover_cnt)); ++ } ++ } ++ else ++ { ++ if (pDM_DigTable->Recover_cnt != 0) ++ { ++ pDM_DigTable->Recover_cnt --; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: Recover_cnt = %d\n", pDM_DigTable->Recover_cnt)); ++ } ++ else ++ { ++ if (pDM_DigTable->LargeFAHit < 3) ++ { ++ if ((pDM_DigTable->ForbiddenIGI - 2) < DIG_Dynamic_MIN) /* DM_DIG_MIN) */ ++ { ++ pDM_DigTable->ForbiddenIGI = DIG_Dynamic_MIN; /* DM_DIG_MIN; */ ++ rx_gain_range_min = DIG_Dynamic_MIN; /* DM_DIG_MIN; */ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: At Lower Bound\n")); ++ } ++ else ++ { ++ pDM_DigTable->ForbiddenIGI -= 2; ++ rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 2); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: Approach Lower Bound\n")); ++ } ++ } ++ else ++ { ++ pDM_DigTable->LargeFAHit = 0; ++ } ++ } ++ } ++ ++ return rx_gain_range_min; ++ ++} ++ ++/* 3 ============================================================ */ ++/* 3 CCK Packet Detect Threshold */ ++/* 3 ============================================================ */ ++ ++void ++odm_CCKPacketDetectionThresh( ++ void * pDM_VOID ++ ) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ Pfalse_ALARM_STATISTICS FalseAlmCnt = &(pDM_Odm->FalseAlmCnt); ++ u8 CurCCK_CCAThres; ++ ++ ++ if ((!(pDM_Odm->SupportAbility & ODM_BB_CCK_PD)) ||(!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT))) ++ { ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CCK_PD, ODM_DBG_LOUD, ("odm_CCKPacketDetectionThresh() return ==========\n")); ++ return; ++ } ++ ++ if (pDM_Odm->ExtLNA) ++ return; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CCK_PD, ODM_DBG_LOUD, ("odm_CCKPacketDetectionThresh() ==========>\n")); ++ ++ if (pDM_Odm->bLinked) ++ { ++ if (pDM_Odm->RSSI_Min > 25) ++ CurCCK_CCAThres = 0xcd; ++ else if ((pDM_Odm->RSSI_Min <= 25) && (pDM_Odm->RSSI_Min > 10)) ++ CurCCK_CCAThres = 0x83; ++ else ++ { ++ if (FalseAlmCnt->Cnt_Cck_fail > 1000) ++ CurCCK_CCAThres = 0x83; ++ else ++ CurCCK_CCAThres = 0x40; ++ } ++ } ++ else ++ { ++ if (FalseAlmCnt->Cnt_Cck_fail > 1000) ++ CurCCK_CCAThres = 0x83; ++ else ++ CurCCK_CCAThres = 0x40; ++ } ++ ++ ODM_Write_CCK_CCA_Thres(pDM_Odm, CurCCK_CCAThres); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_CCK_PD, ODM_DBG_LOUD, ("odm_CCKPacketDetectionThresh() CurCCK_CCAThres = 0x%x\n", CurCCK_CCAThres)); ++} ++ ++void ++ODM_Write_CCK_CCA_Thres( ++void * pDM_VOID, ++u8 CurCCK_CCAThres ++ ) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ ++ if (pDM_DigTable->CurCCK_CCAThres!=CurCCK_CCAThres) /* modify by Guo.Mingzhi 2012-01-03 */ ++ { ++ rtw_write8(pDM_Odm->Adapter, ODM_REG(CCK_CCA, pDM_Odm), CurCCK_CCAThres); ++ } ++ pDM_DigTable->PreCCK_CCAThres = pDM_DigTable->CurCCK_CCAThres; ++ pDM_DigTable->CurCCK_CCAThres = CurCCK_CCAThres; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_DIG.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_DIG.h +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_DIG.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_DIG.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,263 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#ifndef __ODMDIG_H__ ++#define __ODMDIG_H__ ++ ++typedef struct _Dynamic_Initial_Gain_Threshold_ ++{ ++ bool bStopDIG; ++ bool bPSDInProgress; ++ ++ u8 Dig_Enable_Flag; ++ u8 Dig_Ext_Port_Stage; ++ ++ int RssiLowThresh; ++ int RssiHighThresh; ++ ++ u32 FALowThresh; ++ u32 FAHighThresh; ++ ++ u8 CurSTAConnectState; ++ u8 PreSTAConnectState; ++ u8 CurMultiSTAConnectState; ++ ++ u8 PreIGValue; ++ u8 CurIGValue; ++ u8 BackupIGValue; /* MP DIG */ ++ u8 BT30_CurIGI; ++ u8 IGIBackup; ++ ++ s8 BackoffVal; ++ s8 BackoffVal_range_max; ++ s8 BackoffVal_range_min; ++ u8 rx_gain_range_max; ++ u8 rx_gain_range_min; ++ u8 Rssi_val_min; ++ ++ u8 PreCCK_CCAThres; ++ u8 CurCCK_CCAThres; ++ u8 PreCCKPDState; ++ u8 CurCCKPDState; ++ u8 CCKPDBackup; ++ ++ u8 LargeFAHit; ++ u8 ForbiddenIGI; ++ u32 Recover_cnt; ++ ++ u8 DIG_Dynamic_MIN_0; ++ u8 DIG_Dynamic_MIN_1; ++ bool bMediaConnect_0; ++ bool bMediaConnect_1; ++ ++ u32 AntDiv_RSSI_max; ++ u32 RSSI_max; ++ ++ u8 *pbP2pLinkInProgress; ++}DIG_T,*pDIG_T; ++ ++typedef struct false_ALARM_STATISTICS{ ++ u32 Cnt_Parity_Fail; ++ u32 Cnt_Rate_Illegal; ++ u32 Cnt_Crc8_fail; ++ u32 Cnt_Mcs_fail; ++ u32 Cnt_Ofdm_fail; ++ u32 Cnt_Ofdm_fail_pre; /* For RTL8881A */ ++ u32 Cnt_Cck_fail; ++ u32 Cnt_all; ++ u32 Cnt_Fast_Fsync; ++ u32 Cnt_SB_Search_fail; ++ u32 Cnt_OFDM_CCA; ++ u32 Cnt_CCK_CCA; ++ u32 Cnt_CCA_all; ++ u32 Cnt_BW_USC; /* Gary */ ++ u32 Cnt_BW_LSC; /* Gary */ ++}false_ALARM_STATISTICS, *Pfalse_ALARM_STATISTICS; ++ ++typedef enum tag_Dynamic_Init_Gain_Operation_Type_Definition ++{ ++ DIG_TYPE_THRESH_HIGH = 0, ++ DIG_TYPE_THRESH_LOW = 1, ++ DIG_TYPE_BACKOFF = 2, ++ DIG_TYPE_RX_GAIN_MIN = 3, ++ DIG_TYPE_RX_GAIN_MAX = 4, ++ DIG_TYPE_ENABLE = 5, ++ DIG_TYPE_DISABLE = 6, ++ DIG_OP_TYPE_MAX ++}DM_DIG_OP_E; ++ ++typedef enum tag_ODM_PauseDIG_Type { ++ ODM_PAUSE_DIG = BIT0, ++ ODM_RESUME_DIG = BIT1 ++} ODM_Pause_DIG_TYPE; ++ ++typedef enum tag_ODM_PauseCCKPD_Type { ++ ODM_PAUSE_CCKPD = BIT0, ++ ODM_RESUME_CCKPD = BIT1 ++} ODM_Pause_CCKPD_TYPE; ++ ++#define DM_DIG_THRESH_HIGH 40 ++#define DM_DIG_THRESH_LOW 35 ++ ++#define DMfalseALARM_THRESH_LOW 400 ++#define DMfalseALARM_THRESH_HIGH 1000 ++ ++#define DM_DIG_MAX_NIC 0x3e ++#define DM_DIG_MIN_NIC 0x1e /* 0x22//0x1c */ ++#define DM_DIG_MAX_OF_MIN_NIC 0x3e ++ ++#define DM_DIG_MAX_AP 0x3e ++#define DM_DIG_MIN_AP 0x1c ++#define DM_DIG_MAX_OF_MIN 0x2A /* 0x32 */ ++#define DM_DIG_MIN_AP_DFS 0x20 ++ ++#define DM_DIG_MAX_NIC_HP 0x46 ++#define DM_DIG_MIN_NIC_HP 0x2e ++ ++#define DM_DIG_MAX_AP_HP 0x42 ++#define DM_DIG_MIN_AP_HP 0x30 ++ ++#define DM_DIG_FA_TH0 0x200/* 0x20 */ ++ ++#define DM_DIG_FA_TH1 0x300 ++#define DM_DIG_FA_TH2 0x400 ++/* this is for 92d */ ++#define DM_DIG_FA_TH0_92D 0x100 ++#define DM_DIG_FA_TH1_92D 0x400 ++#define DM_DIG_FA_TH2_92D 0x600 ++ ++#define DM_DIG_BACKOFF_MAX 12 ++#define DM_DIG_BACKOFF_MIN -4 ++#define DM_DIG_BACKOFF_DEFAULT 10 ++ ++#define DM_DIG_FA_TH0_LPS 4 /* 4 in lps */ ++#define DM_DIG_FA_TH1_LPS 15 /* 15 lps */ ++#define DM_DIG_FA_TH2_LPS 30 /* 30 lps */ ++#define RSSI_OFFSET_DIG 0x05 ++ ++void ++odm_NHMCounterStatisticsInit( ++ void * pDM_VOID ++ ); ++ ++void ++odm_NHMCounterStatistics( ++ void * pDM_VOID ++ ); ++ ++void ++odm_NHMBBInit( ++ void * pDM_VOID ++); ++ ++void ++odm_NHMBB( ++ void * pDM_VOID ++); ++ ++void ++odm_NHMCounterStatisticsReset( ++ void * pDM_VOID ++); ++ ++void ++odm_GetNHMCounterStatistics( ++ void * pDM_VOID ++); ++ ++void ++odm_SearchPwdBLowerBound( ++ void * pDM_VOID, ++ u8 IGI_target ++); ++ ++void ++odm_AdaptivityInit( ++ void * pDM_VOID ++ ); ++ ++void ++odm_Adaptivity( ++ void * pDM_VOID, ++ u8 IGI ++ ); ++ ++void ++ODM_Write_DIG( ++ void * pDM_VOID, ++ u8 CurrentIGI ++ ); ++ ++void ++odm_PauseDIG( ++ void * pDM_VOID, ++ ODM_Pause_DIG_TYPE PauseType, ++ u8 IGIValue ++ ); ++ ++void ++odm_DIGInit( ++ void * pDM_VOID ++ ); ++ ++void ++odm_DIG( ++ void * pDM_VOID ++ ); ++ ++void ++odm_DIGbyRSSI_LPS( ++ void * pDM_VOID ++ ); ++ ++void ++odm_FalseAlarmCounterStatistics( ++ void * pDM_VOID ++ ); ++ ++void ++odm_FAThresholdCheck( ++ void * pDM_VOID, ++ bool bDFSBand, ++ bool bPerformance, ++ u32 RxTp, ++ u32 TxTp, ++ u32* dm_FA_thres ++ ); ++ ++u8 ++odm_ForbiddenIGICheck( ++ void * pDM_VOID, ++ u8 DIG_Dynamic_MIN, ++ u8 CurrentIGI ++ ); ++ ++bool ++odm_DigAbort( ++ void * pDM_VOID ++ ); ++ ++void ++odm_CCKPacketDetectionThresh( ++ void * pDM_VOID ++ ); ++ ++void ++ODM_Write_CCK_CCA_Thres( ++ void * pDM_VOID, ++ u8 CurCCK_CCAThres ++ ); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_DynamicBBPowerSaving.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_DynamicBBPowerSaving.c +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_DynamicBBPowerSaving.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_DynamicBBPowerSaving.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,107 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#include "odm_precomp.h" ++ ++void ++odm_DynamicBBPowerSavingInit( ++ void * pDM_VOID ++ ) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ pPS_T pDM_PSTable = &pDM_Odm->DM_PSTable; ++ ++ pDM_PSTable->PreCCAState = CCA_MAX; ++ pDM_PSTable->CurCCAState = CCA_MAX; ++ pDM_PSTable->PreRFState = RF_MAX; ++ pDM_PSTable->CurRFState = RF_MAX; ++ pDM_PSTable->Rssi_val_min = 0; ++ pDM_PSTable->initialize = 0; ++} ++ ++void ++ODM_RF_Saving( ++ void * pDM_VOID, ++u8 bForceInNormal ++ ) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ pPS_T pDM_PSTable = &pDM_Odm->DM_PSTable; ++ u8 Rssi_Up_bound = 30 ; ++ u8 Rssi_Low_bound = 25; ++ if (pDM_Odm->PatchID == 40) /* RT_CID_819x_FUNAI_TV */ ++ { ++ Rssi_Up_bound = 50 ; ++ Rssi_Low_bound = 45; ++ } ++ if (pDM_PSTable->initialize == 0) { ++ ++ pDM_PSTable->Reg874 = (PHY_QueryBBReg(pDM_Odm->Adapter, 0x874, bMaskDWord)&0x1CC000)>>14; ++ pDM_PSTable->RegC70 = (PHY_QueryBBReg(pDM_Odm->Adapter, 0xc70, bMaskDWord)&BIT3)>>3; ++ pDM_PSTable->Reg85C = (PHY_QueryBBReg(pDM_Odm->Adapter, 0x85c, bMaskDWord)&0xFF000000)>>24; ++ pDM_PSTable->RegA74 = (PHY_QueryBBReg(pDM_Odm->Adapter, 0xa74, bMaskDWord)&0xF000)>>12; ++ /* Reg818 = PHY_QueryBBReg(padapter, 0x818, bMaskDWord); */ ++ pDM_PSTable->initialize = 1; ++ } ++ ++ if (!bForceInNormal) ++ { ++ if (pDM_Odm->RSSI_Min != 0xFF) ++ { ++ if (pDM_PSTable->PreRFState == RF_Normal) ++ { ++ if (pDM_Odm->RSSI_Min >= Rssi_Up_bound) ++ pDM_PSTable->CurRFState = RF_Save; ++ else ++ pDM_PSTable->CurRFState = RF_Normal; ++ } ++ else { ++ if (pDM_Odm->RSSI_Min <= Rssi_Low_bound) ++ pDM_PSTable->CurRFState = RF_Normal; ++ else ++ pDM_PSTable->CurRFState = RF_Save; ++ } ++ } ++ else ++ pDM_PSTable->CurRFState =RF_MAX; ++ } ++ else ++ { ++ pDM_PSTable->CurRFState = RF_Normal; ++ } ++ ++ if (pDM_PSTable->PreRFState != pDM_PSTable->CurRFState) ++ { ++ if (pDM_PSTable->CurRFState == RF_Save) ++ { ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x874 , 0x1C0000, 0x2); /* Reg874[20:18]=3'b010 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0xc70, BIT3, 0); /* RegC70[3]= 1'b0 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x85c, 0xFF000000, 0x63); /* Reg85C[31:24]= 0x63 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x874, 0xC000, 0x2); /* Reg874[15:14]=2'b10 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0xa74, 0xF000, 0x3); /* RegA75[7:4]= 0x3 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x818, BIT28, 0x0); /* Reg818[28]= 1'b0 */ ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x818, BIT28, 0x1); /* Reg818[28]= 1'b1 */ ++ } ++ else ++ { ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x874 , 0x1CC000, pDM_PSTable->Reg874); ++ PHY_SetBBReg(pDM_Odm->Adapter, 0xc70, BIT3, pDM_PSTable->RegC70); ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x85c, 0xFF000000, pDM_PSTable->Reg85C); ++ PHY_SetBBReg(pDM_Odm->Adapter, 0xa74, 0xF000, pDM_PSTable->RegA74); ++ PHY_SetBBReg(pDM_Odm->Adapter, 0x818, BIT28, 0x0); ++ } ++ pDM_PSTable->PreRFState =pDM_PSTable->CurRFState; ++ } ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_DynamicBBPowerSaving.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_DynamicBBPowerSaving.h +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_DynamicBBPowerSaving.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_DynamicBBPowerSaving.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,46 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#ifndef __ODMDYNAMICBBPOWERSAVING_H__ ++#define __ODMDYNAMICBBPOWERSAVING_H__ ++ ++typedef struct _Dynamic_Power_Saving_ ++{ ++ u8 PreCCAState; ++ u8 CurCCAState; ++ ++ u8 PreRFState; ++ u8 CurRFState; ++ ++ int Rssi_val_min; ++ ++ u8 initialize; ++ u32 Reg874, RegC70, Reg85C, RegA74; ++ ++}PS_T,*pPS_T; ++ ++#define dm_RF_Saving ODM_RF_Saving ++ ++void ODM_RF_Saving( ++ void * pDM_VOID, ++u8 bForceInNormal ++ ); ++ ++void ++odm_DynamicBBPowerSavingInit( ++ void * pDM_VOID ++ ); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_DynamicTxPower.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_DynamicTxPower.c +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_DynamicTxPower.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_DynamicTxPower.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,32 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#include "odm_precomp.h" ++ ++void ++odm_DynamicTxPowerInit( ++ void * pDM_VOID ++ ) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ pdmpriv->bDynamicTxPowerEnable = false; ++ ++ pdmpriv->LastDTPLvl = TxHighPwrLevel_Normal; ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_DynamicTxPower.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_DynamicTxPower.h +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_DynamicTxPower.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_DynamicTxPower.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,40 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#ifndef __ODMDYNAMICTXPOWER_H__ ++#define __ODMDYNAMICTXPOWER_H__ ++ ++#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 ++#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 ++#define TX_POWER_NEAR_FIELD_THRESH_AP 0x3F ++#define TX_POWER_NEAR_FIELD_THRESH_8812 60 ++ ++#define TxHighPwrLevel_Normal 0 ++#define TxHighPwrLevel_Level1 1 ++#define TxHighPwrLevel_Level2 2 ++#define TxHighPwrLevel_BT1 3 ++#define TxHighPwrLevel_BT2 4 ++#define TxHighPwrLevel_15 5 ++#define TxHighPwrLevel_35 6 ++#define TxHighPwrLevel_50 7 ++#define TxHighPwrLevel_70 8 ++#define TxHighPwrLevel_100 9 ++ ++void ++odm_DynamicTxPowerInit( ++ void * pDM_VOID ++ ); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_EdcaTurboCheck.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_EdcaTurboCheck.c +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_EdcaTurboCheck.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_EdcaTurboCheck.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,187 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#include "odm_precomp.h" ++ ++static u32 edca_setting_DL_GMode[HT_IOT_PEER_MAX] = { ++/*UNKNOWN, REALTEK_90, ALTEK_92SE BROADCOM, LINK ATHEROS, ++ *CISCO, MERU, MARVELL, 92U_AP, SELF_AP ++ */ ++ 0x4322, 0xa44f, 0x5e4322, 0xa42b, 0x5e4322, 0x4322, ++ 0xa42b, 0x5ea42b, 0xa44f, 0x5e4322, 0x5ea42b ++}; ++ ++static u32 edca_setting_UL[HT_IOT_PEER_MAX] = { ++/*UNKNOWN, REALTEK_90, REALTEK_92SE, BROADCOM, RALINK, ATHEROS, ++ *CISCO, MERU, MARVELL, 92U_AP, SELF_AP(DownLink/Tx) ++ */ ++ 0x5e4322, 0xa44f, 0x5e4322, 0x5ea32b, 0x5ea422, 0x5ea322, ++ 0x3ea430, 0x5ea42b, 0x5ea44f, 0x5e4322, 0x5e4322}; ++ ++static u32 edca_setting_DL[HT_IOT_PEER_MAX] = { ++/*UNKNOWN, REALTEK_90, REALTEK_92SE, BROADCOM, RALINK, ATHEROS, ++ *CISCO, MERU, MARVELL, 92U_AP, SELF_AP(UpLink/Rx) ++ */ ++ 0xa44f, 0x5ea44f, 0x5e4322, 0x5ea42b, 0xa44f, 0xa630, ++ 0x5ea630, 0x5ea42b, 0xa44f, 0xa42b, 0xa42b}; ++ ++void ODM_EdcaTurboInit(void *pDM_VOID) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ ++ pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false; ++ pDM_Odm->DM_EDCA_Table.bIsCurRDLState = false; ++ Adapter->recvpriv.bIsAnyNonBEPkts = false; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ++ ("Orginial VO PARAM: 0x%x\n", ++ rtw_read32(pDM_Odm->Adapter, ODM_EDCA_VO_PARAM))); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ++ ("Orginial VI PARAM: 0x%x\n", ++ rtw_read32(pDM_Odm->Adapter, ODM_EDCA_VI_PARAM))); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ++ ("Orginial BE PARAM: 0x%x\n", ++ rtw_read32(pDM_Odm->Adapter, ODM_EDCA_BE_PARAM))); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ++ ("Orginial BK PARAM: 0x%x\n", ++ rtw_read32(pDM_Odm->Adapter, ODM_EDCA_BK_PARAM))); ++} /* ODM_InitEdcaTurbo */ ++ ++void odm_EdcaTurboCheck(void *pDM_VOID) ++{ ++ /* In HW integration first stage, we provide 4 different handles to ++ * operate at the same time. In stage2/3, we need to prove universal ++ * interface and merge all HW dynamic mechanism. ++ */ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ++ ("odm_EdcaTurboCheck ========================>\n")); ++ ++ if (!(pDM_Odm->SupportAbility & ODM_MAC_EDCA_TURBO)) ++ return; ++ ++ odm_EdcaTurboCheckCE(pDM_Odm); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ++ ("<========================odm_EdcaTurboCheck\n")); ++} /* odm_CheckEdcaTurbo */ ++ ++void odm_EdcaTurboCheckCE(void *pDM_VOID) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ struct adapter * Adapter = pDM_Odm->Adapter; ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter); ++ struct recv_priv *precvpriv = &(Adapter->recvpriv); ++ struct registry_priv *pregpriv = &Adapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &(Adapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ u32 EDCA_BE_UL = 0x5ea42b; ++ u32 EDCA_BE_DL = 0x5ea42b; ++ u32 iot_peer = 0; ++ u8 wirelessmode = 0xFF; /* invalid value */ ++ u32 trafficIndex; ++ u32 edca_param; ++ u64 cur_tx_bytes = 0; ++ u64 cur_rx_bytes = 0; ++ u8 bbtchange = false; ++ u8 biasonrx = false; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++ if (!pDM_Odm->bLinked) { ++ precvpriv->bIsAnyNonBEPkts = false; ++ return; ++ } ++ ++ if ((pregpriv->wifi_spec == 1)) { ++ precvpriv->bIsAnyNonBEPkts = false; ++ return; ++ } ++ ++ if (pDM_Odm->pwirelessmode) ++ wirelessmode = *(pDM_Odm->pwirelessmode); ++ ++ iot_peer = pmlmeinfo->assoc_AP_vendor; ++ ++ if (iot_peer >= HT_IOT_PEER_MAX) { ++ precvpriv->bIsAnyNonBEPkts = false; ++ return; ++ } ++ ++ /* Check if the status needs to be changed. */ ++ if ((bbtchange) || (!precvpriv->bIsAnyNonBEPkts)) { ++ cur_tx_bytes = pdvobjpriv->traffic_stat.cur_tx_bytes; ++ cur_rx_bytes = pdvobjpriv->traffic_stat.cur_rx_bytes; ++ ++ /* traffic, TX or RX */ ++ if (biasonrx) { ++ if (cur_tx_bytes > (cur_rx_bytes << 2)) { ++ /* Uplink TP is present. */ ++ trafficIndex = UP_LINK; ++ } else { /* Balance TP is present. */ ++ trafficIndex = DOWN_LINK; ++ } ++ } else { ++ if (cur_rx_bytes > (cur_tx_bytes << 2)) { ++ /* Downlink TP is present. */ ++ trafficIndex = DOWN_LINK; ++ } else { /* Balance TP is present. */ ++ trafficIndex = UP_LINK; ++ } ++ } ++ ++ /* 92D txop can't be set to 0x3e for cisco1250 */ ++ if ((iot_peer == HT_IOT_PEER_CISCO) && ++ (wirelessmode == ODM_WM_N24G)) { ++ EDCA_BE_DL = edca_setting_DL[iot_peer]; ++ EDCA_BE_UL = edca_setting_UL[iot_peer]; ++ } else if ((iot_peer == HT_IOT_PEER_CISCO) && ++ ((wirelessmode == ODM_WM_G) || ++ (wirelessmode == (ODM_WM_B | ODM_WM_G)) || ++ (wirelessmode == ODM_WM_A) || ++ (wirelessmode == ODM_WM_B))) { ++ EDCA_BE_DL = edca_setting_DL_GMode[iot_peer]; ++ } else if ((iot_peer == HT_IOT_PEER_AIRGO) && ++ ((wirelessmode == ODM_WM_G) || ++ (wirelessmode == ODM_WM_A))) { ++ EDCA_BE_DL = 0xa630; ++ } else if (iot_peer == HT_IOT_PEER_MARVELL) { ++ EDCA_BE_DL = edca_setting_DL[iot_peer]; ++ EDCA_BE_UL = edca_setting_UL[iot_peer]; ++ } else if (iot_peer == HT_IOT_PEER_ATHEROS) { ++ /* Set DL EDCA for Atheros peer to 0x3ea42b. */ ++ EDCA_BE_DL = edca_setting_DL[iot_peer]; ++ } ++ ++ if (trafficIndex == DOWN_LINK) ++ edca_param = EDCA_BE_DL; ++ else ++ edca_param = EDCA_BE_UL; ++ ++ rtw_write32(Adapter, REG_EDCA_BE_PARAM, edca_param); ++ ++ pDM_Odm->DM_EDCA_Table.prv_traffic_idx = trafficIndex; ++ ++ pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = true; ++ } else { ++ /* Turn Off EDCA turbo here. */ ++ /* Restore original EDCA according to the declaration of AP. */ ++ if (pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA) { ++ rtw_write32(Adapter, REG_EDCA_BE_PARAM, ++ pHalData->AcParam_BE); ++ pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false; ++ } ++ } ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_EdcaTurboCheck.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_EdcaTurboCheck.h +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_EdcaTurboCheck.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_EdcaTurboCheck.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,41 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#ifndef __ODMEDCATURBOCHECK_H__ ++#define __ODMEDCATURBOCHECK_H__ ++ ++typedef struct _EDCA_TURBO_ ++{ ++ bool bCurrentTurboEDCA; ++ bool bIsCurRDLState; ++ ++ u32 prv_traffic_idx; /* edca turbo */ ++}EDCA_T,*pEDCA_T; ++ ++void ++odm_EdcaTurboCheck( ++void * pDM_VOID ++ ); ++void ++ODM_EdcaTurboInit( ++void * pDM_VOID ++); ++ ++void ++odm_EdcaTurboCheckCE( ++void * pDM_VOID ++ ); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm.h +--- linux-4.3/3rdparty/rtl8723bs/hal/odm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,1558 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++ ++#ifndef __HALDMOUTSRC_H__ ++#define __HALDMOUTSRC_H__ ++ ++ ++#include "odm_EdcaTurboCheck.h" ++#include "odm_DIG.h" ++#include "odm_PathDiv.h" ++#include "odm_DynamicBBPowerSaving.h" ++#include "odm_DynamicTxPower.h" ++#include "odm_CfoTracking.h" ++#include "odm_NoiseMonitor.h" ++ ++#define TP_MODE 0 ++#define RSSI_MODE 1 ++#define TRAFFIC_LOW 0 ++#define TRAFFIC_HIGH 1 ++#define NONE 0 ++ ++ ++/* 3 Tx Power Tracking */ ++/* 3 ============================================================ */ ++#define DPK_DELTA_MAPPING_NUM 13 ++#define index_mapping_HP_NUM 15 ++#define OFDM_TABLE_SIZE 43 ++#define CCK_TABLE_SIZE 33 ++#define TXSCALE_TABLE_SIZE 37 ++#define TXPWR_TRACK_TABLE_SIZE 30 ++#define DELTA_SWINGIDX_SIZE 30 ++#define BAND_NUM 4 ++ ++/* 3 PSD Handler */ ++/* 3 ============================================================ */ ++ ++#define AFH_PSD 1 /* 0:normal PSD scan, 1: only do 20 pts PSD */ ++#define MODE_40M 0 /* 0:20M, 1:40M */ ++#define PSD_TH2 3 ++#define PSD_CHMIN 20 /* Minimum channel number for BT AFH */ ++#define SIR_STEP_SIZE 3 ++#define Smooth_Size_1 5 ++#define Smooth_TH_1 3 ++#define Smooth_Size_2 10 ++#define Smooth_TH_2 4 ++#define Smooth_Size_3 20 ++#define Smooth_TH_3 4 ++#define Smooth_Step_Size 5 ++#define Adaptive_SIR 1 ++#define PSD_RESCAN 4 ++#define PSD_SCAN_INTERVAL 700 /* ms */ ++ ++/* 8723A High Power IGI Setting */ ++#define DM_DIG_HIGH_PWR_IGI_LOWER_BOUND 0x22 ++#define DM_DIG_Gmode_HIGH_PWR_IGI_LOWER_BOUND 0x28 ++#define DM_DIG_HIGH_PWR_THRESHOLD 0x3a ++#define DM_DIG_LOW_PWR_THRESHOLD 0x14 ++ ++/* ANT Test */ ++#define ANTTESTALL 0x00 /* Ant A or B will be Testing */ ++#define ANTTESTA 0x01 /* Ant A will be Testing */ ++#define ANTTESTB 0x02 /* Ant B will be testing */ ++ ++#define PS_MODE_ACTIVE 0x01 ++ ++/* for 8723A Ant Definition--2012--06--07 due to different IC may be different ANT define */ ++#define MAIN_ANT 1 /* Ant A or Ant Main */ ++#define AUX_ANT 2 /* AntB or Ant Aux */ ++#define MAX_ANT 3 /* 3 for AP using */ ++ ++ ++/* Antenna Diversity Type */ ++#define SW_ANTDIV 0 ++#define HW_ANTDIV 1 ++/* structure and define */ ++ ++/* Remove DIG by Yuchen */ ++ ++/* Remoce BB power saving by Yuchn */ ++ ++/* Remove DIG by yuchen */ ++ ++typedef struct _Dynamic_Primary_CCA{ ++ u8 PriCCA_flag; ++ u8 intf_flag; ++ u8 intf_type; ++ u8 DupRTS_flag; ++ u8 Monitor_flag; ++ u8 CH_offset; ++ u8 MF_state; ++}Pri_CCA_T, *pPri_CCA_T; ++ ++typedef struct _Rate_Adaptive_Table_{ ++ u8 firstconnect; ++}RA_T, *pRA_T; ++ ++typedef struct _RX_High_Power_ ++{ ++ u8 RXHP_flag; ++ u8 PSD_func_trigger; ++ u8 PSD_bitmap_RXHP[80]; ++ u8 Pre_IGI; ++ u8 Cur_IGI; ++ u8 Pre_pw_th; ++ u8 Cur_pw_th; ++ bool First_time_enter; ++ bool RXHP_enable; ++ u8 TP_Mode; ++ RT_TIMER PSDTimer; ++}RXHP_T, *pRXHP_T; ++ ++#define ASSOCIATE_ENTRY_NUM 32 /* Max size of AsocEntry[]. */ ++#define ODM_ASSOCIATE_ENTRY_NUM ASSOCIATE_ENTRY_NUM ++ ++/* This indicates two different the steps. */ ++/* In SWAW_STEP_PEAK, driver needs to switch antenna and listen to the signal on the air. */ ++/* In SWAW_STEP_DETERMINE, driver just compares the signal captured in SWAW_STEP_PEAK */ ++/* with original RSSI to determine if it is necessary to switch antenna. */ ++#define SWAW_STEP_PEAK 0 ++#define SWAW_STEP_DETERMINE 1 ++ ++#define TP_MODE 0 ++#define RSSI_MODE 1 ++#define TRAFFIC_LOW 0 ++#define TRAFFIC_HIGH 1 ++#define TRAFFIC_UltraLOW 2 ++ ++typedef struct _SW_Antenna_Switch_ ++{ ++ u8 Double_chk_flag; ++ u8 try_flag; ++ s32 PreRSSI; ++ u8 CurAntenna; ++ u8 PreAntenna; ++ u8 RSSI_Trying; ++ u8 TestMode; ++ u8 bTriggerAntennaSwitch; ++ u8 SelectAntennaMap; ++ u8 RSSI_target; ++ u8 reset_idx; ++ u16 Single_Ant_Counter; ++ u16 Dual_Ant_Counter; ++ u16 Aux_FailDetec_Counter; ++ u16 Retry_Counter; ++ ++ /* Before link Antenna Switch check */ ++ u8 SWAS_NoLink_State; ++ u32 SWAS_NoLink_BK_Reg860; ++ u32 SWAS_NoLink_BK_Reg92c; ++ u32 SWAS_NoLink_BK_Reg948; ++ bool ANTA_ON; /* To indicate Ant A is or not */ ++ bool ANTB_ON; /* To indicate Ant B is on or not */ ++ bool Pre_Aux_FailDetec; ++ bool RSSI_AntDect_bResult; ++ u8 Ant5G; ++ u8 Ant2G; ++ ++ s32 RSSI_sum_A; ++ s32 RSSI_sum_B; ++ s32 RSSI_cnt_A; ++ s32 RSSI_cnt_B; ++ ++ u64 lastTxOkCnt; ++ u64 lastRxOkCnt; ++ u64 TXByteCnt_A; ++ u64 TXByteCnt_B; ++ u64 RXByteCnt_A; ++ u64 RXByteCnt_B; ++ u8 TrafficLoad; ++ u8 Train_time; ++ u8 Train_time_flag; ++ RT_TIMER SwAntennaSwitchTimer; ++ RT_TIMER SwAntennaSwitchTimer_8723B; ++ u32 PktCnt_SWAntDivByCtrlFrame; ++ bool bSWAntDivByCtrlFrame; ++}SWAT_T, *pSWAT_T; ++ ++/* Remove Edca by YuChen */ ++ ++ ++typedef struct _ODM_RATE_ADAPTIVE ++{ ++ u8 Type; /* DM_Type_ByFW/DM_Type_ByDriver */ ++ u8 LdpcThres; /* if RSSI > LdpcThres => switch from LPDC to BCC */ ++ bool bUseLdpc; ++ bool bLowerRtsRate; ++ u8 HighRSSIThresh; /* if RSSI > HighRSSIThresh => RATRState is DM_RATR_STA_HIGH */ ++ u8 LowRSSIThresh; /* if RSSI <= LowRSSIThresh => RATRState is DM_RATR_STA_LOW */ ++ u8 RATRState; /* Current RSSI level, DM_RATR_STA_HIGH/DM_RATR_STA_MIDDLE/DM_RATR_STA_LOW */ ++ ++} ODM_RATE_ADAPTIVE, *PODM_RATE_ADAPTIVE; ++ ++ ++#define IQK_MAC_REG_NUM 4 ++#define IQK_ADDA_REG_NUM 16 ++#define IQK_BB_REG_NUM_MAX 10 ++#define IQK_BB_REG_NUM 9 ++#define HP_THERMAL_NUM 8 ++ ++#define AVG_THERMAL_NUM 8 ++#define IQK_Matrix_REG_NUM 8 ++#define IQK_Matrix_Settings_NUM 14+24+21 /* Channels_2_4G_NUM + Channels_5G_20M_NUM + Channels_5G */ ++ ++#define DM_Type_ByFW 0 ++#define DM_Type_ByDriver 1 ++ ++/* */ ++/* Declare for common info */ ++/* */ ++#define MAX_PATH_NUM_92CS 2 ++#define MAX_PATH_NUM_8188E 1 ++#define MAX_PATH_NUM_8192E 2 ++#define MAX_PATH_NUM_8723B 1 ++#define MAX_PATH_NUM_8812A 2 ++#define MAX_PATH_NUM_8821A 1 ++#define MAX_PATH_NUM_8814A 4 ++#define MAX_PATH_NUM_8822B 2 ++ ++ ++#define IQK_THRESHOLD 8 ++#define DPK_THRESHOLD 4 ++ ++typedef struct _ODM_Phy_Status_Info_ ++{ ++ /* */ ++ /* Be care, if you want to add any element please insert between */ ++ /* RxPWDBAll & SignalStrength. */ ++ /* */ ++ u8 RxPWDBAll; ++ ++ u8 SignalQuality; /* in 0-100 index. */ ++ s8 RxMIMOSignalQuality[4]; /* per-path's EVM */ ++ u8 RxMIMOEVMdbm[4]; /* per-path's EVM dbm */ ++ ++ u8 RxMIMOSignalStrength[4];/* in 0~100 index */ ++ ++ u16 Cfo_short[4]; /* per-path's Cfo_short */ ++ u16 Cfo_tail[4]; /* per-path's Cfo_tail */ ++ ++ s8 RxPower; /* in dBm Translate from PWdB */ ++ s8 RecvSignalPower; /* Real power in dBm for this packet, no beautification and aggregation. Keep this raw info to be used for the other procedures. */ ++ u8 BTRxRSSIPercentage; ++ u8 SignalStrength; /* in 0-100 index. */ ++ ++ s8 RxPwr[4]; /* per-path's pwdb */ ++ ++ u8 RxSNR[4]; /* per-path's SNR */ ++ u8 BandWidth; ++ u8 btCoexPwrAdjust; ++}ODM_PHY_INFO_T,*PODM_PHY_INFO_T; ++ ++ ++typedef struct _ODM_Per_Pkt_Info_ ++{ ++ /* u8 Rate; */ ++ u8 DataRate; ++ u8 StationID; ++ bool bPacketMatchBSSID; ++ bool bPacketToSelf; ++ bool bPacketBeacon; ++ bool bToSelf; ++}ODM_PACKET_INFO_T,*PODM_PACKET_INFO_T; ++ ++ ++typedef struct _ODM_Phy_Dbg_Info_ ++{ ++ /* ODM Write, debug info */ ++ s8 RxSNRdB[4]; ++ u32 NumQryPhyStatus; ++ u32 NumQryPhyStatusCCK; ++ u32 NumQryPhyStatusOFDM; ++ u8 NumQryBeaconPkt; ++ /* Others */ ++ s32 RxEVM[4]; ++ ++}ODM_PHY_DBG_INFO_T; ++ ++ ++typedef struct _ODM_Mac_Status_Info_ ++{ ++ u8 test; ++ ++}ODM_MAC_INFO; ++ ++ ++typedef enum tag_Dynamic_ODM_Support_Ability_Type ++{ ++ /* BB Team */ ++ ODM_DIG = 0x00000001, ++ ODM_HIGH_POWER = 0x00000002, ++ ODM_CCK_CCA_TH = 0x00000004, ++ ODM_FA_STATISTICS = 0x00000008, ++ ODM_RAMASK = 0x00000010, ++ ODM_RSSI_MONITOR = 0x00000020, ++ ODM_SW_ANTDIV = 0x00000040, ++ ODM_HW_ANTDIV = 0x00000080, ++ ODM_BB_PWRSV = 0x00000100, ++ ODM_2TPATHDIV = 0x00000200, ++ ODM_1TPATHDIV = 0x00000400, ++ ODM_PSD2AFH = 0x00000800 ++}ODM_Ability_E; ++ ++/* */ ++/* 2011/20/20 MH For MP driver RT_WLAN_STA = STA_INFO_T */ ++/* Please declare below ODM relative info in your STA info structure. */ ++/* */ ++typedef struct _ODM_STA_INFO{ ++ /* Driver Write */ ++ bool bUsed; /* record the sta status link or not? */ ++ /* u8 WirelessMode; */ ++ u8 IOTPeer; /* Enum value. HT_IOT_PEER_E */ ++ ++ /* ODM Write */ ++ /* 1 PHY_STATUS_INFO */ ++ u8 RSSI_Path[4]; /* */ ++ u8 RSSI_Ave; ++ u8 RXEVM[4]; ++ u8 RXSNR[4]; ++ ++ /* ODM Write */ ++ /* 1 TX_INFO (may changed by IC) */ ++ /* TX_INFO_T pTxInfo; Define in IC folder. Move lower layer. */ ++ ++ /* */ ++ /* Please use compile flag to disabe the strcutrue for other IC except 88E. */ ++ /* Move To lower layer. */ ++ /* */ ++ /* ODM Write Wilson will handle this part(said by Luke.Lee) */ ++ /* TX_RPT_T pTxRpt; Define in IC folder. Move lower layer. */ ++}ODM_STA_INFO_T, *PODM_STA_INFO_T; ++ ++/* */ ++/* 2011/10/20 MH Define Common info enum for all team. */ ++/* */ ++typedef enum _ODM_Common_Info_Definition ++{ ++ /* Fixed value: */ ++ ++ /* HOOK BEFORE REG INIT----------- */ ++ ODM_CMNINFO_PLATFORM = 0, ++ ODM_CMNINFO_ABILITY, /* ODM_ABILITY_E */ ++ ODM_CMNINFO_INTERFACE, /* ODM_INTERFACE_E */ ++ ODM_CMNINFO_MP_TEST_CHIP, ++ ODM_CMNINFO_IC_TYPE, /* ODM_IC_TYPE_E */ ++ ODM_CMNINFO_CUT_VER, /* ODM_CUT_VERSION_E */ ++ ODM_CMNINFO_FAB_VER, /* ODM_FAB_E */ ++ ODM_CMNINFO_RF_TYPE, /* ODM_RF_PATH_E or ODM_RF_TYPE_E? */ ++ ODM_CMNINFO_RFE_TYPE, ++ ODM_CMNINFO_BOARD_TYPE, /* ODM_BOARD_TYPE_E */ ++ ODM_CMNINFO_PACKAGE_TYPE, ++ ODM_CMNINFO_EXT_LNA, /* true */ ++ ODM_CMNINFO_5G_EXT_LNA, ++ ODM_CMNINFO_EXT_PA, ++ ODM_CMNINFO_5G_EXT_PA, ++ ODM_CMNINFO_GPA, ++ ODM_CMNINFO_APA, ++ ODM_CMNINFO_GLNA, ++ ODM_CMNINFO_ALNA, ++ ODM_CMNINFO_EXT_TRSW, ++ ODM_CMNINFO_PATCH_ID, /* CUSTOMER ID */ ++ ODM_CMNINFO_BINHCT_TEST, ++ ODM_CMNINFO_BWIFI_TEST, ++ ODM_CMNINFO_SMART_CONCURRENT, ++ /* HOOK BEFORE REG INIT----------- */ ++ ++ ++ /* Dynamic value: */ ++/* POINTER REFERENCE----------- */ ++ ODM_CMNINFO_MAC_PHY_MODE, /* ODM_MAC_PHY_MODE_E */ ++ ODM_CMNINFO_TX_UNI, ++ ODM_CMNINFO_RX_UNI, ++ ODM_CMNINFO_WM_MODE, /* ODM_WIRELESS_MODE_E */ ++ ODM_CMNINFO_BAND, /* ODM_BAND_TYPE_E */ ++ ODM_CMNINFO_SEC_CHNL_OFFSET, /* ODM_SEC_CHNL_OFFSET_E */ ++ ODM_CMNINFO_SEC_MODE, /* ODM_SECURITY_E */ ++ ODM_CMNINFO_BW, /* ODM_BW_E */ ++ ODM_CMNINFO_CHNL, ++ ODM_CMNINFO_FORCED_RATE, ++ ++ ODM_CMNINFO_DMSP_GET_VALUE, ++ ODM_CMNINFO_BUDDY_ADAPTOR, ++ ODM_CMNINFO_DMSP_IS_MASTER, ++ ODM_CMNINFO_SCAN, ++ ODM_CMNINFO_POWER_SAVING, ++ ODM_CMNINFO_ONE_PATH_CCA, /* ODM_CCA_PATH_E */ ++ ODM_CMNINFO_DRV_STOP, ++ ODM_CMNINFO_PNP_IN, ++ ODM_CMNINFO_INIT_ON, ++ ODM_CMNINFO_ANT_TEST, ++ ODM_CMNINFO_NET_CLOSED, ++ ODM_CMNINFO_MP_MODE, ++ /* ODM_CMNINFO_RTSTA_AID, For win driver only? */ ++ ODM_CMNINFO_FORCED_IGI_LB, ++ ODM_CMNINFO_IS1ANTENNA, ++ ODM_CMNINFO_RFDEFAULTPATH, ++/* POINTER REFERENCE----------- */ ++ ++/* CALL BY VALUE------------- */ ++ ODM_CMNINFO_WIFI_DIRECT, ++ ODM_CMNINFO_WIFI_DISPLAY, ++ ODM_CMNINFO_LINK_IN_PROGRESS, ++ ODM_CMNINFO_LINK, ++ ODM_CMNINFO_STATION_STATE, ++ ODM_CMNINFO_RSSI_MIN, ++ ODM_CMNINFO_DBG_COMP, /* u64 */ ++ ODM_CMNINFO_DBG_LEVEL, /* u32 */ ++ ODM_CMNINFO_RA_THRESHOLD_HIGH, /* u8 */ ++ ODM_CMNINFO_RA_THRESHOLD_LOW, /* u8 */ ++ ODM_CMNINFO_RF_ANTENNA_TYPE, /* u8 */ ++ ODM_CMNINFO_BT_ENABLED, ++ ODM_CMNINFO_BT_HS_CONNECT_PROCESS, ++ ODM_CMNINFO_BT_HS_RSSI, ++ ODM_CMNINFO_BT_OPERATION, ++ ODM_CMNINFO_BT_LIMITED_DIG, /* Need to Limited Dig or not */ ++ ODM_CMNINFO_BT_DISABLE_EDCA, ++/* CALL BY VALUE------------- */ ++ ++ /* Dynamic ptr array hook itms. */ ++ ODM_CMNINFO_STA_STATUS, ++ ODM_CMNINFO_PHY_STATUS, ++ ODM_CMNINFO_MAC_STATUS, ++ ++ ODM_CMNINFO_MAX, ++ ++ ++}ODM_CMNINFO_E; ++ ++/* 2011/10/20 MH Define ODM support ability. ODM_CMNINFO_ABILITY */ ++typedef enum _ODM_Support_Ability_Definition ++{ ++ /* */ ++ /* BB ODM section BIT 0-15 */ ++ /* */ ++ ODM_BB_DIG = BIT0, ++ ODM_BB_RA_MASK = BIT1, ++ ODM_BB_DYNAMIC_TXPWR = BIT2, ++ ODM_BB_FA_CNT = BIT3, ++ ODM_BB_RSSI_MONITOR = BIT4, ++ ODM_BB_CCK_PD = BIT5, ++ ODM_BB_ANT_DIV = BIT6, ++ ODM_BB_PWR_SAVE = BIT7, ++ ODM_BB_PWR_TRAIN = BIT8, ++ ODM_BB_RATE_ADAPTIVE = BIT9, ++ ODM_BB_PATH_DIV = BIT10, ++ ODM_BB_PSD = BIT11, ++ ODM_BB_RXHP = BIT12, ++ ODM_BB_ADAPTIVITY = BIT13, ++ ODM_BB_CFO_TRACKING = BIT14, ++ ++ /* MAC DM section BIT 16-23 */ ++ ODM_MAC_EDCA_TURBO = BIT16, ++ ODM_MAC_EARLY_MODE = BIT17, ++ ++ /* RF ODM section BIT 24-31 */ ++ ODM_RF_TX_PWR_TRACK = BIT24, ++ ODM_RF_RX_GAIN_TRACK = BIT25, ++ ODM_RF_CALIBRATION = BIT26, ++}ODM_ABILITY_E; ++ ++/* ODM_CMNINFO_INTERFACE */ ++typedef enum tag_ODM_Support_Interface_Definition ++{ ++ ODM_ITRF_SDIO = 0x4, ++ ODM_ITRF_ALL = 0x7, ++}ODM_INTERFACE_E; ++ ++/* ODM_CMNINFO_IC_TYPE */ ++typedef enum tag_ODM_Support_IC_Type_Definition ++{ ++ ODM_RTL8723B = BIT8, ++}ODM_IC_TYPE_E; ++ ++/* ODM_CMNINFO_CUT_VER */ ++typedef enum tag_ODM_Cut_Version_Definition ++{ ++ ODM_CUT_A = 0, ++ ODM_CUT_B = 1, ++ ODM_CUT_C = 2, ++ ODM_CUT_D = 3, ++ ODM_CUT_E = 4, ++ ODM_CUT_F = 5, ++ ++ ODM_CUT_I = 8, ++ ODM_CUT_J = 9, ++ ODM_CUT_K = 10, ++ ODM_CUT_TEST = 15, ++}ODM_CUT_VERSION_E; ++ ++/* ODM_CMNINFO_FAB_VER */ ++typedef enum tag_ODM_Fab_Version_Definition ++{ ++ ODM_TSMC = 0, ++ ODM_UMC = 1, ++}ODM_FAB_E; ++ ++/* ODM_CMNINFO_RF_TYPE */ ++/* */ ++/* For example 1T2R (A+AB = BIT0|BIT4|BIT5) */ ++/* */ ++typedef enum tag_ODM_RF_Path_Bit_Definition ++{ ++ ODM_RF_TX_A = BIT0, ++ ODM_RF_TX_B = BIT1, ++ ODM_RF_TX_C = BIT2, ++ ODM_RF_TX_D = BIT3, ++ ODM_RF_RX_A = BIT4, ++ ODM_RF_RX_B = BIT5, ++ ODM_RF_RX_C = BIT6, ++ ODM_RF_RX_D = BIT7, ++}ODM_RF_PATH_E; ++ ++ ++typedef enum tag_ODM_RF_Type_Definition ++{ ++ ODM_1T1R = 0, ++ ODM_1T2R = 1, ++ ODM_2T2R = 2, ++ ODM_2T3R = 3, ++ ODM_2T4R = 4, ++ ODM_3T3R = 5, ++ ODM_3T4R = 6, ++ ODM_4T4R = 7, ++}ODM_RF_TYPE_E; ++ ++ ++/* */ ++/* ODM Dynamic common info value definition */ ++/* */ ++ ++/* typedef enum _MACPHY_MODE_8192D{ */ ++/* SINGLEMAC_SINGLEPHY, */ ++/* DUALMAC_DUALPHY, */ ++/* DUALMAC_SINGLEPHY, */ ++/* MACPHY_MODE_8192D,*PMACPHY_MODE_8192D; */ ++/* Above is the original define in MP driver. Please use the same define. THX. */ ++typedef enum tag_ODM_MAC_PHY_Mode_Definition ++{ ++ ODM_SMSP = 0, ++ ODM_DMSP = 1, ++ ODM_DMDP = 2, ++}ODM_MAC_PHY_MODE_E; ++ ++ ++typedef enum tag_BT_Coexist_Definition ++{ ++ ODM_BT_BUSY = 1, ++ ODM_BT_ON = 2, ++ ODM_BT_OFF = 3, ++ ODM_BT_NONE = 4, ++}ODM_BT_COEXIST_E; ++ ++/* ODM_CMNINFO_OP_MODE */ ++typedef enum tag_Operation_Mode_Definition ++{ ++ ODM_NO_LINK = BIT0, ++ ODM_LINK = BIT1, ++ ODM_SCAN = BIT2, ++ ODM_POWERSAVE = BIT3, ++ ODM_AP_MODE = BIT4, ++ ODM_CLIENT_MODE = BIT5, ++ ODM_AD_HOC = BIT6, ++ ODM_WIFI_DIRECT = BIT7, ++ ODM_WIFI_DISPLAY = BIT8, ++}ODM_OPERATION_MODE_E; ++ ++/* ODM_CMNINFO_WM_MODE */ ++typedef enum tag_Wireless_Mode_Definition ++{ ++ ODM_WM_UNKNOW = 0x0, ++ ODM_WM_B = BIT0, ++ ODM_WM_G = BIT1, ++ ODM_WM_A = BIT2, ++ ODM_WM_N24G = BIT3, ++ ODM_WM_N5G = BIT4, ++ ODM_WM_AUTO = BIT5, ++ ODM_WM_AC = BIT6, ++}ODM_WIRELESS_MODE_E; ++ ++/* ODM_CMNINFO_BAND */ ++typedef enum tag_Band_Type_Definition ++{ ++ ODM_BAND_2_4G = 0, ++ ODM_BAND_5G, ++ ODM_BAND_ON_BOTH, ++ ODM_BANDMAX ++ ++}ODM_BAND_TYPE_E; ++ ++/* ODM_CMNINFO_SEC_CHNL_OFFSET */ ++typedef enum tag_Secondary_Channel_Offset_Definition ++{ ++ ODM_DONT_CARE = 0, ++ ODM_BELOW = 1, ++ ODM_ABOVE = 2 ++}ODM_SEC_CHNL_OFFSET_E; ++ ++/* ODM_CMNINFO_SEC_MODE */ ++typedef enum tag_Security_Definition ++{ ++ ODM_SEC_OPEN = 0, ++ ODM_SEC_WEP40 = 1, ++ ODM_SEC_TKIP = 2, ++ ODM_SEC_RESERVE = 3, ++ ODM_SEC_AESCCMP = 4, ++ ODM_SEC_WEP104 = 5, ++ ODM_WEP_WPA_MIXED = 6, /* WEP + WPA */ ++ ODM_SEC_SMS4 = 7, ++}ODM_SECURITY_E; ++ ++/* ODM_CMNINFO_BW */ ++typedef enum tag_Bandwidth_Definition ++{ ++ ODM_BW20M = 0, ++ ODM_BW40M = 1, ++ ODM_BW80M = 2, ++ ODM_BW160M = 3, ++ ODM_BW10M = 4, ++}ODM_BW_E; ++ ++ ++/* ODM_CMNINFO_BOARD_TYPE */ ++/* For non-AC-series IC , ODM_BOARD_5G_EXT_PA and ODM_BOARD_5G_EXT_LNA are ignored */ ++/* For AC-series IC, external PA & LNA can be indivisuallly added on 2.4G and/or 5G */ ++typedef enum tag_Board_Definition ++{ ++ ODM_BOARD_DEFAULT = 0, /* The DEFAULT case. */ ++ ODM_BOARD_MINICARD = BIT(0), /* 0 = non-mini card, 1 = mini card. */ ++ ODM_BOARD_SLIM = BIT(1), /* 0 = non-slim card, 1 = slim card */ ++ ODM_BOARD_BT = BIT(2), /* 0 = without BT card, 1 = with BT */ ++ ODM_BOARD_EXT_PA = BIT(3), /* 0 = no 2G ext-PA, 1 = existing 2G ext-PA */ ++ ODM_BOARD_EXT_LNA = BIT(4), /* 0 = no 2G ext-LNA, 1 = existing 2G ext-LNA */ ++ ODM_BOARD_EXT_TRSW = BIT(5), /* 0 = no ext-TRSW, 1 = existing ext-TRSW */ ++ ODM_BOARD_EXT_PA_5G = BIT(6), /* 0 = no 5G ext-PA, 1 = existing 5G ext-PA */ ++ ODM_BOARD_EXT_LNA_5G = BIT(7), /* 0 = no 5G ext-LNA, 1 = existing 5G ext-LNA */ ++}ODM_BOARD_TYPE_E; ++ ++typedef enum tag_ODM_Package_Definition ++{ ++ ODM_PACKAGE_DEFAULT = 0, ++ ODM_PACKAGE_QFN68 = BIT(0), ++ ODM_PACKAGE_TFBGA90 = BIT(1), ++ ODM_PACKAGE_TFBGA79 = BIT(2), ++}ODM_Package_TYPE_E; ++ ++typedef enum tag_ODM_TYPE_GPA_Definition ++{ ++ TYPE_GPA0 = 0, ++ TYPE_GPA1 = BIT(1)|BIT(0) ++}ODM_TYPE_GPA_E; ++ ++typedef enum tag_ODM_TYPE_APA_Definition ++{ ++ TYPE_APA0 = 0, ++ TYPE_APA1 = BIT(1)|BIT(0) ++}ODM_TYPE_APA_E; ++ ++typedef enum tag_ODM_TYPE_GLNA_Definition ++{ ++ TYPE_GLNA0 = 0, ++ TYPE_GLNA1 = BIT(2)|BIT(0), ++ TYPE_GLNA2 = BIT(3)|BIT(1), ++ TYPE_GLNA3 = BIT(3)|BIT(2)|BIT(1)|BIT(0) ++}ODM_TYPE_GLNA_E; ++ ++typedef enum tag_ODM_TYPE_ALNA_Definition ++{ ++ TYPE_ALNA0 = 0, ++ TYPE_ALNA1 = BIT(2)|BIT(0), ++ TYPE_ALNA2 = BIT(3)|BIT(1), ++ TYPE_ALNA3 = BIT(3)|BIT(2)|BIT(1)|BIT(0) ++}ODM_TYPE_ALNA_E; ++ ++/* ODM_CMNINFO_ONE_PATH_CCA */ ++typedef enum tag_CCA_Path ++{ ++ ODM_CCA_2R = 0, ++ ODM_CCA_1R_A = 1, ++ ODM_CCA_1R_B = 2, ++}ODM_CCA_PATH_E; ++ ++ ++typedef struct _ODM_RA_Info_ ++{ ++ u8 RateID; ++ u32 RateMask; ++ u32 RAUseRate; ++ u8 RateSGI; ++ u8 RssiStaRA; ++ u8 PreRssiStaRA; ++ u8 SGIEnable; ++ u8 DecisionRate; ++ u8 PreRate; ++ u8 HighestRate; ++ u8 LowestRate; ++ u32 NscUp; ++ u32 NscDown; ++ u16 RTY[5]; ++ u32 TOTAL; ++ u16 DROP; ++ u8 Active; ++ u16 RptTime; ++ u8 RAWaitingCounter; ++ u8 RAPendingCounter; ++ u8 PTActive; /* on or off */ ++ u8 PTTryState; /* 0 trying state, 1 for decision state */ ++ u8 PTStage; /* 0~6 */ ++ u8 PTStopCount; /* Stop PT counter */ ++ u8 PTPreRate; /* if rate change do PT */ ++ u8 PTPreRssi; /* if RSSI change 5% do PT */ ++ u8 PTModeSS; /* decide whitch rate should do PT */ ++ u8 RAstage; /* StageRA, decide how many times RA will be done between PT */ ++ u8 PTSmoothFactor; ++} ODM_RA_INFO_T,*PODM_RA_INFO_T; ++ ++typedef struct _IQK_MATRIX_REGS_SETTING{ ++ bool bIQKDone; ++ s32 Value[3][IQK_Matrix_REG_NUM]; ++ bool bBWIqkResultSaved[3]; ++}IQK_MATRIX_REGS_SETTING,*PIQK_MATRIX_REGS_SETTING; ++ ++ ++/* Remove PATHDIV_PARA struct to odm_PathDiv.h */ ++ ++typedef struct ODM_RF_Calibration_Structure ++{ ++ /* for tx power tracking */ ++ ++ u32 RegA24; /* for TempCCK */ ++ s32 RegE94; ++ s32 RegE9C; ++ s32 RegEB4; ++ s32 RegEBC; ++ ++ u8 TXPowercount; ++ bool bTXPowerTrackingInit; ++ bool bTXPowerTracking; ++ u8 TxPowerTrackControl; /* for mp mode, turn off txpwrtracking as default */ ++ u8 TM_Trigger; ++ u8 InternalPA5G[2]; /* pathA / pathB */ ++ ++ u8 ThermalMeter[2]; /* ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 */ ++ u8 ThermalValue; ++ u8 ThermalValue_LCK; ++ u8 ThermalValue_IQK; ++ u8 ThermalValue_DPK; ++ u8 ThermalValue_AVG[AVG_THERMAL_NUM]; ++ u8 ThermalValue_AVG_index; ++ u8 ThermalValue_RxGain; ++ u8 ThermalValue_Crystal; ++ u8 ThermalValue_DPKstore; ++ u8 ThermalValue_DPKtrack; ++ bool TxPowerTrackingInProgress; ++ ++ bool bReloadtxpowerindex; ++ u8 bRfPiEnable; ++ u32 TXPowerTrackingCallbackCnt; /* cosa add for debug */ ++ ++ ++ /* Tx power Tracking ------------------------- */ ++ u8 bCCKinCH14; ++ u8 CCK_index; ++ u8 OFDM_index[MAX_RF_PATH]; ++ s8 PowerIndexOffset[MAX_RF_PATH]; ++ s8 DeltaPowerIndex[MAX_RF_PATH]; ++ s8 DeltaPowerIndexLast[MAX_RF_PATH]; ++ bool bTxPowerChanged; ++ ++ u8 ThermalValue_HP[HP_THERMAL_NUM]; ++ u8 ThermalValue_HP_index; ++ IQK_MATRIX_REGS_SETTING IQKMatrixRegSetting[IQK_Matrix_Settings_NUM]; ++ bool bNeedIQK; ++ bool bIQKInProgress; ++ u8 Delta_IQK; ++ u8 Delta_LCK; ++ s8 BBSwingDiff2G, BBSwingDiff5G; /* Unit: dB */ ++ u8 DeltaSwingTableIdx_2GCCKA_P[DELTA_SWINGIDX_SIZE]; ++ u8 DeltaSwingTableIdx_2GCCKA_N[DELTA_SWINGIDX_SIZE]; ++ u8 DeltaSwingTableIdx_2GCCKB_P[DELTA_SWINGIDX_SIZE]; ++ u8 DeltaSwingTableIdx_2GCCKB_N[DELTA_SWINGIDX_SIZE]; ++ u8 DeltaSwingTableIdx_2GA_P[DELTA_SWINGIDX_SIZE]; ++ u8 DeltaSwingTableIdx_2GA_N[DELTA_SWINGIDX_SIZE]; ++ u8 DeltaSwingTableIdx_2GB_P[DELTA_SWINGIDX_SIZE]; ++ u8 DeltaSwingTableIdx_2GB_N[DELTA_SWINGIDX_SIZE]; ++ u8 DeltaSwingTableIdx_5GA_P[BAND_NUM][DELTA_SWINGIDX_SIZE]; ++ u8 DeltaSwingTableIdx_5GA_N[BAND_NUM][DELTA_SWINGIDX_SIZE]; ++ u8 DeltaSwingTableIdx_5GB_P[BAND_NUM][DELTA_SWINGIDX_SIZE]; ++ u8 DeltaSwingTableIdx_5GB_N[BAND_NUM][DELTA_SWINGIDX_SIZE]; ++ u8 DeltaSwingTableIdx_2GA_P_8188E[DELTA_SWINGIDX_SIZE]; ++ u8 DeltaSwingTableIdx_2GA_N_8188E[DELTA_SWINGIDX_SIZE]; ++ ++ /* */ ++ ++ /* for IQK */ ++ u32 RegC04; ++ u32 Reg874; ++ u32 RegC08; ++ u32 RegB68; ++ u32 RegB6C; ++ u32 Reg870; ++ u32 Reg860; ++ u32 Reg864; ++ ++ bool bIQKInitialized; ++ bool bLCKInProgress; ++ bool bAntennaDetected; ++ u32 ADDA_backup[IQK_ADDA_REG_NUM]; ++ u32 IQK_MAC_backup[IQK_MAC_REG_NUM]; ++ u32 IQK_BB_backup_recover[9]; ++ u32 IQK_BB_backup[IQK_BB_REG_NUM]; ++ u32 TxIQC_8723B[2][3][2]; /* { {S1: 0xc94, 0xc80, 0xc4c} , {S0: 0xc9c, 0xc88, 0xc4c}} */ ++ u32 RxIQC_8723B[2][2][2]; /* { {S1: 0xc14, 0xca0} , {S0: 0xc14, 0xca0}} */ ++ ++ ++ /* for APK */ ++ u32 APKoutput[2][2]; /* path A/B; output1_1a/output1_2a */ ++ u8 bAPKdone; ++ u8 bAPKThermalMeterIgnore; ++ ++ /* DPK */ ++ bool bDPKFail; ++ u8 bDPdone; ++ u8 bDPPathAOK; ++ u8 bDPPathBOK; ++ ++ u32 TxLOK[2]; ++ ++}ODM_RF_CAL_T,*PODM_RF_CAL_T; ++/* */ ++/* ODM Dynamic common info value definition */ ++/* */ ++ ++typedef struct _FAST_ANTENNA_TRAINNING_ ++{ ++ u8 Bssid[6]; ++ u8 antsel_rx_keep_0; ++ u8 antsel_rx_keep_1; ++ u8 antsel_rx_keep_2; ++ u8 antsel_rx_keep_3; ++ u32 antSumRSSI[7]; ++ u32 antRSSIcnt[7]; ++ u32 antAveRSSI[7]; ++ u8 FAT_State; ++ u32 TrainIdx; ++ u8 antsel_a[ODM_ASSOCIATE_ENTRY_NUM]; ++ u8 antsel_b[ODM_ASSOCIATE_ENTRY_NUM]; ++ u8 antsel_c[ODM_ASSOCIATE_ENTRY_NUM]; ++ u32 MainAnt_Sum[ODM_ASSOCIATE_ENTRY_NUM]; ++ u32 AuxAnt_Sum[ODM_ASSOCIATE_ENTRY_NUM]; ++ u32 MainAnt_Cnt[ODM_ASSOCIATE_ENTRY_NUM]; ++ u32 AuxAnt_Cnt[ODM_ASSOCIATE_ENTRY_NUM]; ++ u8 RxIdleAnt; ++ bool bBecomeLinked; ++ u32 MinMaxRSSI; ++ u8 idx_AntDiv_counter_2G; ++ u8 idx_AntDiv_counter_5G; ++ u32 AntDiv_2G_5G; ++ u32 CCK_counter_main; ++ u32 CCK_counter_aux; ++ u32 OFDM_counter_main; ++ u32 OFDM_counter_aux; ++ ++ ++ u32 CCK_CtrlFrame_Cnt_main; ++ u32 CCK_CtrlFrame_Cnt_aux; ++ u32 OFDM_CtrlFrame_Cnt_main; ++ u32 OFDM_CtrlFrame_Cnt_aux; ++ u32 MainAnt_CtrlFrame_Sum; ++ u32 AuxAnt_CtrlFrame_Sum; ++ u32 MainAnt_CtrlFrame_Cnt; ++ u32 AuxAnt_CtrlFrame_Cnt; ++ ++}FAT_T,*pFAT_T; ++ ++typedef enum _FAT_STATE ++{ ++ FAT_NORMAL_STATE = 0, ++ FAT_TRAINING_STATE = 1, ++}FAT_STATE_E, *PFAT_STATE_E; ++ ++typedef enum _ANT_DIV_TYPE ++{ ++ NO_ANTDIV = 0xFF, ++ CG_TRX_HW_ANTDIV = 0x01, ++ CGCS_RX_HW_ANTDIV = 0x02, ++ FIXED_HW_ANTDIV = 0x03, ++ CG_TRX_SMART_ANTDIV = 0x04, ++ CGCS_RX_SW_ANTDIV = 0x05, ++ S0S1_SW_ANTDIV = 0x06 /* 8723B intrnal switch S0 S1 */ ++}ANT_DIV_TYPE_E, *PANT_DIV_TYPE_E; ++ ++typedef struct _ODM_PATH_DIVERSITY_ ++{ ++ u8 RespTxPath; ++ u8 PathSel[ODM_ASSOCIATE_ENTRY_NUM]; ++ u32 PathA_Sum[ODM_ASSOCIATE_ENTRY_NUM]; ++ u32 PathB_Sum[ODM_ASSOCIATE_ENTRY_NUM]; ++ u32 PathA_Cnt[ODM_ASSOCIATE_ENTRY_NUM]; ++ u32 PathB_Cnt[ODM_ASSOCIATE_ENTRY_NUM]; ++}PATHDIV_T, *pPATHDIV_T; ++ ++ ++typedef enum _BASEBAND_CONFIG_PHY_REG_PG_VALUE_TYPE{ ++ PHY_REG_PG_RELATIVE_VALUE = 0, ++ PHY_REG_PG_EXACT_VALUE = 1 ++} PHY_REG_PG_TYPE; ++ ++ ++/* */ ++/* Antenna detection information from single tone mechanism, added by Roger, 2012.11.27. */ ++/* */ ++typedef struct _ANT_DETECTED_INFO{ ++ bool bAntDetected; ++ u32 dBForAntA; ++ u32 dBForAntB; ++ u32 dBForAntO; ++}ANT_DETECTED_INFO, *PANT_DETECTED_INFO; ++ ++/* */ ++/* 2011/09/22 MH Copy from SD4 defined structure. We use to support PHY DM integration. */ ++/* */ ++typedef struct DM_Out_Source_Dynamic_Mechanism_Structure ++{ ++ /* RT_TIMER FastAntTrainingTimer; */ ++ /* */ ++ /* Add for different team use temporarily */ ++ /* */ ++ struct adapter * Adapter; /* For CE/NIC team */ ++ /* WHen you use Adapter or priv pointer, you must make sure the pointer is ready. */ ++ bool odm_ready; ++ ++ PHY_REG_PG_TYPE PhyRegPgValueType; ++ u8 PhyRegPgVersion; ++ ++ u64 DebugComponents; ++ u32 DebugLevel; ++ ++ u32 NumQryPhyStatusAll; /* CCK + OFDM */ ++ u32 LastNumQryPhyStatusAll; ++ u32 RxPWDBAve; ++ bool MPDIG_2G; /* off MPDIG */ ++ u8 Times_2G; ++ ++/* ODM HANDLE, DRIVER NEEDS NOT TO HOOK------ */ ++ bool bCckHighPower; ++ u8 RFPathRxEnable; /* ODM_CMNINFO_RFPATH_ENABLE */ ++ u8 ControlChannel; ++/* ODM HANDLE, DRIVER NEEDS NOT TO HOOK------ */ ++ ++/* REMOVED COMMON INFO---------- */ ++ /* u8 PseudoMacPhyMode; */ ++ /* bool *BTCoexist; */ ++ /* bool PseudoBtCoexist; */ ++ /* u8 OPMode; */ ++ /* bool bAPMode; */ ++ /* bool bClientMode; */ ++ /* bool bAdHocMode; */ ++ /* bool bSlaveOfDMSP; */ ++/* REMOVED COMMON INFO---------- */ ++ ++ ++/* 1 COMMON INFORMATION */ ++ ++ /* */ ++ /* Init Value */ ++ /* */ ++/* HOOK BEFORE REG INIT----------- */ ++ /* ODM Platform info AP/ADSL/CE/MP = 1/2/3/4 */ ++ u8 SupportPlatform; ++ /* ODM Support Ability DIG/RATR/TX_PWR_TRACK/ ?K?K = 1/2/3/?K */ ++ u32 SupportAbility; ++ /* ODM PCIE/USB/SDIO = 1/2/3 */ ++ u8 SupportInterface; ++ /* ODM composite or independent. Bit oriented/ 92C+92D+ .... or any other type = 1/2/3/... */ ++ u32 SupportICType; ++ /* Cut Version TestChip/A-cut/B-cut... = 0/1/2/3/... */ ++ u8 CutVersion; ++ /* Fab Version TSMC/UMC = 0/1 */ ++ u8 FabVersion; ++ /* RF Type 4T4R/3T3R/2T2R/1T2R/1T1R/... */ ++ u8 RFType; ++ u8 RFEType; ++ /* Board Type Normal/HighPower/MiniCard/SLIM/Combo/... = 0/1/2/3/4/... */ ++ u8 BoardType; ++ u8 PackageType; ++ u8 TypeGLNA; ++ u8 TypeGPA; ++ u8 TypeALNA; ++ u8 TypeAPA; ++ /* with external LNA NO/Yes = 0/1 */ ++ u8 ExtLNA; ++ u8 ExtLNA5G; ++ /* with external PA NO/Yes = 0/1 */ ++ u8 ExtPA; ++ u8 ExtPA5G; ++ /* with external TRSW NO/Yes = 0/1 */ ++ u8 ExtTRSW; ++ u8 PatchID; /* Customer ID */ ++ bool bInHctTest; ++ bool bWIFITest; ++ ++ bool bDualMacSmartConcurrent; ++ u32 BK_SupportAbility; ++ u8 AntDivType; ++/* HOOK BEFORE REG INIT----------- */ ++ ++ /* */ ++ /* Dynamic Value */ ++ /* */ ++/* POINTER REFERENCE----------- */ ++ ++ u8 u8_temp; ++ bool bool_temp; ++ struct adapter *adapter_temp; ++ ++ /* MAC PHY Mode SMSP/DMSP/DMDP = 0/1/2 */ ++ u8 *pMacPhyMode; ++ /* TX Unicast byte count */ ++ u64 *pNumTxBytesUnicast; ++ /* RX Unicast byte count */ ++ u64 *pNumRxBytesUnicast; ++ /* Wireless mode B/G/A/N = BIT0/BIT1/BIT2/BIT3 */ ++ u8 *pwirelessmode; /* ODM_WIRELESS_MODE_E */ ++ /* Frequence band 2.4G/5G = 0/1 */ ++ u8 *pBandType; ++ /* Secondary channel offset don't_care/below/above = 0/1/2 */ ++ u8 *pSecChOffset; ++ /* Security mode Open/WEP/AES/TKIP = 0/1/2/3 */ ++ u8 *pSecurity; ++ /* BW info 20M/40M/80M = 0/1/2 */ ++ u8 *pBandWidth; ++ /* Central channel location Ch1/Ch2/.... */ ++ u8 *pChannel; /* central channel number */ ++ bool DPK_Done; ++ /* Common info for 92D DMSP */ ++ ++ bool *pbGetValueFromOtherMac; ++ struct adapter * *pBuddyAdapter; ++ bool *pbMasterOfDMSP; /* MAC0: master, MAC1: slave */ ++ /* Common info for Status */ ++ bool *pbScanInProcess; ++ bool *pbPowerSaving; ++ /* CCA Path 2-path/path-A/path-B = 0/1/2; using ODM_CCA_PATH_E. */ ++ u8 *pOnePathCCA; ++ /* pMgntInfo->AntennaTest */ ++ u8 *pAntennaTest; ++ bool *pbNet_closed; ++ u8 *mp_mode; ++ /* u8 *pAidMap; */ ++ u8 *pu1ForcedIgiLb; ++/* For 8723B IQK----------- */ ++ bool *pIs1Antenna; ++ u8 *pRFDefaultPath; ++ /* 0:S1, 1:S0 */ ++ ++/* POINTER REFERENCE----------- */ ++ u16 * pForcedDataRate; ++/* CALL BY VALUE------------- */ ++ bool bLinkInProcess; ++ bool bWIFI_Direct; ++ bool bWIFI_Display; ++ bool bLinked; ++ ++ bool bsta_state; ++ u8 RSSI_Min; ++ u8 InterfaceIndex; /* Add for 92D dual MAC: 0--Mac0 1--Mac1 */ ++ bool bIsMPChip; ++ bool bOneEntryOnly; ++ /* Common info for BTDM */ ++ bool bBtEnabled; /* BT is disabled */ ++ bool bBtConnectProcess; /* BT HS is under connection progress. */ ++ u8 btHsRssi; /* BT HS mode wifi rssi value. */ ++ bool bBtHsOperation; /* BT HS mode is under progress */ ++ bool bBtDisableEdcaTurbo; /* Under some condition, don't enable the EDCA Turbo */ ++ bool bBtLimitedDig; /* BT is busy. */ ++/* CALL BY VALUE------------- */ ++ u8 RSSI_A; ++ u8 RSSI_B; ++ u64 RSSI_TRSW; ++ u64 RSSI_TRSW_H; ++ u64 RSSI_TRSW_L; ++ u64 RSSI_TRSW_iso; ++ ++ u8 RxRate; ++ bool bNoisyState; ++ u8 TxRate; ++ u8 LinkedInterval; ++ u8 preChannel; ++ u32 TxagcOffsetValueA; ++ bool IsTxagcOffsetPositiveA; ++ u32 TxagcOffsetValueB; ++ bool IsTxagcOffsetPositiveB; ++ u64 lastTxOkCnt; ++ u64 lastRxOkCnt; ++ u32 BbSwingOffsetA; ++ bool IsBbSwingOffsetPositiveA; ++ u32 BbSwingOffsetB; ++ bool IsBbSwingOffsetPositiveB; ++ s8 TH_L2H_ini; ++ s8 TH_EDCCA_HL_diff; ++ s8 IGI_Base; ++ u8 IGI_target; ++ bool ForceEDCCA; ++ u8 AdapEn_RSSI; ++ s8 Force_TH_H; ++ s8 Force_TH_L; ++ u8 IGI_LowerBound; ++ u8 antdiv_rssi; ++ u8 AntType; ++ u8 pre_AntType; ++ u8 antdiv_period; ++ u8 antdiv_select; ++ u8 NdpaPeriod; ++ bool H2C_RARpt_connect; ++ ++ /* add by Yu Cehn for adaptivtiy */ ++ bool adaptivity_flag; ++ bool NHM_disable; ++ bool TxHangFlg; ++ bool Carrier_Sense_enable; ++ u8 tolerance_cnt; ++ u64 NHMCurTxOkcnt; ++ u64 NHMCurRxOkcnt; ++ u64 NHMLastTxOkcnt; ++ u64 NHMLastRxOkcnt; ++ u8 txEdcca1; ++ u8 txEdcca0; ++ s8 H2L_lb; ++ s8 L2H_lb; ++ u8 Adaptivity_IGI_upper; ++ u8 NHM_cnt_0; ++ ++ ++ ODM_NOISE_MONITOR noise_level;/* ODM_MAX_CHANNEL_NUM]; */ ++ /* */ ++ /* 2 Define STA info. */ ++ /* _ODM_STA_INFO */ ++ /* 2012/01/12 MH For MP, we need to reduce one array pointer for default port.?? */ ++ PSTA_INFO_T pODM_StaInfo[ODM_ASSOCIATE_ENTRY_NUM]; ++ ++ /* */ ++ /* 2012/02/14 MH Add to share 88E ra with other SW team. */ ++ /* We need to colelct all support abilit to a proper area. */ ++ /* */ ++ bool RaSupport88E; ++ ++ /* Define ........... */ ++ ++ /* Latest packet phy info (ODM write) */ ++ ODM_PHY_DBG_INFO_T PhyDbgInfo; ++ /* PHY_INFO_88E PhyInfo; */ ++ ++ /* Latest packet phy info (ODM write) */ ++ ODM_MAC_INFO *pMacInfo; ++ /* MAC_INFO_88E MacInfo; */ ++ ++ /* Different Team independt structure?? */ ++ ++ /* */ ++ /* TX_RTP_CMN TX_retrpo; */ ++ /* TX_RTP_88E TX_retrpo; */ ++ /* TX_RTP_8195 TX_retrpo; */ ++ ++ /* */ ++ /* ODM Structure */ ++ /* */ ++ FAT_T DM_FatTable; ++ DIG_T DM_DigTable; ++ PS_T DM_PSTable; ++ Pri_CCA_T DM_PriCCA; ++ RXHP_T DM_RXHP_Table; ++ RA_T DM_RA_Table; ++ false_ALARM_STATISTICS FalseAlmCnt; ++ false_ALARM_STATISTICS FlaseAlmCntBuddyAdapter; ++ SWAT_T DM_SWAT_Table; ++ bool RSSI_test; ++ CFO_TRACKING DM_CfoTrack; ++ ++ EDCA_T DM_EDCA_Table; ++ u32 WMMEDCA_BE; ++ PATHDIV_T DM_PathDiv; ++ /* Copy from SD4 structure */ ++ /* */ ++ /* ================================================== */ ++ /* */ ++ ++ /* common */ ++ /* u8 DM_Type; */ ++ /* u8 PSD_Report_RXHP[80]; Add By Gary */ ++ /* u8 PSD_func_flag; Add By Gary */ ++ /* for DIG */ ++ /* u8 bDMInitialGainEnable; */ ++ /* u8 binitialized; for dm_initial_gain_Multi_STA use. */ ++ /* for Antenna diversity */ ++ /* u8 AntDivCfg; 0:OFF , 1:ON, 2:by efuse */ ++ /* PSTA_INFO_T RSSI_target; */ ++ ++ bool *pbDriverStopped; ++ bool *pbDriverIsGoingToPnpSetPowerSleep; ++ bool *pinit_adpt_in_progress; ++ ++ /* PSD */ ++ bool bUserAssignLevel; ++ RT_TIMER PSDTimer; ++ u8 RSSI_BT; /* come from BT */ ++ bool bPSDinProcess; ++ bool bPSDactive; ++ bool bDMInitialGainEnable; ++ ++ /* MPT DIG */ ++ RT_TIMER MPT_DIGTimer; ++ ++ /* for rate adaptive, in fact, 88c/92c fw will handle this */ ++ u8 bUseRAMask; ++ ++ ODM_RATE_ADAPTIVE RateAdaptive; ++ ++ ANT_DETECTED_INFO AntDetectedInfo; /* Antenna detected information for RSSI tool */ ++ ++ ODM_RF_CAL_T RFCalibrateInfo; ++ ++ /* */ ++ /* TX power tracking */ ++ /* */ ++ u8 BbSwingIdxOfdm[MAX_RF_PATH]; ++ u8 BbSwingIdxOfdmCurrent; ++ u8 BbSwingIdxOfdmBase[MAX_RF_PATH]; ++ bool BbSwingFlagOfdm; ++ u8 BbSwingIdxCck; ++ u8 BbSwingIdxCckCurrent; ++ u8 BbSwingIdxCckBase; ++ u8 DefaultOfdmIndex; ++ u8 DefaultCckIndex; ++ bool BbSwingFlagCck; ++ ++ s8 Absolute_OFDMSwingIdx[MAX_RF_PATH]; ++ s8 Remnant_OFDMSwingIdx[MAX_RF_PATH]; ++ s8 Remnant_CCKSwingIdx; ++ s8 Modify_TxAGC_Value; /* Remnat compensate value at TxAGC */ ++ bool Modify_TxAGC_Flag_PathA; ++ bool Modify_TxAGC_Flag_PathB; ++ bool Modify_TxAGC_Flag_PathC; ++ bool Modify_TxAGC_Flag_PathD; ++ bool Modify_TxAGC_Flag_PathA_CCK; ++ ++ s8 KfreeOffset[MAX_RF_PATH]; ++ /* */ ++ /* ODM system resource. */ ++ /* */ ++ ++ /* ODM relative time. */ ++ RT_TIMER PathDivSwitchTimer; ++ /* 2011.09.27 add for Path Diversity */ ++ RT_TIMER CCKPathDiversityTimer; ++ RT_TIMER FastAntTrainingTimer; ++ ++ /* ODM relative workitem. */ ++ ++ #if (BEAMFORMING_SUPPORT == 1) ++ RT_BEAMFORMING_INFO BeamformingInfo; ++ #endif ++} DM_ODM_T, *PDM_ODM_T; /* DM_Dynamic_Mechanism_Structure */ ++ ++#define ODM_RF_PATH_MAX 2 ++ ++typedef enum _ODM_RF_RADIO_PATH { ++ ODM_RF_PATH_A = 0, /* Radio Path A */ ++ ODM_RF_PATH_B = 1, /* Radio Path B */ ++ ODM_RF_PATH_C = 2, /* Radio Path C */ ++ ODM_RF_PATH_D = 3, /* Radio Path D */ ++ ODM_RF_PATH_AB, ++ ODM_RF_PATH_AC, ++ ODM_RF_PATH_AD, ++ ODM_RF_PATH_BC, ++ ODM_RF_PATH_BD, ++ ODM_RF_PATH_CD, ++ ODM_RF_PATH_ABC, ++ ODM_RF_PATH_ACD, ++ ODM_RF_PATH_BCD, ++ ODM_RF_PATH_ABCD, ++ /* ODM_RF_PATH_MAX, Max RF number 90 support */ ++} ODM_RF_RADIO_PATH_E, *PODM_RF_RADIO_PATH_E; ++ ++ typedef enum _ODM_RF_CONTENT{ ++ odm_radioa_txt = 0x1000, ++ odm_radiob_txt = 0x1001, ++ odm_radioc_txt = 0x1002, ++ odm_radiod_txt = 0x1003 ++} ODM_RF_CONTENT; ++ ++typedef enum _ODM_BB_Config_Type{ ++ CONFIG_BB_PHY_REG, ++ CONFIG_BB_AGC_TAB, ++ CONFIG_BB_AGC_TAB_2G, ++ CONFIG_BB_AGC_TAB_5G, ++ CONFIG_BB_PHY_REG_PG, ++ CONFIG_BB_PHY_REG_MP, ++ CONFIG_BB_AGC_TAB_DIFF, ++} ODM_BB_Config_Type, *PODM_BB_Config_Type; ++ ++typedef enum _ODM_RF_Config_Type{ ++ CONFIG_RF_RADIO, ++ CONFIG_RF_TXPWR_LMT, ++} ODM_RF_Config_Type, *PODM_RF_Config_Type; ++ ++typedef enum _ODM_FW_Config_Type{ ++ CONFIG_FW_NIC, ++ CONFIG_FW_NIC_2, ++ CONFIG_FW_AP, ++ CONFIG_FW_WoWLAN, ++ CONFIG_FW_WoWLAN_2, ++ CONFIG_FW_AP_WoWLAN, ++ CONFIG_FW_BT, ++} ODM_FW_Config_Type; ++ ++/* Status code */ ++typedef enum _RT_STATUS{ ++ RT_STATUS_SUCCESS, ++ RT_STATUS_FAILURE, ++ RT_STATUS_PENDING, ++ RT_STATUS_RESOURCE, ++ RT_STATUS_INVALID_CONTEXT, ++ RT_STATUS_INVALID_PARAMETER, ++ RT_STATUS_NOT_SUPPORT, ++ RT_STATUS_OS_API_FAILED, ++}RT_STATUS,*PRT_STATUS; ++ ++#ifdef REMOVE_PACK ++#pragma pack() ++#endif ++ ++/* include "odm_function.h" */ ++ ++/* 3 =========================================================== */ ++/* 3 DIG */ ++/* 3 =========================================================== */ ++ ++/* Remove DIG by Yuchen */ ++ ++/* 3 =========================================================== */ ++/* 3 AGC RX High Power Mode */ ++/* 3 =========================================================== */ ++#define LNA_Low_Gain_1 0x64 ++#define LNA_Low_Gain_2 0x5A ++#define LNA_Low_Gain_3 0x58 ++ ++#define FA_RXHP_TH1 5000 ++#define FA_RXHP_TH2 1500 ++#define FA_RXHP_TH3 800 ++#define FA_RXHP_TH4 600 ++#define FA_RXHP_TH5 500 ++ ++/* 3 =========================================================== */ ++/* 3 EDCA */ ++/* 3 =========================================================== */ ++ ++/* 3 =========================================================== */ ++/* 3 Dynamic Tx Power */ ++/* 3 =========================================================== */ ++/* Dynamic Tx Power Control Threshold */ ++ ++/* 3 =========================================================== */ ++/* 3 Rate Adaptive */ ++/* 3 =========================================================== */ ++#define DM_RATR_STA_INIT 0 ++#define DM_RATR_STA_HIGH 1 ++#define DM_RATR_STA_MIDDLE 2 ++#define DM_RATR_STA_LOW 3 ++ ++/* 3 =========================================================== */ ++/* 3 BB Power Save */ ++/* 3 =========================================================== */ ++ ++typedef enum tag_1R_CCA_Type_Definition ++{ ++ CCA_1R = 0, ++ CCA_2R = 1, ++ CCA_MAX = 2, ++}DM_1R_CCA_E; ++ ++typedef enum tag_RF_Type_Definition ++{ ++ RF_Save = 0, ++ RF_Normal = 1, ++ RF_MAX = 2, ++}DM_RF_E; ++ ++/* 3 =========================================================== */ ++/* 3 Antenna Diversity */ ++/* 3 =========================================================== */ ++typedef enum tag_SW_Antenna_Switch_Definition ++{ ++ Antenna_A = 1, ++ Antenna_B = 2, ++ Antenna_MAX = 3, ++}DM_SWAS_E; ++ ++ ++/* Maximal number of antenna detection mechanism needs to perform, added by Roger, 2011.12.28. */ ++#define MAX_ANTENNA_DETECTION_CNT 10 ++ ++/* */ ++/* Extern Global Variables. */ ++/* */ ++extern u32 OFDMSwingTable[OFDM_TABLE_SIZE]; ++extern u8 CCKSwingTable_Ch1_Ch13[CCK_TABLE_SIZE][8]; ++extern u8 CCKSwingTable_Ch14 [CCK_TABLE_SIZE][8]; ++ ++extern u32 OFDMSwingTable_New[OFDM_TABLE_SIZE]; ++extern u8 CCKSwingTable_Ch1_Ch13_New[CCK_TABLE_SIZE][8]; ++extern u8 CCKSwingTable_Ch14_New [CCK_TABLE_SIZE][8]; ++ ++extern u32 TxScalingTable_Jaguar[TXSCALE_TABLE_SIZE]; ++ ++/* */ ++/* check Sta pointer valid or not */ ++/* */ ++#define IS_STA_VALID(pSta) (pSta) ++/* 20100514 Joseph: Add definition for antenna switching test after link. */ ++/* This indicates two different the steps. */ ++/* In SWAW_STEP_PEAK, driver needs to switch antenna and listen to the signal on the air. */ ++/* In SWAW_STEP_DETERMINE, driver just compares the signal captured in SWAW_STEP_PEAK */ ++/* with original RSSI to determine if it is necessary to switch antenna. */ ++#define SWAW_STEP_PEAK 0 ++#define SWAW_STEP_DETERMINE 1 ++ ++/* Remove DIG by yuchen */ ++ ++void ++ODM_SetAntenna( ++PDM_ODM_T pDM_Odm, ++u8 Antenna); ++ ++ ++/* Remove BB power saving by Yuchen */ ++ ++#define dm_CheckTXPowerTracking ODM_TXPowerTrackingCheck ++void ++ODM_TXPowerTrackingCheck( ++ PDM_ODM_T pDM_Odm ++ ); ++ ++bool ++ODM_RAStateCheck( ++ PDM_ODM_T pDM_Odm, ++ s32 RSSI, ++ bool bForceUpdate, ++ u8 * pRATRState ++ ); ++ ++#define dm_SWAW_RSSI_Check ODM_SwAntDivChkPerPktRssi ++void ODM_SwAntDivChkPerPktRssi( ++ PDM_ODM_T pDM_Odm, ++ u8 StationID, ++ PODM_PHY_INFO_T pPhyInfo ++ ); ++ ++u32 ODM_Get_Rate_Bitmap( ++ PDM_ODM_T pDM_Odm, ++ u32 macid, ++ u32 ra_mask, ++ u8 rssi_level); ++ ++#if (BEAMFORMING_SUPPORT == 1) ++BEAMFORMING_CAP ++Beamforming_GetEntryBeamCapByMacId( ++ PMGNT_INFO pMgntInfo, ++ u8 MacId ++); ++#endif ++ ++void ++odm_TXPowerTrackingInit( ++ PDM_ODM_T pDM_Odm ++ ); ++ ++void ++ODM_DMInit( ++ PDM_ODM_T pDM_Odm ++); ++ ++void ++ODM_DMWatchdog( ++ PDM_ODM_T pDM_Odm /* For common use in the future */ ++ ); ++ ++void ++ODM_CmnInfoInit( ++ PDM_ODM_T pDM_Odm, ++ ODM_CMNINFO_E CmnInfo, ++ u32 Value ++ ); ++ ++void ++ODM_CmnInfoHook( ++ PDM_ODM_T pDM_Odm, ++ ODM_CMNINFO_E CmnInfo, ++ void * pValue ++ ); ++ ++void ++ODM_CmnInfoPtrArrayHook( ++ PDM_ODM_T pDM_Odm, ++ ODM_CMNINFO_E CmnInfo, ++ u16 Index, ++ void * pValue ++ ); ++ ++void ++ODM_CmnInfoUpdate( ++ PDM_ODM_T pDM_Odm, ++ u32 CmnInfo, ++ u64 Value ++ ); ++ ++void ++ODM_InitAllTimers( ++ PDM_ODM_T pDM_Odm ++ ); ++ ++void ++ODM_CancelAllTimers( ++ PDM_ODM_T pDM_Odm ++ ); ++ ++void ++ODM_ReleaseAllTimers( ++ PDM_ODM_T pDM_Odm ++ ); ++ ++void ++ODM_AntselStatistics_88C( ++ PDM_ODM_T pDM_Odm, ++ u8 MacId, ++ u32 PWDBAll, ++ bool isCCKrate ++); ++ ++void ++ODM_DynamicARFBSelect( ++ PDM_ODM_T pDM_Odm, ++ u8 rate, ++ bool Collision_State ++ ); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_HWConfig.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_HWConfig.c +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_HWConfig.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_HWConfig.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,608 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#include "odm_precomp.h" ++ ++#define READ_AND_CONFIG_MP(ic, txt) (ODM_ReadAndConfig_MP_##ic##txt(pDM_Odm)) ++#define READ_AND_CONFIG READ_AND_CONFIG_MP ++#define GET_VERSION_MP(ic, txt) (ODM_GetVersion_MP_##ic##txt()) ++#define GET_VERSION(ic, txt) (pDM_Odm->bIsMPChip?GET_VERSION_MP(ic, txt):GET_VERSION_TC(ic, txt)) ++ ++static u8 ++odm_QueryRxPwrPercentage( ++ s8 AntPower ++ ) ++{ ++ if ((AntPower <= -100) || (AntPower >= 20)) ++ { ++ return 0; ++ } ++ else if (AntPower >= 0) ++ { ++ return 100; ++ } ++ else ++ { ++ return (100+AntPower); ++ } ++ ++} ++ ++static s32 ++odm_SignalScaleMapping_92CSeries( ++ PDM_ODM_T pDM_Odm, ++ s32 CurrSig ++) ++{ ++ s32 RetSig = 0; ++ ++ if (pDM_Odm->SupportInterface == ODM_ITRF_SDIO) ++ { ++ if (CurrSig >= 51 && CurrSig <= 100) ++ { ++ RetSig = 100; ++ } ++ else if (CurrSig >= 41 && CurrSig <= 50) ++ { ++ RetSig = 80 + ((CurrSig - 40)*2); ++ } ++ else if (CurrSig >= 31 && CurrSig <= 40) ++ { ++ RetSig = 66 + (CurrSig - 30); ++ } ++ else if (CurrSig >= 21 && CurrSig <= 30) ++ { ++ RetSig = 54 + (CurrSig - 20); ++ } ++ else if (CurrSig >= 10 && CurrSig <= 20) ++ { ++ RetSig = 42 + (((CurrSig - 10) * 2) / 3); ++ } ++ else if (CurrSig >= 5 && CurrSig <= 9) ++ { ++ RetSig = 22 + (((CurrSig - 5) * 3) / 2); ++ } ++ else if (CurrSig >= 1 && CurrSig <= 4) ++ { ++ RetSig = 6 + (((CurrSig - 1) * 3) / 2); ++ } ++ else ++ { ++ RetSig = CurrSig; ++ } ++ } ++ ++ return RetSig; ++} ++s32 ++odm_SignalScaleMapping( ++ PDM_ODM_T pDM_Odm, ++s32 CurrSig ++) ++{ ++ return odm_SignalScaleMapping_92CSeries(pDM_Odm, CurrSig); ++} ++ ++static u8 ++odm_EVMdbToPercentage( ++ s8 Value ++ ) ++{ ++ /* */ ++ /* -33dB~0dB to 0%~99% */ ++ /* */ ++ s8 ret_val; ++ ++ ret_val = Value; ++ ret_val /= 2; ++ ++ /* DbgPrint("Value =%d\n", Value); */ ++ /* ODM_RT_DISP(FRX, RX_PHY_SQ, ("EVMdbToPercentage92C Value =%d / %x\n", ret_val, ret_val)); */ ++ ++ if (ret_val >= 0) ++ ret_val = 0; ++ if (ret_val <= -33) ++ ret_val = -33; ++ ++ ret_val = 0 - ret_val; ++ ret_val*=3; ++ ++ if (ret_val == 99) ++ ret_val = 100; ++ ++ return(ret_val); ++} ++ ++static void ++odm_RxPhyStatus92CSeries_Parsing( ++ PDM_ODM_T pDM_Odm, ++ PODM_PHY_INFO_T pPhyInfo, ++ u8 * pPhyStatus, ++ PODM_PACKET_INFO_T pPktinfo ++ ) ++{ ++ u8 i, Max_spatial_stream; ++ s8 rx_pwr[4], rx_pwr_all = 0; ++ u8 EVM, PWDB_ALL = 0, PWDB_ALL_BT; ++ u8 RSSI, total_rssi = 0; ++ bool isCCKrate =false; ++ u8 rf_rx_num = 0; ++ u8 cck_highpwr = 0; ++ u8 LNA_idx, VGA_idx; ++ PPHY_STATUS_RPT_8192CD_T pPhyStaRpt = (PPHY_STATUS_RPT_8192CD_T)pPhyStatus; ++ ++ isCCKrate = (pPktinfo->DataRate <= DESC_RATE11M)?true :false; ++ pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_A] = -1; ++ pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_B] = -1; ++ ++ ++ if (isCCKrate) { ++ u8 cck_agc_rpt; ++ ++ pDM_Odm->PhyDbgInfo.NumQryPhyStatusCCK++; ++ /* */ ++ /* (1)Hardware does not provide RSSI for CCK */ ++ /* (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */ ++ /* */ ++ ++ /* if (pHalData->eRFPowerState == eRfOn) */ ++ cck_highpwr = pDM_Odm->bCckHighPower; ++ /* else */ ++ /* cck_highpwr = false; */ ++ ++ cck_agc_rpt = pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a ; ++ ++ /* 2011.11.28 LukeLee: 88E use different LNA & VGA gain table */ ++ /* The RSSI formula should be modified according to the gain table */ ++ /* In 88E, cck_highpwr is always set to 1 */ ++ LNA_idx = ((cck_agc_rpt & 0xE0) >>5); ++ VGA_idx = (cck_agc_rpt & 0x1F); ++ rx_pwr_all = odm_CCKRSSI_8723B(LNA_idx, VGA_idx); ++ PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); ++ if (PWDB_ALL>100) ++ PWDB_ALL = 100; ++ ++ pPhyInfo->RxPWDBAll = PWDB_ALL; ++ pPhyInfo->BTRxRSSIPercentage = PWDB_ALL; ++ pPhyInfo->RecvSignalPower = rx_pwr_all; ++ /* */ ++ /* (3) Get Signal Quality (EVM) */ ++ /* */ ++ /* if (pPktinfo->bPacketMatchBSSID) */ ++ { ++ u8 SQ, SQ_rpt; ++ ++ if (pPhyInfo->RxPWDBAll > 40 && !pDM_Odm->bInHctTest) { ++ SQ = 100; ++ } ++ else { ++ SQ_rpt = pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all; ++ ++ if (SQ_rpt > 64) ++ SQ = 0; ++ else if (SQ_rpt < 20) ++ SQ = 100; ++ else ++ SQ = ((64-SQ_rpt) * 100) / 44; ++ ++ } ++ ++ /* DbgPrint("cck SQ = %d\n", SQ); */ ++ pPhyInfo->SignalQuality = SQ; ++ pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_A] = SQ; ++ pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_B] = -1; ++ } ++ } ++ else /* is OFDM rate */ ++ { ++ pDM_Odm->PhyDbgInfo.NumQryPhyStatusOFDM++; ++ ++ /* */ ++ /* (1)Get RSSI for HT rate */ ++ /* */ ++ ++ for (i = ODM_RF_PATH_A; i < ODM_RF_PATH_MAX; i++) { ++ /* 2008/01/30 MH we will judge RF RX path now. */ ++ if (pDM_Odm->RFPathRxEnable & BIT(i)) ++ rf_rx_num++; ++ /* else */ ++ /* continue; */ ++ ++ rx_pwr[i] = ((pPhyStaRpt->path_agc[i].gain& 0x3F)*2) - 110; ++ ++ ++ pPhyInfo->RxPwr[i] = rx_pwr[i]; ++ ++ /* Translate DBM to percentage. */ ++ RSSI = odm_QueryRxPwrPercentage(rx_pwr[i]); ++ total_rssi += RSSI; ++ /* RT_DISP(FRX, RX_PHY_SS, ("RF-%d RXPWR =%x RSSI =%d\n", i, rx_pwr[i], RSSI)); */ ++ ++ pPhyInfo->RxMIMOSignalStrength[i] =(u8) RSSI; ++ ++ /* Get Rx snr value in DB */ ++ pPhyInfo->RxSNR[i] = pDM_Odm->PhyDbgInfo.RxSNRdB[i] = (s32)(pPhyStaRpt->path_rxsnr[i]/2); ++ } ++ ++ ++ /* */ ++ /* (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */ ++ /* */ ++ rx_pwr_all = (((pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all) >> 1)& 0x7f) -110; ++ ++ PWDB_ALL_BT = PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); ++ /* RT_DISP(FRX, RX_PHY_SS, ("PWDB_ALL =%d\n", PWDB_ALL)); */ ++ ++ pPhyInfo->RxPWDBAll = PWDB_ALL; ++ /* ODM_RT_TRACE(pDM_Odm, ODM_COMP_RSSI_MONITOR, ODM_DBG_LOUD, ("ODM OFDM RSSI =%d\n", pPhyInfo->RxPWDBAll)); */ ++ pPhyInfo->BTRxRSSIPercentage = PWDB_ALL_BT; ++ pPhyInfo->RxPower = rx_pwr_all; ++ pPhyInfo->RecvSignalPower = rx_pwr_all; ++ ++ {/* pMgntInfo->CustomerID != RT_CID_819x_Lenovo */ ++ /* */ ++ /* (3)EVM of HT rate */ ++ /* */ ++ if (pPktinfo->DataRate >=DESC_RATEMCS8 && pPktinfo->DataRate <=DESC_RATEMCS15) ++ Max_spatial_stream = 2; /* both spatial stream make sense */ ++ else ++ Max_spatial_stream = 1; /* only spatial stream 1 makes sense */ ++ ++ for (i = 0; i>= 1" because the compilor of free build environment */ ++ /* fill most significant bit to "zero" when doing shifting operation which may change a negative */ ++ /* value to positive one, then the dbm value (which is supposed to be negative) is not correct anymore. */ ++ EVM = odm_EVMdbToPercentage((pPhyStaRpt->stream_rxevm[i])); /* dbm */ ++ ++ /* RT_DISP(FRX, RX_PHY_SQ, ("RXRATE =%x RXEVM =%x EVM =%s%d\n", */ ++ /* GET_RX_STATUS_DESC_RX_MCS(pDesc), pDrvInfo->rxevm[i], "%", EVM)); */ ++ ++ /* if (pPktinfo->bPacketMatchBSSID) */ ++ { ++ if (i ==ODM_RF_PATH_A) /* Fill value in RFD, Get the first spatial stream only */ ++ { ++ pPhyInfo->SignalQuality = (u8)(EVM & 0xff); ++ } ++ pPhyInfo->RxMIMOSignalQuality[i] = (u8)(EVM & 0xff); ++ } ++ } ++ } ++ ++ ODM_ParsingCFO(pDM_Odm, pPktinfo, pPhyStaRpt->path_cfotail); ++ ++ } ++ ++ /* UI BSS List signal strength(in percentage), make it good looking, from 0~100. */ ++ /* It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp(). */ ++ if (isCCKrate) ++ { ++#ifdef CONFIG_SKIP_SIGNAL_SCALE_MAPPING ++ pPhyInfo->SignalStrength = (u8)PWDB_ALL; ++#else ++ pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(pDM_Odm, PWDB_ALL));/* PWDB_ALL; */ ++#endif ++ } ++ else ++ { ++ if (rf_rx_num != 0) ++ { ++#ifdef CONFIG_SKIP_SIGNAL_SCALE_MAPPING ++ total_rssi/=rf_rx_num; ++ pPhyInfo->SignalStrength = (u8)total_rssi; ++#else ++ pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(pDM_Odm, total_rssi/=rf_rx_num)); ++#endif ++ } ++ } ++ ++ /* DbgPrint("isCCKrate = %d, pPhyInfo->RxPWDBAll = %d, pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a = 0x%x\n", */ ++ /* isCCKrate, pPhyInfo->RxPWDBAll, pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a); */ ++} ++ ++static void ++odm_Process_RSSIForDM( ++ PDM_ODM_T pDM_Odm, ++ PODM_PHY_INFO_T pPhyInfo, ++ PODM_PACKET_INFO_T pPktinfo ++ ) ++{ ++ ++ s32 UndecoratedSmoothedPWDB, UndecoratedSmoothedCCK, UndecoratedSmoothedOFDM, RSSI_Ave; ++ u8 isCCKrate = 0; ++ u8 RSSI_max, RSSI_min, i; ++ u32 OFDM_pkt = 0; ++ u32 Weighting = 0; ++ PSTA_INFO_T pEntry; ++ ++ ++ if (pPktinfo->StationID == 0xFF) ++ return; ++ ++ pEntry = pDM_Odm->pODM_StaInfo[pPktinfo->StationID]; ++ ++ if (!IS_STA_VALID(pEntry)) { ++ return; ++ } ++ if ((!pPktinfo->bPacketMatchBSSID)) ++ { ++ return; ++ } ++ ++ if (pPktinfo->bPacketBeacon) ++ pDM_Odm->PhyDbgInfo.NumQryBeaconPkt++; ++ ++ isCCKrate = ((pPktinfo->DataRate <= DESC_RATE11M)) ? true : false; ++ pDM_Odm->RxRate = pPktinfo->DataRate; ++ ++ /* Statistic for antenna/path diversity------------------ */ ++ if (pDM_Odm->SupportAbility & ODM_BB_ANT_DIV) ++ { ++ } ++ ++ /* Smart Antenna Debug Message------------------ */ ++ ++ UndecoratedSmoothedCCK = pEntry->rssi_stat.UndecoratedSmoothedCCK; ++ UndecoratedSmoothedOFDM = pEntry->rssi_stat.UndecoratedSmoothedOFDM; ++ UndecoratedSmoothedPWDB = pEntry->rssi_stat.UndecoratedSmoothedPWDB; ++ ++ if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) ++ { ++ ++ if (!isCCKrate)/* ofdm rate */ ++ { ++ if (pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B] == 0) { ++ RSSI_Ave = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; ++ pDM_Odm->RSSI_A = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; ++ pDM_Odm->RSSI_B = 0; ++ } ++ else ++ { ++ /* DbgPrint("pRfd->Status.RxMIMOSignalStrength[0] = %d, pRfd->Status.RxMIMOSignalStrength[1] = %d\n", */ ++ /* pRfd->Status.RxMIMOSignalStrength[0], pRfd->Status.RxMIMOSignalStrength[1]); */ ++ pDM_Odm->RSSI_A = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; ++ pDM_Odm->RSSI_B = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]; ++ ++ if (pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A] > pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]) ++ { ++ RSSI_max = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; ++ RSSI_min = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]; ++ } ++ else ++ { ++ RSSI_max = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]; ++ RSSI_min = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; ++ } ++ if ((RSSI_max -RSSI_min) < 3) ++ RSSI_Ave = RSSI_max; ++ else if ((RSSI_max -RSSI_min) < 6) ++ RSSI_Ave = RSSI_max - 1; ++ else if ((RSSI_max -RSSI_min) < 10) ++ RSSI_Ave = RSSI_max - 2; ++ else ++ RSSI_Ave = RSSI_max - 3; ++ } ++ ++ /* 1 Process OFDM RSSI */ ++ if (UndecoratedSmoothedOFDM <= 0) /* initialize */ ++ { ++ UndecoratedSmoothedOFDM = pPhyInfo->RxPWDBAll; ++ } ++ else ++ { ++ if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedOFDM) ++ { ++ UndecoratedSmoothedOFDM = ++ (((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) + ++ (RSSI_Ave)) /(Rx_Smooth_Factor); ++ UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM + 1; ++ } ++ else ++ { ++ UndecoratedSmoothedOFDM = ++ (((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) + ++ (RSSI_Ave)) /(Rx_Smooth_Factor); ++ } ++ } ++ ++ pEntry->rssi_stat.PacketMap = (pEntry->rssi_stat.PacketMap<<1) | BIT0; ++ ++ } ++ else ++ { ++ RSSI_Ave = pPhyInfo->RxPWDBAll; ++ pDM_Odm->RSSI_A = (u8) pPhyInfo->RxPWDBAll; ++ pDM_Odm->RSSI_B = 0; ++ ++ /* 1 Process CCK RSSI */ ++ if (UndecoratedSmoothedCCK <= 0) /* initialize */ ++ { ++ UndecoratedSmoothedCCK = pPhyInfo->RxPWDBAll; ++ } ++ else ++ { ++ if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedCCK) ++ { ++ UndecoratedSmoothedCCK = ++ (((UndecoratedSmoothedCCK)*(Rx_Smooth_Factor-1)) + ++ (pPhyInfo->RxPWDBAll)) /(Rx_Smooth_Factor); ++ UndecoratedSmoothedCCK = UndecoratedSmoothedCCK + 1; ++ } ++ else ++ { ++ UndecoratedSmoothedCCK = ++ (((UndecoratedSmoothedCCK)*(Rx_Smooth_Factor-1)) + ++ (pPhyInfo->RxPWDBAll)) /(Rx_Smooth_Factor); ++ } ++ } ++ pEntry->rssi_stat.PacketMap = pEntry->rssi_stat.PacketMap<<1; ++ } ++ ++ /* if (pEntry) */ ++ { ++ /* 2011.07.28 LukeLee: modified to prevent unstable CCK RSSI */ ++ if (pEntry->rssi_stat.ValidBit >= 64) ++ pEntry->rssi_stat.ValidBit = 64; ++ else ++ pEntry->rssi_stat.ValidBit++; ++ ++ for (i = 0; irssi_stat.ValidBit; i++) ++ OFDM_pkt += (u8)(pEntry->rssi_stat.PacketMap>>i)&BIT0; ++ ++ if (pEntry->rssi_stat.ValidBit == 64) ++ { ++ Weighting = ((OFDM_pkt<<4) > 64)?64:(OFDM_pkt<<4); ++ UndecoratedSmoothedPWDB = (Weighting*UndecoratedSmoothedOFDM+(64-Weighting)*UndecoratedSmoothedCCK)>>6; ++ } ++ else ++ { ++ if (pEntry->rssi_stat.ValidBit != 0) ++ UndecoratedSmoothedPWDB = (OFDM_pkt*UndecoratedSmoothedOFDM+(pEntry->rssi_stat.ValidBit-OFDM_pkt)*UndecoratedSmoothedCCK)/pEntry->rssi_stat.ValidBit; ++ else ++ UndecoratedSmoothedPWDB = 0; ++ } ++ ++ pEntry->rssi_stat.UndecoratedSmoothedCCK = UndecoratedSmoothedCCK; ++ pEntry->rssi_stat.UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM; ++ pEntry->rssi_stat.UndecoratedSmoothedPWDB = UndecoratedSmoothedPWDB; ++ ++ /* DbgPrint("OFDM_pkt =%d, Weighting =%d\n", OFDM_pkt, Weighting); */ ++ /* DbgPrint("UndecoratedSmoothedOFDM =%d, UndecoratedSmoothedPWDB =%d, UndecoratedSmoothedCCK =%d\n", */ ++ /* UndecoratedSmoothedOFDM, UndecoratedSmoothedPWDB, UndecoratedSmoothedCCK); */ ++ ++ } ++ ++ } ++} ++ ++ ++/* */ ++/* Endianness before calling this API */ ++/* */ ++static void ++ODM_PhyStatusQuery_92CSeries( ++ PDM_ODM_T pDM_Odm, ++ PODM_PHY_INFO_T pPhyInfo, ++ u8 * pPhyStatus, ++ PODM_PACKET_INFO_T pPktinfo ++ ) ++{ ++ ++ odm_RxPhyStatus92CSeries_Parsing( ++ pDM_Odm, ++ pPhyInfo, ++ pPhyStatus, ++ pPktinfo); ++ ++ if (!pDM_Odm->RSSI_test) ++ odm_Process_RSSIForDM(pDM_Odm, pPhyInfo, pPktinfo); ++} ++ ++void ++ODM_PhyStatusQuery( ++ PDM_ODM_T pDM_Odm, ++ PODM_PHY_INFO_T pPhyInfo, ++ u8 * pPhyStatus, ++ PODM_PACKET_INFO_T pPktinfo ++ ) ++{ ++ ++ ODM_PhyStatusQuery_92CSeries(pDM_Odm, pPhyInfo, pPhyStatus, pPktinfo); ++} ++ ++/* */ ++/* If you want to add a new IC, Please follow below template and generate a new one. */ ++/* */ ++/* */ ++ ++HAL_STATUS ++ODM_ConfigRFWithHeaderFile( ++PDM_ODM_T pDM_Odm, ++ODM_RF_Config_Type ConfigType, ++ODM_RF_RADIO_PATH_E eRFPath ++ ) ++{ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ++ ("===>ODM_ConfigRFWithHeaderFile (%s)\n", (pDM_Odm->bIsMPChip) ? "MPChip" : "TestChip")); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ++ ("pDM_Odm->SupportPlatform: 0x%X, pDM_Odm->SupportInterface: 0x%X, pDM_Odm->BoardType: 0x%X\n", ++ pDM_Odm->SupportPlatform, pDM_Odm->SupportInterface, pDM_Odm->BoardType)); ++ ++ if (ConfigType == CONFIG_RF_RADIO) { ++ READ_AND_CONFIG(8723B, _RadioA); ++ } ++ else if (ConfigType == CONFIG_RF_TXPWR_LMT) { ++ READ_AND_CONFIG(8723B, _TXPWR_LMT); ++ } ++ ++ return HAL_STATUS_SUCCESS; ++} ++ ++HAL_STATUS ++ODM_ConfigRFWithTxPwrTrackHeaderFile( ++PDM_ODM_T pDM_Odm ++ ) ++{ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ++ ("===>ODM_ConfigRFWithTxPwrTrackHeaderFile (%s)\n", (pDM_Odm->bIsMPChip) ? "MPChip" : "TestChip")); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ++ ("pDM_Odm->SupportPlatform: 0x%X, pDM_Odm->SupportInterface: 0x%X, pDM_Odm->BoardType: 0x%X\n", ++ pDM_Odm->SupportPlatform, pDM_Odm->SupportInterface, pDM_Odm->BoardType)); ++ ++ if (pDM_Odm->SupportInterface == ODM_ITRF_SDIO) ++ READ_AND_CONFIG(8723B, _TxPowerTrack_SDIO); ++ ++ return HAL_STATUS_SUCCESS; ++} ++ ++HAL_STATUS ++ODM_ConfigBBWithHeaderFile( ++PDM_ODM_T pDM_Odm, ++ODM_BB_Config_Type ConfigType ++ ) ++{ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ++ ("===>ODM_ConfigBBWithHeaderFile (%s)\n", (pDM_Odm->bIsMPChip) ? "MPChip" : "TestChip")); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ++ ("pDM_Odm->SupportPlatform: 0x%X, pDM_Odm->SupportInterface: 0x%X, pDM_Odm->BoardType: 0x%X\n", ++ pDM_Odm->SupportPlatform, pDM_Odm->SupportInterface, pDM_Odm->BoardType)); ++ ++ if (ConfigType == CONFIG_BB_PHY_REG) ++ READ_AND_CONFIG(8723B, _PHY_REG); ++ else if (ConfigType == CONFIG_BB_AGC_TAB) ++ READ_AND_CONFIG(8723B, _AGC_TAB); ++ else if (ConfigType == CONFIG_BB_PHY_REG_PG) ++ READ_AND_CONFIG(8723B, _PHY_REG_PG); ++ ++ return HAL_STATUS_SUCCESS; ++} ++ ++HAL_STATUS ++ODM_ConfigMACWithHeaderFile( ++PDM_ODM_T pDM_Odm ++ ) ++{ ++ u8 result = HAL_STATUS_SUCCESS; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ++ ("===>ODM_ConfigMACWithHeaderFile (%s)\n", (pDM_Odm->bIsMPChip) ? "MPChip" : "TestChip")); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ++ ("pDM_Odm->SupportPlatform: 0x%X, pDM_Odm->SupportInterface: 0x%X, pDM_Odm->BoardType: 0x%X\n", ++ pDM_Odm->SupportPlatform, pDM_Odm->SupportInterface, pDM_Odm->BoardType)); ++ ++ READ_AND_CONFIG(8723B, _MAC_REG); ++ ++ return result; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_HWConfig.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_HWConfig.h +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_HWConfig.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_HWConfig.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,179 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++ ++#ifndef __HALHWOUTSRC_H__ ++#define __HALHWOUTSRC_H__ ++ ++ ++/*--------------------------Define -------------------------------------------*/ ++/* define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = Array[i]; v2 = Array[i+1]; } while (0) */ ++#define AGC_DIFF_CONFIG_MP(ic, band) (ODM_ReadAndConfig_MP_##ic##_AGC_TAB_DIFF(pDM_Odm, Array_MP_##ic##_AGC_TAB_DIFF_##band, \ ++ sizeof(Array_MP_##ic##_AGC_TAB_DIFF_##band)/sizeof(u32))) ++#define AGC_DIFF_CONFIG_TC(ic, band) (ODM_ReadAndConfig_TC_##ic##_AGC_TAB_DIFF(pDM_Odm, Array_TC_##ic##_AGC_TAB_DIFF_##band, \ ++ sizeof(Array_TC_##ic##_AGC_TAB_DIFF_##band)/sizeof(u32))) ++ ++#define AGC_DIFF_CONFIG(ic, band) do {\ ++ if (pDM_Odm->bIsMPChip)\ ++ AGC_DIFF_CONFIG_MP(ic, band);\ ++ else\ ++ AGC_DIFF_CONFIG_TC(ic, band);\ ++ } while (0) ++ ++ ++/* */ ++/* structure and define */ ++/* */ ++ ++typedef struct _Phy_Rx_AGC_Info ++{ ++ #if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) ++ u8 gain:7, trsw:1; ++ #else ++ u8 trsw:1, gain:7; ++ #endif ++} PHY_RX_AGC_INFO_T,*pPHY_RX_AGC_INFO_T; ++ ++typedef struct _Phy_Status_Rpt_8192cd ++{ ++ PHY_RX_AGC_INFO_T path_agc[2]; ++ u8 ch_corr[2]; ++ u8 cck_sig_qual_ofdm_pwdb_all; ++ u8 cck_agc_rpt_ofdm_cfosho_a; ++ u8 cck_rpt_b_ofdm_cfosho_b; ++ u8 rsvd_1;/* ch_corr_msb; */ ++ u8 noise_power_db_msb; ++ s8 path_cfotail[2]; ++ u8 pcts_mask[2]; ++ s8 stream_rxevm[2]; ++ u8 path_rxsnr[2]; ++ u8 noise_power_db_lsb; ++ u8 rsvd_2[3]; ++ u8 stream_csi[2]; ++ u8 stream_target_csi[2]; ++ s8 sig_evm; ++ u8 rsvd_3; ++ ++#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) ++ u8 antsel_rx_keep_2:1; /* ex_intf_flg:1; */ ++ u8 sgi_en:1; ++ u8 rxsc:2; ++ u8 idle_long:1; ++ u8 r_ant_train_en:1; ++ u8 ant_sel_b:1; ++ u8 ant_sel:1; ++#else /* _BIG_ENDIAN_ */ ++ u8 ant_sel:1; ++ u8 ant_sel_b:1; ++ u8 r_ant_train_en:1; ++ u8 idle_long:1; ++ u8 rxsc:2; ++ u8 sgi_en:1; ++ u8 antsel_rx_keep_2:1; /* ex_intf_flg:1; */ ++#endif ++} PHY_STATUS_RPT_8192CD_T,*PPHY_STATUS_RPT_8192CD_T; ++ ++ ++typedef struct _Phy_Status_Rpt_8812 ++{ ++ /* 2012.05.24 LukeLee: This structure should take big/little endian in consideration later..... */ ++ ++ /* DWORD 0 */ ++ u8 gain_trsw[2]; ++#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) ++ u16 chl_num:10; ++ u16 sub_chnl:4; ++ u16 r_RFMOD:2; ++#else /* _BIG_ENDIAN_ */ ++ u16 r_RFMOD:2; ++ u16 sub_chnl:4; ++ u16 chl_num:10; ++#endif ++ ++ /* DWORD 1 */ ++ u8 pwdb_all; ++ u8 cfosho[4]; /* DW 1 byte 1 DW 2 byte 0 */ ++ ++ /* DWORD 2 */ ++ s8 cfotail[4]; /* DW 2 byte 1 DW 3 byte 0 */ ++ ++ /* DWORD 3 */ ++ s8 rxevm[2]; /* DW 3 byte 1 DW 3 byte 2 */ ++ s8 rxsnr[2]; /* DW 3 byte 3 DW 4 byte 0 */ ++ ++ /* DWORD 4 */ ++ u8 PCTS_MSK_RPT[2]; ++ u8 pdsnr[2]; /* DW 4 byte 3 DW 5 Byte 0 */ ++ ++ /* DWORD 5 */ ++ u8 csi_current[2]; ++ u8 rx_gain_c; ++ ++ /* DWORD 6 */ ++ u8 rx_gain_d; ++ s8 sigevm; ++ u8 resvd_0; ++ u8 antidx_anta:3; ++ u8 antidx_antb:3; ++ u8 resvd_1:2; ++} PHY_STATUS_RPT_8812_T,*PPHY_STATUS_RPT_8812_T; ++ ++ ++void ++ODM_PhyStatusQuery( ++ PDM_ODM_T pDM_Odm, ++ PODM_PHY_INFO_T pPhyInfo, ++ u8 * pPhyStatus, ++ PODM_PACKET_INFO_T pPktinfo ++ ); ++ ++HAL_STATUS ++ODM_ConfigRFWithTxPwrTrackHeaderFile( ++PDM_ODM_T pDM_Odm ++ ); ++ ++HAL_STATUS ++ODM_ConfigRFWithHeaderFile( ++PDM_ODM_T pDM_Odm, ++ODM_RF_Config_Type ConfigType, ++ODM_RF_RADIO_PATH_E eRFPath ++ ); ++ ++HAL_STATUS ++ODM_ConfigBBWithHeaderFile( ++PDM_ODM_T pDM_Odm, ++ODM_BB_Config_Type ConfigType ++ ); ++ ++HAL_STATUS ++ODM_ConfigMACWithHeaderFile( ++PDM_ODM_T pDM_Odm ++ ); ++ ++HAL_STATUS ++ODM_ConfigFWWithHeaderFile( ++PDM_ODM_T pDM_Odm, ++ODM_FW_Config_Type ConfigType, ++ u8 *pFirmware, ++ u32 *pSize ++ ); ++ ++s32 ++odm_SignalScaleMapping( ++ PDM_ODM_T pDM_Odm, ++s32 CurrSig ++ ); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_interface.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_interface.h +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_interface.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_interface.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,60 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++ ++#ifndef __ODM_INTERFACE_H__ ++#define __ODM_INTERFACE_H__ ++ ++ ++ ++/* =========== Constant/Structure/Enum/... Define */ ++ ++/* =========== Macro Define */ ++ ++#define _reg_all(_name) ODM_##_name ++#define _reg_ic(_name, _ic) ODM_##_name##_ic ++#define _bit_all(_name) BIT_##_name ++#define _bit_ic(_name, _ic) BIT_##_name##_ic ++ ++/*=================================== ++ ++#define ODM_REG_DIG_11N 0xC50 ++#define ODM_REG_DIG_11AC 0xDDD ++ ++ODM_REG(DIG, _pDM_Odm) ++=====================================*/ ++ ++#define _reg_11N(_name) ODM_REG_##_name##_11N ++#define _bit_11N(_name) ODM_BIT_##_name##_11N ++ ++#define _cat(_name, _ic_type, _func) _func##_11N(_name) ++ ++/* _name: name of register or bit. */ ++/* Example: "ODM_REG(R_A_AGC_CORE1, pDM_Odm)" */ ++/* gets "ODM_R_A_AGC_CORE1" or "ODM_R_A_AGC_CORE1_8192C", depends on SupportICType. */ ++#define ODM_REG(_name, _pDM_Odm) _cat(_name, _pDM_Odm->SupportICType, _reg) ++#define ODM_BIT(_name, _pDM_Odm) _cat(_name, _pDM_Odm->SupportICType, _bit) ++ ++typedef enum _ODM_H2C_CMD ++{ ++ ODM_H2C_RSSI_REPORT = 0, ++ ODM_H2C_PSD_RESULT = 1, ++ ODM_H2C_PathDiv = 2, ++ ODM_H2C_WIFI_CALIBRATION = 3, ++ ODM_MAX_H2CCMD ++}ODM_H2C_CMD; ++ ++ ++#endif /* __ODM_INTERFACE_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_NoiseMonitor.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_NoiseMonitor.c +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_NoiseMonitor.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_NoiseMonitor.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,172 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#include "odm_precomp.h" ++ ++/* This function is for inband noise test utility only */ ++/* To obtain the inband noise level(dbm), do the following. */ ++/* 1. disable DIG and Power Saving */ ++/* 2. Set initial gain = 0x1a */ ++/* 3. Stop updating idle time pwer report (for driver read) */ ++/* - 0x80c[25] */ ++ ++#define Valid_Min -35 ++#define Valid_Max 10 ++#define ValidCnt 5 ++ ++static s16 odm_InbandNoise_Monitor_NSeries(PDM_ODM_T pDM_Odm, u8 bPauseDIG, u8 IGIValue, u32 max_time) ++{ ++ u32 tmp4b; ++ u8 max_rf_path = 0, rf_path; ++ u8 reg_c50, reg_c58, valid_done = 0; ++ struct noise_level noise_data; ++ u32 start = 0, func_start = 0, func_end = 0; ++ ++ func_start = jiffies; ++ pDM_Odm->noise_level.noise_all = 0; ++ ++ if ((pDM_Odm->RFType == ODM_1T2R) ||(pDM_Odm->RFType == ODM_2T2R)) ++ max_rf_path = 2; ++ else ++ max_rf_path = 1; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_DebugControlInbandNoise_Nseries() ==>\n")); ++ ++ memset(&noise_data, 0, sizeof(struct noise_level)); ++ ++ /* */ ++ /* Step 1. Disable DIG && Set initial gain. */ ++ /* */ ++ ++ if (bPauseDIG) ++ { ++ odm_PauseDIG(pDM_Odm, ODM_PAUSE_DIG, IGIValue); ++ } ++ /* */ ++ /* Step 2. Disable all power save for read registers */ ++ /* */ ++ /* dcmd_DebugControlPowerSave(padapter, PSDisable); */ ++ ++ /* */ ++ /* Step 3. Get noise power level */ ++ /* */ ++ start = jiffies; ++ while (1) ++ { ++ ++ /* Stop updating idle time pwer report (for driver read) */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_TxGainStage, BIT25, 1); ++ ++ /* Read Noise Floor Report */ ++ tmp4b = PHY_QueryBBReg(pDM_Odm->Adapter, 0x8f8, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("Noise Floor Report (0x8f8) = 0x%08x\n", tmp4b)); ++ ++ /* PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XAAGCCore1, bMaskByte0, TestInitialGain); */ ++ /* if (max_rf_path == 2) */ ++ /* PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XBAGCCore1, bMaskByte0, TestInitialGain); */ ++ ++ /* update idle time pwer report per 5us */ ++ PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_TxGainStage, BIT25, 0); ++ ++ noise_data.value[ODM_RF_PATH_A] = (u8)(tmp4b&0xff); ++ noise_data.value[ODM_RF_PATH_B] = (u8)((tmp4b&0xff00)>>8); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("value_a = 0x%x(%d), value_b = 0x%x(%d)\n", ++ noise_data.value[ODM_RF_PATH_A], noise_data.value[ODM_RF_PATH_A], noise_data.value[ODM_RF_PATH_B], noise_data.value[ODM_RF_PATH_B])); ++ ++ for (rf_path = ODM_RF_PATH_A; rf_path < max_rf_path; rf_path++) ++ { ++ noise_data.sval[rf_path] = (s8)noise_data.value[rf_path]; ++ noise_data.sval[rf_path] /= 2; ++ } ++ ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("sval_a = %d, sval_b = %d\n", ++ noise_data.sval[ODM_RF_PATH_A], noise_data.sval[ODM_RF_PATH_B])); ++ /* mdelay(10); */ ++ /* msleep(10); */ ++ ++ for (rf_path = ODM_RF_PATH_A; rf_path < max_rf_path; rf_path++) ++ { ++ if ((noise_data.valid_cnt[rf_path] < ValidCnt) && (noise_data.sval[rf_path] < Valid_Max && noise_data.sval[rf_path] >= Valid_Min)) ++ { ++ noise_data.valid_cnt[rf_path]++; ++ noise_data.sum[rf_path] += noise_data.sval[rf_path]; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RF_Path:%d Valid sval = %d\n", rf_path, noise_data.sval[rf_path])); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("Sum of sval = %d,\n", noise_data.sum[rf_path])); ++ if (noise_data.valid_cnt[rf_path] == ValidCnt) ++ { ++ valid_done++; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("After divided, RF_Path:%d , sum = %d\n", rf_path, noise_data.sum[rf_path])); ++ } ++ ++ } ++ ++ } ++ ++ /* printk("####### valid_done:%d #############\n", valid_done); */ ++ if ((valid_done ==max_rf_path) || (jiffies_to_msecs(jiffies - start) > max_time)) ++ { ++ for (rf_path = ODM_RF_PATH_A; rf_path < max_rf_path; rf_path++) ++ { ++ /* printk("%s PATH_%d - sum = %d, valid_cnt = %d\n", __func__, rf_path, noise_data.sum[rf_path], noise_data.valid_cnt[rf_path]); */ ++ if (noise_data.valid_cnt[rf_path]) ++ noise_data.sum[rf_path] /= noise_data.valid_cnt[rf_path]; ++ else ++ noise_data.sum[rf_path] = 0; ++ } ++ break; ++ } ++ } ++ reg_c50 = (s32)PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_XAAGCCore1, bMaskByte0); ++ reg_c50 &= ~BIT7; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("0x%x = 0x%02x(%d)\n", rOFDM0_XAAGCCore1, reg_c50, reg_c50)); ++ pDM_Odm->noise_level.noise[ODM_RF_PATH_A] = -110 + reg_c50 + noise_data.sum[ODM_RF_PATH_A]; ++ pDM_Odm->noise_level.noise_all += pDM_Odm->noise_level.noise[ODM_RF_PATH_A]; ++ ++ if (max_rf_path == 2) { ++ reg_c58 = (s32)PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_XBAGCCore1, bMaskByte0); ++ reg_c58 &= ~BIT7; ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("0x%x = 0x%02x(%d)\n", rOFDM0_XBAGCCore1, reg_c58, reg_c58)); ++ pDM_Odm->noise_level.noise[ODM_RF_PATH_B] = -110 + reg_c58 + noise_data.sum[ODM_RF_PATH_B]; ++ pDM_Odm->noise_level.noise_all += pDM_Odm->noise_level.noise[ODM_RF_PATH_B]; ++ } ++ pDM_Odm->noise_level.noise_all /= max_rf_path; ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("noise_a = %d, noise_b = %d\n", ++ pDM_Odm->noise_level.noise[ODM_RF_PATH_A], ++ pDM_Odm->noise_level.noise[ODM_RF_PATH_B])); ++ ++ /* */ ++ /* Step 4. Recover the Dig */ ++ /* */ ++ if (bPauseDIG) ++ { ++ odm_PauseDIG(pDM_Odm, ODM_RESUME_DIG, IGIValue); ++ } ++ func_end = jiffies_to_msecs(jiffies - func_start) ; ++ /* printk("%s noise_a = %d, noise_b = %d noise_all:%d (%d ms)\n", __func__, */ ++ /* pDM_Odm->noise_level.noise[ODM_RF_PATH_A], */ ++ /* pDM_Odm->noise_level.noise[ODM_RF_PATH_B], */ ++ /* pDM_Odm->noise_level.noise_all, func_end); */ ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_DebugControlInbandNoise_Nseries() <==\n")); ++ return pDM_Odm->noise_level.noise_all; ++ ++} ++s16 ODM_InbandNoise_Monitor(void *pDM_VOID, u8 bPauseDIG, u8 IGIValue, u32 max_time) ++{ ++ return odm_InbandNoise_Monitor_NSeries(pDM_VOID, bPauseDIG, IGIValue, max_time); ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_NoiseMonitor.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_NoiseMonitor.h +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_NoiseMonitor.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_NoiseMonitor.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,44 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ *****************************************************************************/ ++#ifndef __ODMNOISEMONITOR_H__ ++#define __ODMNOISEMONITOR_H__ ++ ++#define ODM_MAX_CHANNEL_NUM 38/* 14+24 */ ++struct noise_level ++{ ++ /* u8 value_a, value_b; */ ++ u8 value[MAX_RF_PATH]; ++ /* s8 sval_a, sval_b; */ ++ s8 sval[MAX_RF_PATH]; ++ ++ /* s32 noise_a = 0, noise_b = 0, sum_a = 0, sum_b = 0; */ ++ /* s32 noise[ODM_RF_PATH_MAX]; */ ++ s32 sum[MAX_RF_PATH]; ++ /* u8 valid_cnt_a = 0, valid_cnt_b = 0, */ ++ u8 valid[MAX_RF_PATH]; ++ u8 valid_cnt[MAX_RF_PATH]; ++ ++}; ++ ++ ++typedef struct _ODM_NOISE_MONITOR_ ++{ ++ s8 noise[MAX_RF_PATH]; ++ s16 noise_all; ++}ODM_NOISE_MONITOR; ++ ++s16 ODM_InbandNoise_Monitor(void *pDM_VOID, u8 bPauseDIG, u8 IGIValue, u32 max_time); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_PathDiv.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_PathDiv.c +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_PathDiv.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_PathDiv.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,34 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#include "odm_precomp.h" ++ ++void odm_PathDiversityInit(void *pDM_VOID) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_PATH_DIV)) ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ++ ("Return: Not Support PathDiv\n")); ++} ++ ++void odm_PathDiversity(void *pDM_VOID) ++{ ++ PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; ++ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_PATH_DIV)) ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ++ ("Return: Not Support PathDiv\n")); ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_PathDiv.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_PathDiv.h +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_PathDiv.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_PathDiv.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,29 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#ifndef __ODMPATHDIV_H__ ++#define __ODMPATHDIV_H__ ++ ++void ++odm_PathDiversityInit( ++ void *pDM_VOID ++ ); ++ ++void ++odm_PathDiversity( ++ void *pDM_VOID ++ ); ++ ++ #endif /* ifndef __ODMPATHDIV_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_precomp.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_precomp.h +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_precomp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_precomp.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,60 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#ifndef __ODM_PRECOMP_H__ ++#define __ODM_PRECOMP_H__ ++ ++#include "odm_types.h" ++ ++#define TEST_FALG___ 1 ++ ++/* 2 Config Flags and Structs - defined by each ODM Type */ ++ ++ /* include */ ++ /* include */ ++ /* include */ ++ /* include */ ++ /* include */ ++#define BEAMFORMING_SUPPORT 0 ++ ++/* 2 Hardware Parameter Files */ ++ ++/* 2 OutSrc Header Files */ ++ ++#include "odm.h" ++#include "odm_HWConfig.h" ++#include "odm_debug.h" ++#include "odm_RegDefine11N.h" ++#include "odm_AntDiv.h" ++#include "odm_EdcaTurboCheck.h" ++#include "odm_DIG.h" ++#include "odm_PathDiv.h" ++#include "odm_DynamicBBPowerSaving.h" ++#include "odm_DynamicTxPower.h" ++#include "odm_CfoTracking.h" ++#include "odm_NoiseMonitor.h" ++#include "HalPhyRf.h" ++#include "HalPhyRf_8723B.h"/* for IQK, LCK, Power-tracking */ ++#include "rtl8723b_hal.h" ++#include "odm_interface.h" ++#include "odm_reg.h" ++#include "HalHWImg8723B_MAC.h" ++#include "HalHWImg8723B_RF.h" ++#include "HalHWImg8723B_BB.h" ++#include "Hal8723BReg.h" ++#include "odm_RTL8723B.h" ++#include "odm_RegConfig8723B.h" ++ ++#endif /* __ODM_PRECOMP_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_RegConfig8723B.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_RegConfig8723B.c +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_RegConfig8723B.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_RegConfig8723B.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,189 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#include "odm_precomp.h" ++ ++void ++odm_ConfigRFReg_8723B( ++PDM_ODM_T pDM_Odm, ++u32 Addr, ++u32 Data, ++ ODM_RF_RADIO_PATH_E RF_PATH, ++u32 RegAddr ++ ) ++{ ++ if (Addr == 0xfe || Addr == 0xffe) ++ { ++ msleep(50); ++ } ++ else ++ { ++ PHY_SetRFReg(pDM_Odm->Adapter, RF_PATH, RegAddr, bRFRegOffsetMask, Data); ++ /* Add 1us delay between BB/RF register setting. */ ++ udelay(1); ++ ++ /* For disable/enable test in high temperature, the B6 value will fail to fill. Suggestion by BB Stanley, 2013.06.25. */ ++ if (Addr == 0xb6) ++ { ++ u32 getvalue = 0; ++ u8 count = 0; ++ getvalue = PHY_QueryRFReg(pDM_Odm->Adapter, RF_PATH, Addr, bMaskDWord); ++ ++ udelay(1); ++ ++ while ((getvalue>>8)!=(Data>>8)) ++ { ++ count++; ++ PHY_SetRFReg(pDM_Odm->Adapter, RF_PATH, RegAddr, bRFRegOffsetMask, Data); ++ udelay(1); ++ getvalue = PHY_QueryRFReg(pDM_Odm->Adapter, RF_PATH, Addr, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigRFWithHeaderFile: [B6] getvalue 0x%x, Data 0x%x, count %d\n", getvalue, Data, count)); ++ if (count>5) ++ break; ++ } ++ } ++ ++ if (Addr == 0xb2) ++ { ++ u32 getvalue = 0; ++ u8 count = 0; ++ getvalue = PHY_QueryRFReg(pDM_Odm->Adapter, RF_PATH, Addr, bMaskDWord); ++ ++ udelay(1); ++ ++ while (getvalue!=Data) ++ { ++ count++; ++ PHY_SetRFReg(pDM_Odm->Adapter, RF_PATH, RegAddr, bRFRegOffsetMask, Data); ++ udelay(1); ++ /* Do LCK againg */ ++ PHY_SetRFReg(pDM_Odm->Adapter, RF_PATH, 0x18, bRFRegOffsetMask, 0x0fc07); ++ udelay(1); ++ getvalue = PHY_QueryRFReg(pDM_Odm->Adapter, RF_PATH, Addr, bMaskDWord); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigRFWithHeaderFile: [B2] getvalue 0x%x, Data 0x%x, count %d\n", getvalue, Data, count)); ++ if (count>5) ++ break; ++ } ++ } ++ } ++} ++ ++ ++void ++odm_ConfigRF_RadioA_8723B( ++PDM_ODM_T pDM_Odm, ++u32 Addr, ++u32 Data ++ ) ++{ ++ u32 content = 0x1000; /* RF_Content: radioa_txt */ ++ u32 maskforPhySet = (u32)(content&0xE000); ++ ++ odm_ConfigRFReg_8723B(pDM_Odm, Addr, Data, ODM_RF_PATH_A, Addr|maskforPhySet); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigRFWithHeaderFile: [RadioA] %08X %08X\n", Addr, Data)); ++} ++ ++void ++odm_ConfigMAC_8723B( ++PDM_ODM_T pDM_Odm, ++u32 Addr, ++u8 Data ++ ) ++{ ++ rtw_write8(pDM_Odm->Adapter, Addr, Data); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigMACWithHeaderFile: [MAC_REG] %08X %08X\n", Addr, Data)); ++} ++ ++void ++odm_ConfigBB_AGC_8723B( ++ PDM_ODM_T pDM_Odm, ++ u32 Addr, ++ u32 Bitmask, ++ u32 Data ++ ) ++{ ++ PHY_SetBBReg(pDM_Odm->Adapter, Addr, Bitmask, Data); ++ /* Add 1us delay between BB/RF register setting. */ ++ udelay(1); ++ ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigBBWithHeaderFile: [AGC_TAB] %08X %08X\n", Addr, Data)); ++} ++ ++void ++odm_ConfigBB_PHY_REG_PG_8723B( ++PDM_ODM_T pDM_Odm, ++u32 Band, ++u32 RfPath, ++u32 TxNum, ++ u32 Addr, ++ u32 Bitmask, ++ u32 Data ++ ) ++{ ++ if (Addr == 0xfe || Addr == 0xffe) ++ msleep(50); ++ else ++ { ++ PHY_StoreTxPowerByRate(pDM_Odm->Adapter, Band, RfPath, TxNum, Addr, Bitmask, Data); ++ } ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("===> ODM_ConfigBBWithHeaderFile: [PHY_REG] %08X %08X %08X\n", Addr, Bitmask, Data)); ++} ++ ++void ++odm_ConfigBB_PHY_8723B( ++PDM_ODM_T pDM_Odm, ++ u32 Addr, ++ u32 Bitmask, ++ u32 Data ++ ) ++{ ++ if (Addr == 0xfe) ++ msleep(50); ++ else if (Addr == 0xfd) ++ mdelay(5); ++ else if (Addr == 0xfc) ++ mdelay(1); ++ else if (Addr == 0xfb) ++ udelay(50); ++ else if (Addr == 0xfa) ++ udelay(5); ++ else if (Addr == 0xf9) ++ udelay(1); ++ else ++ { ++ PHY_SetBBReg(pDM_Odm->Adapter, Addr, Bitmask, Data); ++ } ++ ++ /* Add 1us delay between BB/RF register setting. */ ++ udelay(1); ++ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigBBWithHeaderFile: [PHY_REG] %08X %08X\n", Addr, Data)); ++} ++ ++void ++odm_ConfigBB_TXPWR_LMT_8723B( ++PDM_ODM_T pDM_Odm, ++u8 * Regulation, ++u8 * Band, ++u8 * Bandwidth, ++u8 * RateSection, ++u8 * RfPath, ++u8 * Channel, ++u8 * PowerLimit ++ ) ++{ ++ PHY_SetTxPowerLimit(pDM_Odm->Adapter, Regulation, Band, ++ Bandwidth, RateSection, RfPath, Channel, PowerLimit); ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_RegConfig8723B.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_RegConfig8723B.h +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_RegConfig8723B.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_RegConfig8723B.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,80 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __INC_ODM_REGCONFIG_H_8723B ++#define __INC_ODM_REGCONFIG_H_8723B ++ ++void ++odm_ConfigRFReg_8723B( ++PDM_ODM_T pDM_Odm, ++u32 Addr, ++u32 Data, ++ ODM_RF_RADIO_PATH_E RF_PATH, ++u32 RegAddr ++ ); ++ ++void ++odm_ConfigRF_RadioA_8723B( ++PDM_ODM_T pDM_Odm, ++u32 Addr, ++u32 Data ++ ); ++ ++void ++odm_ConfigMAC_8723B( ++PDM_ODM_T pDM_Odm, ++u32 Addr, ++u8 Data ++ ); ++ ++void ++odm_ConfigBB_AGC_8723B( ++ PDM_ODM_T pDM_Odm, ++ u32 Addr, ++ u32 Bitmask, ++ u32 Data ++ ); ++ ++void ++odm_ConfigBB_PHY_REG_PG_8723B( ++PDM_ODM_T pDM_Odm, ++u32 Band, ++u32 RfPath, ++u32 TxNum, ++ u32 Addr, ++ u32 Bitmask, ++ u32 Data ++ ); ++ ++void ++odm_ConfigBB_PHY_8723B( ++PDM_ODM_T pDM_Odm, ++ u32 Addr, ++ u32 Bitmask, ++ u32 Data ++ ); ++ ++void ++odm_ConfigBB_TXPWR_LMT_8723B( ++PDM_ODM_T pDM_Odm, ++u8 * Regulation, ++u8 * Band, ++u8 * Bandwidth, ++u8 * RateSection, ++u8 * RfPath, ++u8 * Channel, ++u8 * PowerLimit ++ ); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_RegDefine11N.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_RegDefine11N.h +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_RegDefine11N.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_RegDefine11N.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,172 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#ifndef __ODM_REGDEFINE11N_H__ ++#define __ODM_REGDEFINE11N_H__ ++ ++ ++/* 2 RF REG LIST */ ++#define ODM_REG_RF_MODE_11N 0x00 ++#define ODM_REG_RF_0B_11N 0x0B ++#define ODM_REG_CHNBW_11N 0x18 ++#define ODM_REG_T_METER_11N 0x24 ++#define ODM_REG_RF_25_11N 0x25 ++#define ODM_REG_RF_26_11N 0x26 ++#define ODM_REG_RF_27_11N 0x27 ++#define ODM_REG_RF_2B_11N 0x2B ++#define ODM_REG_RF_2C_11N 0x2C ++#define ODM_REG_RXRF_A3_11N 0x3C ++#define ODM_REG_T_METER_92D_11N 0x42 ++#define ODM_REG_T_METER_88E_11N 0x42 ++ ++/* 2 BB REG LIST */ ++/* PAGE 8 */ ++#define ODM_REG_BB_CTRL_11N 0x800 ++#define ODM_REG_RF_PIN_11N 0x804 ++#define ODM_REG_PSD_CTRL_11N 0x808 ++#define ODM_REG_TX_ANT_CTRL_11N 0x80C ++#define ODM_REG_BB_PWR_SAV5_11N 0x818 ++#define ODM_REG_CCK_RPT_FORMAT_11N 0x824 ++#define ODM_REG_RX_DEFUALT_A_11N 0x858 ++#define ODM_REG_RX_DEFUALT_B_11N 0x85A ++#define ODM_REG_BB_PWR_SAV3_11N 0x85C ++#define ODM_REG_ANTSEL_CTRL_11N 0x860 ++#define ODM_REG_RX_ANT_CTRL_11N 0x864 ++#define ODM_REG_PIN_CTRL_11N 0x870 ++#define ODM_REG_BB_PWR_SAV1_11N 0x874 ++#define ODM_REG_ANTSEL_PATH_11N 0x878 ++#define ODM_REG_BB_3WIRE_11N 0x88C ++#define ODM_REG_SC_CNT_11N 0x8C4 ++#define ODM_REG_PSD_DATA_11N 0x8B4 ++#define ODM_REG_PSD_DATA_11N 0x8B4 ++#define ODM_REG_NHM_TIMER_11N 0x894 ++#define ODM_REG_NHM_TH9_TH10_11N 0x890 ++#define ODM_REG_NHM_TH3_TO_TH0_11N 0x898 ++#define ODM_REG_NHM_TH7_TO_TH4_11N 0x89c ++#define ODM_REG_NHM_CNT_11N 0x8d8 ++/* PAGE 9 */ ++#define ODM_REG_DBG_RPT_11N 0x908 ++#define ODM_REG_ANT_MAPPING1_11N 0x914 ++#define ODM_REG_ANT_MAPPING2_11N 0x918 ++/* PAGE A */ ++#define ODM_REG_CCK_ANTDIV_PARA1_11N 0xA00 ++#define ODM_REG_CCK_CCA_11N 0xA0A ++#define ODM_REG_CCK_ANTDIV_PARA2_11N 0xA0C ++#define ODM_REG_CCK_ANTDIV_PARA3_11N 0xA10 ++#define ODM_REG_CCK_ANTDIV_PARA4_11N 0xA14 ++#define ODM_REG_CCK_FILTER_PARA1_11N 0xA22 ++#define ODM_REG_CCK_FILTER_PARA2_11N 0xA23 ++#define ODM_REG_CCK_FILTER_PARA3_11N 0xA24 ++#define ODM_REG_CCK_FILTER_PARA4_11N 0xA25 ++#define ODM_REG_CCK_FILTER_PARA5_11N 0xA26 ++#define ODM_REG_CCK_FILTER_PARA6_11N 0xA27 ++#define ODM_REG_CCK_FILTER_PARA7_11N 0xA28 ++#define ODM_REG_CCK_FILTER_PARA8_11N 0xA29 ++#define ODM_REG_CCK_FA_RST_11N 0xA2C ++#define ODM_REG_CCK_FA_MSB_11N 0xA58 ++#define ODM_REG_CCK_FA_LSB_11N 0xA5C ++#define ODM_REG_CCK_CCA_CNT_11N 0xA60 ++#define ODM_REG_BB_PWR_SAV4_11N 0xA74 ++/* PAGE B */ ++#define ODM_REG_LNA_SWITCH_11N 0xB2C ++#define ODM_REG_PATH_SWITCH_11N 0xB30 ++#define ODM_REG_RSSI_CTRL_11N 0xB38 ++#define ODM_REG_CONFIG_ANTA_11N 0xB68 ++#define ODM_REG_RSSI_BT_11N 0xB9C ++/* PAGE C */ ++#define ODM_REG_OFDM_FA_HOLDC_11N 0xC00 ++#define ODM_REG_BB_RX_PATH_11N 0xC04 ++#define ODM_REG_TRMUX_11N 0xC08 ++#define ODM_REG_OFDM_FA_RSTC_11N 0xC0C ++#define ODM_REG_RXIQI_MATRIX_11N 0xC14 ++#define ODM_REG_TXIQK_MATRIX_LSB1_11N 0xC4C ++#define ODM_REG_IGI_A_11N 0xC50 ++#define ODM_REG_ANTDIV_PARA2_11N 0xC54 ++#define ODM_REG_IGI_B_11N 0xC58 ++#define ODM_REG_ANTDIV_PARA3_11N 0xC5C ++#define ODM_REG_L1SBD_PD_CH_11N 0XC6C ++#define ODM_REG_BB_PWR_SAV2_11N 0xC70 ++#define ODM_REG_RX_OFF_11N 0xC7C ++#define ODM_REG_TXIQK_MATRIXA_11N 0xC80 ++#define ODM_REG_TXIQK_MATRIXB_11N 0xC88 ++#define ODM_REG_TXIQK_MATRIXA_LSB2_11N 0xC94 ++#define ODM_REG_TXIQK_MATRIXB_LSB2_11N 0xC9C ++#define ODM_REG_RXIQK_MATRIX_LSB_11N 0xCA0 ++#define ODM_REG_ANTDIV_PARA1_11N 0xCA4 ++#define ODM_REG_OFDM_FA_TYPE1_11N 0xCF0 ++/* PAGE D */ ++#define ODM_REG_OFDM_FA_RSTD_11N 0xD00 ++#define ODM_REG_BB_ATC_11N 0xD2C ++#define ODM_REG_OFDM_FA_TYPE2_11N 0xDA0 ++#define ODM_REG_OFDM_FA_TYPE3_11N 0xDA4 ++#define ODM_REG_OFDM_FA_TYPE4_11N 0xDA8 ++#define ODM_REG_RPT_11N 0xDF4 ++/* PAGE E */ ++#define ODM_REG_TXAGC_A_6_18_11N 0xE00 ++#define ODM_REG_TXAGC_A_24_54_11N 0xE04 ++#define ODM_REG_TXAGC_A_1_MCS32_11N 0xE08 ++#define ODM_REG_TXAGC_A_MCS0_3_11N 0xE10 ++#define ODM_REG_TXAGC_A_MCS4_7_11N 0xE14 ++#define ODM_REG_TXAGC_A_MCS8_11_11N 0xE18 ++#define ODM_REG_TXAGC_A_MCS12_15_11N 0xE1C ++#define ODM_REG_FPGA0_IQK_11N 0xE28 ++#define ODM_REG_TXIQK_TONE_A_11N 0xE30 ++#define ODM_REG_RXIQK_TONE_A_11N 0xE34 ++#define ODM_REG_TXIQK_PI_A_11N 0xE38 ++#define ODM_REG_RXIQK_PI_A_11N 0xE3C ++#define ODM_REG_TXIQK_11N 0xE40 ++#define ODM_REG_RXIQK_11N 0xE44 ++#define ODM_REG_IQK_AGC_PTS_11N 0xE48 ++#define ODM_REG_IQK_AGC_RSP_11N 0xE4C ++#define ODM_REG_BLUETOOTH_11N 0xE6C ++#define ODM_REG_RX_WAIT_CCA_11N 0xE70 ++#define ODM_REG_TX_CCK_RFON_11N 0xE74 ++#define ODM_REG_TX_CCK_BBON_11N 0xE78 ++#define ODM_REG_OFDM_RFON_11N 0xE7C ++#define ODM_REG_OFDM_BBON_11N 0xE80 ++#define ODM_REG_TX2RX_11N 0xE84 ++#define ODM_REG_TX2TX_11N 0xE88 ++#define ODM_REG_RX_CCK_11N 0xE8C ++#define ODM_REG_RX_OFDM_11N 0xED0 ++#define ODM_REG_RX_WAIT_RIFS_11N 0xED4 ++#define ODM_REG_RX2RX_11N 0xED8 ++#define ODM_REG_STANDBY_11N 0xEDC ++#define ODM_REG_SLEEP_11N 0xEE0 ++#define ODM_REG_PMPD_ANAEN_11N 0xEEC ++#define ODM_REG_IGI_C_11N 0xF84 ++#define ODM_REG_IGI_D_11N 0xF88 ++ ++/* 2 MAC REG LIST */ ++#define ODM_REG_BB_RST_11N 0x02 ++#define ODM_REG_ANTSEL_PIN_11N 0x4C ++#define ODM_REG_EARLY_MODE_11N 0x4D0 ++#define ODM_REG_RSSI_MONITOR_11N 0x4FE ++#define ODM_REG_EDCA_VO_11N 0x500 ++#define ODM_REG_EDCA_VI_11N 0x504 ++#define ODM_REG_EDCA_BE_11N 0x508 ++#define ODM_REG_EDCA_BK_11N 0x50C ++#define ODM_REG_TXPAUSE_11N 0x522 ++#define ODM_REG_RESP_TX_11N 0x6D8 ++#define ODM_REG_ANT_TRAIN_PARA1_11N 0x7b0 ++#define ODM_REG_ANT_TRAIN_PARA2_11N 0x7b4 ++ ++ ++/* DIG Related */ ++#define ODM_BIT_IGI_11N 0x0000007F ++#define ODM_BIT_CCK_RPT_FORMAT_11N BIT9 ++#define ODM_BIT_BB_RX_PATH_11N 0xF ++#define ODM_BIT_BB_ATC_11N BIT11 ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_reg.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_reg.h +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_reg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_reg.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,103 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++/* File Name: odm_reg.h */ ++/* Description: */ ++/* This file is for general register definition. */ ++#ifndef __HAL_ODM_REG_H__ ++#define __HAL_ODM_REG_H__ ++ ++/* Register Definition */ ++ ++/* MAC REG */ ++#define ODM_BB_RESET 0x002 ++#define ODM_DUMMY 0x4fe ++#define RF_T_METER_OLD 0x24 ++#define RF_T_METER_NEW 0x42 ++ ++#define ODM_EDCA_VO_PARAM 0x500 ++#define ODM_EDCA_VI_PARAM 0x504 ++#define ODM_EDCA_BE_PARAM 0x508 ++#define ODM_EDCA_BK_PARAM 0x50C ++#define ODM_TXPAUSE 0x522 ++ ++/* BB REG */ ++#define ODM_FPGA_PHY0_PAGE8 0x800 ++#define ODM_PSD_SETTING 0x808 ++#define ODM_AFE_SETTING 0x818 ++#define ODM_TXAGC_B_24_54 0x834 ++#define ODM_TXAGC_B_MCS32_5 0x838 ++#define ODM_TXAGC_B_MCS0_MCS3 0x83c ++#define ODM_TXAGC_B_MCS4_MCS7 0x848 ++#define ODM_TXAGC_B_MCS8_MCS11 0x84c ++#define ODM_ANALOG_REGISTER 0x85c ++#define ODM_RF_INTERFACE_OUTPUT 0x860 ++#define ODM_TXAGC_B_MCS12_MCS15 0x868 ++#define ODM_TXAGC_B_11_A_2_11 0x86c ++#define ODM_AD_DA_LSB_MASK 0x874 ++#define ODM_ENABLE_3_WIRE 0x88c ++#define ODM_PSD_REPORT 0x8b4 ++#define ODM_R_ANT_SELECT 0x90c ++#define ODM_CCK_ANT_SELECT 0xa07 ++#define ODM_CCK_PD_THRESH 0xa0a ++#define ODM_CCK_RF_REG1 0xa11 ++#define ODM_CCK_MATCH_FILTER 0xa20 ++#define ODM_CCK_RAKE_MAC 0xa2e ++#define ODM_CCK_CNT_RESET 0xa2d ++#define ODM_CCK_TX_DIVERSITY 0xa2f ++#define ODM_CCK_FA_CNT_MSB 0xa5b ++#define ODM_CCK_FA_CNT_LSB 0xa5c ++#define ODM_CCK_NEW_FUNCTION 0xa75 ++#define ODM_OFDM_PHY0_PAGE_C 0xc00 ++#define ODM_OFDM_RX_ANT 0xc04 ++#define ODM_R_A_RXIQI 0xc14 ++#define ODM_R_A_AGC_CORE1 0xc50 ++#define ODM_R_A_AGC_CORE2 0xc54 ++#define ODM_R_B_AGC_CORE1 0xc58 ++#define ODM_R_AGC_PAR 0xc70 ++#define ODM_R_HTSTF_AGC_PAR 0xc7c ++#define ODM_TX_PWR_TRAINING_A 0xc90 ++#define ODM_TX_PWR_TRAINING_B 0xc98 ++#define ODM_OFDM_FA_CNT1 0xcf0 ++#define ODM_OFDM_PHY0_PAGE_D 0xd00 ++#define ODM_OFDM_FA_CNT2 0xda0 ++#define ODM_OFDM_FA_CNT3 0xda4 ++#define ODM_OFDM_FA_CNT4 0xda8 ++#define ODM_TXAGC_A_6_18 0xe00 ++#define ODM_TXAGC_A_24_54 0xe04 ++#define ODM_TXAGC_A_1_MCS32 0xe08 ++#define ODM_TXAGC_A_MCS0_MCS3 0xe10 ++#define ODM_TXAGC_A_MCS4_MCS7 0xe14 ++#define ODM_TXAGC_A_MCS8_MCS11 0xe18 ++#define ODM_TXAGC_A_MCS12_MCS15 0xe1c ++ ++/* RF REG */ ++#define ODM_GAIN_SETTING 0x00 ++#define ODM_CHANNEL 0x18 ++ ++/* Ant Detect Reg */ ++#define ODM_DPDT 0x300 ++ ++/* PSD Init */ ++#define ODM_PSDREG 0x808 ++ ++/* 92D Path Div */ ++#define PATHDIV_REG 0xB30 ++#define PATHDIV_TRI 0xBA0 ++ ++/* Bitmap Definition */ ++ ++#define BIT_FA_RESET BIT0 ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_RTL8723B.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_RTL8723B.c +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_RTL8723B.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_RTL8723B.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,49 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#include "odm_precomp.h" ++ ++ s8 ++odm_CCKRSSI_8723B( ++ u8 LNA_idx, ++ u8 VGA_idx ++ ) ++{ ++ s8 rx_pwr_all = 0x00; ++ switch (LNA_idx) ++ { ++ /* 46 53 73 95 201301231630 */ ++ /* 46 53 77 99 201301241630 */ ++ ++ case 6: ++ rx_pwr_all = -34 - (2 * VGA_idx); ++ break; ++ case 4: ++ rx_pwr_all = -14 - (2 * VGA_idx); ++ break; ++ case 1: ++ rx_pwr_all = 6 - (2 * VGA_idx); ++ break; ++ case 0: ++ rx_pwr_all = 16 - (2 * VGA_idx); ++ break; ++ default: ++ /* rx_pwr_all = -53+(2*(31-VGA_idx)); */ ++ /* DbgPrint("wrong LNA index\n"); */ ++ break; ++ ++ } ++ return rx_pwr_all; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_RTL8723B.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_RTL8723B.h +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_RTL8723B.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_RTL8723B.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,22 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __ODM_RTL8723B_H__ ++#define __ODM_RTL8723B_H__ ++ ++#define DM_DIG_MIN_NIC_8723 0x1C ++ ++s8 odm_CCKRSSI_8723B(u8 LNA_idx, u8 VGA_idx); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/odm_types.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_types.h +--- linux-4.3/3rdparty/rtl8723bs/hal/odm_types.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/odm_types.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,102 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __ODM_TYPES_H__ ++#define __ODM_TYPES_H__ ++ ++#include ++ ++/* Deifne HW endian support */ ++#define ODM_ENDIAN_BIG 0 ++#define ODM_ENDIAN_LITTLE 1 ++ ++#define GET_ODM(__padapter) ((PDM_ODM_T)(&((GET_HAL_DATA(__padapter))->odmpriv))) ++ ++typedef enum _HAL_STATUS{ ++ HAL_STATUS_SUCCESS, ++ HAL_STATUS_FAILURE, ++ /*RT_STATUS_PENDING, ++ RT_STATUS_RESOURCE, ++ RT_STATUS_INVALID_CONTEXT, ++ RT_STATUS_INVALID_PARAMETER, ++ RT_STATUS_NOT_SUPPORT, ++ RT_STATUS_OS_API_FAILED,*/ ++}HAL_STATUS,*PHAL_STATUS; ++ ++ ++/* */ ++/* Declare for ODM spin lock defintion temporarily fro compile pass. */ ++/* */ ++typedef enum _RT_SPINLOCK_TYPE{ ++ RT_TX_SPINLOCK = 1, ++ RT_RX_SPINLOCK = 2, ++ RT_RM_SPINLOCK = 3, ++ RT_CAM_SPINLOCK = 4, ++ RT_SCAN_SPINLOCK = 5, ++ RT_LOG_SPINLOCK = 7, ++ RT_BW_SPINLOCK = 8, ++ RT_CHNLOP_SPINLOCK = 9, ++ RT_RF_OPERATE_SPINLOCK = 10, ++ RT_INITIAL_SPINLOCK = 11, ++ RT_RF_STATE_SPINLOCK = 12, /* For RF state. Added by Bruce, 2007-10-30. */ ++ /* Shall we define Ndis 6.2 SpinLock Here ? */ ++ RT_PORT_SPINLOCK = 16, ++ RT_H2C_SPINLOCK = 20, /* For H2C cmd. Added by tynli. 2009.11.09. */ ++ ++ RT_BTData_SPINLOCK =25, ++ ++ RT_WAPI_OPTION_SPINLOCK =26, ++ RT_WAPI_RX_SPINLOCK =27, ++ ++ /* add for 92D CCK control issue */ ++ RT_CCK_PAGEA_SPINLOCK = 28, ++ RT_BUFFER_SPINLOCK = 29, ++ RT_CHANNEL_AND_BANDWIDTH_SPINLOCK = 30, ++ RT_GEN_TEMP_BUF_SPINLOCK = 31, ++ RT_AWB_SPINLOCK = 32, ++ RT_FW_PS_SPINLOCK = 33, ++ RT_HW_TIMER_SPIN_LOCK = 34, ++ RT_MPT_WI_SPINLOCK = 35, ++ RT_P2P_SPIN_LOCK = 36, /* Protect P2P context */ ++ RT_DBG_SPIN_LOCK = 37, ++ RT_IQK_SPINLOCK = 38, ++ RT_PENDED_OID_SPINLOCK = 39, ++ RT_CHNLLIST_SPINLOCK = 40, ++ RT_INDIC_SPINLOCK = 41, /* protect indication */ ++}RT_SPINLOCK_TYPE; ++ ++ #if defined(__LITTLE_ENDIAN) ++ #define ODM_ENDIAN_TYPE ODM_ENDIAN_LITTLE ++ #else ++ #define ODM_ENDIAN_TYPE ODM_ENDIAN_BIG ++ #endif ++ ++ typedef struct timer_list RT_TIMER, *PRT_TIMER; ++ typedef void * RT_TIMER_CALL_BACK; ++ #define STA_INFO_T struct sta_info ++ #define PSTA_INFO_T struct sta_info * ++ ++ #define SET_TX_DESC_ANTSEL_A_88E(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 24, 1, __Value) ++ #define SET_TX_DESC_ANTSEL_B_88E(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 25, 1, __Value) ++ #define SET_TX_DESC_ANTSEL_C_88E(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+28, 29, 1, __Value) ++ ++ /* define useless flag to avoid compile warning */ ++ #define USE_WORKITEM 0 ++ #define FPGA_TWO_MAC_VERIFICATION 0 ++ ++#define READ_NEXT_PAIR(v1, v2, i) do { if (i+2 >= ArrayLen) break; i += 2; v1 = Array[i]; v2 = Array[i+1]; } while (0) ++#define COND_ELSE 2 ++#define COND_ENDIF 3 ++ ++#endif /* __ODM_TYPES_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/rtl8723b_cmd.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/rtl8723b_cmd.c +--- linux-4.3/3rdparty/rtl8723bs/hal/rtl8723b_cmd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/rtl8723b_cmd.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,2412 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTL8723B_CMD_C_ ++ ++#include ++#include ++#include ++#include "hal_com_h2c.h" ++ ++#define MAX_H2C_BOX_NUMS 4 ++#define MESSAGE_BOX_SIZE 4 ++ ++#define RTL8723B_MAX_CMD_LEN 7 ++#define RTL8723B_EX_MESSAGE_BOX_SIZE 4 ++ ++static u8 _is_fw_read_cmd_down(struct adapter *padapter, u8 msgbox_num) ++{ ++ u8 read_down = false; ++ int retry_cnts = 100; ++ ++ u8 valid; ++ ++ /* DBG_8192C(" _is_fw_read_cmd_down , reg_1cc(%x), msg_box(%d)...\n", rtw_read8(padapter, REG_HMETFR), msgbox_num); */ ++ ++ do{ ++ valid = rtw_read8(padapter, REG_HMETFR) & BIT(msgbox_num); ++ if (0 == valid) { ++ read_down = true; ++ } ++#ifdef CONFIG_WOWLAN ++ else ++ msleep(1); ++#endif ++ }while ((!read_down) && (retry_cnts--)); ++ ++ return read_down; ++ ++} ++ ++ ++/***************************************** ++* H2C Msg format : ++*| 31 - 8 |7-5 | 4 - 0 | ++*| h2c_msg |Class |CMD_ID | ++*| 31-0 | ++*| Ext msg | ++* ++******************************************/ ++s32 FillH2CCmd8723B(struct adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer) ++{ ++ u8 h2c_box_num; ++ u32 msgbox_addr; ++ u32 msgbox_ex_addr = 0; ++ struct hal_com_data *pHalData; ++ u32 h2c_cmd = 0; ++ u32 h2c_cmd_ex = 0; ++ s32 ret = _FAIL; ++ ++ padapter = GET_PRIMARY_ADAPTER(padapter); ++ pHalData = GET_HAL_DATA(padapter); ++ if (mutex_lock_interruptible(&(adapter_to_dvobj(padapter)->h2c_fwcmd_mutex))) ++ return ret; ++ ++ if (!pCmdBuffer) { ++ goto exit; ++ } ++ if (CmdLen > RTL8723B_MAX_CMD_LEN) { ++ goto exit; ++ } ++ if (padapter->bSurpriseRemoved == true) ++ goto exit; ++ ++ /* pay attention to if race condition happened in H2C cmd setting. */ ++ do{ ++ h2c_box_num = pHalData->LastHMEBoxNum; ++ ++ if (!_is_fw_read_cmd_down(padapter, h2c_box_num)) { ++ DBG_8192C(" fw read cmd failed...\n"); ++ /* DBG_8192C(" 0x1c0: 0x%8x\n", rtw_read32(padapter, 0x1c0)); */ ++ /* DBG_8192C(" 0x1c4: 0x%8x\n", rtw_read32(padapter, 0x1c4)); */ ++ goto exit; ++ } ++ ++ if (CmdLen<=3) ++ { ++ memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, CmdLen); ++ } ++ else { ++ memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, 3); ++ memcpy((u8 *)(&h2c_cmd_ex), pCmdBuffer+3, CmdLen-3); ++/* *(u8 *)(&h2c_cmd) |= BIT(7); */ ++ } ++ ++ *(u8 *)(&h2c_cmd) |= ElementID; ++ ++ if (CmdLen>3) { ++ msgbox_ex_addr = REG_HMEBOX_EXT0_8723B + (h2c_box_num *RTL8723B_EX_MESSAGE_BOX_SIZE); ++ rtw_write32(padapter, msgbox_ex_addr, h2c_cmd_ex); ++ } ++ msgbox_addr =REG_HMEBOX_0 + (h2c_box_num *MESSAGE_BOX_SIZE); ++ rtw_write32(padapter, msgbox_addr, h2c_cmd); ++ ++ /* DBG_8192C("MSG_BOX:%d, CmdLen(%d), CmdID(0x%x), reg:0x%x =>h2c_cmd:0x%.8x, reg:0x%x =>h2c_cmd_ex:0x%.8x\n" */ ++ /* , pHalData->LastHMEBoxNum , CmdLen, ElementID, msgbox_addr, h2c_cmd, msgbox_ex_addr, h2c_cmd_ex); */ ++ ++ pHalData->LastHMEBoxNum = (h2c_box_num+1) % MAX_H2C_BOX_NUMS; ++ ++ }while (0); ++ ++ ret = _SUCCESS; ++ ++exit: ++ ++ mutex_unlock(&(adapter_to_dvobj(padapter)->h2c_fwcmd_mutex)); ++ return ret; ++} ++ ++static void ConstructBeacon(struct adapter *padapter, u8 *pframe, u32 *pLength) ++{ ++ struct ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ u32 rate_len, pktlen; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); ++ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ ++ /* DBG_871X("%s\n", __func__); */ ++ ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ ++ fctrl = &(pwlanhdr->frame_control); ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); ++ /* pmlmeext->mgnt_seq++; */ ++ SetFrameSubType(pframe, WIFI_BEACON); ++ ++ pframe += sizeof(struct ieee80211_hdr_3addr); ++ pktlen = sizeof (struct ieee80211_hdr_3addr); ++ ++ /* timestamp will be inserted by hardware */ ++ pframe += 8; ++ pktlen += 8; ++ ++ /* beacon interval: 2 bytes */ ++ memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ pktlen += 2; ++ ++ /* capability info: 2 bytes */ ++ memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ pktlen += 2; ++ ++ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) ++ { ++ /* DBG_871X("ie len =%d\n", cur_network->IELength); */ ++ pktlen += cur_network->IELength - sizeof(struct ndis_802_11_fix_ie); ++ memcpy(pframe, cur_network->IEs+sizeof(struct ndis_802_11_fix_ie), pktlen); ++ ++ goto _ConstructBeacon; ++ } ++ ++ /* below for ad-hoc mode */ ++ ++ /* SSID */ ++ pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pktlen); ++ ++ /* supported rates... */ ++ rate_len = rtw_get_rateset_len(cur_network->SupportedRates); ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8)? 8: rate_len), cur_network->SupportedRates, &pktlen); ++ ++ /* DS parameter set */ ++ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pktlen); ++ ++ if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) ++ { ++ u32 ATIMWindow; ++ /* IBSS Parameter Set... */ ++ /* ATIMWindow = cur->Configuration.ATIMWindow; */ ++ ATIMWindow = 0; ++ pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pktlen); ++ } ++ ++ ++ /* todo: ERP IE */ ++ ++ ++ /* EXTERNDED SUPPORTED RATE */ ++ if (rate_len > 8) ++ { ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen); ++ } ++ ++ ++ /* todo:HT for adhoc */ ++ ++_ConstructBeacon: ++ ++ if ((pktlen + TXDESC_SIZE) > 512) ++ { ++ DBG_871X("beacon frame too large\n"); ++ return; ++ } ++ ++ *pLength = pktlen; ++ ++ /* DBG_871X("%s bcn_sz =%d\n", __func__, pktlen); */ ++ ++} ++ ++static void ConstructPSPoll(struct adapter *padapter, u8 *pframe, u32 *pLength) ++{ ++ struct ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ /* DBG_871X("%s\n", __func__); */ ++ ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ ++ /* Frame control. */ ++ fctrl = &(pwlanhdr->frame_control); ++ *(fctrl) = 0; ++ SetPwrMgt(fctrl); ++ SetFrameSubType(pframe, WIFI_PSPOLL); ++ ++ /* AID. */ ++ SetDuration(pframe, (pmlmeinfo->aid | 0xc000)); ++ ++ /* BSSID. */ ++ memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ /* TA. */ ++ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ ++ *pLength = 16; ++} ++ ++static void ConstructNullFunctionData( ++ struct adapter *padapter, ++ u8 *pframe, ++ u32 *pLength, ++ u8 *StaAddr, ++ u8 bQoS, ++ u8 AC, ++ u8 bEosp, ++ u8 bForcePowerSave) ++{ ++ struct ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ u32 pktlen; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *cur_network = &pmlmepriv->cur_network; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ ++ /* DBG_871X("%s:%d\n", __func__, bForcePowerSave); */ ++ ++ pwlanhdr = (struct ieee80211_hdr*)pframe; ++ ++ fctrl = &pwlanhdr->frame_control; ++ *(fctrl) = 0; ++ if (bForcePowerSave) ++ { ++ SetPwrMgt(fctrl); ++ } ++ ++ switch (cur_network->network.InfrastructureMode) ++ { ++ case Ndis802_11Infrastructure: ++ SetToDs(fctrl); ++ memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN); ++ break; ++ case Ndis802_11APMode: ++ SetFrDs(fctrl); ++ memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ break; ++ case Ndis802_11IBSS: ++ default: ++ memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ break; ++ } ++ ++ SetSeqNum(pwlanhdr, 0); ++ ++ if (bQoS == true) { ++ struct ieee80211_qos_hdr *pwlanqoshdr; ++ ++ SetFrameSubType(pframe, WIFI_QOS_DATA_NULL); ++ ++ pwlanqoshdr = (struct ieee80211_qos_hdr*)pframe; ++ SetPriority(&pwlanqoshdr->qos_ctrl, AC); ++ SetEOSP(&pwlanqoshdr->qos_ctrl, bEosp); ++ ++ pktlen = sizeof(struct ieee80211_qos_hdr); ++ } else { ++ SetFrameSubType(pframe, WIFI_DATA_NULL); ++ ++ pktlen = sizeof(struct ieee80211_hdr_3addr); ++ } ++ ++ *pLength = pktlen; ++} ++ ++ ++#ifdef CONFIG_WOWLAN ++/* */ ++/* Description: */ ++/* Construct the ARP response packet to support ARP offload. */ ++/* */ ++static void ConstructARPResponse( ++ struct adapter *padapter, ++ u8 *pframe, ++ u32 *pLength, ++ u8 *pIPAddress ++ ) ++{ ++ struct ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ static u8 ARPLLCHeader[8] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x08, 0x06}; ++ u8 *pARPRspPkt = pframe; ++ /* for TKIP Cal MIC */ ++ u8 *payload = pframe; ++ u8 EncryptionHeadOverhead = 0; ++ /* DBG_871X("%s:%d\n", __func__, bForcePowerSave); */ ++ ++ pwlanhdr = (struct ieee80211_hdr*)pframe; ++ ++ fctrl = &pwlanhdr->frame_control; ++ *(fctrl) = 0; ++ ++ /* */ ++ /* MAC Header. */ ++ /* */ ++ SetFrameType(fctrl, WIFI_DATA); ++ /* SetFrameSubType(fctrl, 0); */ ++ SetToDs(fctrl); ++ memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, 0); ++ SetDuration(pwlanhdr, 0); ++ /* SET_80211_HDR_FRAME_CONTROL(pARPRspPkt, 0); */ ++ /* SET_80211_HDR_TYPE_AND_SUBTYPE(pARPRspPkt, Type_Data); */ ++ /* SET_80211_HDR_TO_DS(pARPRspPkt, 1); */ ++ /* SET_80211_HDR_ADDRESS1(pARPRspPkt, pMgntInfo->Bssid); */ ++ /* SET_80211_HDR_ADDRESS2(pARPRspPkt, Adapter->CurrentAddress); */ ++ /* SET_80211_HDR_ADDRESS3(pARPRspPkt, pMgntInfo->Bssid); */ ++ ++ /* SET_80211_HDR_DURATION(pARPRspPkt, 0); */ ++ /* SET_80211_HDR_FRAGMENT_SEQUENCE(pARPRspPkt, 0); */ ++ *pLength = 24; ++ ++ /* */ ++ /* Security Header: leave space for it if necessary. */ ++ /* */ ++ ++ switch (psecuritypriv->dot11PrivacyAlgrthm) ++ { ++ case _WEP40_: ++ case _WEP104_: ++ EncryptionHeadOverhead = 4; ++ break; ++ case _TKIP_: ++ EncryptionHeadOverhead = 8; ++ break; ++ case _AES_: ++ EncryptionHeadOverhead = 8; ++ break; ++ default: ++ EncryptionHeadOverhead = 0; ++ } ++ ++ if (EncryptionHeadOverhead > 0) ++ { ++ memset(&(pframe[*pLength]), 0, EncryptionHeadOverhead); ++ *pLength += EncryptionHeadOverhead; ++ SetPrivacy(fctrl); ++ } ++ ++ /* */ ++ /* Frame Body. */ ++ /* */ ++ pARPRspPkt = (u8 *)(pframe+ *pLength); ++ payload = pARPRspPkt; /* Get Payload pointer */ ++ /* LLC header */ ++ memcpy(pARPRspPkt, ARPLLCHeader, 8); ++ *pLength += 8; ++ ++ /* ARP element */ ++ pARPRspPkt += 8; ++ SET_ARP_PKT_HW(pARPRspPkt, 0x0100); ++ SET_ARP_PKT_PROTOCOL(pARPRspPkt, 0x0008); /* IP protocol */ ++ SET_ARP_PKT_HW_ADDR_LEN(pARPRspPkt, 6); ++ SET_ARP_PKT_PROTOCOL_ADDR_LEN(pARPRspPkt, 4); ++ SET_ARP_PKT_OPERATION(pARPRspPkt, 0x0200); /* ARP response */ ++ SET_ARP_PKT_SENDER_MAC_ADDR(pARPRspPkt, myid(&(padapter->eeprompriv))); ++ SET_ARP_PKT_SENDER_IP_ADDR(pARPRspPkt, pIPAddress); ++ { ++ SET_ARP_PKT_TARGET_MAC_ADDR(pARPRspPkt, get_my_bssid(&(pmlmeinfo->network))); ++ SET_ARP_PKT_TARGET_IP_ADDR(pARPRspPkt, pIPAddress); ++ DBG_871X("%s Target Mac Addr:" MAC_FMT "\n", __func__, MAC_ARG(get_my_bssid(&(pmlmeinfo->network)))); ++ DBG_871X("%s Target IP Addr" IP_FMT "\n", __func__, IP_ARG(pIPAddress)); ++ } ++ ++ *pLength += 28; ++ ++ if (psecuritypriv->dot11PrivacyAlgrthm == _TKIP_) ++ { ++ u8 mic[8]; ++ struct mic_data micdata; ++ struct sta_info *psta = NULL; ++ u8 priority[4]={0x0, 0x0, 0x0, 0x0}; ++ u8 null_key[16]={0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; ++ ++ DBG_871X("%s(): Add MIC\n", __func__); ++ ++ psta = rtw_get_stainfo(&padapter->stapriv, get_my_bssid(&(pmlmeinfo->network))); ++ if (psta != NULL) { ++ if (!memcmp(&psta->dot11tkiptxmickey.skey[0], null_key, 16)) { ++ DBG_871X("%s(): STA dot11tkiptxmickey == 0\n", __func__); ++ } ++ /* start to calculate the mic code */ ++ rtw_secmicsetkey(&micdata, &psta->dot11tkiptxmickey.skey[0]); ++ } ++ ++ rtw_secmicappend(&micdata, pwlanhdr->addr3, 6); /* DA */ ++ ++ rtw_secmicappend(&micdata, pwlanhdr->addr2, 6); /* SA */ ++ ++ priority[0]= 0; ++ rtw_secmicappend(&micdata, &priority[0], 4); ++ ++ rtw_secmicappend(&micdata, payload, 36); /* payload length = 8 + 28 */ ++ ++ rtw_secgetmic(&micdata,&(mic[0])); ++ ++ pARPRspPkt += 28; ++ memcpy(pARPRspPkt, &(mic[0]), 8); ++ ++ *pLength += 8; ++ } ++} ++ ++#ifdef CONFIG_PNO_SUPPORT ++static void ConstructPnoInfo( ++ struct adapter *padapter, ++ u8 *pframe, ++ u32 *pLength ++ ) ++{ ++ ++ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); ++ ++ u8 *pPnoInfoPkt = pframe; ++ pPnoInfoPkt = (u8 *)(pframe+ *pLength); ++ memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->ssid_num, 4); ++ ++ *pLength+=4; ++ pPnoInfoPkt += 4; ++ memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->fast_scan_period, 4); ++ ++ *pLength+=4; ++ pPnoInfoPkt += 4; ++ memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->fast_scan_iterations, 4); ++ ++ *pLength+=4; ++ pPnoInfoPkt += 4; ++ memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->slow_scan_period, 4); ++ ++ *pLength+=4; ++ pPnoInfoPkt += 4; ++ memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->ssid_length, ++ MAX_PNO_LIST_COUNT); ++ ++ *pLength+=MAX_PNO_LIST_COUNT; ++ pPnoInfoPkt += MAX_PNO_LIST_COUNT; ++ memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->ssid_cipher_info, ++ MAX_PNO_LIST_COUNT); ++ ++ *pLength+=MAX_PNO_LIST_COUNT; ++ pPnoInfoPkt += MAX_PNO_LIST_COUNT; ++ memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->ssid_channel_info, ++ MAX_PNO_LIST_COUNT); ++ ++ *pLength+=MAX_PNO_LIST_COUNT; ++ pPnoInfoPkt += MAX_PNO_LIST_COUNT; ++} ++ ++static void ConstructSSIDList( ++ struct adapter *padapter, ++ u8 *pframe, ++ u32 *pLength ++ ) ++{ ++ int i = 0; ++ u8 *pSSIDListPkt = pframe; ++ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); ++ ++ pSSIDListPkt = (u8 *)(pframe+ *pLength); ++ ++ for (i = 0; i < pwrctl->pnlo_info->ssid_num ; i++) { ++ memcpy(pSSIDListPkt, &pwrctl->pno_ssid_list->node[i].SSID, ++ pwrctl->pnlo_info->ssid_length[i]); ++ ++ *pLength += WLAN_SSID_MAXLEN; ++ pSSIDListPkt += WLAN_SSID_MAXLEN; ++ } ++} ++ ++static void ConstructScanInfo( ++ struct adapter *padapter, ++ u8 *pframe, ++ u32 *pLength ++ ) ++{ ++ int i = 0; ++ u8 *pScanInfoPkt = pframe; ++ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); ++ ++ pScanInfoPkt = (u8 *)(pframe+ *pLength); ++ ++ memcpy(pScanInfoPkt, &pwrctl->pscan_info->channel_num, 1); ++ ++ *pLength+= 1; ++ pScanInfoPkt += 1; ++ memcpy(pScanInfoPkt, &pwrctl->pscan_info->orig_ch, 1); ++ ++ ++ *pLength+= 1; ++ pScanInfoPkt += 1; ++ memcpy(pScanInfoPkt, &pwrctl->pscan_info->orig_bw, 1); ++ ++ ++ *pLength+= 1; ++ pScanInfoPkt += 1; ++ memcpy(pScanInfoPkt, &pwrctl->pscan_info->orig_40_offset, 1); ++ ++ *pLength+= 1; ++ pScanInfoPkt += 1; ++ memcpy(pScanInfoPkt, &pwrctl->pscan_info->orig_80_offset, 1); ++ ++ *pLength+= 1; ++ pScanInfoPkt += 1; ++ memcpy(pScanInfoPkt, &pwrctl->pscan_info->periodScan, 1); ++ ++ *pLength+= 1; ++ pScanInfoPkt += 1; ++ memcpy(pScanInfoPkt, &pwrctl->pscan_info->period_scan_time, 1); ++ ++ *pLength+= 1; ++ pScanInfoPkt += 1; ++ memcpy(pScanInfoPkt, &pwrctl->pscan_info->enableRFE, 1); ++ ++ *pLength+= 1; ++ pScanInfoPkt += 1; ++ memcpy(pScanInfoPkt, &pwrctl->pscan_info->rfe_type, 8); ++ ++ *pLength+=8; ++ pScanInfoPkt += 8; ++ ++ for (i = 0 ; i < MAX_SCAN_LIST_COUNT ; i ++) { ++ memcpy(pScanInfoPkt, ++ &pwrctl->pscan_info->ssid_channel_info[i], 4); ++ *pLength+=4; ++ pScanInfoPkt += 4; ++ } ++} ++#endif ++ ++#ifdef CONFIG_GTK_OL ++static void ConstructGTKResponse( ++ struct adapter *padapter, ++ u8 *pframe, ++ u32 *pLength ++ ) ++{ ++ struct ieee80211_hdr *pwlanhdr; ++ u16 *fctrl; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ static u8 LLCHeader[8] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8E}; ++ static u8 GTKbody_a[11] ={0x01, 0x03, 0x00, 0x5F, 0x02, 0x03, 0x12, 0x00, 0x10, 0x42, 0x0B}; ++ u8 *pGTKRspPkt = pframe; ++ u8 EncryptionHeadOverhead = 0; ++ /* DBG_871X("%s:%d\n", __func__, bForcePowerSave); */ ++ ++ pwlanhdr = (struct ieee80211_hdr*)pframe; ++ ++ fctrl = &pwlanhdr->frame_control; ++ *(fctrl) = 0; ++ ++ /* */ ++ /* MAC Header. */ ++ /* */ ++ SetFrameType(fctrl, WIFI_DATA); ++ /* SetFrameSubType(fctrl, 0); */ ++ SetToDs(fctrl); ++ memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, 0); ++ SetDuration(pwlanhdr, 0); ++ ++ *pLength = 24; ++ ++ /* */ ++ /* Security Header: leave space for it if necessary. */ ++ /* */ ++ ++ switch (psecuritypriv->dot11PrivacyAlgrthm) ++ { ++ case _WEP40_: ++ case _WEP104_: ++ EncryptionHeadOverhead = 4; ++ break; ++ case _TKIP_: ++ EncryptionHeadOverhead = 8; ++ break; ++ case _AES_: ++ EncryptionHeadOverhead = 8; ++ break; ++ default: ++ EncryptionHeadOverhead = 0; ++ } ++ ++ if (EncryptionHeadOverhead > 0) ++ { ++ memset(&(pframe[*pLength]), 0, EncryptionHeadOverhead); ++ *pLength += EncryptionHeadOverhead; ++ /* GTK's privacy bit is done by FW */ ++ /* SetPrivacy(fctrl); */ ++ } ++ ++ /* */ ++ /* Frame Body. */ ++ /* */ ++ pGTKRspPkt = (u8 *)(pframe+ *pLength); ++ /* LLC header */ ++ memcpy(pGTKRspPkt, LLCHeader, 8); ++ *pLength += 8; ++ ++ /* GTK element */ ++ pGTKRspPkt += 8; ++ ++ /* GTK frame body after LLC, part 1 */ ++ memcpy(pGTKRspPkt, GTKbody_a, 11); ++ *pLength += 11; ++ pGTKRspPkt += 11; ++ /* GTK frame body after LLC, part 2 */ ++ memset(&(pframe[*pLength]), 0, 88); ++ *pLength += 88; ++ pGTKRspPkt += 88; ++ ++} ++#endif /* CONFIG_GTK_OL */ ++ ++#ifdef CONFIG_PNO_SUPPORT ++static void ConstructProbeReq(struct adapter *padapter, u8 *pframe, u32 *pLength) ++{ ++ struct ieee80211_hdr *pwlanhdr; ++ u16 *fctrl; ++ u32 pktlen; ++ unsigned char *mac; ++ unsigned char bssrate[NumRates]; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ int bssrate_len = 0; ++ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ mac = myid(&(padapter->eeprompriv)); ++ ++ fctrl = &(pwlanhdr->frame_control); ++ *(fctrl) = 0; ++ ++ /* broadcast probe request frame */ ++ memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN); ++ ++ memcpy(pwlanhdr->addr2, mac, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, 0); ++ SetFrameSubType(pframe, WIFI_PROBEREQ); ++ ++ pktlen = sizeof(struct ieee80211_hdr_3addr); ++ pframe += pktlen; ++ ++ pframe = rtw_set_ie(pframe, _SSID_IE_, 0, NULL, &pktlen); ++ ++ get_rate_set(padapter, bssrate, &bssrate_len); ++ ++ if (bssrate_len > 8) ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &pktlen); ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &pktlen); ++ } ++ else ++ { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &pktlen); ++ } ++ ++ *pLength = pktlen; ++} ++#endif /* CONFIG_PNO_SUPPORT */ ++#endif /* CONFIG_WOWLAN */ ++ ++#ifdef CONFIG_AP_WOWLAN ++static void ConstructProbeRsp(struct adapter *padapter, u8 *pframe, u32 *pLength, u8 *StaAddr, bool bHideSSID) ++{ ++ struct ieee80211_hdr *pwlanhdr; ++ u16 *fctrl; ++ u8 *mac, *bssid; ++ u32 pktlen; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); ++ u8 *pwps_ie; ++ uint wps_ielen; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ /* DBG_871X("%s\n", __func__); */ ++ ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ ++ mac = myid(&(padapter->eeprompriv)); ++ bssid = cur_network->MacAddress; ++ ++ fctrl = &(pwlanhdr->frame_control); ++ *(fctrl) = 0; ++ memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, mac, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); ++ ++ DBG_871X("%s FW Mac Addr:" MAC_FMT "\n", __func__, MAC_ARG(mac)); ++ DBG_871X("%s FW IP Addr" IP_FMT "\n", __func__, IP_ARG(StaAddr)); ++ ++ SetSeqNum(pwlanhdr, 0); ++ SetFrameSubType(fctrl, WIFI_PROBERSP); ++ ++ pktlen = sizeof(struct ieee80211_hdr_3addr); ++ pframe += pktlen; ++ ++ if (cur_network->IELength>MAX_IE_SZ) ++ return; ++ ++ pwps_ie = rtw_get_wps_ie(cur_network->IEs+_FIXED_IE_LENGTH_, ++ cur_network->IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen); ++ ++ /* inerset & update wps_probe_resp_ie */ ++ if ((pmlmepriv->wps_probe_resp_ie!= NULL) && pwps_ie && (wps_ielen>0)) { ++ uint wps_offset, remainder_ielen; ++ u8 *premainder_ie; ++ ++ wps_offset = (uint)(pwps_ie - cur_network->IEs); ++ ++ premainder_ie = pwps_ie + wps_ielen; ++ ++ remainder_ielen = cur_network->IELength - wps_offset - wps_ielen; ++ ++ memcpy(pframe, cur_network->IEs, wps_offset); ++ pframe += wps_offset; ++ pktlen += wps_offset; ++ ++ wps_ielen = (uint)pmlmepriv->wps_probe_resp_ie[1];/* to get ie data len */ ++ if ((wps_offset+wps_ielen+2)<=MAX_IE_SZ) { ++ memcpy(pframe, pmlmepriv->wps_probe_resp_ie, wps_ielen+2); ++ pframe += wps_ielen+2; ++ pktlen += wps_ielen+2; ++ } ++ ++ if ((wps_offset+wps_ielen+2+remainder_ielen)<=MAX_IE_SZ) { ++ memcpy(pframe, premainder_ie, remainder_ielen); ++ pframe += remainder_ielen; ++ pktlen += remainder_ielen; ++ } ++ } else { ++ memcpy(pframe, cur_network->IEs, cur_network->IELength); ++ pframe += cur_network->IELength; ++ pktlen += cur_network->IELength; ++ } ++ ++ /* retrieve SSID IE from cur_network->Ssid */ ++ { ++ u8 *ssid_ie; ++ sint ssid_ielen; ++ sint ssid_ielen_diff; ++ u8 buf[MAX_IE_SZ]; ++ u8 *ies = pframe + sizeof(struct ieee80211_hdr_3addr); ++ ++ ssid_ie = rtw_get_ie(ies+_FIXED_IE_LENGTH_, _SSID_IE_, &ssid_ielen, ++ (pframe-ies)-_FIXED_IE_LENGTH_); ++ ++ ssid_ielen_diff = cur_network->Ssid.SsidLength - ssid_ielen; ++ ++ if (ssid_ie && cur_network->Ssid.SsidLength) { ++ uint remainder_ielen; ++ u8 *remainder_ie; ++ remainder_ie = ssid_ie+2; ++ remainder_ielen = (pframe-remainder_ie); ++ ++ if (remainder_ielen > MAX_IE_SZ) { ++ DBG_871X_LEVEL(_drv_warning_, FUNC_ADPT_FMT" remainder_ielen > MAX_IE_SZ\n", FUNC_ADPT_ARG(padapter)); ++ remainder_ielen = MAX_IE_SZ; ++ } ++ ++ memcpy(buf, remainder_ie, remainder_ielen); ++ memcpy(remainder_ie+ssid_ielen_diff, buf, remainder_ielen); ++ *(ssid_ie+1) = cur_network->Ssid.SsidLength; ++ memcpy(ssid_ie+2, cur_network->Ssid.Ssid, cur_network->Ssid.SsidLength); ++ pframe += ssid_ielen_diff; ++ pktlen += ssid_ielen_diff; ++ } ++ } ++ ++ *pLength = pktlen; ++ ++} ++#endif /* CONFIG_AP_WOWLAN */ ++ ++/* To check if reserved page content is destroyed by beacon beacuse beacon is too large. */ ++/* 2010.06.23. Added by tynli. */ ++void ++CheckFwRsvdPageContent( ++ struct adapter * Adapter ++) ++{ ++} ++ ++static void rtl8723b_set_FwRsvdPage_cmd(struct adapter *padapter, PRSVDPAGE_LOC rsvdpageloc) ++{ ++ u8 u1H2CRsvdPageParm[H2C_RSVDPAGE_LOC_LEN]={0}; ++ ++ DBG_871X("8723BRsvdPageLoc: ProbeRsp =%d PsPoll =%d Null =%d QoSNull =%d BTNull =%d\n", ++ rsvdpageloc->LocProbeRsp, rsvdpageloc->LocPsPoll, ++ rsvdpageloc->LocNullData, rsvdpageloc->LocQosNull, ++ rsvdpageloc->LocBTQosNull); ++ ++ SET_8723B_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1H2CRsvdPageParm, rsvdpageloc->LocProbeRsp); ++ SET_8723B_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1H2CRsvdPageParm, rsvdpageloc->LocPsPoll); ++ SET_8723B_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocNullData); ++ SET_8723B_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocQosNull); ++ SET_8723B_H2CCMD_RSVDPAGE_LOC_BT_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocBTQosNull); ++ ++ RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CRsvdPageParm:", u1H2CRsvdPageParm, H2C_RSVDPAGE_LOC_LEN); ++ FillH2CCmd8723B(padapter, H2C_8723B_RSVD_PAGE, H2C_RSVDPAGE_LOC_LEN, u1H2CRsvdPageParm); ++} ++ ++static void rtl8723b_set_FwAoacRsvdPage_cmd(struct adapter *padapter, PRSVDPAGE_LOC rsvdpageloc) ++{ ++#ifdef CONFIG_WOWLAN ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u8 u1H2CAoacRsvdPageParm[H2C_AOAC_RSVDPAGE_LOC_LEN]={0}; ++ ++ DBG_871X("8723BAOACRsvdPageLoc: RWC =%d ArpRsp =%d NbrAdv =%d GtkRsp =%d GtkInfo =%d ProbeReq =%d NetworkList =%d\n", ++ rsvdpageloc->LocRemoteCtrlInfo, rsvdpageloc->LocArpRsp, ++ rsvdpageloc->LocNbrAdv, rsvdpageloc->LocGTKRsp, ++ rsvdpageloc->LocGTKInfo, rsvdpageloc->LocProbeReq, ++ rsvdpageloc->LocNetList); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ SET_H2CCMD_AOAC_RSVDPAGE_LOC_REMOTE_WAKE_CTRL_INFO(u1H2CAoacRsvdPageParm, rsvdpageloc->LocRemoteCtrlInfo); ++ SET_H2CCMD_AOAC_RSVDPAGE_LOC_ARP_RSP(u1H2CAoacRsvdPageParm, rsvdpageloc->LocArpRsp); ++ /* SET_H2CCMD_AOAC_RSVDPAGE_LOC_NEIGHBOR_ADV(u1H2CAoacRsvdPageParm, rsvdpageloc->LocNbrAdv); */ ++ SET_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_RSP(u1H2CAoacRsvdPageParm, rsvdpageloc->LocGTKRsp); ++ SET_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_INFO(u1H2CAoacRsvdPageParm, rsvdpageloc->LocGTKInfo); ++#ifdef CONFIG_GTK_OL ++ SET_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_EXT_MEM(u1H2CAoacRsvdPageParm, rsvdpageloc->LocGTKEXTMEM); ++#endif /* CONFIG_GTK_OL */ ++ RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CAoacRsvdPageParm:", u1H2CAoacRsvdPageParm, H2C_AOAC_RSVDPAGE_LOC_LEN); ++ FillH2CCmd8723B(padapter, H2C_8723B_AOAC_RSVD_PAGE, H2C_AOAC_RSVDPAGE_LOC_LEN, u1H2CAoacRsvdPageParm); ++ } else { ++#ifdef CONFIG_PNO_SUPPORT ++ if (!pwrpriv->pno_in_resume) { ++ DBG_871X("NLO_INFO =%d\n", rsvdpageloc->LocPNOInfo); ++ memset(&u1H2CAoacRsvdPageParm, 0, sizeof(u1H2CAoacRsvdPageParm)); ++ SET_H2CCMD_AOAC_RSVDPAGE_LOC_NLO_INFO(u1H2CAoacRsvdPageParm, rsvdpageloc->LocPNOInfo); ++ FillH2CCmd8723B(padapter, H2C_AOAC_RSVDPAGE3, H2C_AOAC_RSVDPAGE_LOC_LEN, u1H2CAoacRsvdPageParm); ++ msleep(10); ++ } ++#endif ++ } ++ ++#endif /* CONFIG_WOWLAN */ ++} ++ ++#ifdef CONFIG_AP_WOWLAN ++static void rtl8723b_set_ap_wow_rsvdpage_cmd(struct adapter *padapter, ++ PRSVDPAGE_LOC rsvdpageloc) ++{ ++ u8 header; ++ u8 rsvdparm[H2C_AOAC_RSVDPAGE_LOC_LEN]={0}; ++ ++ header = rtw_read8(padapter, REG_BCNQ_BDNY); ++ ++ DBG_871X("%s: beacon: %d, probeRsp: %d, header:0x%02x\n", __func__, ++ rsvdpageloc->LocApOffloadBCN, ++ rsvdpageloc->LocProbeRsp, ++ header); ++ ++ SET_H2CCMD_AP_WOWLAN_RSVDPAGE_LOC_BCN(rsvdparm, ++ rsvdpageloc->LocApOffloadBCN + header); ++ ++ FillH2CCmd8723B(padapter, H2C_8723B_BCN_RSVDPAGE, ++ H2C_BCN_RSVDPAGE_LEN, rsvdparm); ++ ++ msleep(10); ++ ++ memset(&rsvdparm, 0, sizeof(rsvdparm)); ++ ++ SET_H2CCMD_AP_WOWLAN_RSVDPAGE_LOC_ProbeRsp( ++ rsvdparm, ++ rsvdpageloc->LocProbeRsp + header); ++ ++ FillH2CCmd8723B(padapter, H2C_8723B_PROBERSP_RSVDPAGE, ++ H2C_PROBERSP_RSVDPAGE_LEN, rsvdparm); ++ ++ msleep(10); ++} ++#endif /* CONFIG_AP_WOWLAN */ ++ ++void rtl8723b_set_FwMediaStatusRpt_cmd(struct adapter *padapter, u8 mstatus, u8 macid) ++{ ++ u8 u1H2CMediaStatusRptParm[H2C_MEDIA_STATUS_RPT_LEN]={0}; ++ u8 macid_end = 0; ++ ++ DBG_871X("%s(): mstatus = %d macid =%d\n", __func__, mstatus, macid); ++ ++ SET_8723B_H2CCMD_MSRRPT_PARM_OPMODE(u1H2CMediaStatusRptParm, mstatus); ++ SET_8723B_H2CCMD_MSRRPT_PARM_MACID_IND(u1H2CMediaStatusRptParm, 0); ++ SET_8723B_H2CCMD_MSRRPT_PARM_MACID(u1H2CMediaStatusRptParm, macid); ++ SET_8723B_H2CCMD_MSRRPT_PARM_MACID_END(u1H2CMediaStatusRptParm, macid_end); ++ ++ RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CMediaStatusRptParm:", u1H2CMediaStatusRptParm, H2C_MEDIA_STATUS_RPT_LEN); ++ FillH2CCmd8723B(padapter, H2C_8723B_MEDIA_STATUS_RPT, H2C_MEDIA_STATUS_RPT_LEN, u1H2CMediaStatusRptParm); ++} ++ ++#ifdef CONFIG_WOWLAN ++static void rtl8723b_set_FwKeepAlive_cmd(struct adapter *padapter, u8 benable, u8 pkt_type) ++{ ++ u8 u1H2CKeepAliveParm[H2C_KEEP_ALIVE_CTRL_LEN]={0}; ++ u8 adopt = 1, check_period = 5; ++ ++ DBG_871X("%s(): benable = %d\n", __func__, benable); ++ SET_8723B_H2CCMD_KEEPALIVE_PARM_ENABLE(u1H2CKeepAliveParm, benable); ++ SET_8723B_H2CCMD_KEEPALIVE_PARM_ADOPT(u1H2CKeepAliveParm, adopt); ++ SET_8723B_H2CCMD_KEEPALIVE_PARM_PKT_TYPE(u1H2CKeepAliveParm, pkt_type); ++ SET_8723B_H2CCMD_KEEPALIVE_PARM_CHECK_PERIOD(u1H2CKeepAliveParm, check_period); ++ ++ RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CKeepAliveParm:", u1H2CKeepAliveParm, H2C_KEEP_ALIVE_CTRL_LEN); ++ ++ FillH2CCmd8723B(padapter, H2C_8723B_KEEP_ALIVE, H2C_KEEP_ALIVE_CTRL_LEN, u1H2CKeepAliveParm); ++} ++ ++static void rtl8723b_set_FwDisconDecision_cmd(struct adapter *padapter, u8 benable) ++{ ++ u8 u1H2CDisconDecisionParm[H2C_DISCON_DECISION_LEN]={0}; ++ u8 adopt = 1, check_period = 10, trypkt_num = 0; ++ ++ DBG_871X("%s(): benable = %d\n", __func__, benable); ++ SET_8723B_H2CCMD_DISCONDECISION_PARM_ENABLE(u1H2CDisconDecisionParm, benable); ++ SET_8723B_H2CCMD_DISCONDECISION_PARM_ADOPT(u1H2CDisconDecisionParm, adopt); ++ SET_8723B_H2CCMD_DISCONDECISION_PARM_CHECK_PERIOD(u1H2CDisconDecisionParm, check_period); ++ SET_8723B_H2CCMD_DISCONDECISION_PARM_TRY_PKT_NUM(u1H2CDisconDecisionParm, trypkt_num); ++ ++ RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CDisconDecisionParm:", u1H2CDisconDecisionParm, H2C_DISCON_DECISION_LEN); ++ ++ FillH2CCmd8723B(padapter, H2C_8723B_DISCON_DECISION, H2C_DISCON_DECISION_LEN, u1H2CDisconDecisionParm); ++} ++#endif /* CONFIG_WOWLAN */ ++ ++void rtl8723b_set_FwMacIdConfig_cmd(struct adapter *padapter, u8 mac_id, u8 raid, u8 bw, u8 sgi, u32 mask) ++{ ++ u8 u1H2CMacIdConfigParm[H2C_MACID_CFG_LEN]={0}; ++ ++ DBG_871X("%s(): mac_id =%d raid = 0x%x bw =%d mask = 0x%x\n", __func__, mac_id, raid, bw, mask); ++ ++ SET_8723B_H2CCMD_MACID_CFG_MACID(u1H2CMacIdConfigParm, mac_id); ++ SET_8723B_H2CCMD_MACID_CFG_RAID(u1H2CMacIdConfigParm, raid); ++ SET_8723B_H2CCMD_MACID_CFG_SGI_EN(u1H2CMacIdConfigParm, (sgi)? 1:0); ++ SET_8723B_H2CCMD_MACID_CFG_BW(u1H2CMacIdConfigParm, bw); ++ SET_8723B_H2CCMD_MACID_CFG_RATE_MASK0(u1H2CMacIdConfigParm, (u8)(mask & 0x000000ff)); ++ SET_8723B_H2CCMD_MACID_CFG_RATE_MASK1(u1H2CMacIdConfigParm, (u8)((mask & 0x0000ff00) >>8)); ++ SET_8723B_H2CCMD_MACID_CFG_RATE_MASK2(u1H2CMacIdConfigParm, (u8)((mask & 0x00ff0000) >> 16)); ++ SET_8723B_H2CCMD_MACID_CFG_RATE_MASK3(u1H2CMacIdConfigParm, (u8)((mask & 0xff000000) >> 24)); ++ ++ RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CMacIdConfigParm:", u1H2CMacIdConfigParm, H2C_MACID_CFG_LEN); ++ FillH2CCmd8723B(padapter, H2C_8723B_MACID_CFG, H2C_MACID_CFG_LEN, u1H2CMacIdConfigParm); ++} ++ ++static void rtl8723b_set_FwRssiSetting_cmd(struct adapter *padapter, u8 *param) ++{ ++ u8 u1H2CRssiSettingParm[H2C_RSSI_SETTING_LEN]={0}; ++ u8 mac_id = *param; ++ u8 rssi = *(param+2); ++ u8 uldl_state = 0; ++ ++ /* DBG_871X("%s(): param =%.2x-%.2x-%.2x\n", __func__, *param, *(param+1), *(param+2)); */ ++ /* DBG_871X("%s(): mac_id =%d rssi =%d\n", __func__, mac_id, rssi); */ ++ ++ SET_8723B_H2CCMD_RSSI_SETTING_MACID(u1H2CRssiSettingParm, mac_id); ++ SET_8723B_H2CCMD_RSSI_SETTING_RSSI(u1H2CRssiSettingParm, rssi); ++ SET_8723B_H2CCMD_RSSI_SETTING_ULDL_STATE(u1H2CRssiSettingParm, uldl_state); ++ ++ RT_PRINT_DATA(_module_hal_init_c_, _drv_notice_, "u1H2CRssiSettingParm:", u1H2CRssiSettingParm, H2C_RSSI_SETTING_LEN); ++ FillH2CCmd8723B(padapter, H2C_8723B_RSSI_SETTING, H2C_RSSI_SETTING_LEN, u1H2CRssiSettingParm); ++} ++ ++void rtl8723b_set_FwPwrMode_cmd(struct adapter *padapter, u8 psmode) ++{ ++ int i; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ u8 u1H2CPwrModeParm[H2C_PWRMODE_LEN]={0}; ++ u8 PowerState = 0, awake_intvl = 1, byte5 = 0, rlbm = 0; ++ ++ if (pwrpriv->dtim > 0) ++ DBG_871X("%s(): FW LPS mode = %d, SmartPS =%d, dtim =%d\n", __func__, psmode, pwrpriv->smart_ps, pwrpriv->dtim); ++ else ++ DBG_871X("%s(): FW LPS mode = %d, SmartPS =%d\n", __func__, psmode, pwrpriv->smart_ps); ++ ++#ifdef CONFIG_WOWLAN ++ if (psmode == PS_MODE_DTIM) /* For WOWLAN LPS, DTIM = (awake_intvl - 1) */ ++ { ++ awake_intvl = 3;/* DTIM =2 */ ++ rlbm = 2; ++ } ++ else ++#endif /* CONFIG_WOWLAN */ ++ { ++ if (pwrpriv->dtim > 0 && pwrpriv->dtim < 16) ++ awake_intvl = pwrpriv->dtim+1;/* DTIM = (awake_intvl - 1) */ ++ else ++ awake_intvl = 3;/* DTIM =2 */ ++ ++ rlbm = 2; ++ } ++ ++ ++ if (padapter->registrypriv.wifi_spec == 1) ++ { ++ awake_intvl = 2; ++ rlbm = 2; ++ } ++ ++ if (psmode > 0) ++ { ++ if (rtw_btcoex_IsBtControlLps(padapter) == true) ++ { ++ PowerState = rtw_btcoex_RpwmVal(padapter); ++ byte5 = rtw_btcoex_LpsVal(padapter); ++ ++ if ((rlbm == 2) && (byte5 & BIT(4))) ++ { ++ /* Keep awake interval to 1 to prevent from */ ++ /* decreasing coex performance */ ++ awake_intvl = 2; ++ rlbm = 2; ++ } ++ } ++ else ++ { ++ PowerState = 0x00;/* AllON(0x0C), RFON(0x04), RFOFF(0x00) */ ++ byte5 = 0x40; ++ } ++ } ++ else ++ { ++ PowerState = 0x0C;/* AllON(0x0C), RFON(0x04), RFOFF(0x00) */ ++ byte5 = 0x40; ++ } ++ ++ SET_8723B_H2CCMD_PWRMODE_PARM_MODE(u1H2CPwrModeParm, (psmode>0)?1:0); ++ SET_8723B_H2CCMD_PWRMODE_PARM_SMART_PS(u1H2CPwrModeParm, pwrpriv->smart_ps); ++ SET_8723B_H2CCMD_PWRMODE_PARM_RLBM(u1H2CPwrModeParm, rlbm); ++ SET_8723B_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1H2CPwrModeParm, awake_intvl); ++ SET_8723B_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1H2CPwrModeParm, padapter->registrypriv.uapsd_enable); ++ SET_8723B_H2CCMD_PWRMODE_PARM_PWR_STATE(u1H2CPwrModeParm, PowerState); ++ SET_8723B_H2CCMD_PWRMODE_PARM_BYTE5(u1H2CPwrModeParm, byte5); ++ if (psmode != PS_MODE_ACTIVE) ++ { ++ if (pmlmeext ->adaptive_tsf_done == false && pmlmeext->bcn_cnt>0) ++ { ++ u8 ratio_20_delay, ratio_80_delay; ++ ++ /* byte 6 for adaptive_early_32k */ ++ /* 0:3] = DrvBcnEarly (ms) , [4:7] = DrvBcnTimeOut (ms) */ ++ /* 20% for DrvBcnEarly, 80% for DrvBcnTimeOut */ ++ ratio_20_delay = 0; ++ ratio_80_delay = 0; ++ pmlmeext->DrvBcnEarly = 0xff; ++ pmlmeext->DrvBcnTimeOut = 0xff; ++ ++ DBG_871X("%s(): bcn_cnt = %d\n", __func__, pmlmeext->bcn_cnt); ++ ++ for (i = 0; i<9; i++) ++ { ++ pmlmeext->bcn_delay_ratio[i] = (pmlmeext->bcn_delay_cnt[i] * 100) /pmlmeext->bcn_cnt; ++ ++ DBG_871X("%s(): bcn_delay_cnt[%d]=%d, bcn_delay_ratio[%d] = %d\n", __func__, i, pmlmeext->bcn_delay_cnt[i] ++ , i , pmlmeext->bcn_delay_ratio[i]); ++ ++ ratio_20_delay += pmlmeext->bcn_delay_ratio[i]; ++ ratio_80_delay += pmlmeext->bcn_delay_ratio[i]; ++ ++ if (ratio_20_delay > 20 && pmlmeext->DrvBcnEarly == 0xff) ++ { ++ pmlmeext->DrvBcnEarly = i; ++ DBG_871X("%s(): DrvBcnEarly = %d\n", __func__, pmlmeext->DrvBcnEarly); ++ } ++ ++ if (ratio_80_delay > 80 && pmlmeext->DrvBcnTimeOut == 0xff) ++ { ++ pmlmeext->DrvBcnTimeOut = i; ++ DBG_871X("%s(): DrvBcnTimeOut = %d\n", __func__, pmlmeext->DrvBcnTimeOut); ++ } ++ ++ /* reset adaptive_early_32k cnt */ ++ pmlmeext->bcn_delay_cnt[i] = 0; ++ pmlmeext->bcn_delay_ratio[i] = 0; ++ ++ } ++ ++ pmlmeext->bcn_cnt = 0; ++ pmlmeext ->adaptive_tsf_done = true; ++ ++ } ++ else ++ { ++ DBG_871X("%s(): DrvBcnEarly = %d\n", __func__, pmlmeext->DrvBcnEarly); ++ DBG_871X("%s(): DrvBcnTimeOut = %d\n", __func__, pmlmeext->DrvBcnTimeOut); ++ } ++ ++/* offload to FW if fw version > v15.10 ++ pmlmeext->DrvBcnEarly = 0; ++ pmlmeext->DrvBcnTimeOut =7; ++ ++ if ((pmlmeext->DrvBcnEarly!= 0Xff) && (pmlmeext->DrvBcnTimeOut!= 0xff)) ++ u1H2CPwrModeParm[H2C_PWRMODE_LEN-1] = BIT(0) | ((pmlmeext->DrvBcnEarly<<1)&0x0E) |((pmlmeext->DrvBcnTimeOut<<4)&0xf0) ; ++*/ ++ ++ } ++ ++ rtw_btcoex_RecordPwrMode(padapter, u1H2CPwrModeParm, H2C_PWRMODE_LEN); ++ ++ RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CPwrModeParm:", u1H2CPwrModeParm, H2C_PWRMODE_LEN); ++ ++ FillH2CCmd8723B(padapter, H2C_8723B_SET_PWR_MODE, H2C_PWRMODE_LEN, u1H2CPwrModeParm); ++} ++ ++void rtl8723b_set_FwPsTuneParam_cmd(struct adapter *padapter) ++{ ++ u8 u1H2CPsTuneParm[H2C_PSTUNEPARAM_LEN]={0}; ++ u8 bcn_to_limit = 10; /* 10 * 100 * awakeinterval (ms) */ ++ u8 dtim_timeout = 5; /* ms wait broadcast data timer */ ++ u8 ps_timeout = 20; /* ms Keep awake when tx */ ++ u8 dtim_period = 3; ++ ++ /* DBG_871X("%s(): FW LPS mode = %d\n", __func__, psmode); */ ++ ++ SET_8723B_H2CCMD_PSTUNE_PARM_BCN_TO_LIMIT(u1H2CPsTuneParm, bcn_to_limit); ++ SET_8723B_H2CCMD_PSTUNE_PARM_DTIM_TIMEOUT(u1H2CPsTuneParm, dtim_timeout); ++ SET_8723B_H2CCMD_PSTUNE_PARM_PS_TIMEOUT(u1H2CPsTuneParm, ps_timeout); ++ SET_8723B_H2CCMD_PSTUNE_PARM_ADOPT(u1H2CPsTuneParm, 1); ++ SET_8723B_H2CCMD_PSTUNE_PARM_DTIM_PERIOD(u1H2CPsTuneParm, dtim_period); ++ ++ RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CPsTuneParm:", u1H2CPsTuneParm, H2C_PSTUNEPARAM_LEN); ++ ++ FillH2CCmd8723B(padapter, H2C_8723B_PS_TUNING_PARA, H2C_PSTUNEPARAM_LEN, u1H2CPsTuneParm); ++} ++ ++void rtl8723b_set_FwPwrModeInIPS_cmd(struct adapter *padapter, u8 cmd_param) ++{ ++ /* BIT0:enable, BIT1:NoConnect32k */ ++ ++ DBG_871X("%s()\n", __func__); ++ ++ FillH2CCmd8723B(padapter, H2C_8723B_FWLPS_IN_IPS_, 1, &cmd_param); ++} ++ ++#ifdef CONFIG_WOWLAN ++static void rtl8723b_set_FwWoWlanCtrl_Cmd(struct adapter *padapter, u8 bFuncEn) ++{ ++ struct security_priv *psecpriv = &padapter->securitypriv; ++ u8 u1H2CWoWlanCtrlParm[H2C_WOWLAN_LEN]={0}; ++ u8 discont_wake = 1, gpionum = 0, gpio_dur = 0, hw_unicast = 0; ++ u8 sdio_wakeup_enable = 1; ++ u8 gpio_high_active = 0; /* 0: low active, 1: high active */ ++ u8 magic_pkt = 0; ++ ++#ifdef CONFIG_GPIO_WAKEUP ++ gpionum = WAKEUP_GPIO_IDX; ++ sdio_wakeup_enable = 0; ++#endif ++ ++#ifdef CONFIG_PNO_SUPPORT ++ if (!ppwrpriv->wowlan_pno_enable) { ++ magic_pkt = 1; ++ } ++#endif ++ ++ if (psecpriv->dot11PrivacyAlgrthm == _WEP40_ || psecpriv->dot11PrivacyAlgrthm == _WEP104_) ++ hw_unicast = 1; ++ ++ DBG_871X("%s(): bFuncEn =%d\n", __func__, bFuncEn); ++ ++ SET_H2CCMD_WOWLAN_FUNC_ENABLE(u1H2CWoWlanCtrlParm, bFuncEn); ++ SET_H2CCMD_WOWLAN_PATTERN_MATCH_ENABLE(u1H2CWoWlanCtrlParm, 0); ++ SET_H2CCMD_WOWLAN_MAGIC_PKT_ENABLE(u1H2CWoWlanCtrlParm, magic_pkt); ++ SET_H2CCMD_WOWLAN_UNICAST_PKT_ENABLE(u1H2CWoWlanCtrlParm, hw_unicast); ++ SET_H2CCMD_WOWLAN_ALL_PKT_DROP(u1H2CWoWlanCtrlParm, 0); ++ SET_H2CCMD_WOWLAN_GPIO_ACTIVE(u1H2CWoWlanCtrlParm, gpio_high_active); ++ SET_H2CCMD_WOWLAN_DISCONNECT_WAKE_UP(u1H2CWoWlanCtrlParm, discont_wake); ++ SET_H2CCMD_WOWLAN_GPIONUM(u1H2CWoWlanCtrlParm, gpionum); ++ SET_H2CCMD_WOWLAN_DATAPIN_WAKE_UP(u1H2CWoWlanCtrlParm, sdio_wakeup_enable); ++ SET_H2CCMD_WOWLAN_GPIO_DURATION(u1H2CWoWlanCtrlParm, gpio_dur); ++ /* SET_H2CCMD_WOWLAN_GPIO_PULSE_EN(u1H2CWoWlanCtrlParm, 1); */ ++ SET_H2CCMD_WOWLAN_GPIO_PULSE_COUNT(u1H2CWoWlanCtrlParm, 0x09); ++ ++ RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CWoWlanCtrlParm:", u1H2CWoWlanCtrlParm, H2C_WOWLAN_LEN); ++ ++ FillH2CCmd8723B(padapter, H2C_8723B_WOWLAN, H2C_WOWLAN_LEN, u1H2CWoWlanCtrlParm); ++} ++ ++static void rtl8723b_set_FwRemoteWakeCtrl_Cmd(struct adapter *padapter, u8 benable) ++{ ++ u8 u1H2CRemoteWakeCtrlParm[H2C_REMOTE_WAKE_CTRL_LEN]={0}; ++ struct security_priv* psecuritypriv =&(padapter->securitypriv); ++ struct pwrctrl_priv *ppwrpriv = adapter_to_pwrctl(padapter); ++ ++ DBG_871X("%s(): Enable =%d\n", __func__, benable); ++ ++ if (!ppwrpriv->wowlan_pno_enable) { ++ SET_H2CCMD_REMOTE_WAKECTRL_ENABLE(u1H2CRemoteWakeCtrlParm, benable); ++ SET_H2CCMD_REMOTE_WAKE_CTRL_ARP_OFFLOAD_EN(u1H2CRemoteWakeCtrlParm, 1); ++#ifdef CONFIG_GTK_OL ++ if (psecuritypriv->binstallKCK_KEK && ++ psecuritypriv->dot11PrivacyAlgrthm == _AES_) { ++ SET_H2CCMD_REMOTE_WAKE_CTRL_GTK_OFFLOAD_EN(u1H2CRemoteWakeCtrlParm, 1); ++ } else { ++ DBG_871X("no kck or security is not AES\n"); ++ SET_H2CCMD_REMOTE_WAKE_CTRL_GTK_OFFLOAD_EN(u1H2CRemoteWakeCtrlParm, 0); ++ } ++#endif /* CONFIG_GTK_OL */ ++ ++ SET_H2CCMD_REMOTE_WAKE_CTRL_FW_UNICAST_EN(u1H2CRemoteWakeCtrlParm, 1); ++ ++ if ((psecuritypriv->dot11PrivacyAlgrthm == _AES_) || ++ (psecuritypriv->dot11PrivacyAlgrthm == _NO_PRIVACY_)) ++ SET_H2CCMD_REMOTE_WAKE_CTRL_ARP_ACTION(u1H2CRemoteWakeCtrlParm, 0); ++ else ++ SET_H2CCMD_REMOTE_WAKE_CTRL_ARP_ACTION(u1H2CRemoteWakeCtrlParm, 1); ++ } ++#ifdef CONFIG_PNO_SUPPORT ++ else { ++ SET_H2CCMD_REMOTE_WAKECTRL_ENABLE(u1H2CRemoteWakeCtrlParm, benable); ++ SET_H2CCMD_REMOTE_WAKE_CTRL_NLO_OFFLOAD_EN(u1H2CRemoteWakeCtrlParm, benable); ++ } ++#endif ++ RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CRemoteWakeCtrlParm:", u1H2CRemoteWakeCtrlParm, H2C_REMOTE_WAKE_CTRL_LEN); ++ FillH2CCmd8723B(padapter, H2C_8723B_REMOTE_WAKE_CTRL, ++ H2C_REMOTE_WAKE_CTRL_LEN, u1H2CRemoteWakeCtrlParm); ++#ifdef CONFIG_PNO_SUPPORT ++ if (ppwrpriv->wowlan_pno_enable && ppwrpriv->pno_in_resume == false) { ++ res = rtw_read8(padapter, REG_PNO_STATUS); ++ DBG_871X("cmd: 0x81 REG_PNO_STATUS: 0x%02x\n", res); ++ while (!(res&BIT(7)) && count < 25) { ++ DBG_871X("[%d] cmd: 0x81 REG_PNO_STATUS: 0x%02x\n", count, res); ++ res = rtw_read8(padapter, REG_PNO_STATUS); ++ count++; ++ msleep(2); ++ } ++ DBG_871X("cmd: 0x81 REG_PNO_STATUS: 0x%02x\n", res); ++ } ++#endif /* CONFIG_PNO_SUPPORT */ ++} ++ ++static void rtl8723b_set_FwAOACGlobalInfo_Cmd(struct adapter *padapter, u8 group_alg, u8 pairwise_alg) ++{ ++ u8 u1H2CAOACGlobalInfoParm[H2C_AOAC_GLOBAL_INFO_LEN]={0}; ++ ++ DBG_871X("%s(): group_alg =%d pairwise_alg =%d\n", __func__, group_alg, pairwise_alg); ++ ++ SET_H2CCMD_AOAC_GLOBAL_INFO_PAIRWISE_ENC_ALG(u1H2CAOACGlobalInfoParm, pairwise_alg); ++ SET_H2CCMD_AOAC_GLOBAL_INFO_GROUP_ENC_ALG(u1H2CAOACGlobalInfoParm, group_alg); ++ ++ RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CAOACGlobalInfoParm:", u1H2CAOACGlobalInfoParm, H2C_AOAC_GLOBAL_INFO_LEN); ++ ++ FillH2CCmd8723B(padapter, H2C_8723B_AOAC_GLOBAL_INFO, H2C_AOAC_GLOBAL_INFO_LEN, u1H2CAOACGlobalInfoParm); ++} ++ ++#ifdef CONFIG_PNO_SUPPORT ++static void rtl8723b_set_FwScanOffloadInfo_cmd(struct adapter *padapter, PRSVDPAGE_LOC rsvdpageloc, u8 enable) ++{ ++ u8 u1H2CScanOffloadInfoParm[H2C_SCAN_OFFLOAD_CTRL_LEN]={0}; ++ u8 res = 0, count = 0; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ ++ DBG_871X("%s: loc_probe_packet:%d, loc_scan_info: %d loc_ssid_info:%d\n", ++ __func__, rsvdpageloc->LocProbePacket, rsvdpageloc->LocScanInfo, rsvdpageloc->LocSSIDInfo); ++ ++ SET_H2CCMD_AOAC_NLO_FUN_EN(u1H2CScanOffloadInfoParm, enable); ++ SET_H2CCMD_AOAC_RSVDPAGE_LOC_SCAN_INFO(u1H2CScanOffloadInfoParm, rsvdpageloc->LocScanInfo); ++ SET_H2CCMD_AOAC_RSVDPAGE_LOC_PROBE_PACKET(u1H2CScanOffloadInfoParm, rsvdpageloc->LocProbePacket); ++ SET_H2CCMD_AOAC_RSVDPAGE_LOC_SSID_INFO(u1H2CScanOffloadInfoParm, rsvdpageloc->LocSSIDInfo); ++ ++ RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CScanOffloadInfoParm:", u1H2CScanOffloadInfoParm, H2C_SCAN_OFFLOAD_CTRL_LEN); ++ FillH2CCmd8723B(padapter, H2C_8723B_D0_SCAN_OFFLOAD_INFO, H2C_SCAN_OFFLOAD_CTRL_LEN, u1H2CScanOffloadInfoParm); ++ ++ msleep(20); ++} ++#endif /* CONFIG_PNO_SUPPORT */ ++ ++static void rtl8723b_set_FwWoWlanRelated_cmd(struct adapter *padapter, u8 enable) ++{ ++ struct security_priv *psecpriv = &padapter->securitypriv; ++ struct pwrctrl_priv *ppwrpriv = adapter_to_pwrctl(padapter); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct sta_info *psta = NULL; ++ u8 pkt_type = 0; ++ ++ DBG_871X_LEVEL(_drv_always_, "+%s()+: enable =%d\n", __func__, enable); ++ if (enable) { ++ rtl8723b_set_FwAOACGlobalInfo_Cmd(padapter, psecpriv->dot118021XGrpPrivacy, psecpriv->dot11PrivacyAlgrthm); ++ ++ rtl8723b_set_FwJoinBssRpt_cmd(padapter, RT_MEDIA_CONNECT); /* RT_MEDIA_CONNECT will confuse in the future */ ++ ++ if (!(ppwrpriv->wowlan_pno_enable)) ++ { ++ psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(pmlmepriv)); ++ if (psta != NULL) ++ rtl8723b_set_FwMediaStatusRpt_cmd(padapter, RT_MEDIA_CONNECT, psta->mac_id); ++ } ++ else ++ DBG_871X("%s(): Disconnected, no FwMediaStatusRpt CONNECT\n", __func__); ++ ++ msleep(2); ++ ++ if (!(ppwrpriv->wowlan_pno_enable)) { ++ rtl8723b_set_FwDisconDecision_cmd(padapter, enable); ++ msleep(2); ++ ++ if ((psecpriv->dot11PrivacyAlgrthm != _WEP40_) || (psecpriv->dot11PrivacyAlgrthm != _WEP104_)) ++ pkt_type = 1; ++ rtl8723b_set_FwKeepAlive_cmd(padapter, enable, pkt_type); ++ msleep(2); ++ } ++ ++ rtl8723b_set_FwWoWlanCtrl_Cmd(padapter, enable); ++ msleep(2); ++ ++ rtl8723b_set_FwRemoteWakeCtrl_Cmd(padapter, enable); ++ } ++ else ++ { ++ rtl8723b_set_FwRemoteWakeCtrl_Cmd(padapter, enable); ++ msleep(2); ++ rtl8723b_set_FwWoWlanCtrl_Cmd(padapter, enable); ++ } ++ ++ DBG_871X_LEVEL(_drv_always_, "-%s()-\n", __func__); ++ return ; ++} ++ ++void rtl8723b_set_wowlan_cmd(struct adapter *padapter, u8 enable) ++{ ++ rtl8723b_set_FwWoWlanRelated_cmd(padapter, enable); ++} ++#endif /* CONFIG_WOWLAN */ ++ ++#ifdef CONFIG_AP_WOWLAN ++static void rtl8723b_set_FwAPWoWlanCtrl_Cmd(struct adapter *padapter, u8 bFuncEn) ++{ ++ u8 u1H2CAPWoWlanCtrlParm[H2C_WOWLAN_LEN]={0}; ++ u8 gpionum = 0, gpio_dur = 0; ++ u8 gpio_high_active = 1; /* 0: low active, 1: high active */ ++ u8 gpio_pulse = bFuncEn; ++#ifdef CONFIG_GPIO_WAKEUP ++ gpionum = WAKEUP_GPIO_IDX; ++#endif ++ ++ DBG_871X("%s(): bFuncEn =%d\n", __func__, bFuncEn); ++ ++ if (bFuncEn) ++ gpio_dur = 16; ++ else ++ gpio_dur = 0; ++ ++ SET_H2CCMD_AP_WOW_GPIO_CTRL_INDEX(u1H2CAPWoWlanCtrlParm, ++ gpionum); ++ SET_H2CCMD_AP_WOW_GPIO_CTRL_PLUS(u1H2CAPWoWlanCtrlParm, ++ gpio_pulse); ++ SET_H2CCMD_AP_WOW_GPIO_CTRL_HIGH_ACTIVE(u1H2CAPWoWlanCtrlParm, ++ gpio_high_active); ++ SET_H2CCMD_AP_WOW_GPIO_CTRL_EN(u1H2CAPWoWlanCtrlParm, ++ bFuncEn); ++ SET_H2CCMD_AP_WOW_GPIO_CTRL_DURATION(u1H2CAPWoWlanCtrlParm, ++ gpio_dur); ++ ++ FillH2CCmd8723B(padapter, H2C_8723B_AP_WOW_GPIO_CTRL, ++ H2C_AP_WOW_GPIO_CTRL_LEN, u1H2CAPWoWlanCtrlParm); ++} ++ ++static void rtl8723b_set_Fw_AP_Offload_Cmd(struct adapter *padapter, u8 bFuncEn) ++{ ++ u8 u1H2CAPOffloadCtrlParm[H2C_WOWLAN_LEN]={0}; ++ ++ DBG_871X("%s(): bFuncEn =%d\n", __func__, bFuncEn); ++ ++ SET_H2CCMD_AP_WOWLAN_EN(u1H2CAPOffloadCtrlParm, bFuncEn); ++ ++ FillH2CCmd8723B(padapter, H2C_8723B_AP_OFFLOAD, ++ H2C_AP_OFFLOAD_LEN, u1H2CAPOffloadCtrlParm); ++} ++ ++static void rtl8723b_set_AP_FwWoWlan_cmd(struct adapter *padapter, u8 enable) ++{ ++ DBG_871X_LEVEL(_drv_always_, "+%s()+: enable =%d\n", __func__, enable); ++ if (enable) { ++ rtl8723b_set_FwJoinBssRpt_cmd(padapter, RT_MEDIA_CONNECT); ++ issue_beacon(padapter, 0); ++ } ++ ++ rtl8723b_set_FwAPWoWlanCtrl_Cmd(padapter, enable); ++ msleep(10); ++ rtl8723b_set_Fw_AP_Offload_Cmd(padapter, enable); ++ msleep(10); ++ DBG_871X_LEVEL(_drv_always_, "-%s()-\n", __func__); ++ return ; ++} ++ ++void rtl8723b_set_ap_wowlan_cmd(struct adapter *padapter, u8 enable) ++{ ++ rtl8723b_set_AP_FwWoWlan_cmd(padapter, enable); ++} ++#endif /* CONFIG_AP_WOWLAN */ ++ ++/* */ ++/* Description: Fill the reserved packets that FW will use to RSVD page. */ ++/* Now we just send 4 types packet to rsvd page. */ ++/* (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp. */ ++/* Input: */ ++/* bDLFinished - false: At the first time we will send all the packets as a large packet to Hw, */ ++/* so we need to set the packet length to total lengh. */ ++/* true: At the second time, we should send the first packet (default:beacon) */ ++/* to Hw again and set the lengh in descriptor to the real beacon lengh. */ ++/* 2009.10.15 by tynli. */ ++static void rtl8723b_set_FwRsvdPagePkt(struct adapter *padapter, bool bDLFinished) ++{ ++ struct hal_com_data *pHalData; ++ struct xmit_frame *pcmdframe; ++ struct pkt_attrib *pattrib; ++ struct xmit_priv *pxmitpriv; ++ struct mlme_ext_priv *pmlmeext; ++ struct mlme_ext_info *pmlmeinfo; ++ struct pwrctrl_priv *pwrctl; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u32 BeaconLength = 0, PSPollLength = 0; ++ u32 NullDataLength = 0, QosNullLength = 0, BTQosNullLength = 0; ++ u8 *ReservedPagePacket; ++ u8 TxDescLen = TXDESC_SIZE, TxDescOffset = TXDESC_OFFSET; ++ u8 TotalPageNum = 0, CurtPktPageNum = 0, RsvdPageNum = 0; ++ u16 BufIndex, PageSize = 128; ++ u32 TotalPacketLen, MaxRsvdPageBufSize = 0; ++ RSVDPAGE_LOC RsvdPageLoc; ++#ifdef CONFIG_WOWLAN ++ u32 ARPLegnth = 0, GTKLegnth = 0; ++ u8 currentip[4]; ++ u8 cur_dot11txpn[8]; ++#ifdef CONFIG_GTK_OL ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info * psta; ++ u8 kek[RTW_KEK_LEN]; ++ u8 kck[RTW_KCK_LEN]; ++#endif ++#endif ++ ++ /* DBG_871X("%s---->\n", __func__); */ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ pxmitpriv = &padapter->xmitpriv; ++ pmlmeext = &padapter->mlmeextpriv; ++ pmlmeinfo = &pmlmeext->mlmext_info; ++ pwrctl = adapter_to_pwrctl(padapter); ++ ++ RsvdPageNum = BCNQ_PAGE_NUM_8723B + WOWLAN_PAGE_NUM_8723B; ++ MaxRsvdPageBufSize = RsvdPageNum*PageSize; ++ ++ pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv); ++ if (pcmdframe == NULL) { ++ DBG_871X("%s: alloc ReservedPagePacket fail!\n", __func__); ++ return; ++ } ++ ++ ReservedPagePacket = pcmdframe->buf_addr; ++ memset(&RsvdPageLoc, 0, sizeof(RSVDPAGE_LOC)); ++ ++ /* 3 (1) beacon */ ++ BufIndex = TxDescOffset; ++ ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength); ++ ++ /* When we count the first page size, we need to reserve description size for the RSVD */ ++ /* packet, it will be filled in front of the packet in TXPKTBUF. */ ++ CurtPktPageNum = (u8)PageNum_128(TxDescLen + BeaconLength); ++ /* If we don't add 1 more page, the WOWLAN function has a problem. Baron thinks it's a bug of firmware */ ++ if (CurtPktPageNum == 1) ++ { ++ CurtPktPageNum += 1; ++ } ++ TotalPageNum += CurtPktPageNum; ++ ++ BufIndex += (CurtPktPageNum*PageSize); ++ ++ /* 3 (2) ps-poll */ ++ RsvdPageLoc.LocPsPoll = TotalPageNum; ++ ConstructPSPoll(padapter, &ReservedPagePacket[BufIndex], &PSPollLength); ++ rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, true, false, false); ++ ++ /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: PS-POLL %p %d\n", */ ++ /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], (PSPollLength+TxDescLen)); */ ++ ++ CurtPktPageNum = (u8)PageNum_128(TxDescLen + PSPollLength); ++ ++ TotalPageNum += CurtPktPageNum; ++ ++ BufIndex += (CurtPktPageNum*PageSize); ++ ++ /* 3 (3) null data */ ++ RsvdPageLoc.LocNullData = TotalPageNum; ++ ConstructNullFunctionData( ++ padapter, ++ &ReservedPagePacket[BufIndex], ++ &NullDataLength, ++ get_my_bssid(&pmlmeinfo->network), ++ false, 0, 0, false); ++ rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false, false); ++ ++ /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: NULL DATA %p %d\n", */ ++ /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], (NullDataLength+TxDescLen)); */ ++ ++ CurtPktPageNum = (u8)PageNum_128(TxDescLen + NullDataLength); ++ ++ TotalPageNum += CurtPktPageNum; ++ ++ BufIndex += (CurtPktPageNum*PageSize); ++ ++ /* 3 (5) Qos null data */ ++ RsvdPageLoc.LocQosNull = TotalPageNum; ++ ConstructNullFunctionData( ++ padapter, ++ &ReservedPagePacket[BufIndex], ++ &QosNullLength, ++ get_my_bssid(&pmlmeinfo->network), ++ true, 0, 0, false); ++ rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false, false); ++ ++ /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: QOS NULL DATA %p %d\n", */ ++ /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], (QosNullLength+TxDescLen)); */ ++ ++ CurtPktPageNum = (u8)PageNum_128(TxDescLen + QosNullLength); ++ ++ TotalPageNum += CurtPktPageNum; ++ ++ BufIndex += (CurtPktPageNum*PageSize); ++ ++ /* 3 (6) BT Qos null data */ ++ RsvdPageLoc.LocBTQosNull = TotalPageNum; ++ ConstructNullFunctionData( ++ padapter, ++ &ReservedPagePacket[BufIndex], ++ &BTQosNullLength, ++ get_my_bssid(&pmlmeinfo->network), ++ true, 0, 0, false); ++ rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true, false); ++ ++ /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: BT QOS NULL DATA %p %d\n", */ ++ /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], (BTQosNullLength+TxDescLen)); */ ++ ++ CurtPktPageNum = (u8)PageNum_128(TxDescLen + BTQosNullLength); ++ ++ TotalPageNum += CurtPktPageNum; ++ ++ BufIndex += (CurtPktPageNum*PageSize); ++ ++#ifdef CONFIG_WOWLAN ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ /* if (pwrctl->wowlan_mode == true) { */ ++ /* BufIndex += (CurtPktPageNum*PageSize); */ ++ ++ /* 3(7) ARP RSP */ ++ rtw_get_current_ip_address(padapter, currentip); ++ RsvdPageLoc.LocArpRsp = TotalPageNum; ++ { ++ ConstructARPResponse( ++ padapter, ++ &ReservedPagePacket[BufIndex], ++ &ARPLegnth, ++ currentip ++ ); ++ rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], ARPLegnth, false, false, true); ++ ++ /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: ARP RSP %p %d\n", */ ++ /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], (ARPLegnth+TxDescLen)); */ ++ ++ CurtPktPageNum = (u8)PageNum_128(TxDescLen + ARPLegnth); ++ } ++ TotalPageNum += CurtPktPageNum; ++ ++ BufIndex += (CurtPktPageNum*PageSize); ++ ++ /* 3(8) SEC IV */ ++ rtw_get_sec_iv(padapter, cur_dot11txpn, get_my_bssid(&pmlmeinfo->network)); ++ RsvdPageLoc.LocRemoteCtrlInfo = TotalPageNum; ++ memcpy(ReservedPagePacket+BufIndex-TxDescLen, cur_dot11txpn, _AES_IV_LEN_); ++ ++ /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: SEC IV %p %d\n", */ ++ /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], _AES_IV_LEN_); */ ++ ++ CurtPktPageNum = (u8)PageNum_128(_AES_IV_LEN_); ++ ++ TotalPageNum += CurtPktPageNum; ++ ++#ifdef CONFIG_GTK_OL ++ BufIndex += (CurtPktPageNum*PageSize); ++ ++ /* if the ap staion info. exists, get the kek, kck from staion info. */ ++ psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv)); ++ if (psta == NULL) ++ { ++ memset(kek, 0, RTW_KEK_LEN); ++ memset(kck, 0, RTW_KCK_LEN); ++ DBG_8192C("%s, KEK, KCK download rsvd page all zero\n", __func__); ++ } ++ else ++ { ++ memcpy(kek, psta->kek, RTW_KEK_LEN); ++ memcpy(kck, psta->kck, RTW_KCK_LEN); ++ } ++ ++ /* 3(9) KEK, KCK */ ++ RsvdPageLoc.LocGTKInfo = TotalPageNum; ++ memcpy(ReservedPagePacket+BufIndex-TxDescLen, kck, RTW_KCK_LEN); ++ memcpy(ReservedPagePacket+BufIndex-TxDescLen+RTW_KCK_LEN, kek, RTW_KEK_LEN); ++ ++ /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: KEK KCK %p %d\n", */ ++ /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], (TxDescLen + RTW_KCK_LEN + RTW_KEK_LEN)); */ ++ ++ CurtPktPageNum = (u8)PageNum_128(TxDescLen + RTW_KCK_LEN + RTW_KEK_LEN); ++ ++ TotalPageNum += CurtPktPageNum; ++ ++ BufIndex += (CurtPktPageNum*PageSize); ++ ++ /* 3(10) GTK Response */ ++ RsvdPageLoc.LocGTKRsp = TotalPageNum; ++ ConstructGTKResponse( ++ padapter, ++ &ReservedPagePacket[BufIndex], ++ >KLegnth ++ ); ++ ++ rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], GTKLegnth, false, false, true); ++ /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: GTK RSP %p %d\n", */ ++ /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], (TxDescLen + GTKLegnth)); */ ++ ++ CurtPktPageNum = (u8)PageNum_128(TxDescLen + GTKLegnth); ++ ++ TotalPageNum += CurtPktPageNum; ++ ++ BufIndex += (CurtPktPageNum*PageSize); ++ ++ /* below page is empty for GTK extension memory */ ++ /* 3(11) GTK EXT MEM */ ++ RsvdPageLoc.LocGTKEXTMEM = TotalPageNum; ++ ++ CurtPktPageNum = 2; ++ ++ TotalPageNum += CurtPktPageNum; ++ ++ TotalPacketLen = BufIndex-TxDescLen + 256; /* extension memory for FW */ ++#else ++ TotalPacketLen = BufIndex-TxDescLen + sizeof (union pn48); /* IV len */ ++#endif /* CONFIG_GTK_OL */ ++ } else ++#endif /* CONFIG_WOWLAN */ ++ { ++#ifdef CONFIG_PNO_SUPPORT ++ if (pwrctl->pno_in_resume == false && pwrctl->pno_inited == true) { ++ /* Probe Request */ ++ RsvdPageLoc.LocProbePacket = TotalPageNum; ++ ConstructProbeReq( ++ padapter, ++ &ReservedPagePacket[BufIndex], ++ &ProbeReqLength); ++ ++ rtl8723b_fill_fake_txdesc(padapter, ++ &ReservedPagePacket[BufIndex-TxDescLen], ++ ProbeReqLength, false, false, false); ++#ifdef CONFIG_PNO_SET_DEBUG ++ { ++ int gj; ++ printk("probe req pkt =>\n"); ++ for (gj = 0; gj < ProbeReqLength + TxDescLen; gj++) { ++ printk(" %02x ", ReservedPagePacket[BufIndex- TxDescLen + gj]); ++ if ((gj + 1)%8 == 0) ++ printk("\n"); ++ } ++ printk(" <=end\n"); ++ } ++#endif ++ CurtPktPageNum = ++ (u8)PageNum_128(TxDescLen + ProbeReqLength); ++ ++ TotalPageNum += CurtPktPageNum; ++ ++ BufIndex += (CurtPktPageNum*PageSize); ++ ++ /* PNO INFO Page */ ++ RsvdPageLoc.LocPNOInfo = TotalPageNum; ++ ConstructPnoInfo(padapter, &ReservedPagePacket[BufIndex -TxDescLen], &PNOLength); ++#ifdef CONFIG_PNO_SET_DEBUG ++ { ++ int gj; ++ printk("PNO pkt =>\n"); ++ for (gj = 0; gj < PNOLength; gj++) { ++ printk(" %02x ", ReservedPagePacket[BufIndex-TxDescLen +gj]); ++ if ((gj + 1)%8 == 0) ++ printk("\n"); ++ } ++ printk(" <=end\n"); ++ } ++#endif ++ ++ CurtPktPageNum = (u8)PageNum_128(PNOLength); ++ TotalPageNum += CurtPktPageNum; ++ BufIndex += (CurtPktPageNum*PageSize); ++ ++ /* SSID List Page */ ++ RsvdPageLoc.LocSSIDInfo = TotalPageNum; ++ ConstructSSIDList(padapter, &ReservedPagePacket[BufIndex-TxDescLen], &SSIDLegnth); ++#ifdef CONFIG_PNO_SET_DEBUG ++ { ++ int gj; ++ printk("SSID list pkt =>\n"); ++ for (gj = 0; gj < SSIDLegnth; gj++) { ++ printk(" %02x ", ReservedPagePacket[BufIndex-TxDescLen+gj]); ++ if ((gj + 1)%8 == 0) ++ printk("\n"); ++ } ++ printk(" <=end\n"); ++ } ++#endif ++ CurtPktPageNum = (u8)PageNum_128(SSIDLegnth); ++ TotalPageNum += CurtPktPageNum; ++ BufIndex += (CurtPktPageNum*PageSize); ++ ++ /* Scan Info Page */ ++ RsvdPageLoc.LocScanInfo = TotalPageNum; ++ ConstructScanInfo(padapter, &ReservedPagePacket[BufIndex-TxDescLen], &ScanInfoLength); ++#ifdef CONFIG_PNO_SET_DEBUG ++ { ++ int gj; ++ printk("Scan info pkt =>\n"); ++ for (gj = 0; gj < ScanInfoLength; gj++) { ++ printk(" %02x ", ReservedPagePacket[BufIndex-TxDescLen+gj]); ++ if ((gj + 1)%8 == 0) ++ printk("\n"); ++ } ++ printk(" <=end\n"); ++ } ++#endif ++ CurtPktPageNum = (u8)PageNum_128(ScanInfoLength); ++ TotalPageNum += CurtPktPageNum; ++ BufIndex += (CurtPktPageNum*PageSize); ++ ++ TotalPacketLen = BufIndex + ScanInfoLength; ++ } else { ++ TotalPacketLen = BufIndex + BTQosNullLength; ++ } ++#else /* CONFIG_PNO_SUPPORT */ ++ TotalPacketLen = BufIndex + BTQosNullLength; ++#endif ++ } ++ ++ if (TotalPacketLen > MaxRsvdPageBufSize) ++ { ++ DBG_871X("%s(): ERROR: The rsvd page size is not enough!!TotalPacketLen %d, MaxRsvdPageBufSize %d\n", __func__, ++ TotalPacketLen, MaxRsvdPageBufSize); ++ goto error; ++ } ++ else ++ { ++ /* update attribute */ ++ pattrib = &pcmdframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ pattrib->qsel = 0x10; ++ pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TxDescOffset; ++ dump_mgntframe_and_wait(padapter, pcmdframe, 100); ++ } ++ ++ DBG_871X("%s: Set RSVD page location to Fw , TotalPacketLen(%d), TotalPageNum(%d)\n", __func__, TotalPacketLen, TotalPageNum); ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ rtl8723b_set_FwRsvdPage_cmd(padapter, &RsvdPageLoc); ++ rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc); ++ } else { ++ rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc); ++#ifdef CONFIG_PNO_SUPPORT ++ if (pwrctl->pno_in_resume) ++ rtl8723b_set_FwScanOffloadInfo_cmd(padapter, ++ &RsvdPageLoc, 0); ++ else ++ rtl8723b_set_FwScanOffloadInfo_cmd(padapter, ++ &RsvdPageLoc, 1); ++#endif ++ } ++ return; ++ ++error: ++ ++ rtw_free_xmitframe(pxmitpriv, pcmdframe); ++} ++ ++#ifdef CONFIG_AP_WOWLAN ++/* */ ++/* Description: Fill the reserved packets that FW will use to RSVD page. */ ++/* Now we just send 2 types packet to rsvd page. (1)Beacon, (2)ProbeRsp. */ ++/* */ ++/* Input: bDLFinished */ ++/* */ ++/* false: At the first time we will send all the packets as a large packet to Hw, */ ++/* so we need to set the packet length to total lengh. */ ++/* */ ++/* true: At the second time, we should send the first packet (default:beacon) */ ++/* to Hw again and set the lengh in descriptor to the real beacon lengh. */ ++/* 2009.10.15 by tynli. */ ++static void rtl8723b_set_AP_FwRsvdPagePkt(struct adapter *padapter, ++ bool bDLFinished) ++{ ++ struct hal_com_data *pHalData; ++ struct xmit_frame *pcmdframe; ++ struct pkt_attrib *pattrib; ++ struct xmit_priv *pxmitpriv; ++ struct mlme_ext_priv *pmlmeext; ++ struct mlme_ext_info *pmlmeinfo; ++ struct pwrctrl_priv *pwrctl; ++ u32 BeaconLength = 0, ProbeRspLength = 0; ++ u8 *ReservedPagePacket; ++ u8 TxDescLen = TXDESC_SIZE, TxDescOffset = TXDESC_OFFSET; ++ u8 TotalPageNum = 0, CurtPktPageNum = 0, RsvdPageNum = 0; ++ u8 currentip[4]; ++ u16 BufIndex, PageSize = 128; ++ u32 TotalPacketLen = 0, MaxRsvdPageBufSize = 0; ++ RSVDPAGE_LOC RsvdPageLoc; ++ ++ /* DBG_871X("%s---->\n", __func__); */ ++ DBG_8192C("+" FUNC_ADPT_FMT ": iface_type =%d\n", ++ FUNC_ADPT_ARG(padapter), get_iface_type(padapter)); ++ ++ pHalData = GET_HAL_DATA(padapter); ++ pxmitpriv = &padapter->xmitpriv; ++ pmlmeext = &padapter->mlmeextpriv; ++ pmlmeinfo = &pmlmeext->mlmext_info; ++ pwrctl = adapter_to_pwrctl(padapter); ++ ++ RsvdPageNum = BCNQ_PAGE_NUM_8723B + AP_WOWLAN_PAGE_NUM_8723B; ++ MaxRsvdPageBufSize = RsvdPageNum*PageSize; ++ ++ pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv); ++ if (pcmdframe == NULL) { ++ DBG_871X("%s: alloc ReservedPagePacket fail!\n", __func__); ++ return; ++ } ++ ++ ReservedPagePacket = pcmdframe->buf_addr; ++ memset(&RsvdPageLoc, 0, sizeof(RSVDPAGE_LOC)); ++ ++ /* 3 (1) beacon */ ++ BufIndex = TxDescOffset; ++ ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength); ++ ++ /* When we count the first page size, we need to reserve description size for the RSVD */ ++ /* packet, it will be filled in front of the packet in TXPKTBUF. */ ++ CurtPktPageNum = (u8)PageNum_128(TxDescLen + BeaconLength); ++ /* If we don't add 1 more page, the WOWLAN function has a problem. Baron thinks it's a bug of firmware */ ++ if (CurtPktPageNum == 1) ++ { ++ CurtPktPageNum += 1; ++ } ++ TotalPageNum += CurtPktPageNum; ++ ++ BufIndex += (CurtPktPageNum*PageSize); ++ ++ /* 2 (4) probe response */ ++ RsvdPageLoc.LocProbeRsp = TotalPageNum; ++ ++ rtw_get_current_ip_address(padapter, currentip); ++ ++ ConstructProbeRsp( ++ padapter, ++ &ReservedPagePacket[BufIndex], ++ &ProbeRspLength, ++ currentip, ++ false); ++ rtl8723b_fill_fake_txdesc(padapter, ++ &ReservedPagePacket[BufIndex-TxDescLen], ++ ProbeRspLength, ++ false, false, false); ++ ++ DBG_871X("%s(): HW_VAR_SET_TX_CMD: PROBE RSP %p %d\n", ++ __func__, &ReservedPagePacket[BufIndex-TxDescLen], ++ (ProbeRspLength+TxDescLen)); ++ ++ CurtPktPageNum = (u8)PageNum_128(TxDescLen + ProbeRspLength); ++ ++ TotalPageNum += CurtPktPageNum; ++ ++ BufIndex += (CurtPktPageNum*PageSize); ++ ++ TotalPacketLen = BufIndex + ProbeRspLength; ++ ++ if (TotalPacketLen > MaxRsvdPageBufSize) { ++ DBG_871X("%s(): ERROR: The rsvd page size is not enough \ ++ !!TotalPacketLen %d, MaxRsvdPageBufSize %d\n", ++ __func__, TotalPacketLen, MaxRsvdPageBufSize); ++ goto error; ++ } else { ++ /* update attribute */ ++ pattrib = &pcmdframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ pattrib->qsel = 0x10; ++ pattrib->pktlen = TotalPacketLen - TxDescOffset; ++ pattrib->last_txcmdsz = TotalPacketLen - TxDescOffset; ++ dump_mgntframe_and_wait(padapter, pcmdframe, 100); ++ } ++ ++ DBG_871X("%s: Set RSVD page location to Fw , TotalPacketLen(%d), TotalPageNum(%d)\n", __func__, TotalPacketLen, TotalPageNum); ++ rtl8723b_set_ap_wow_rsvdpage_cmd(padapter, &RsvdPageLoc); ++ ++ return; ++error: ++ rtw_free_xmitframe(pxmitpriv, pcmdframe); ++} ++#endif /* CONFIG_AP_WOWLAN */ ++ ++ void rtl8723b_download_rsvd_page(struct adapter *padapter, u8 mstatus) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++#ifdef CONFIG_AP_WOWLAN ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++#endif ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ bool bcn_valid = false; ++ u8 DLBcnCount = 0; ++ u32 poll = 0; ++ u8 val8; ++ ++ DBG_8192C("+" FUNC_ADPT_FMT ": iface_type =%d mstatus(%x)\n", ++ FUNC_ADPT_ARG(padapter), get_iface_type(padapter), mstatus); ++ ++ if (mstatus == RT_MEDIA_CONNECT) ++ { ++ bool bRecover = false; ++ u8 v8; ++ ++ /* We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */ ++ /* Suggested by filen. Added by tynli. */ ++ rtw_write16(padapter, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid)); ++ ++ /* set REG_CR bit 8 */ ++ v8 = rtw_read8(padapter, REG_CR+1); ++ v8 |= BIT(0); /* ENSWBCN */ ++ rtw_write8(padapter, REG_CR+1, v8); ++ ++ /* Disable Hw protection for a time which revserd for Hw sending beacon. */ ++ /* Fix download reserved page packet fail that access collision with the protection time. */ ++ /* 2010.05.11. Added by tynli. */ ++ val8 = rtw_read8(padapter, REG_BCN_CTRL); ++ val8 &= ~EN_BCN_FUNCTION; ++ val8 |= DIS_TSF_UDT; ++ rtw_write8(padapter, REG_BCN_CTRL, val8); ++ ++ /* Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */ ++ if (pHalData->RegFwHwTxQCtrl & BIT(6)) ++ bRecover = true; ++ ++ /* To tell Hw the packet is not a real beacon frame. */ ++ rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl & ~BIT(6)); ++ pHalData->RegFwHwTxQCtrl &= ~BIT(6); ++ ++ /* Clear beacon valid check bit. */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL); ++ rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL); ++ ++ DLBcnCount = 0; ++ poll = 0; ++ do { ++#ifdef CONFIG_AP_WOWLAN ++ if (pwrpriv->wowlan_ap_mode) ++ rtl8723b_set_AP_FwRsvdPagePkt(padapter, 0); ++ else ++ rtl8723b_set_FwRsvdPagePkt(padapter, 0); ++#else ++ /* download rsvd page. */ ++ rtl8723b_set_FwRsvdPagePkt(padapter, 0); ++#endif ++ DLBcnCount++; ++ do ++ { ++ yield(); ++ /* mdelay(10); */ ++ /* check rsvd page download OK. */ ++ rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bcn_valid)); ++ poll++; ++ } while (!bcn_valid && (poll%10)!= 0 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); ++ ++ }while (!bcn_valid && DLBcnCount<= 100 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); ++ ++ if (padapter->bSurpriseRemoved || padapter->bDriverStopped) ++ { ++ } ++ else if (!bcn_valid) ++ DBG_871X(ADPT_FMT": 1 DL RSVD page failed! DLBcnCount:%u, poll:%u\n", ++ ADPT_ARG(padapter) , DLBcnCount, poll); ++ else { ++ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); ++ pwrctl->fw_psmode_iface_id = padapter->iface_id; ++ DBG_871X(ADPT_FMT": 1 DL RSVD page success! DLBcnCount:%u, poll:%u\n", ++ ADPT_ARG(padapter), DLBcnCount, poll); ++ } ++ ++ /* 2010.05.11. Added by tynli. */ ++ val8 = rtw_read8(padapter, REG_BCN_CTRL); ++ val8 |= EN_BCN_FUNCTION; ++ val8 &= ~DIS_TSF_UDT; ++ rtw_write8(padapter, REG_BCN_CTRL, val8); ++ ++ /* To make sure that if there exists an adapter which would like to send beacon. */ ++ /* If exists, the origianl value of 0x422[6] will be 1, we should check this to */ ++ /* prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */ ++ /* the beacon cannot be sent by HW. */ ++ /* 2010.06.23. Added by tynli. */ ++ if (bRecover) ++ { ++ rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl | BIT(6)); ++ pHalData->RegFwHwTxQCtrl |= BIT(6); ++ } ++ ++ /* Clear CR[8] or beacon packet will not be send to TxBuf anymore. */ ++ v8 = rtw_read8(padapter, REG_CR+1); ++ v8 &= ~BIT(0); /* ~ENSWBCN */ ++ rtw_write8(padapter, REG_CR+1, v8); ++ } ++} ++ ++void rtl8723b_set_rssi_cmd(struct adapter *padapter, u8 *param) ++{ ++ rtl8723b_set_FwRssiSetting_cmd(padapter, param); ++} ++ ++void rtl8723b_set_FwJoinBssRpt_cmd(struct adapter *padapter, u8 mstatus) ++{ ++ if (mstatus == 1) ++ rtl8723b_download_rsvd_page(padapter, RT_MEDIA_CONNECT); ++} ++ ++/* arg[0] = macid */ ++/* arg[1] = raid */ ++/* arg[2] = shortGIrate */ ++/* arg[3] = init_rate */ ++void rtl8723b_Add_RateATid(struct adapter *padapter, u32 bitmap, u8 *arg, u8 rssi_level) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct sta_info *psta; ++ u8 mac_id = arg[0]; ++ u8 raid = arg[1]; ++ u8 shortGI = arg[2]; ++ u8 bw; ++ u32 mask = bitmap&0x0FFFFFFF; ++ ++ psta = pmlmeinfo->FW_sta_info[mac_id].psta; ++ if (psta == NULL) ++ { ++ return; ++ } ++ ++ bw = psta->bw_mode; ++ ++ if (rssi_level != DM_RATR_STA_INIT) ++ mask = ODM_Get_Rate_Bitmap(&pHalData->odmpriv, mac_id, mask, rssi_level); ++ ++ DBG_871X("%s(): mac_id =%d raid = 0x%x bw =%d mask = 0x%x\n", __func__, mac_id, raid, bw, mask); ++ rtl8723b_set_FwMacIdConfig_cmd(padapter, mac_id, raid, bw, shortGI, mask); ++} ++ ++static void ConstructBtNullFunctionData( ++ struct adapter *padapter, ++ u8 *pframe, ++ u32 *pLength, ++ u8 *StaAddr, ++ u8 bQoS, ++ u8 AC, ++ u8 bEosp, ++ u8 bForcePowerSave) ++{ ++ struct ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ u32 pktlen; ++ struct mlme_ext_priv *pmlmeext; ++ struct mlme_ext_info *pmlmeinfo; ++ u8 bssid[ETH_ALEN]; ++ ++ ++ DBG_871X("+" FUNC_ADPT_FMT ": qos =%d eosp =%d ps =%d\n", ++ FUNC_ADPT_ARG(padapter), bQoS, bEosp, bForcePowerSave); ++ ++ pwlanhdr = (struct ieee80211_hdr*)pframe; ++ pmlmeext = &padapter->mlmeextpriv; ++ pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ if (NULL == StaAddr) ++ { ++ memcpy(bssid, myid(&padapter->eeprompriv), ETH_ALEN); ++ StaAddr = bssid; ++ } ++ ++ fctrl = &pwlanhdr->frame_control; ++ *fctrl = 0; ++ if (bForcePowerSave) ++ SetPwrMgt(fctrl); ++ ++ SetFrDs(fctrl); ++ memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, myid(&padapter->eeprompriv), ETH_ALEN); ++ ++ SetDuration(pwlanhdr, 0); ++ SetSeqNum(pwlanhdr, 0); ++ ++ if (bQoS == true) ++ { ++ struct ieee80211_qos_hdr *pwlanqoshdr; ++ ++ SetFrameSubType(pframe, WIFI_QOS_DATA_NULL); ++ ++ pwlanqoshdr = (struct ieee80211_qos_hdr*)pframe; ++ SetPriority(&pwlanqoshdr->qos_ctrl, AC); ++ SetEOSP(&pwlanqoshdr->qos_ctrl, bEosp); ++ ++ pktlen = sizeof(struct ieee80211_qos_hdr); ++ } ++ else ++ { ++ SetFrameSubType(pframe, WIFI_DATA_NULL); ++ ++ pktlen = sizeof(struct ieee80211_hdr_3addr); ++ } ++ ++ *pLength = pktlen; ++} ++ ++static void SetFwRsvdPagePkt_BTCoex(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData; ++ struct xmit_frame *pcmdframe; ++ struct pkt_attrib *pattrib; ++ struct xmit_priv *pxmitpriv; ++ struct mlme_ext_priv *pmlmeext; ++ struct mlme_ext_info *pmlmeinfo; ++ u32 BeaconLength = 0; ++ u32 BTQosNullLength = 0; ++ u8 *ReservedPagePacket; ++ u8 TxDescLen, TxDescOffset; ++ u8 TotalPageNum = 0, CurtPktPageNum = 0, RsvdPageNum = 0; ++ u16 BufIndex, PageSize; ++ u32 TotalPacketLen, MaxRsvdPageBufSize = 0; ++ RSVDPAGE_LOC RsvdPageLoc; ++ ++ ++/* DBG_8192C("+" FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(padapter)); */ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ pxmitpriv = &padapter->xmitpriv; ++ pmlmeext = &padapter->mlmeextpriv; ++ pmlmeinfo = &pmlmeext->mlmext_info; ++ TxDescLen = TXDESC_SIZE; ++ TxDescOffset = TXDESC_OFFSET; ++ PageSize = PAGE_SIZE_TX_8723B; ++ ++ RsvdPageNum = BCNQ_PAGE_NUM_8723B; ++ MaxRsvdPageBufSize = RsvdPageNum*PageSize; ++ ++ pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv); ++ if (pcmdframe == NULL) { ++ DBG_8192C("%s: alloc ReservedPagePacket fail!\n", __func__); ++ return; ++ } ++ ++ ReservedPagePacket = pcmdframe->buf_addr; ++ memset(&RsvdPageLoc, 0, sizeof(RSVDPAGE_LOC)); ++ ++ /* 3 (1) beacon */ ++ BufIndex = TxDescOffset; ++ ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength); ++ ++ /* When we count the first page size, we need to reserve description size for the RSVD */ ++ /* packet, it will be filled in front of the packet in TXPKTBUF. */ ++ CurtPktPageNum = (u8)PageNum_128(TxDescLen + BeaconLength); ++ /* If we don't add 1 more page, the WOWLAN function has a problem. Baron thinks it's a bug of firmware */ ++ if (CurtPktPageNum == 1) ++ { ++ CurtPktPageNum += 1; ++ } ++ TotalPageNum += CurtPktPageNum; ++ ++ BufIndex += (CurtPktPageNum*PageSize); ++ ++ /* Jump to lastest page */ ++ if (BufIndex < (MaxRsvdPageBufSize - PageSize)) ++ { ++ BufIndex = TxDescOffset + (MaxRsvdPageBufSize - PageSize); ++ TotalPageNum = BCNQ_PAGE_NUM_8723B - 1; ++ } ++ ++ /* 3 (6) BT Qos null data */ ++ RsvdPageLoc.LocBTQosNull = TotalPageNum; ++ ConstructBtNullFunctionData( ++ padapter, ++ &ReservedPagePacket[BufIndex], ++ &BTQosNullLength, ++ NULL, ++ true, 0, 0, false); ++ rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true, false); ++ ++ CurtPktPageNum = (u8)PageNum_128(TxDescLen + BTQosNullLength); ++ ++ TotalPageNum += CurtPktPageNum; ++ ++ TotalPacketLen = BufIndex + BTQosNullLength; ++ if (TotalPacketLen > MaxRsvdPageBufSize) ++ { ++ DBG_8192C(FUNC_ADPT_FMT ": ERROR: The rsvd page size is not enough!!TotalPacketLen %d, MaxRsvdPageBufSize %d\n", ++ FUNC_ADPT_ARG(padapter), TotalPacketLen, MaxRsvdPageBufSize); ++ goto error; ++ } ++ ++ /* update attribute */ ++ pattrib = &pcmdframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ pattrib->qsel = 0x10; ++ pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TxDescOffset; ++ dump_mgntframe_and_wait(padapter, pcmdframe, 100); ++ ++/* DBG_8192C(FUNC_ADPT_FMT ": Set RSVD page location to Fw, TotalPacketLen(%d), TotalPageNum(%d)\n", */ ++/* FUNC_ADPT_ARG(padapter), TotalPacketLen, TotalPageNum); */ ++ rtl8723b_set_FwRsvdPage_cmd(padapter, &RsvdPageLoc); ++ rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc); ++ ++ return; ++ ++error: ++ rtw_free_xmitframe(pxmitpriv, pcmdframe); ++} ++ ++void rtl8723b_download_BTCoex_AP_mode_rsvd_page(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData; ++ struct mlme_ext_priv *pmlmeext; ++ struct mlme_ext_info *pmlmeinfo; ++ u8 bRecover = false; ++ u8 bcn_valid = false; ++ u8 DLBcnCount = 0; ++ u32 poll = 0; ++ u8 val8; ++ ++ ++ DBG_8192C("+" FUNC_ADPT_FMT ": iface_type =%d fw_state = 0x%08X\n", ++ FUNC_ADPT_ARG(padapter), get_iface_type(padapter), get_fwstate(&padapter->mlmepriv)); ++ ++#ifdef CONFIG_DEBUG ++ if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == false) ++ { ++ DBG_8192C(FUNC_ADPT_FMT ": [WARNING] not in AP mode!!\n", ++ FUNC_ADPT_ARG(padapter)); ++ } ++#endif /* CONFIG_DEBUG */ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ pmlmeext = &padapter->mlmeextpriv; ++ pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ /* We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */ ++ /* Suggested by filen. Added by tynli. */ ++ rtw_write16(padapter, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid)); ++ ++ /* set REG_CR bit 8 */ ++ val8 = rtw_read8(padapter, REG_CR+1); ++ val8 |= BIT(0); /* ENSWBCN */ ++ rtw_write8(padapter, REG_CR+1, val8); ++ ++ /* Disable Hw protection for a time which revserd for Hw sending beacon. */ ++ /* Fix download reserved page packet fail that access collision with the protection time. */ ++ /* 2010.05.11. Added by tynli. */ ++ val8 = rtw_read8(padapter, REG_BCN_CTRL); ++ val8 &= ~EN_BCN_FUNCTION; ++ val8 |= DIS_TSF_UDT; ++ rtw_write8(padapter, REG_BCN_CTRL, val8); ++ ++ /* Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */ ++ if (pHalData->RegFwHwTxQCtrl & BIT(6)) ++ bRecover = true; ++ ++ /* To tell Hw the packet is not a real beacon frame. */ ++ pHalData->RegFwHwTxQCtrl &= ~BIT(6); ++ rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl); ++ ++ /* Clear beacon valid check bit. */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL); ++ rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL); ++ ++ DLBcnCount = 0; ++ poll = 0; ++ do { ++ SetFwRsvdPagePkt_BTCoex(padapter); ++ DLBcnCount++; ++ do { ++ yield(); ++/* mdelay(10); */ ++ /* check rsvd page download OK. */ ++ rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, &bcn_valid); ++ poll++; ++ } while (!bcn_valid && (poll%10)!= 0 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); ++ } while (!bcn_valid && (DLBcnCount<= 100) && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); ++ ++ if (true == bcn_valid) ++ { ++ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); ++ pwrctl->fw_psmode_iface_id = padapter->iface_id; ++ DBG_8192C(ADPT_FMT": DL RSVD page success! DLBcnCount:%d, poll:%d\n", ++ ADPT_ARG(padapter), DLBcnCount, poll); ++ } ++ else ++ { ++ DBG_8192C(ADPT_FMT": DL RSVD page fail! DLBcnCount:%d, poll:%d\n", ++ ADPT_ARG(padapter), DLBcnCount, poll); ++ DBG_8192C(ADPT_FMT": DL RSVD page fail! bSurpriseRemoved =%d\n", ++ ADPT_ARG(padapter), padapter->bSurpriseRemoved); ++ DBG_8192C(ADPT_FMT": DL RSVD page fail! bDriverStopped =%d\n", ++ ADPT_ARG(padapter), padapter->bDriverStopped); ++ } ++ ++ /* 2010.05.11. Added by tynli. */ ++ val8 = rtw_read8(padapter, REG_BCN_CTRL); ++ val8 |= EN_BCN_FUNCTION; ++ val8 &= ~DIS_TSF_UDT; ++ rtw_write8(padapter, REG_BCN_CTRL, val8); ++ ++ /* To make sure that if there exists an adapter which would like to send beacon. */ ++ /* If exists, the origianl value of 0x422[6] will be 1, we should check this to */ ++ /* prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */ ++ /* the beacon cannot be sent by HW. */ ++ /* 2010.06.23. Added by tynli. */ ++ if (bRecover) ++ { ++ pHalData->RegFwHwTxQCtrl |= BIT(6); ++ rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl); ++ } ++ ++ /* Clear CR[8] or beacon packet will not be send to TxBuf anymore. */ ++ val8 = rtw_read8(padapter, REG_CR+1); ++ val8 &= ~BIT(0); /* ~ENSWBCN */ ++ rtw_write8(padapter, REG_CR+1, val8); ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/rtl8723b_dm.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/rtl8723b_dm.c +--- linux-4.3/3rdparty/rtl8723bs/hal/rtl8723b_dm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/rtl8723b_dm.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,314 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++/* Description: */ ++/* This file is for 92CE/92CU dynamic mechanism only */ ++ ++#define _RTL8723B_DM_C_ ++ ++#include ++#include ++#include ++ ++/* Global var */ ++ ++static void ++dm_CheckStatistics( ++struct adapter *Adapter ++ ) ++{ ++} ++/* */ ++/* functions */ ++/* */ ++static void Init_ODM_ComInfo_8723b(struct adapter *Adapter) ++{ ++ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ u8 cut_ver, fab_ver; ++ ++ /* */ ++ /* Init Value */ ++ /* */ ++ memset(pDM_Odm, 0, sizeof(*pDM_Odm)); ++ ++ pDM_Odm->Adapter = Adapter; ++#define ODM_CE 0x04 ++ ODM_CmnInfoInit(pDM_Odm, ODM_CMNINFO_PLATFORM, ODM_CE); ++ ODM_CmnInfoInit(pDM_Odm, ODM_CMNINFO_INTERFACE, RTW_SDIO); ++ ODM_CmnInfoInit(pDM_Odm, ODM_CMNINFO_PACKAGE_TYPE, pHalData->PackageType); ++ ODM_CmnInfoInit(pDM_Odm, ODM_CMNINFO_IC_TYPE, ODM_RTL8723B); ++ ++ fab_ver = ODM_TSMC; ++ cut_ver = ODM_CUT_A; ++ ++ DBG_871X("%s(): fab_ver =%d cut_ver =%d\n", __func__, fab_ver, cut_ver); ++ ODM_CmnInfoInit(pDM_Odm, ODM_CMNINFO_FAB_VER, fab_ver); ++ ODM_CmnInfoInit(pDM_Odm, ODM_CMNINFO_CUT_VER, cut_ver); ++ ODM_CmnInfoInit(pDM_Odm, ODM_CMNINFO_MP_TEST_CHIP, IS_NORMAL_CHIP(pHalData->VersionID)); ++ ++ ODM_CmnInfoInit(pDM_Odm, ODM_CMNINFO_PATCH_ID, pHalData->CustomerID); ++ /* ODM_CMNINFO_BINHCT_TEST only for MP Team */ ++ ODM_CmnInfoInit(pDM_Odm, ODM_CMNINFO_BWIFI_TEST, Adapter->registrypriv.wifi_spec); ++ ++ ++ if (pHalData->rf_type == RF_1T1R) { ++ ODM_CmnInfoUpdate(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_1T1R); ++ } ++ else if (pHalData->rf_type == RF_2T2R) { ++ ODM_CmnInfoUpdate(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_2T2R); ++ } ++ else if (pHalData->rf_type == RF_1T2R) { ++ ODM_CmnInfoUpdate(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_1T2R); ++ } ++ ++ pdmpriv->InitODMFlag = ODM_RF_CALIBRATION | ++ ODM_RF_TX_PWR_TRACK /* */ ++ ; ++ ++ ODM_CmnInfoUpdate(pDM_Odm, ODM_CMNINFO_ABILITY, pdmpriv->InitODMFlag); ++} ++ ++static void Update_ODM_ComInfo_8723b(struct adapter *Adapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; ++ struct dvobj_priv *dvobj = adapter_to_dvobj(Adapter); ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(Adapter); ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ int i; ++ u8 zero = 0; ++ ++ pdmpriv->InitODMFlag = 0 ++ | ODM_BB_DIG ++ | ODM_BB_RA_MASK ++ | ODM_BB_DYNAMIC_TXPWR ++ | ODM_BB_FA_CNT ++ | ODM_BB_RSSI_MONITOR ++ | ODM_BB_CCK_PD ++ | ODM_BB_PWR_SAVE ++ | ODM_BB_CFO_TRACKING ++ | ODM_MAC_EDCA_TURBO ++ | ODM_RF_TX_PWR_TRACK ++ | ODM_RF_CALIBRATION ++#ifdef CONFIG_ODM_ADAPTIVITY ++ | ODM_BB_ADAPTIVITY ++#endif ++ ; ++ ++ /* */ ++ /* Pointer reference */ ++ /* */ ++ /* ODM_CMNINFO_MAC_PHY_MODE pHalData->MacPhyMode92D */ ++ /* ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_MAC_PHY_MODE,&(pDM_Odm->u8_temp)); */ ++ ++ ODM_CmnInfoUpdate(pDM_Odm, ODM_CMNINFO_ABILITY, pdmpriv->InitODMFlag); ++ ++ ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_TX_UNI,&(dvobj->traffic_stat.tx_bytes)); ++ ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_RX_UNI,&(dvobj->traffic_stat.rx_bytes)); ++ ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_WM_MODE,&(pmlmeext->cur_wireless_mode)); ++ ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_SEC_CHNL_OFFSET,&(pHalData->nCur40MhzPrimeSC)); ++ ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_SEC_MODE,&(Adapter->securitypriv.dot11PrivacyAlgrthm)); ++ ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_BW,&(pHalData->CurrentChannelBW)); ++ ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_CHNL,&(pHalData->CurrentChannel)); ++ ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_NET_CLOSED,&(Adapter->net_closed)); ++ ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_MP_MODE, &zero); ++ ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_BAND,&(pHalData->CurrentBandType)); ++ ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_FORCED_IGI_LB,&(pHalData->u1ForcedIgiLb)); ++ ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_FORCED_RATE,&(pHalData->ForcedDataRate)); ++ ++ ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_SCAN,&(pmlmepriv->bScanInProcess)); ++ ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_POWER_SAVING,&(pwrctrlpriv->bpower_saving)); ++ ++ ++ for (i = 0; i < NUM_STA; i++) ++ ODM_CmnInfoPtrArrayHook(pDM_Odm, ODM_CMNINFO_STA_STATUS, i, NULL); ++} ++ ++void ++rtl8723b_InitHalDm( ++struct adapter *Adapter ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); ++ ++ pdmpriv->DM_Type = DM_Type_ByDriver; ++ pdmpriv->DMFlag = DYNAMIC_FUNC_DISABLE; ++ ++ pdmpriv->DMFlag |= DYNAMIC_FUNC_BT; ++ ++ pdmpriv->InitDMFlag = pdmpriv->DMFlag; ++ ++ Update_ODM_ComInfo_8723b(Adapter); ++ ++ ODM_DMInit(pDM_Odm); ++} ++ ++void ++rtl8723b_HalDmWatchDog( ++struct adapter *Adapter ++ ) ++{ ++ bool bFwCurrentInPSMode = false; ++ bool bFwPSAwake = true; ++ u8 hw_init_completed = false; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++ hw_init_completed = Adapter->hw_init_completed; ++ ++ if (hw_init_completed == false) ++ goto skip_dm; ++ ++ bFwCurrentInPSMode = adapter_to_pwrctl(Adapter)->bFwCurrentInPSMode; ++ rtw_hal_get_hwreg(Adapter, HW_VAR_FWLPS_RF_ON, (u8 *)(&bFwPSAwake)); ++ ++ if ((hw_init_completed == true) ++ && ((!bFwCurrentInPSMode) && bFwPSAwake)) ++ { ++ /* */ ++ /* Calculate Tx/Rx statistics. */ ++ /* */ ++ dm_CheckStatistics(Adapter); ++ rtw_hal_check_rxfifo_full(Adapter); ++ } ++ ++ /* ODM */ ++ if (hw_init_completed == true) ++ { ++ u8 bLinked =false; ++ u8 bsta_state =false; ++ u8 bBtDisabled = true; ++ ++ if (rtw_linked_check(Adapter)) { ++ bLinked = true; ++ if (check_fwstate(&Adapter->mlmepriv, WIFI_STATION_STATE)) ++ bsta_state = true; ++ } ++ ++ ODM_CmnInfoUpdate(&pHalData->odmpriv , ODM_CMNINFO_LINK, bLinked); ++ ODM_CmnInfoUpdate(&pHalData->odmpriv , ODM_CMNINFO_STATION_STATE, bsta_state); ++ ++ /* ODM_CmnInfoUpdate(&pHalData->odmpriv , ODM_CMNINFO_RSSI_MIN, pdmpriv->MinUndecoratedPWDBForDM); */ ++ ++ bBtDisabled = rtw_btcoex_IsBtDisabled(Adapter); ++ ++ ODM_CmnInfoUpdate(&pHalData->odmpriv, ODM_CMNINFO_BT_ENABLED, ((bBtDisabled == true)?false:true)); ++ ++ ODM_DMWatchdog(&pHalData->odmpriv); ++ } ++ ++skip_dm: ++ return; ++} ++ ++void rtl8723b_hal_dm_in_lps(struct adapter *padapter) ++{ ++ u32 PWDB_rssi = 0; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *psta = NULL; ++ ++ DBG_871X("%s, RSSI_Min =%d\n", __func__, pDM_Odm->RSSI_Min); ++ ++ /* update IGI */ ++ ODM_Write_DIG(pDM_Odm, pDM_Odm->RSSI_Min); ++ ++ ++ /* set rssi to fw */ ++ psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv)); ++ if (psta && (psta->rssi_stat.UndecoratedSmoothedPWDB > 0)) ++ { ++ PWDB_rssi = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB<<16)); ++ ++ rtl8723b_set_rssi_cmd(padapter, (u8 *)&PWDB_rssi); ++ } ++ ++} ++ ++void rtl8723b_HalDmWatchDog_in_LPS(struct adapter *Adapter) ++{ ++ u8 bLinked =false; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; ++ struct sta_priv *pstapriv = &Adapter->stapriv; ++ struct sta_info *psta = NULL; ++ ++ if (Adapter->hw_init_completed == false) ++ goto skip_lps_dm; ++ ++ ++ if (rtw_linked_check(Adapter)) ++ bLinked = true; ++ ++ ODM_CmnInfoUpdate(&pHalData->odmpriv , ODM_CMNINFO_LINK, bLinked); ++ ++ if (bLinked == false) ++ goto skip_lps_dm; ++ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_RSSI_MONITOR)) ++ goto skip_lps_dm; ++ ++ ++ /* ODM_DMWatchdog(&pHalData->odmpriv); */ ++ /* Do DIG by RSSI In LPS-32K */ ++ ++ /* 1 Find MIN-RSSI */ ++ psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv)); ++ if (psta == NULL) ++ goto skip_lps_dm; ++ ++ pdmpriv->EntryMinUndecoratedSmoothedPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; ++ ++ DBG_871X("CurIGValue =%d, EntryMinUndecoratedSmoothedPWDB = %d\n", pDM_DigTable->CurIGValue, pdmpriv->EntryMinUndecoratedSmoothedPWDB); ++ ++ if (pdmpriv->EntryMinUndecoratedSmoothedPWDB <= 0) ++ goto skip_lps_dm; ++ ++ pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB; ++ ++ pDM_Odm->RSSI_Min = pdmpriv->MinUndecoratedPWDBForDM; ++ ++ /* if (pDM_DigTable->CurIGValue != pDM_Odm->RSSI_Min) */ ++ if ((pDM_DigTable->CurIGValue > pDM_Odm->RSSI_Min + 5) || ++ (pDM_DigTable->CurIGValue < pDM_Odm->RSSI_Min - 5)) ++ ++ { ++ rtw_dm_in_lps_wk_cmd(Adapter); ++ } ++ ++ ++skip_lps_dm: ++ ++ return; ++ ++} ++ ++void rtl8723b_init_dm_priv(struct adapter * Adapter) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ memset(pdmpriv, 0, sizeof(struct dm_priv)); ++ Init_ODM_ComInfo_8723b(Adapter); ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/rtl8723b_hal_init.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/rtl8723b_hal_init.c +--- linux-4.3/3rdparty/rtl8723bs/hal/rtl8723b_hal_init.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/rtl8723b_hal_init.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,4844 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2013 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _HAL_INIT_C_ ++ ++#include ++#include ++#include ++#include ++#include ++#include "hal_com_h2c.h" ++ ++static void ++_FWDownloadEnable( ++struct adapter * padapter, ++bool enable ++ ) ++{ ++ u8 tmp, count = 0; ++ ++ if (enable) ++ { ++ /* 8051 enable */ ++ tmp = rtw_read8(padapter, REG_SYS_FUNC_EN+1); ++ rtw_write8(padapter, REG_SYS_FUNC_EN+1, tmp|0x04); ++ ++ tmp = rtw_read8(padapter, REG_MCUFWDL); ++ rtw_write8(padapter, REG_MCUFWDL, tmp|0x01); ++ ++ do{ ++ tmp = rtw_read8(padapter, REG_MCUFWDL); ++ if (tmp & 0x01) ++ break; ++ rtw_write8(padapter, REG_MCUFWDL, tmp|0x01); ++ msleep(1); ++ }while (count++<100); ++ if (count > 0) ++ DBG_871X("%s: !!!!!!!!Write 0x80 Fail!: count = %d\n", __func__, count); ++ ++ /* 8051 reset */ ++ tmp = rtw_read8(padapter, REG_MCUFWDL+2); ++ rtw_write8(padapter, REG_MCUFWDL+2, tmp&0xf7); ++ } ++ else ++ { ++ /* MCU firmware download disable. */ ++ tmp = rtw_read8(padapter, REG_MCUFWDL); ++ rtw_write8(padapter, REG_MCUFWDL, tmp&0xfe); ++ } ++} ++ ++static int ++_BlockWrite( ++ struct adapter * padapter, ++ void * buffer, ++ u32 buffSize ++ ) ++{ ++ int ret = _SUCCESS; ++ ++ u32 blockSize_p1 = 4; /* (Default) Phase #1 : PCI muse use 4-byte write to download FW */ ++ u32 blockSize_p2 = 8; /* Phase #2 : Use 8-byte, if Phase#1 use big size to write FW. */ ++ u32 blockSize_p3 = 1; /* Phase #3 : Use 1-byte, the remnant of FW image. */ ++ u32 blockCount_p1 = 0, blockCount_p2 = 0, blockCount_p3 = 0; ++ u32 remainSize_p1 = 0, remainSize_p2 = 0; ++ u8 *bufferPtr = (u8 *)buffer; ++ u32 i = 0, offset = 0; ++ ++/* printk("====>%s %d\n", __func__, __LINE__); */ ++ ++ /* 3 Phase #1 */ ++ blockCount_p1 = buffSize / blockSize_p1; ++ remainSize_p1 = buffSize % blockSize_p1; ++ ++ if (blockCount_p1) { ++ RT_TRACE(_module_hal_init_c_, _drv_notice_, ++ ("_BlockWrite: [P1] buffSize(%d) blockSize_p1(%d) blockCount_p1(%d) remainSize_p1(%d)\n", ++ buffSize, blockSize_p1, blockCount_p1, remainSize_p1)); ++ } ++ ++ for (i = 0; i < blockCount_p1; i++) ++ { ++ ret = rtw_write32(padapter, (FW_8723B_START_ADDRESS + i * blockSize_p1), *((u32*)(bufferPtr + i * blockSize_p1))); ++ if (ret == _FAIL) { ++ printk("====>%s %d i:%d\n", __func__, __LINE__, i); ++ goto exit; ++ } ++ } ++ ++ /* 3 Phase #2 */ ++ if (remainSize_p1) ++ { ++ offset = blockCount_p1 * blockSize_p1; ++ ++ blockCount_p2 = remainSize_p1/blockSize_p2; ++ remainSize_p2 = remainSize_p1%blockSize_p2; ++ ++ if (blockCount_p2) { ++ RT_TRACE(_module_hal_init_c_, _drv_notice_, ++ ("_BlockWrite: [P2] buffSize_p2(%d) blockSize_p2(%d) blockCount_p2(%d) remainSize_p2(%d)\n", ++ (buffSize-offset), blockSize_p2 , blockCount_p2, remainSize_p2)); ++ } ++ ++ } ++ ++ /* 3 Phase #3 */ ++ if (remainSize_p2) ++ { ++ offset = (blockCount_p1 * blockSize_p1) + (blockCount_p2 * blockSize_p2); ++ ++ blockCount_p3 = remainSize_p2 / blockSize_p3; ++ ++ RT_TRACE(_module_hal_init_c_, _drv_notice_, ++ ("_BlockWrite: [P3] buffSize_p3(%d) blockSize_p3(%d) blockCount_p3(%d)\n", ++ (buffSize-offset), blockSize_p3, blockCount_p3)); ++ ++ for (i = 0 ; i < blockCount_p3 ; i++) { ++ ret = rtw_write8(padapter, (FW_8723B_START_ADDRESS + offset + i), *(bufferPtr + offset + i)); ++ ++ if (ret == _FAIL) { ++ printk("====>%s %d i:%d\n", __func__, __LINE__, i); ++ goto exit; ++ } ++ } ++ } ++exit: ++ return ret; ++} ++ ++static int ++_PageWrite( ++ struct adapter *padapter, ++ u32 page, ++ void * buffer, ++ u32 size ++ ) ++{ ++ u8 value8; ++ u8 u8Page = (u8) (page & 0x07) ; ++ ++ value8 = (rtw_read8(padapter, REG_MCUFWDL+2) & 0xF8) | u8Page ; ++ rtw_write8(padapter, REG_MCUFWDL+2, value8); ++ ++ return _BlockWrite(padapter, buffer, size); ++} ++ ++static int ++_WriteFW( ++ struct adapter * padapter, ++ void * buffer, ++ u32 size ++ ) ++{ ++ /* Since we need dynamic decide method of dwonload fw, so we call this function to get chip version. */ ++ /* We can remove _ReadChipVersion from ReadpadapterInfo8192C later. */ ++ int ret = _SUCCESS; ++ u32 pageNums, remainSize ; ++ u32 page, offset; ++ u8 *bufferPtr = (u8 *)buffer; ++ ++ pageNums = size / MAX_DLFW_PAGE_SIZE ; ++ /* RT_ASSERT((pageNums <= 4), ("Page numbers should not greater then 4\n")); */ ++ remainSize = size % MAX_DLFW_PAGE_SIZE; ++ ++ for (page = 0; page < pageNums; page++) { ++ offset = page * MAX_DLFW_PAGE_SIZE; ++ ret = _PageWrite(padapter, page, bufferPtr+offset, MAX_DLFW_PAGE_SIZE); ++ ++ if (ret == _FAIL) { ++ printk("====>%s %d\n", __func__, __LINE__); ++ goto exit; ++ } ++ } ++ if (remainSize) { ++ offset = pageNums * MAX_DLFW_PAGE_SIZE; ++ page = pageNums; ++ ret = _PageWrite(padapter, page, bufferPtr+offset, remainSize); ++ ++ if (ret == _FAIL) { ++ printk("====>%s %d\n", __func__, __LINE__); ++ goto exit; ++ } ++ } ++ RT_TRACE(_module_hal_init_c_, _drv_info_, ("_WriteFW Done- for Normal chip.\n")); ++ ++exit: ++ return ret; ++} ++ ++void _8051Reset8723(struct adapter *padapter) ++{ ++ u8 cpu_rst; ++ u8 io_rst; ++ ++ ++ /* Reset 8051(WLMCU) IO wrapper */ ++ /* 0x1c[8] = 0 */ ++ /* Suggested by Isaac@SD1 and Gimmy@SD1, coding by Lucas@20130624 */ ++ io_rst = rtw_read8(padapter, REG_RSV_CTRL+1); ++ io_rst &= ~BIT(0); ++ rtw_write8(padapter, REG_RSV_CTRL+1, io_rst); ++ ++ cpu_rst = rtw_read8(padapter, REG_SYS_FUNC_EN+1); ++ cpu_rst &= ~BIT(2); ++ rtw_write8(padapter, REG_SYS_FUNC_EN+1, cpu_rst); ++ ++ /* Enable 8051 IO wrapper */ ++ /* 0x1c[8] = 1 */ ++ io_rst = rtw_read8(padapter, REG_RSV_CTRL+1); ++ io_rst |= BIT(0); ++ rtw_write8(padapter, REG_RSV_CTRL+1, io_rst); ++ ++ cpu_rst = rtw_read8(padapter, REG_SYS_FUNC_EN+1); ++ cpu_rst |= BIT(2); ++ rtw_write8(padapter, REG_SYS_FUNC_EN+1, cpu_rst); ++ ++ DBG_8192C("%s: Finish\n", __func__); ++} ++ ++static s32 polling_fwdl_chksum(struct adapter *adapter, u32 min_cnt, u32 timeout_ms) ++{ ++ s32 ret = _FAIL; ++ u32 value32; ++ unsigned long start = jiffies; ++ u32 cnt = 0; ++ ++ /* polling CheckSum report */ ++ do { ++ cnt++; ++ value32 = rtw_read32(adapter, REG_MCUFWDL); ++ if (value32 & FWDL_ChkSum_rpt || adapter->bSurpriseRemoved || adapter->bDriverStopped) ++ break; ++ yield(); ++ } while (jiffies_to_msecs(jiffies - start) < timeout_ms || cnt < min_cnt); ++ ++ if (!(value32 & FWDL_ChkSum_rpt)) { ++ goto exit; ++ } ++ ++ if (g_fwdl_chksum_fail) { ++ DBG_871X("%s: fwdl test case: fwdl_chksum_fail\n", __func__); ++ g_fwdl_chksum_fail--; ++ goto exit; ++ } ++ ++ ret = _SUCCESS; ++ ++exit: ++ DBG_871X("%s: Checksum report %s! (%u, %dms), REG_MCUFWDL:0x%08x\n", __func__ ++ , (ret == _SUCCESS)?"OK":"Fail", cnt, jiffies_to_msecs(jiffies - start), value32); ++ ++ return ret; ++} ++ ++static s32 _FWFreeToGo(struct adapter *adapter, u32 min_cnt, u32 timeout_ms) ++{ ++ s32 ret = _FAIL; ++ u32 value32; ++ unsigned long start = jiffies; ++ u32 cnt = 0; ++ ++ value32 = rtw_read32(adapter, REG_MCUFWDL); ++ value32 |= MCUFWDL_RDY; ++ value32 &= ~WINTINI_RDY; ++ rtw_write32(adapter, REG_MCUFWDL, value32); ++ ++ _8051Reset8723(adapter); ++ ++ /* polling for FW ready */ ++ do { ++ cnt++; ++ value32 = rtw_read32(adapter, REG_MCUFWDL); ++ if (value32 & WINTINI_RDY || adapter->bSurpriseRemoved || adapter->bDriverStopped) ++ break; ++ yield(); ++ } while (jiffies_to_msecs(jiffies - start) < timeout_ms || cnt < min_cnt); ++ ++ if (!(value32 & WINTINI_RDY)) { ++ goto exit; ++ } ++ ++ if (g_fwdl_wintint_rdy_fail) { ++ DBG_871X("%s: fwdl test case: wintint_rdy_fail\n", __func__); ++ g_fwdl_wintint_rdy_fail--; ++ goto exit; ++ } ++ ++ ret = _SUCCESS; ++ ++exit: ++ DBG_871X("%s: Polling FW ready %s! (%u, %dms), REG_MCUFWDL:0x%08x\n", __func__ ++ , (ret == _SUCCESS)?"OK":"Fail", cnt, jiffies_to_msecs(jiffies - start), value32); ++ ++ return ret; ++} ++ ++#define IS_FW_81xxC(padapter) (((GET_HAL_DATA(padapter))->FirmwareSignature & 0xFFF0) == 0x88C0) ++ ++void rtl8723b_FirmwareSelfReset(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ u8 u1bTmp; ++ u8 Delay = 100; ++ ++ if (!(IS_FW_81xxC(padapter) && ++ ((pHalData->FirmwareVersion < 0x21) || ++ (pHalData->FirmwareVersion == 0x21 && ++ pHalData->FirmwareSubVersion < 0x01)))) /* after 88C Fw v33.1 */ ++ { ++ /* 0x1cf = 0x20. Inform 8051 to reset. 2009.12.25. tynli_test */ ++ rtw_write8(padapter, REG_HMETFR+3, 0x20); ++ ++ u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN+1); ++ while (u1bTmp & BIT2) ++ { ++ Delay--; ++ if (Delay == 0) ++ break; ++ udelay(50); ++ u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN+1); ++ } ++ RT_TRACE(_module_hal_init_c_, _drv_notice_, ("-%s: 8051 reset success (%d)\n", __func__, Delay)); ++ ++ if (Delay == 0) ++ { ++ RT_TRACE(_module_hal_init_c_, _drv_notice_, ("%s: Force 8051 reset!!!\n", __func__)); ++ /* force firmware reset */ ++ u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN+1); ++ rtw_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp&(~BIT2)); ++ } ++ } ++} ++ ++/* */ ++/* Description: */ ++/* Download 8192C firmware code. */ ++/* */ ++/* */ ++s32 rtl8723b_FirmwareDownload(struct adapter *padapter, bool bUsedWoWLANFw) ++{ ++ s32 rtStatus = _SUCCESS; ++ u8 write_fw = 0; ++ unsigned long fwdl_start_time; ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ struct rt_firmware *pFirmware; ++ struct rt_firmware *pBTFirmware; ++ struct rt_firmware_hdr *pFwHdr = NULL; ++ u8 *pFirmwareBuf; ++ u32 FirmwareLen; ++ const struct firmware *fw; ++ struct device *device = dvobj_to_dev(padapter->dvobj); ++ u8 *fwfilepath; ++ struct dvobj_priv *psdpriv = padapter->dvobj; ++ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; ++ u8 tmp_ps; ++ ++ RT_TRACE(_module_hal_init_c_, _drv_info_, ("+%s\n", __func__)); ++#ifdef CONFIG_WOWLAN ++ RT_TRACE(_module_hal_init_c_, _drv_notice_, ("+%s, bUsedWoWLANFw:%d\n", __func__, bUsedWoWLANFw)); ++#endif ++ pFirmware = kzalloc(sizeof(struct rt_firmware), GFP_KERNEL); ++ pBTFirmware = kzalloc(sizeof(struct rt_firmware), GFP_KERNEL); ++ ++ if (!pFirmware||!pBTFirmware) { ++ rtStatus = _FAIL; ++ goto exit; ++ } ++ ++ tmp_ps = rtw_read8(padapter, 0xa3); ++ tmp_ps &= 0xf8; ++ tmp_ps |= 0x02; ++ /* 1. write 0xA3[:2:0] = 3b'010 */ ++ rtw_write8(padapter, 0xa3, tmp_ps); ++ /* 2. read power_state = 0xA0[1:0] */ ++ tmp_ps = rtw_read8(padapter, 0xa0); ++ tmp_ps &= 0x03; ++ if (tmp_ps != 0x01) { ++ DBG_871X(FUNC_ADPT_FMT" tmp_ps =%x\n", FUNC_ADPT_ARG(padapter), tmp_ps); ++ pdbgpriv->dbg_downloadfw_pwr_state_cnt++; ++ } ++#ifdef CONFIG_WOWLAN ++ if (bUsedWoWLANFw) ++ fwfilepath = "rtlwifi/rtl8723bs_wowlan.bin"; ++ else ++#endif /* CONFIG_WOWLAN */ ++ fwfilepath = "rtlwifi/rtl8723bs_nic.bin"; ++ ++ pr_info("rtl8723bs: accquire FW from file:%s\n", fwfilepath); ++ ++ rtStatus = request_firmware(&fw, fwfilepath, device); ++ if (rtStatus) { ++ pr_err("Request firmware failed with error 0x%x\n", rtStatus); ++ rtStatus = _FAIL; ++ goto exit; ++ } ++ if (!fw) { ++ pr_err("Firmware %s not available\n", fwfilepath); ++ rtStatus = _FAIL; ++ goto exit; ++ } ++ if (fw->size > FW_8723B_SIZE) { ++ rtStatus = _FAIL; ++ RT_TRACE(_module_hal_init_c_, _drv_err_, ++ ("Firmware size exceed 0x%X. Check it.\n", ++ FW_8188E_SIZE)); ++ goto exit; ++ } ++ pFirmware->szFwBuffer = kzalloc(fw->size, GFP_KERNEL); ++ if (! pFirmware->szFwBuffer) { ++ rtStatus = _FAIL; ++ goto exit; ++ } ++ memcpy(pFirmware->szFwBuffer, fw->data, fw->size); ++ pFirmware->ulFwLength = fw->size; ++ release_firmware(fw); ++ if (pFirmware->ulFwLength > FW_8723B_SIZE) { ++ rtStatus = _FAIL; ++ DBG_871X_LEVEL(_drv_emerg_, "Firmware size:%u exceed %u\n", pFirmware->ulFwLength, FW_8723B_SIZE); ++ goto exit; ++ } ++ ++ pFirmwareBuf = pFirmware->szFwBuffer; ++ FirmwareLen = pFirmware->ulFwLength; ++ ++ /* To Check Fw header. Added by tynli. 2009.12.04. */ ++ pFwHdr = (struct rt_firmware_hdr *)pFirmwareBuf; ++ ++ pHalData->FirmwareVersion = le16_to_cpu(pFwHdr->Version); ++ pHalData->FirmwareSubVersion = le16_to_cpu(pFwHdr->Subversion); ++ pHalData->FirmwareSignature = le16_to_cpu(pFwHdr->Signature); ++ ++ DBG_871X("%s: fw_ver =%x fw_subver =%04x sig = 0x%x, Month =%02x, Date =%02x, Hour =%02x, Minute =%02x\n", ++ __func__, pHalData->FirmwareVersion, pHalData->FirmwareSubVersion, pHalData->FirmwareSignature ++ , pFwHdr->Month, pFwHdr->Date, pFwHdr->Hour, pFwHdr->Minute); ++ ++ if (IS_FW_HEADER_EXIST_8723B(pFwHdr)) ++ { ++ DBG_871X("%s(): Shift for fw header!\n", __func__); ++ /* Shift 32 bytes for FW header */ ++ pFirmwareBuf = pFirmwareBuf + 32; ++ FirmwareLen = FirmwareLen - 32; ++ } ++ ++ /* Suggested by Filen. If 8051 is running in RAM code, driver should inform Fw to reset by itself, */ ++ /* or it will cause download Fw fail. 2010.02.01. by tynli. */ ++ if (rtw_read8(padapter, REG_MCUFWDL) & RAM_DL_SEL) /* 8051 RAM code */ ++ { ++ rtw_write8(padapter, REG_MCUFWDL, 0x00); ++ rtl8723b_FirmwareSelfReset(padapter); ++ } ++ ++ _FWDownloadEnable(padapter, true); ++ fwdl_start_time = jiffies; ++ while (!padapter->bDriverStopped && !padapter->bSurpriseRemoved ++ && (write_fw++ < 3 || jiffies_to_msecs(jiffies - fwdl_start_time) < 500)) ++ { ++ /* reset FWDL chksum */ ++ rtw_write8(padapter, REG_MCUFWDL, rtw_read8(padapter, REG_MCUFWDL)|FWDL_ChkSum_rpt); ++ ++ rtStatus = _WriteFW(padapter, pFirmwareBuf, FirmwareLen); ++ if (rtStatus != _SUCCESS) ++ continue; ++ ++ rtStatus = polling_fwdl_chksum(padapter, 5, 50); ++ if (rtStatus == _SUCCESS) ++ break; ++ } ++ _FWDownloadEnable(padapter, false); ++ if (_SUCCESS != rtStatus) ++ goto fwdl_stat; ++ ++ rtStatus = _FWFreeToGo(padapter, 10, 200); ++ if (_SUCCESS != rtStatus) ++ goto fwdl_stat; ++ ++fwdl_stat: ++ DBG_871X("FWDL %s. write_fw:%u, %dms\n" ++ , (rtStatus == _SUCCESS)?"success":"fail" ++ , write_fw ++ , jiffies_to_msecs(jiffies - fwdl_start_time) ++ ); ++ ++exit: ++ kfree(pFirmware->szFwBuffer); ++ kfree(pFirmware); ++ kfree(pBTFirmware); ++ DBG_871X(" <=== rtl8723b_FirmwareDownload()\n"); ++ return rtStatus; ++} ++ ++void rtl8723b_InitializeFirmwareVars(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ ++ /* Init Fw LPS related. */ ++ adapter_to_pwrctl(padapter)->bFwCurrentInPSMode = false; ++ ++ /* Init H2C cmd. */ ++ rtw_write8(padapter, REG_HMETFR, 0x0f); ++ ++ /* Init H2C counter. by tynli. 2009.12.09. */ ++ pHalData->LastHMEBoxNum = 0; ++/* pHalData->H2CQueueHead = 0; */ ++/* pHalData->H2CQueueTail = 0; */ ++/* pHalData->H2CStopInsertQueue = false; */ ++} ++ ++#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) ++/* */ ++ ++/* */ ++/* Description: Prepare some information to Fw for WoWLAN. */ ++/* (1) Download wowlan Fw. */ ++/* (2) Download RSVD page packets. */ ++/* (3) Enable AP offload if needed. */ ++/* */ ++/* 2011.04.12 by tynli. */ ++/* */ ++void ++SetFwRelatedForWoWLAN8723b( ++ struct adapter * padapter, ++ u8 bHostIsGoingtoSleep ++) ++{ ++ int status = _FAIL; ++ /* */ ++ /* 1. Before WoWLAN we need to re-download WoWLAN Fw. */ ++ /* */ ++ status = rtl8723b_FirmwareDownload(padapter, bHostIsGoingtoSleep); ++ if (status != _SUCCESS) { ++ DBG_871X("SetFwRelatedForWoWLAN8723b(): Re-Download Firmware failed!!\n"); ++ return; ++ } else { ++ DBG_871X("SetFwRelatedForWoWLAN8723b(): Re-Download Firmware Success !!\n"); ++ } ++ /* */ ++ /* 2. Re-Init the variables about Fw related setting. */ ++ /* */ ++ rtl8723b_InitializeFirmwareVars(padapter); ++} ++#endif /* CONFIG_WOWLAN */ ++ ++static void rtl8723b_free_hal_data(struct adapter *padapter) ++{ ++} ++ ++/* */ ++/* Efuse related code */ ++/* */ ++static u8 ++hal_EfuseSwitchToBank( ++ struct adapter *padapter, ++ u8 bank, ++ bool bPseudoTest) ++{ ++ u8 bRet = false; ++ u32 value32 = 0; ++#ifdef HAL_EFUSE_MEMORY ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; ++#endif ++ ++ ++ DBG_8192C("%s: Efuse switch bank to %d\n", __func__, bank); ++ if (bPseudoTest) ++ { ++#ifdef HAL_EFUSE_MEMORY ++ pEfuseHal->fakeEfuseBank = bank; ++#else ++ fakeEfuseBank = bank; ++#endif ++ bRet = true; ++ } ++ else ++ { ++ value32 = rtw_read32(padapter, EFUSE_TEST); ++ bRet = true; ++ switch (bank) ++ { ++ case 0: ++ value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); ++ break; ++ case 1: ++ value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_0); ++ break; ++ case 2: ++ value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_1); ++ break; ++ case 3: ++ value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_2); ++ break; ++ default: ++ value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); ++ bRet = false; ++ break; ++ } ++ rtw_write32(padapter, EFUSE_TEST, value32); ++ } ++ ++ return bRet; ++} ++ ++static void ++Hal_GetEfuseDefinition( ++ struct adapter *padapter, ++ u8 efuseType, ++ u8 type, ++ void *pOut, ++ bool bPseudoTest) ++{ ++ switch (type) ++ { ++ case TYPE_EFUSE_MAX_SECTION: ++ { ++ u8 *pMax_section; ++ pMax_section = (u8 *)pOut; ++ ++ if (efuseType == EFUSE_WIFI) ++ *pMax_section = EFUSE_MAX_SECTION_8723B; ++ else ++ *pMax_section = EFUSE_BT_MAX_SECTION; ++ } ++ break; ++ ++ case TYPE_EFUSE_REAL_CONTENT_LEN: ++ { ++ u16 *pu2Tmp; ++ pu2Tmp = (u16*)pOut; ++ ++ if (efuseType == EFUSE_WIFI) ++ *pu2Tmp = EFUSE_REAL_CONTENT_LEN_8723B; ++ else ++ *pu2Tmp = EFUSE_BT_REAL_CONTENT_LEN; ++ } ++ break; ++ ++ case TYPE_AVAILABLE_EFUSE_BYTES_BANK: ++ { ++ u16 *pu2Tmp; ++ pu2Tmp = (u16*)pOut; ++ ++ if (efuseType == EFUSE_WIFI) ++ *pu2Tmp = (EFUSE_REAL_CONTENT_LEN_8723B-EFUSE_OOB_PROTECT_BYTES); ++ else ++ *pu2Tmp = (EFUSE_BT_REAL_BANK_CONTENT_LEN-EFUSE_PROTECT_BYTES_BANK); ++ } ++ break; ++ ++ case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL: ++ { ++ u16 *pu2Tmp; ++ pu2Tmp = (u16*)pOut; ++ ++ if (efuseType == EFUSE_WIFI) ++ *pu2Tmp = (EFUSE_REAL_CONTENT_LEN_8723B-EFUSE_OOB_PROTECT_BYTES); ++ else ++ *pu2Tmp = (EFUSE_BT_REAL_CONTENT_LEN-(EFUSE_PROTECT_BYTES_BANK*3)); ++ } ++ break; ++ ++ case TYPE_EFUSE_MAP_LEN: ++ { ++ u16 *pu2Tmp; ++ pu2Tmp = (u16*)pOut; ++ ++ if (efuseType == EFUSE_WIFI) ++ *pu2Tmp = EFUSE_MAX_MAP_LEN; ++ else ++ *pu2Tmp = EFUSE_BT_MAP_LEN; ++ } ++ break; ++ ++ case TYPE_EFUSE_PROTECT_BYTES_BANK: ++ { ++ u8 *pu1Tmp; ++ pu1Tmp = (u8 *)pOut; ++ ++ if (efuseType == EFUSE_WIFI) ++ *pu1Tmp = EFUSE_OOB_PROTECT_BYTES; ++ else ++ *pu1Tmp = EFUSE_PROTECT_BYTES_BANK; ++ } ++ break; ++ ++ case TYPE_EFUSE_CONTENT_LEN_BANK: ++ { ++ u16 *pu2Tmp; ++ pu2Tmp = (u16*)pOut; ++ ++ if (efuseType == EFUSE_WIFI) ++ *pu2Tmp = EFUSE_REAL_CONTENT_LEN_8723B; ++ else ++ *pu2Tmp = EFUSE_BT_REAL_BANK_CONTENT_LEN; ++ } ++ break; ++ ++ default: ++ { ++ u8 *pu1Tmp; ++ pu1Tmp = (u8 *)pOut; ++ *pu1Tmp = 0; ++ } ++ break; ++ } ++} ++ ++#define VOLTAGE_V25 0x03 ++#define LDOE25_SHIFT 28 ++ ++/* */ ++/* The following is for compile ok */ ++/* That should be merged with the original in the future */ ++/* */ ++#define EFUSE_ACCESS_ON_8723 0x69 /* For RTL8723 only. */ ++#define EFUSE_ACCESS_OFF_8723 0x00 /* For RTL8723 only. */ ++#define REG_EFUSE_ACCESS_8723 0x00CF /* Efuse access protection for RTL8723 */ ++ ++/* */ ++static void Hal_BT_EfusePowerSwitch( ++ struct adapter *padapter, ++ u8 bWrite, ++ u8 PwrState) ++{ ++ u8 tempval; ++ if (PwrState == true) ++ { ++ /* enable BT power cut */ ++ /* 0x6A[14] = 1 */ ++ tempval = rtw_read8(padapter, 0x6B); ++ tempval |= BIT(6); ++ rtw_write8(padapter, 0x6B, tempval); ++ ++ /* Attention!! Between 0x6A[14] and 0x6A[15] setting need 100us delay */ ++ /* So don't wirte 0x6A[14]= 1 and 0x6A[15]= 0 together! */ ++ msleep(1); ++ /* disable BT output isolation */ ++ /* 0x6A[15] = 0 */ ++ tempval = rtw_read8(padapter, 0x6B); ++ tempval &= ~BIT(7); ++ rtw_write8(padapter, 0x6B, tempval); ++ } ++ else ++ { ++ /* enable BT output isolation */ ++ /* 0x6A[15] = 1 */ ++ tempval = rtw_read8(padapter, 0x6B); ++ tempval |= BIT(7); ++ rtw_write8(padapter, 0x6B, tempval); ++ ++ /* Attention!! Between 0x6A[14] and 0x6A[15] setting need 100us delay */ ++ /* So don't wirte 0x6A[14]= 1 and 0x6A[15]= 0 together! */ ++ ++ /* disable BT power cut */ ++ /* 0x6A[14] = 1 */ ++ tempval = rtw_read8(padapter, 0x6B); ++ tempval &= ~BIT(6); ++ rtw_write8(padapter, 0x6B, tempval); ++ } ++ ++} ++static void ++Hal_EfusePowerSwitch( ++ struct adapter *padapter, ++ u8 bWrite, ++ u8 PwrState) ++{ ++ u8 tempval; ++ u16 tmpV16; ++ ++ ++ if (PwrState == true) ++ { ++ /* To avoid cannot access efuse regsiters after disable/enable several times during DTM test. */ ++ /* Suggested by SD1 IsaacHsu. 2013.07.08, added by tynli. */ ++ tempval = rtw_read8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HSUS_CTRL); ++ if (tempval & BIT(0)) /* SDIO local register is suspend */ ++ { ++ u8 count = 0; ++ ++ ++ tempval &= ~BIT(0); ++ rtw_write8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HSUS_CTRL, tempval); ++ ++ /* check 0x86[1:0]= 10'2h, wait power state to leave suspend */ ++ do { ++ tempval = rtw_read8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HSUS_CTRL); ++ tempval &= 0x3; ++ if (tempval == 0x02) ++ break; ++ ++ count++; ++ if (count >= 100) ++ break; ++ ++ mdelay(10); ++ } while (1); ++ ++ if (count >= 100) ++ { ++ DBG_8192C(FUNC_ADPT_FMT ": Leave SDIO local register suspend fail! Local 0x86 =%#X\n", ++ FUNC_ADPT_ARG(padapter), tempval); ++ } ++ else ++ { ++ DBG_8192C(FUNC_ADPT_FMT ": Leave SDIO local register suspend OK! Local 0x86 =%#X\n", ++ FUNC_ADPT_ARG(padapter), tempval); ++ } ++ } ++ ++ rtw_write8(padapter, REG_EFUSE_ACCESS_8723, EFUSE_ACCESS_ON_8723); ++ ++ /* Reset: 0x0000h[28], default valid */ ++ tmpV16 = rtw_read16(padapter, REG_SYS_FUNC_EN); ++ if (!(tmpV16 & FEN_ELDR)) { ++ tmpV16 |= FEN_ELDR ; ++ rtw_write16(padapter, REG_SYS_FUNC_EN, tmpV16); ++ } ++ ++ /* Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock from ANA, default valid */ ++ tmpV16 = rtw_read16(padapter, REG_SYS_CLKR); ++ if ((!(tmpV16 & LOADER_CLK_EN)) || (!(tmpV16 & ANA8M))) { ++ tmpV16 |= (LOADER_CLK_EN | ANA8M) ; ++ rtw_write16(padapter, REG_SYS_CLKR, tmpV16); ++ } ++ ++ if (bWrite == true) ++ { ++ /* Enable LDO 2.5V before read/write action */ ++ tempval = rtw_read8(padapter, EFUSE_TEST+3); ++ tempval &= 0x0F; ++ tempval |= (VOLTAGE_V25 << 4); ++ rtw_write8(padapter, EFUSE_TEST+3, (tempval | 0x80)); ++ ++ /* rtw_write8(padapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON); */ ++ } ++ } ++ else ++ { ++ rtw_write8(padapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF); ++ ++ if (bWrite == true) { ++ /* Disable LDO 2.5V after read/write action */ ++ tempval = rtw_read8(padapter, EFUSE_TEST+3); ++ rtw_write8(padapter, EFUSE_TEST+3, (tempval & 0x7F)); ++ } ++ ++ } ++} ++ ++static void ++hal_ReadEFuse_WiFi( ++ struct adapter *padapter, ++ u16 _offset, ++ u16 _size_byte, ++ u8 *pbuf, ++ bool bPseudoTest) ++{ ++#ifdef HAL_EFUSE_MEMORY ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; ++#endif ++ u8 *efuseTbl = NULL; ++ u16 eFuse_Addr = 0; ++ u8 offset, wden; ++ u8 efuseHeader, efuseExtHdr, efuseData; ++ u16 i, total, used; ++ u8 efuse_usage = 0; ++ ++ /* DBG_871X("YJ: ====>%s():_offset =%d _size_byte =%d bPseudoTest =%d\n", __func__, _offset, _size_byte, bPseudoTest); */ ++ /* */ ++ /* Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. */ ++ /* */ ++ if ((_offset+_size_byte) > EFUSE_MAX_MAP_LEN) ++ { ++ DBG_8192C("%s: Invalid offset(%#x) with read bytes(%#x)!!\n", __func__, _offset, _size_byte); ++ return; ++ } ++ ++ efuseTbl = (u8 *)rtw_malloc(EFUSE_MAX_MAP_LEN); ++ if (efuseTbl == NULL) ++ { ++ DBG_8192C("%s: alloc efuseTbl fail!\n", __func__); ++ return; ++ } ++ /* 0xff will be efuse default value instead of 0x00. */ ++ memset(efuseTbl, 0xFF, EFUSE_MAX_MAP_LEN); ++ ++ ++#ifdef CONFIG_DEBUG ++if (0) ++{ ++ for (i = 0; i<256; i++) ++ efuse_OneByteRead(padapter, i, &efuseTbl[i], false); ++ DBG_871X("Efuse Content:\n"); ++ for (i = 0; i<256; i++) ++ { ++ if (i % 16 == 0) ++ printk("\n"); ++ printk("%02X ", efuseTbl[i]); ++ } ++ printk("\n"); ++} ++#endif ++ ++ ++ /* switch bank back to bank 0 for later BT and wifi use. */ ++ hal_EfuseSwitchToBank(padapter, 0, bPseudoTest); ++ ++ while (AVAILABLE_EFUSE_ADDR(eFuse_Addr)) ++ { ++ efuse_OneByteRead(padapter, eFuse_Addr++, &efuseHeader, bPseudoTest); ++ if (efuseHeader == 0xFF) ++ { ++ DBG_8192C("%s: data end at address =%#x\n", __func__, eFuse_Addr-1); ++ break; ++ } ++ /* DBG_8192C("%s: efuse[0x%X]= 0x%02X\n", __func__, eFuse_Addr-1, efuseHeader); */ ++ ++ /* Check PG header for section num. */ ++ if (EXT_HEADER(efuseHeader)) /* extended header */ ++ { ++ offset = GET_HDR_OFFSET_2_0(efuseHeader); ++ /* DBG_8192C("%s: extended header offset = 0x%X\n", __func__, offset); */ ++ ++ efuse_OneByteRead(padapter, eFuse_Addr++, &efuseExtHdr, bPseudoTest); ++ /* DBG_8192C("%s: efuse[0x%X]= 0x%02X\n", __func__, eFuse_Addr-1, efuseExtHdr); */ ++ if (ALL_WORDS_DISABLED(efuseExtHdr)) ++ { ++ continue; ++ } ++ ++ offset |= ((efuseExtHdr & 0xF0) >> 1); ++ wden = (efuseExtHdr & 0x0F); ++ } ++ else ++ { ++ offset = ((efuseHeader >> 4) & 0x0f); ++ wden = (efuseHeader & 0x0f); ++ } ++ /* DBG_8192C("%s: Offset =%d Worden = 0x%X\n", __func__, offset, wden); */ ++ ++ if (offset < EFUSE_MAX_SECTION_8723B) ++ { ++ u16 addr; ++ /* Get word enable value from PG header */ ++/* DBG_8192C("%s: Offset =%d Worden = 0x%X\n", __func__, offset, wden); */ ++ ++ addr = offset * PGPKT_DATA_SIZE; ++ for (i = 0; ifakeEfuseUsedBytes = used; ++#else ++ fakeEfuseUsedBytes = used; ++#endif ++ } ++ else ++ { ++ rtw_hal_set_hwreg(padapter, HW_VAR_EFUSE_BYTES, (u8 *)&used); ++ rtw_hal_set_hwreg(padapter, HW_VAR_EFUSE_USAGE, (u8 *)&efuse_usage); ++ } ++ ++ if (efuseTbl) ++ kfree(efuseTbl); ++} ++ ++static void ++hal_ReadEFuse_BT( ++ struct adapter *padapter, ++ u16 _offset, ++ u16 _size_byte, ++ u8 *pbuf, ++ bool bPseudoTest ++ ) ++{ ++#ifdef HAL_EFUSE_MEMORY ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; ++#endif ++ u8 *efuseTbl; ++ u8 bank; ++ u16 eFuse_Addr; ++ u8 efuseHeader, efuseExtHdr, efuseData; ++ u8 offset, wden; ++ u16 i, total, used; ++ u8 efuse_usage; ++ ++ ++ /* */ ++ /* Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. */ ++ /* */ ++ if ((_offset+_size_byte) > EFUSE_BT_MAP_LEN) ++ { ++ DBG_8192C("%s: Invalid offset(%#x) with read bytes(%#x)!!\n", __func__, _offset, _size_byte); ++ return; ++ } ++ ++ efuseTbl = rtw_malloc(EFUSE_BT_MAP_LEN); ++ if (efuseTbl == NULL) { ++ DBG_8192C("%s: efuseTbl malloc fail!\n", __func__); ++ return; ++ } ++ /* 0xff will be efuse default value instead of 0x00. */ ++ memset(efuseTbl, 0xFF, EFUSE_BT_MAP_LEN); ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &total, bPseudoTest); ++ ++ for (bank = 1; bank<3; bank++) /* 8723b Max bake 0~2 */ ++ { ++ if (hal_EfuseSwitchToBank(padapter, bank, bPseudoTest) == false) ++ { ++ DBG_8192C("%s: hal_EfuseSwitchToBank Fail!!\n", __func__); ++ goto exit; ++ } ++ ++ eFuse_Addr = 0; ++ ++ while (AVAILABLE_EFUSE_ADDR(eFuse_Addr)) ++ { ++ efuse_OneByteRead(padapter, eFuse_Addr++, &efuseHeader, bPseudoTest); ++ if (efuseHeader == 0xFF) break; ++ DBG_8192C("%s: efuse[%#X]= 0x%02x (header)\n", __func__, (((bank-1)*EFUSE_REAL_CONTENT_LEN_8723B)+eFuse_Addr-1), efuseHeader); ++ ++ /* Check PG header for section num. */ ++ if (EXT_HEADER(efuseHeader)) /* extended header */ ++ { ++ offset = GET_HDR_OFFSET_2_0(efuseHeader); ++ DBG_8192C("%s: extended header offset_2_0 = 0x%X\n", __func__, offset); ++ ++ efuse_OneByteRead(padapter, eFuse_Addr++, &efuseExtHdr, bPseudoTest); ++ DBG_8192C("%s: efuse[%#X]= 0x%02x (ext header)\n", __func__, (((bank-1)*EFUSE_REAL_CONTENT_LEN_8723B)+eFuse_Addr-1), efuseExtHdr); ++ if (ALL_WORDS_DISABLED(efuseExtHdr)) ++ { ++ continue; ++ } ++ ++ offset |= ((efuseExtHdr & 0xF0) >> 1); ++ wden = (efuseExtHdr & 0x0F); ++ } ++ else ++ { ++ offset = ((efuseHeader >> 4) & 0x0f); ++ wden = (efuseHeader & 0x0f); ++ } ++ ++ if (offset < EFUSE_BT_MAX_SECTION) ++ { ++ u16 addr; ++ ++ /* Get word enable value from PG header */ ++ DBG_8192C("%s: Offset =%d Worden =%#X\n", __func__, offset, wden); ++ ++ addr = offset * PGPKT_DATA_SIZE; ++ for (i = 0; ifakeBTEfuseUsedBytes = used; ++#else ++ fakeBTEfuseUsedBytes = used; ++#endif ++ } ++ else ++ { ++ rtw_hal_set_hwreg(padapter, HW_VAR_EFUSE_BT_BYTES, (u8 *)&used); ++ rtw_hal_set_hwreg(padapter, HW_VAR_EFUSE_BT_USAGE, (u8 *)&efuse_usage); ++ } ++ ++exit: ++ if (efuseTbl) ++ kfree(efuseTbl); ++} ++ ++static void ++Hal_ReadEFuse( ++ struct adapter *padapter, ++ u8 efuseType, ++ u16 _offset, ++ u16 _size_byte, ++ u8 *pbuf, ++ bool bPseudoTest) ++{ ++ if (efuseType == EFUSE_WIFI) ++ hal_ReadEFuse_WiFi(padapter, _offset, _size_byte, pbuf, bPseudoTest); ++ else ++ hal_ReadEFuse_BT(padapter, _offset, _size_byte, pbuf, bPseudoTest); ++} ++ ++static u16 ++hal_EfuseGetCurrentSize_WiFi( ++ struct adapter *padapter, ++ bool bPseudoTest) ++{ ++#ifdef HAL_EFUSE_MEMORY ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; ++#endif ++ u16 efuse_addr = 0; ++ u16 start_addr = 0; /* for debug */ ++ u8 hoffset = 0, hworden = 0; ++ u8 efuse_data, word_cnts = 0; ++ u32 count = 0; /* for debug */ ++ ++ ++ if (bPseudoTest) ++ { ++#ifdef HAL_EFUSE_MEMORY ++ efuse_addr = (u16)pEfuseHal->fakeEfuseUsedBytes; ++#else ++ efuse_addr = (u16)fakeEfuseUsedBytes; ++#endif ++ } ++ else ++ { ++ rtw_hal_get_hwreg(padapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr); ++ } ++ start_addr = efuse_addr; ++ DBG_8192C("%s: start_efuse_addr = 0x%X\n", __func__, efuse_addr); ++ ++ /* switch bank back to bank 0 for later BT and wifi use. */ ++ hal_EfuseSwitchToBank(padapter, 0, bPseudoTest); ++ ++ count = 0; ++ while (AVAILABLE_EFUSE_ADDR(efuse_addr)) ++ { ++ if (efuse_OneByteRead(padapter, efuse_addr, &efuse_data, bPseudoTest) == false) ++ { ++ DBG_8192C(KERN_ERR "%s: efuse_OneByteRead Fail! addr = 0x%X !!\n", __func__, efuse_addr); ++ goto error; ++ } ++ ++ if (efuse_data == 0xFF) break; ++ ++ if ((start_addr != 0) && (efuse_addr == start_addr)) ++ { ++ count++; ++ DBG_8192C(FUNC_ADPT_FMT ": [WARNING] efuse raw 0x%X = 0x%02X not 0xFF!!(%d times)\n", ++ FUNC_ADPT_ARG(padapter), efuse_addr, efuse_data, count); ++ ++ efuse_data = 0xFF; ++ if (count < 4) ++ { ++ /* try again! */ ++ ++ if (count > 2) ++ { ++ /* try again form address 0 */ ++ efuse_addr = 0; ++ start_addr = 0; ++ } ++ ++ continue; ++ } ++ ++ goto error; ++ } ++ ++ if (EXT_HEADER(efuse_data)) ++ { ++ hoffset = GET_HDR_OFFSET_2_0(efuse_data); ++ efuse_addr++; ++ efuse_OneByteRead(padapter, efuse_addr, &efuse_data, bPseudoTest); ++ if (ALL_WORDS_DISABLED(efuse_data)) ++ { ++ continue; ++ } ++ ++ hoffset |= ((efuse_data & 0xF0) >> 1); ++ hworden = efuse_data & 0x0F; ++ } ++ else ++ { ++ hoffset = (efuse_data>>4) & 0x0F; ++ hworden = efuse_data & 0x0F; ++ } ++ ++ word_cnts = Efuse_CalculateWordCnts(hworden); ++ efuse_addr += (word_cnts*2)+1; ++ } ++ ++ if (bPseudoTest) ++ { ++#ifdef HAL_EFUSE_MEMORY ++ pEfuseHal->fakeEfuseUsedBytes = efuse_addr; ++#else ++ fakeEfuseUsedBytes = efuse_addr; ++#endif ++ } ++ else ++ { ++ rtw_hal_set_hwreg(padapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr); ++ } ++ ++ goto exit; ++ ++error: ++ /* report max size to prevent wirte efuse */ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &efuse_addr, bPseudoTest); ++ ++exit: ++ DBG_8192C("%s: CurrentSize =%d\n", __func__, efuse_addr); ++ ++ return efuse_addr; ++} ++ ++static u16 ++hal_EfuseGetCurrentSize_BT( ++ struct adapter *padapter, ++ u8 bPseudoTest) ++{ ++#ifdef HAL_EFUSE_MEMORY ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; ++#endif ++ u16 btusedbytes; ++ u16 efuse_addr; ++ u8 bank, startBank; ++ u8 hoffset = 0, hworden = 0; ++ u8 efuse_data, word_cnts = 0; ++ u16 retU2 = 0; ++ ++ if (bPseudoTest) { ++#ifdef HAL_EFUSE_MEMORY ++ btusedbytes = pEfuseHal->fakeBTEfuseUsedBytes; ++#else ++ btusedbytes = fakeBTEfuseUsedBytes; ++#endif ++ } ++ else ++ { ++ rtw_hal_get_hwreg(padapter, HW_VAR_EFUSE_BT_BYTES, (u8 *)&btusedbytes); ++ } ++ efuse_addr = (u16)((btusedbytes%EFUSE_BT_REAL_BANK_CONTENT_LEN)); ++ startBank = (u8)(1+(btusedbytes/EFUSE_BT_REAL_BANK_CONTENT_LEN)); ++ ++ DBG_8192C("%s: start from bank =%d addr = 0x%X\n", __func__, startBank, efuse_addr); ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &retU2, bPseudoTest); ++ ++ for (bank =startBank; bank<3; bank++) ++ { ++ if (hal_EfuseSwitchToBank(padapter, bank, bPseudoTest) == false) ++ { ++ DBG_8192C(KERN_ERR "%s: switch bank(%d) Fail!!\n", __func__, bank); ++ /* bank = EFUSE_MAX_BANK; */ ++ break; ++ } ++ ++ /* only when bank is switched we have to reset the efuse_addr. */ ++ if (bank != startBank) ++ efuse_addr = 0; ++#if 1 ++ ++ while (AVAILABLE_EFUSE_ADDR(efuse_addr)) ++ { ++ if (efuse_OneByteRead(padapter, efuse_addr, &efuse_data, bPseudoTest) == false) ++ { ++ DBG_8192C(KERN_ERR "%s: efuse_OneByteRead Fail! addr = 0x%X !!\n", __func__, efuse_addr); ++ /* bank = EFUSE_MAX_BANK; */ ++ break; ++ } ++ DBG_8192C("%s: efuse_OneByteRead ! addr = 0x%X !efuse_data = 0x%X! bank =%d\n", __func__, efuse_addr, efuse_data, bank); ++ ++ if (efuse_data == 0xFF) break; ++ ++ if (EXT_HEADER(efuse_data)) ++ { ++ hoffset = GET_HDR_OFFSET_2_0(efuse_data); ++ efuse_addr++; ++ efuse_OneByteRead(padapter, efuse_addr, &efuse_data, bPseudoTest); ++ DBG_8192C("%s: efuse_OneByteRead EXT_HEADER ! addr = 0x%X !efuse_data = 0x%X! bank =%d\n", __func__, efuse_addr, efuse_data, bank); ++ ++ if (ALL_WORDS_DISABLED(efuse_data)) ++ { ++ efuse_addr++; ++ continue; ++ } ++ ++/* hoffset = ((hoffset & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); */ ++ hoffset |= ((efuse_data & 0xF0) >> 1); ++ hworden = efuse_data & 0x0F; ++ } ++ else ++ { ++ hoffset = (efuse_data>>4) & 0x0F; ++ hworden = efuse_data & 0x0F; ++ } ++ ++ DBG_8192C(FUNC_ADPT_FMT": Offset =%d Worden =%#X\n", ++ FUNC_ADPT_ARG(padapter), hoffset, hworden); ++ ++ word_cnts = Efuse_CalculateWordCnts(hworden); ++ /* read next header */ ++ efuse_addr += (word_cnts*2)+1; ++ } ++#else ++ while (bContinual && ++ efuse_OneByteRead(padapter, efuse_addr ,&efuse_data, bPseudoTest) && ++ AVAILABLE_EFUSE_ADDR(efuse_addr)) ++ { ++ if (efuse_data!= 0xFF) ++ { ++ if ((efuse_data&0x1F) == 0x0F) /* extended header */ ++ { ++ hoffset = efuse_data; ++ efuse_addr++; ++ efuse_OneByteRead(padapter, efuse_addr ,&efuse_data, bPseudoTest); ++ if ((efuse_data & 0x0F) == 0x0F) ++ { ++ efuse_addr++; ++ continue; ++ } ++ else ++ { ++ hoffset = ((hoffset & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); ++ hworden = efuse_data & 0x0F; ++ } ++ } ++ else ++ { ++ hoffset = (efuse_data>>4) & 0x0F; ++ hworden = efuse_data & 0x0F; ++ } ++ word_cnts = Efuse_CalculateWordCnts(hworden); ++ /* read next header */ ++ efuse_addr = efuse_addr + (word_cnts*2)+1; ++ } ++ else ++ { ++ bContinual = false ; ++ } ++ } ++#endif ++ ++ ++ /* Check if we need to check next bank efuse */ ++ if (efuse_addr < retU2) ++ { ++ break;/* don't need to check next bank. */ ++ } ++ } ++ ++ retU2 = ((bank-1)*EFUSE_BT_REAL_BANK_CONTENT_LEN)+efuse_addr; ++ if (bPseudoTest) ++ { ++ pEfuseHal->fakeBTEfuseUsedBytes = retU2; ++ /* RT_DISP(FEEPROM, EFUSE_PG, ("Hal_EfuseGetCurrentSize_BT92C(), already use %u bytes\n", pEfuseHal->fakeBTEfuseUsedBytes)); */ ++ } ++ else ++ { ++ pEfuseHal->BTEfuseUsedBytes = retU2; ++ /* RT_DISP(FEEPROM, EFUSE_PG, ("Hal_EfuseGetCurrentSize_BT92C(), already use %u bytes\n", pEfuseHal->BTEfuseUsedBytes)); */ ++ } ++ ++ DBG_8192C("%s: CurrentSize =%d\n", __func__, retU2); ++ return retU2; ++} ++ ++static u16 ++Hal_EfuseGetCurrentSize( ++ struct adapter *padapter, ++ u8 efuseType, ++ bool bPseudoTest) ++{ ++ u16 ret = 0; ++ ++ if (efuseType == EFUSE_WIFI) ++ ret = hal_EfuseGetCurrentSize_WiFi(padapter, bPseudoTest); ++ else ++ ret = hal_EfuseGetCurrentSize_BT(padapter, bPseudoTest); ++ ++ return ret; ++} ++ ++static u8 ++Hal_EfuseWordEnableDataWrite( ++ struct adapter *padapter, ++ u16 efuse_addr, ++ u8 word_en, ++ u8 *data, ++ bool bPseudoTest) ++{ ++ u16 tmpaddr = 0; ++ u16 start_addr = efuse_addr; ++ u8 badworden = 0x0F; ++ u8 tmpdata[PGPKT_DATA_SIZE]; ++ ++ ++/* DBG_8192C("%s: efuse_addr =%#x word_en =%#x\n", __func__, efuse_addr, word_en); */ ++ memset(tmpdata, 0xFF, PGPKT_DATA_SIZE); ++ ++ if (!(word_en & BIT(0))) ++ { ++ tmpaddr = start_addr; ++ efuse_OneByteWrite(padapter, start_addr++, data[0], bPseudoTest); ++ efuse_OneByteWrite(padapter, start_addr++, data[1], bPseudoTest); ++ ++ efuse_OneByteRead(padapter, tmpaddr, &tmpdata[0], bPseudoTest); ++ efuse_OneByteRead(padapter, tmpaddr+1, &tmpdata[1], bPseudoTest); ++ if ((data[0]!=tmpdata[0]) || (data[1]!=tmpdata[1])) { ++ badworden &= (~BIT(0)); ++ } ++ } ++ if (!(word_en & BIT(1))) ++ { ++ tmpaddr = start_addr; ++ efuse_OneByteWrite(padapter, start_addr++, data[2], bPseudoTest); ++ efuse_OneByteWrite(padapter, start_addr++, data[3], bPseudoTest); ++ ++ efuse_OneByteRead(padapter, tmpaddr, &tmpdata[2], bPseudoTest); ++ efuse_OneByteRead(padapter, tmpaddr+1, &tmpdata[3], bPseudoTest); ++ if ((data[2]!=tmpdata[2]) || (data[3]!=tmpdata[3])) { ++ badworden &= (~BIT(1)); ++ } ++ } ++ if (!(word_en & BIT(2))) ++ { ++ tmpaddr = start_addr; ++ efuse_OneByteWrite(padapter, start_addr++, data[4], bPseudoTest); ++ efuse_OneByteWrite(padapter, start_addr++, data[5], bPseudoTest); ++ ++ efuse_OneByteRead(padapter, tmpaddr, &tmpdata[4], bPseudoTest); ++ efuse_OneByteRead(padapter, tmpaddr+1, &tmpdata[5], bPseudoTest); ++ if ((data[4]!=tmpdata[4]) || (data[5]!=tmpdata[5])) { ++ badworden &= (~BIT(2)); ++ } ++ } ++ if (!(word_en & BIT(3))) ++ { ++ tmpaddr = start_addr; ++ efuse_OneByteWrite(padapter, start_addr++, data[6], bPseudoTest); ++ efuse_OneByteWrite(padapter, start_addr++, data[7], bPseudoTest); ++ ++ efuse_OneByteRead(padapter, tmpaddr, &tmpdata[6], bPseudoTest); ++ efuse_OneByteRead(padapter, tmpaddr+1, &tmpdata[7], bPseudoTest); ++ if ((data[6]!=tmpdata[6]) || (data[7]!=tmpdata[7])) { ++ badworden &= (~BIT(3)); ++ } ++ } ++ ++ return badworden; ++} ++ ++static s32 ++Hal_EfusePgPacketRead( ++ struct adapter *padapter, ++ u8 offset, ++ u8 *data, ++ bool bPseudoTest) ++{ ++ u8 efuse_data, word_cnts = 0; ++ u16 efuse_addr = 0; ++ u8 hoffset = 0, hworden = 0; ++ u8 i; ++ u8 max_section = 0; ++ s32 ret; ++ ++ ++ if (data == NULL) ++ return false; ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAX_SECTION, &max_section, bPseudoTest); ++ if (offset > max_section) ++ { ++ DBG_8192C("%s: Packet offset(%d) is illegal(>%d)!\n", __func__, offset, max_section); ++ return false; ++ } ++ ++ memset(data, 0xFF, PGPKT_DATA_SIZE); ++ ret = true; ++ ++ /* */ ++ /* Efuse has been pre-programmed dummy 5Bytes at the end of Efuse by CP. */ ++ /* Skip dummy parts to prevent unexpected data read from Efuse. */ ++ /* By pass right now. 2009.02.19. */ ++ /* */ ++ while (AVAILABLE_EFUSE_ADDR(efuse_addr)) ++ { ++ if (efuse_OneByteRead(padapter, efuse_addr++, &efuse_data, bPseudoTest) == false) ++ { ++ ret = false; ++ break; ++ } ++ ++ if (efuse_data == 0xFF) break; ++ ++ if (EXT_HEADER(efuse_data)) ++ { ++ hoffset = GET_HDR_OFFSET_2_0(efuse_data); ++ efuse_OneByteRead(padapter, efuse_addr++, &efuse_data, bPseudoTest); ++ if (ALL_WORDS_DISABLED(efuse_data)) ++ { ++ DBG_8192C("%s: Error!! All words disabled!\n", __func__); ++ continue; ++ } ++ ++ hoffset |= ((efuse_data & 0xF0) >> 1); ++ hworden = efuse_data & 0x0F; ++ } ++ else ++ { ++ hoffset = (efuse_data>>4) & 0x0F; ++ hworden = efuse_data & 0x0F; ++ } ++ ++ if (hoffset == offset) ++ { ++ for (i = 0; i= max_available) ++ { ++ DBG_8192C("%s: Error!! current_size(%d)>max_available(%d)\n", __func__, current_size, max_available); ++ return false; ++ } ++ return true; ++} ++ ++static void ++hal_EfuseConstructPGPkt( ++ u8 offset, ++ u8 word_en, ++ u8 *pData, ++ PPGPKT_STRUCT pTargetPkt) ++{ ++ memset(pTargetPkt->data, 0xFF, PGPKT_DATA_SIZE); ++ pTargetPkt->offset = offset; ++ pTargetPkt->word_en = word_en; ++ efuse_WordEnableDataRead(word_en, pData, pTargetPkt->data); ++ pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en); ++} ++ ++static u8 ++hal_EfusePartialWriteCheck( ++ struct adapter * padapter, ++ u8 efuseType, ++ u16 *pAddr, ++ PPGPKT_STRUCT pTargetPkt, ++ u8 bPseudoTest) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; ++ u8 bRet =false; ++ u16 startAddr = 0, efuse_max_available_len = 0, efuse_max = 0; ++ u8 efuse_data = 0; ++ ++ EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &efuse_max_available_len, bPseudoTest); ++ EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_CONTENT_LEN_BANK, &efuse_max, bPseudoTest); ++ ++ if (efuseType == EFUSE_WIFI) ++ { ++ if (bPseudoTest) ++ { ++#ifdef HAL_EFUSE_MEMORY ++ startAddr = (u16)pEfuseHal->fakeEfuseUsedBytes; ++#else ++ startAddr = (u16)fakeEfuseUsedBytes; ++#endif ++ } ++ else ++ { ++ rtw_hal_get_hwreg(padapter, HW_VAR_EFUSE_BYTES, (u8 *)&startAddr); ++ } ++ } ++ else ++ { ++ if (bPseudoTest) ++ { ++#ifdef HAL_EFUSE_MEMORY ++ startAddr = (u16)pEfuseHal->fakeBTEfuseUsedBytes; ++#else ++ startAddr = (u16)fakeBTEfuseUsedBytes; ++#endif ++ } ++ else ++ { ++ rtw_hal_get_hwreg(padapter, HW_VAR_EFUSE_BT_BYTES, (u8 *)&startAddr); ++ } ++ } ++ startAddr %= efuse_max; ++ DBG_8192C("%s: startAddr =%#X\n", __func__, startAddr); ++ ++ while (1) ++ { ++ if (startAddr >= efuse_max_available_len) ++ { ++ bRet = false; ++ DBG_8192C("%s: startAddr(%d) >= efuse_max_available_len(%d)\n", ++ __func__, startAddr, efuse_max_available_len); ++ break; ++ } ++ ++ if (efuse_OneByteRead(padapter, startAddr, &efuse_data, bPseudoTest) && (efuse_data!= 0xFF)) ++ { ++#if 1 ++ bRet = false; ++ DBG_8192C("%s: Something Wrong! last bytes(%#X = 0x%02X) is not 0xFF\n", ++ __func__, startAddr, efuse_data); ++ break; ++#else ++ if (EXT_HEADER(efuse_data)) ++ { ++ cur_header = efuse_data; ++ startAddr++; ++ efuse_OneByteRead(padapter, startAddr, &efuse_data, bPseudoTest); ++ if (ALL_WORDS_DISABLED(efuse_data)) ++ { ++ DBG_8192C("%s: Error condition, all words disabled!", __func__); ++ bRet = false; ++ break; ++ } ++ else ++ { ++ curPkt.offset = ((cur_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); ++ curPkt.word_en = efuse_data & 0x0F; ++ } ++ } ++ else ++ { ++ cur_header = efuse_data; ++ curPkt.offset = (cur_header>>4) & 0x0F; ++ curPkt.word_en = cur_header & 0x0F; ++ } ++ ++ curPkt.word_cnts = Efuse_CalculateWordCnts(curPkt.word_en); ++ /* if same header is found but no data followed */ ++ /* write some part of data followed by the header. */ ++ if ((curPkt.offset == pTargetPkt->offset) && ++ (hal_EfuseCheckIfDatafollowed(padapter, curPkt.word_cnts, startAddr+1, bPseudoTest) == false) && ++ wordEnMatched(pTargetPkt, &curPkt, &matched_wden) == true) ++ { ++ DBG_8192C("%s: Need to partial write data by the previous wrote header\n", __func__); ++ /* Here to write partial data */ ++ badworden = Efuse_WordEnableDataWrite(padapter, startAddr+1, matched_wden, pTargetPkt->data, bPseudoTest); ++ if (badworden != 0x0F) ++ { ++ u32 PgWriteSuccess = 0; ++ /* if write fail on some words, write these bad words again */ ++ if (efuseType == EFUSE_WIFI) ++ PgWriteSuccess = Efuse_PgPacketWrite(padapter, pTargetPkt->offset, badworden, pTargetPkt->data, bPseudoTest); ++ else ++ PgWriteSuccess = Efuse_PgPacketWrite_BT(padapter, pTargetPkt->offset, badworden, pTargetPkt->data, bPseudoTest); ++ ++ if (!PgWriteSuccess) ++ { ++ bRet = false; /* write fail, return */ ++ break; ++ } ++ } ++ /* partial write ok, update the target packet for later use */ ++ for (i = 0; i<4; i++) ++ { ++ if ((matched_wden & (0x1<word_en |= (0x1<word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en); ++ } ++ /* read from next header */ ++ startAddr = startAddr + (curPkt.word_cnts*2) + 1; ++#endif ++ } ++ else ++ { ++ /* not used header, 0xff */ ++ *pAddr = startAddr; ++/* DBG_8192C("%s: Started from unused header offset =%d\n", __func__, startAddr)); */ ++ bRet = true; ++ break; ++ } ++ } ++ ++ return bRet; ++} ++ ++static u8 ++hal_EfusePgPacketWrite1ByteHeader( ++ struct adapter * padapter, ++ u8 efuseType, ++ u16 *pAddr, ++ PPGPKT_STRUCT pTargetPkt, ++ u8 bPseudoTest) ++{ ++ u8 pg_header = 0, tmp_header = 0; ++ u16 efuse_addr =*pAddr; ++ u8 repeatcnt = 0; ++ ++ ++/* DBG_8192C("%s\n", __func__); */ ++ pg_header = ((pTargetPkt->offset << 4) & 0xf0) | pTargetPkt->word_en; ++ ++ do { ++ efuse_OneByteWrite(padapter, efuse_addr, pg_header, bPseudoTest); ++ efuse_OneByteRead(padapter, efuse_addr, &tmp_header, bPseudoTest); ++ if (tmp_header != 0xFF) break; ++ if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) ++ { ++ DBG_8192C("%s: Repeat over limit for pg_header!!\n", __func__); ++ return false; ++ } ++ } while (1); ++ ++ if (tmp_header != pg_header) ++ { ++ DBG_8192C(KERN_ERR "%s: PG Header Fail!!(pg = 0x%02X read = 0x%02X)\n", __func__, pg_header, tmp_header); ++ return false; ++ } ++ ++ *pAddr = efuse_addr; ++ ++ return true; ++} ++ ++static u8 ++hal_EfusePgPacketWrite2ByteHeader( ++ struct adapter * padapter, ++ u8 efuseType, ++ u16 *pAddr, ++ PPGPKT_STRUCT pTargetPkt, ++ u8 bPseudoTest) ++{ ++ u16 efuse_addr, efuse_max_available_len = 0; ++ u8 pg_header = 0, tmp_header = 0; ++ u8 repeatcnt = 0; ++ ++ ++/* DBG_8192C("%s\n", __func__); */ ++ EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &efuse_max_available_len, bPseudoTest); ++ ++ efuse_addr = *pAddr; ++ if (efuse_addr >= efuse_max_available_len) ++ { ++ DBG_8192C("%s: addr(%d) over avaliable(%d)!!\n", __func__, efuse_addr, efuse_max_available_len); ++ return false; ++ } ++ ++ pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F; ++/* DBG_8192C("%s: pg_header = 0x%x\n", __func__, pg_header); */ ++ ++ do { ++ efuse_OneByteWrite(padapter, efuse_addr, pg_header, bPseudoTest); ++ efuse_OneByteRead(padapter, efuse_addr, &tmp_header, bPseudoTest); ++ if (tmp_header != 0xFF) break; ++ if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) ++ { ++ DBG_8192C("%s: Repeat over limit for pg_header!!\n", __func__); ++ return false; ++ } ++ } while (1); ++ ++ if (tmp_header != pg_header) ++ { ++ DBG_8192C(KERN_ERR "%s: PG Header Fail!!(pg = 0x%02X read = 0x%02X)\n", __func__, pg_header, tmp_header); ++ return false; ++ } ++ ++ /* to write ext_header */ ++ efuse_addr++; ++ pg_header = ((pTargetPkt->offset & 0x78) << 1) | pTargetPkt->word_en; ++ ++ do { ++ efuse_OneByteWrite(padapter, efuse_addr, pg_header, bPseudoTest); ++ efuse_OneByteRead(padapter, efuse_addr, &tmp_header, bPseudoTest); ++ if (tmp_header != 0xFF) break; ++ if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) ++ { ++ DBG_8192C("%s: Repeat over limit for ext_header!!\n", __func__); ++ return false; ++ } ++ } while (1); ++ ++ if (tmp_header != pg_header) /* offset PG fail */ ++ { ++ DBG_8192C(KERN_ERR "%s: PG EXT Header Fail!!(pg = 0x%02X read = 0x%02X)\n", __func__, pg_header, tmp_header); ++ return false; ++ } ++ ++ *pAddr = efuse_addr; ++ ++ return true; ++} ++ ++static u8 ++hal_EfusePgPacketWriteHeader( ++ struct adapter * padapter, ++ u8 efuseType, ++ u16 *pAddr, ++ PPGPKT_STRUCT pTargetPkt, ++ u8 bPseudoTest) ++{ ++ u8 bRet =false; ++ ++ if (pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE) ++ { ++ bRet = hal_EfusePgPacketWrite2ByteHeader(padapter, efuseType, pAddr, pTargetPkt, bPseudoTest); ++ } ++ else ++ { ++ bRet = hal_EfusePgPacketWrite1ByteHeader(padapter, efuseType, pAddr, pTargetPkt, bPseudoTest); ++ } ++ ++ return bRet; ++} ++ ++static u8 ++hal_EfusePgPacketWriteData( ++ struct adapter * padapter, ++ u8 efuseType, ++ u16 *pAddr, ++ PPGPKT_STRUCT pTargetPkt, ++ u8 bPseudoTest) ++{ ++ u16 efuse_addr; ++ u8 badworden; ++ ++ ++ efuse_addr = *pAddr; ++ badworden = Efuse_WordEnableDataWrite(padapter, efuse_addr+1, pTargetPkt->word_en, pTargetPkt->data, bPseudoTest); ++ if (badworden != 0x0F) ++ { ++ DBG_8192C("%s: Fail!!\n", __func__); ++ return false; ++ } ++ ++/* DBG_8192C("%s: ok\n", __func__); */ ++ return true; ++} ++ ++static s32 ++Hal_EfusePgPacketWrite( ++ struct adapter *padapter, ++ u8 offset, ++ u8 word_en, ++ u8 *pData, ++ bool bPseudoTest) ++{ ++ PGPKT_STRUCT targetPkt; ++ u16 startAddr = 0; ++ u8 efuseType =EFUSE_WIFI; ++ ++ if (!hal_EfusePgCheckAvailableAddr(padapter, efuseType, bPseudoTest)) ++ return false; ++ ++ hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt); ++ ++ if (!hal_EfusePartialWriteCheck(padapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) ++ return false; ++ ++ if (!hal_EfusePgPacketWriteHeader(padapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) ++ return false; ++ ++ if (!hal_EfusePgPacketWriteData(padapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) ++ return false; ++ ++ return true; ++} ++ ++static bool ++Hal_EfusePgPacketWrite_BT( ++ struct adapter *padapter, ++ u8 offset, ++ u8 word_en, ++ u8 *pData, ++ bool bPseudoTest) ++{ ++ PGPKT_STRUCT targetPkt; ++ u16 startAddr = 0; ++ u8 efuseType =EFUSE_BT; ++ ++ if (!hal_EfusePgCheckAvailableAddr(padapter, efuseType, bPseudoTest)) ++ return false; ++ ++ hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt); ++ ++ if (!hal_EfusePartialWriteCheck(padapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) ++ return false; ++ ++ if (!hal_EfusePgPacketWriteHeader(padapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) ++ return false; ++ ++ if (!hal_EfusePgPacketWriteData(padapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) ++ return false; ++ ++ return true; ++} ++ ++static HAL_VERSION ++ReadChipVersion8723B( ++struct adapter *padapter ++ ) ++{ ++ u32 value32; ++ HAL_VERSION ChipVersion; ++ struct hal_com_data *pHalData; ++ ++/* YJ, TODO, move read chip type here */ ++ pHalData = GET_HAL_DATA(padapter); ++ ++ value32 = rtw_read32(padapter, REG_SYS_CFG); ++ ChipVersion.ICType = CHIP_8723B; ++ ChipVersion.ChipType = ((value32 & RTL_ID) ? TEST_CHIP : NORMAL_CHIP); ++ ChipVersion.RFType = RF_TYPE_1T1R ; ++ ChipVersion.VendorType = ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : CHIP_VENDOR_TSMC); ++ ChipVersion.CUTVersion = (value32 & CHIP_VER_RTL_MASK)>>CHIP_VER_RTL_SHIFT; /* IC version (CUT) */ ++ ++ /* For regulator mode. by tynli. 2011.01.14 */ ++ pHalData->RegulatorMode = ((value32 & SPS_SEL) ? RT_LDO_REGULATOR : RT_SWITCHING_REGULATOR); ++ ++ value32 = rtw_read32(padapter, REG_GPIO_OUTSTS); ++ ChipVersion.ROMVer = ((value32 & RF_RL_ID) >> 20); /* ROM code version. */ ++ ++ /* For multi-function consideration. Added by Roger, 2010.10.06. */ ++ pHalData->MultiFunc = RT_MULTI_FUNC_NONE; ++ value32 = rtw_read32(padapter, REG_MULTI_FUNC_CTRL); ++ pHalData->MultiFunc |= ((value32 & WL_FUNC_EN) ? RT_MULTI_FUNC_WIFI : 0); ++ pHalData->MultiFunc |= ((value32 & BT_FUNC_EN) ? RT_MULTI_FUNC_BT : 0); ++ pHalData->MultiFunc |= ((value32 & GPS_FUNC_EN) ? RT_MULTI_FUNC_GPS : 0); ++ pHalData->PolarityCtl = ((value32 & WL_HWPDN_SL) ? RT_POLARITY_HIGH_ACT : RT_POLARITY_LOW_ACT); ++#if 1 ++ dump_chip_info(ChipVersion); ++#endif ++ pHalData->VersionID = ChipVersion; ++ if (IS_1T2R(ChipVersion)) ++ pHalData->rf_type = RF_1T2R; ++ else if (IS_2T2R(ChipVersion)) ++ pHalData->rf_type = RF_2T2R; ++ else ++ pHalData->rf_type = RF_1T1R; ++ ++ MSG_8192C("RF_Type is %x!!\n", pHalData->rf_type); ++ ++ return ChipVersion; ++} ++ ++static void rtl8723b_read_chip_version(struct adapter *padapter) ++{ ++ ReadChipVersion8723B(padapter); ++} ++ ++void rtl8723b_InitBeaconParameters(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ u16 val16; ++ u8 val8; ++ ++ ++ val8 = DIS_TSF_UDT; ++ val16 = val8 | (val8 << 8); /* port0 and port1 */ ++ ++ /* Enable prot0 beacon function for PSTDMA */ ++ val16 |= EN_BCN_FUNCTION; ++ ++ rtw_write16(padapter, REG_BCN_CTRL, val16); ++ ++ /* TODO: Remove these magic number */ ++ rtw_write16(padapter, REG_TBTT_PROHIBIT, 0x6404);/* ms */ ++ /* Firmware will control REG_DRVERLYINT when power saving is enable, */ ++ /* so don't set this register on STA mode. */ ++ if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE) == false) ++ rtw_write8(padapter, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME_8723B); /* 5ms */ ++ rtw_write8(padapter, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME_8723B); /* 2ms */ ++ ++ /* Suggested by designer timchen. Change beacon AIFS to the largest number */ ++ /* beacause test chip does not contension before sending beacon. by tynli. 2009.11.03 */ ++ rtw_write16(padapter, REG_BCNTCFG, 0x660F); ++ ++ pHalData->RegBcnCtrlVal = rtw_read8(padapter, REG_BCN_CTRL); ++ pHalData->RegTxPause = rtw_read8(padapter, REG_TXPAUSE); ++ pHalData->RegFwHwTxQCtrl = rtw_read8(padapter, REG_FWHW_TXQ_CTRL+2); ++ pHalData->RegReg542 = rtw_read8(padapter, REG_TBTT_PROHIBIT+2); ++ pHalData->RegCR_1 = rtw_read8(padapter, REG_CR+1); ++} ++ ++void _InitBurstPktLen_8723BS(struct adapter * Adapter) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++ rtw_write8(Adapter, 0x4c7, rtw_read8(Adapter, 0x4c7)|BIT(7)); /* enable single pkt ampdu */ ++ rtw_write8(Adapter, REG_RX_PKT_LIMIT_8723B, 0x18); /* for VHT packet length 11K */ ++ rtw_write8(Adapter, REG_MAX_AGGR_NUM_8723B, 0x1F); ++ rtw_write8(Adapter, REG_PIFS_8723B, 0x00); ++ rtw_write8(Adapter, REG_FWHW_TXQ_CTRL_8723B, rtw_read8(Adapter, REG_FWHW_TXQ_CTRL)&(~BIT(7))); ++ if (pHalData->AMPDUBurstMode) ++ { ++ rtw_write8(Adapter, REG_AMPDU_BURST_MODE_8723B, 0x5F); ++ } ++ rtw_write8(Adapter, REG_AMPDU_MAX_TIME_8723B, 0x70); ++ ++ /* ARFB table 9 for 11ac 5G 2SS */ ++ rtw_write32(Adapter, REG_ARFR0_8723B, 0x00000010); ++ if (IS_NORMAL_CHIP(pHalData->VersionID)) ++ rtw_write32(Adapter, REG_ARFR0_8723B+4, 0xfffff000); ++ else ++ rtw_write32(Adapter, REG_ARFR0_8723B+4, 0x3e0ff000); ++ ++ /* ARFB table 10 for 11ac 5G 1SS */ ++ rtw_write32(Adapter, REG_ARFR1_8723B, 0x00000010); ++ rtw_write32(Adapter, REG_ARFR1_8723B+4, 0x003ff000); ++} ++ ++static void ResumeTxBeacon(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ ++ ++ /* 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */ ++ /* which should be read from register to a global variable. */ ++ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("+ResumeTxBeacon\n")); ++ ++ pHalData->RegFwHwTxQCtrl |= BIT(6); ++ rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl); ++ rtw_write8(padapter, REG_TBTT_PROHIBIT+1, 0xff); ++ pHalData->RegReg542 |= BIT(0); ++ rtw_write8(padapter, REG_TBTT_PROHIBIT+2, pHalData->RegReg542); ++} ++ ++static void StopTxBeacon(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ ++ ++ /* 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */ ++ /* which should be read from register to a global variable. */ ++ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("+StopTxBeacon\n")); ++ ++ pHalData->RegFwHwTxQCtrl &= ~BIT(6); ++ rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl); ++ rtw_write8(padapter, REG_TBTT_PROHIBIT+1, 0x64); ++ pHalData->RegReg542 &= ~BIT(0); ++ rtw_write8(padapter, REG_TBTT_PROHIBIT+2, pHalData->RegReg542); ++ ++ CheckFwRsvdPageContent(padapter); /* 2010.06.23. Added by tynli. */ ++} ++ ++static void _BeaconFunctionEnable(struct adapter *padapter, u8 Enable, u8 Linked) ++{ ++ rtw_write8(padapter, REG_BCN_CTRL, DIS_TSF_UDT | EN_BCN_FUNCTION | DIS_BCNQ_SUB); ++ rtw_write8(padapter, REG_RD_CTRL+1, 0x6F); ++} ++ ++static void rtl8723b_SetBeaconRelatedRegisters(struct adapter *padapter) ++{ ++ u8 val8; ++ u32 value32; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ u32 bcn_ctrl_reg; ++ ++ /* reset TSF, enable update TSF, correcting TSF On Beacon */ ++ ++ /* REG_BCN_INTERVAL */ ++ /* REG_BCNDMATIM */ ++ /* REG_ATIMWND */ ++ /* REG_TBTT_PROHIBIT */ ++ /* REG_DRVERLYINT */ ++ /* REG_BCN_MAX_ERR */ ++ /* REG_BCNTCFG (0x510) */ ++ /* REG_DUAL_TSF_RST */ ++ /* REG_BCN_CTRL (0x550) */ ++ ++ ++ bcn_ctrl_reg = REG_BCN_CTRL; ++ ++ /* */ ++ /* ATIM window */ ++ /* */ ++ rtw_write16(padapter, REG_ATIMWND, 2); ++ ++ /* */ ++ /* Beacon interval (in unit of TU). */ ++ /* */ ++ rtw_write16(padapter, REG_BCN_INTERVAL, pmlmeinfo->bcn_interval); ++ ++ rtl8723b_InitBeaconParameters(padapter); ++ ++ rtw_write8(padapter, REG_SLOT, 0x09); ++ ++ /* */ ++ /* Reset TSF Timer to zero, added by Roger. 2008.06.24 */ ++ /* */ ++ value32 = rtw_read32(padapter, REG_TCR); ++ value32 &= ~TSFRST; ++ rtw_write32(padapter, REG_TCR, value32); ++ ++ value32 |= TSFRST; ++ rtw_write32(padapter, REG_TCR, value32); ++ ++ /* NOTE: Fix test chip's bug (about contention windows's randomness) */ ++ if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE) == true) ++ { ++ rtw_write8(padapter, REG_RXTSF_OFFSET_CCK, 0x50); ++ rtw_write8(padapter, REG_RXTSF_OFFSET_OFDM, 0x50); ++ } ++ ++ _BeaconFunctionEnable(padapter, true, true); ++ ++ ResumeTxBeacon(padapter); ++ val8 = rtw_read8(padapter, bcn_ctrl_reg); ++ val8 |= DIS_BCNQ_SUB; ++ rtw_write8(padapter, bcn_ctrl_reg, val8); ++} ++ ++static void rtl8723b_GetHalODMVar( ++ struct adapter * Adapter, ++ enum HAL_ODM_VARIABLE eVariable, ++ void * pValue1, ++ void * pValue2) ++{ ++ GetHalODMVar(Adapter, eVariable, pValue1, pValue2); ++} ++ ++static void rtl8723b_SetHalODMVar( ++ struct adapter * Adapter, ++ enum HAL_ODM_VARIABLE eVariable, ++ void * pValue1, ++ bool bSet) ++{ ++ SetHalODMVar(Adapter, eVariable, pValue1, bSet); ++} ++ ++static void hal_notch_filter_8723b(struct adapter *adapter, bool enable) ++{ ++ if (enable) { ++ DBG_871X("Enable notch filter\n"); ++ rtw_write8(adapter, rOFDM0_RxDSP+1, rtw_read8(adapter, rOFDM0_RxDSP+1) | BIT1); ++ } else { ++ DBG_871X("Disable notch filter\n"); ++ rtw_write8(adapter, rOFDM0_RxDSP+1, rtw_read8(adapter, rOFDM0_RxDSP+1) & ~BIT1); ++ } ++} ++ ++static void UpdateHalRAMask8723B(struct adapter *padapter, u32 mac_id, u8 rssi_level) ++{ ++ u32 mask, rate_bitmap; ++ u8 shortGIrate = false; ++ struct sta_info *psta; ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ DBG_871X("%s(): mac_id =%d rssi_level =%d\n", __func__, mac_id, rssi_level); ++ ++ if (mac_id >= NUM_STA) /* CAM_SIZE */ ++ { ++ return; ++ } ++ ++ psta = pmlmeinfo->FW_sta_info[mac_id].psta; ++ if (psta == NULL) ++ { ++ return; ++ } ++ ++ shortGIrate = query_ra_short_GI(psta); ++ ++ mask = psta->ra_mask; ++ ++ rate_bitmap = 0xffffffff; ++ rate_bitmap = ODM_Get_Rate_Bitmap(&pHalData->odmpriv, mac_id, mask, rssi_level); ++ DBG_871X("%s => mac_id:%d, networkType:0x%02x, mask:0x%08x\n\t ==> rssi_level:%d, rate_bitmap:0x%08x\n", ++ __func__, mac_id, psta->wireless_mode, mask, rssi_level, rate_bitmap); ++ ++ mask &= rate_bitmap; ++ ++ rate_bitmap = rtw_btcoex_GetRaMask(padapter); ++ mask &= ~rate_bitmap; ++ ++#ifdef CONFIG_CMCC_TEST ++ if (pmlmeext->cur_wireless_mode & WIRELESS_11G) { ++ if (mac_id == 0) { ++ DBG_871X("CMCC_BT update raid entry, mask = 0x%x\n", mask); ++ mask &= 0xffffff00; /* disable CCK & <24M OFDM rate for 11G mode for CMCC */ ++ DBG_871X("CMCC_BT update raid entry, mask = 0x%x\n", mask); ++ } ++ } ++#endif ++ ++ if (pHalData->fw_ractrl == true) ++ { ++ rtl8723b_set_FwMacIdConfig_cmd(padapter, mac_id, psta->raid, psta->bw_mode, shortGIrate, mask); ++ } ++ ++ /* set correct initial date rate for each mac_id */ ++ pdmpriv->INIDATA_RATE[mac_id] = psta->init_rate; ++ DBG_871X("%s(): mac_id =%d raid = 0x%x bw =%d mask = 0x%x init_rate = 0x%x\n", __func__, mac_id, psta->raid, psta->bw_mode, mask, psta->init_rate); ++} ++ ++ ++void rtl8723b_set_hal_ops(struct hal_ops *pHalFunc) ++{ ++ pHalFunc->free_hal_data = &rtl8723b_free_hal_data; ++ ++ pHalFunc->dm_init = &rtl8723b_init_dm_priv; ++ ++ pHalFunc->read_chip_version = &rtl8723b_read_chip_version; ++ ++ pHalFunc->UpdateRAMaskHandler = &UpdateHalRAMask8723B; ++ ++ pHalFunc->set_bwmode_handler = &PHY_SetBWMode8723B; ++ pHalFunc->set_channel_handler = &PHY_SwChnl8723B; ++ pHalFunc->set_chnl_bw_handler = &PHY_SetSwChnlBWMode8723B; ++ ++ pHalFunc->set_tx_power_level_handler = &PHY_SetTxPowerLevel8723B; ++ pHalFunc->get_tx_power_level_handler = &PHY_GetTxPowerLevel8723B; ++ ++ pHalFunc->hal_dm_watchdog = &rtl8723b_HalDmWatchDog; ++ pHalFunc->hal_dm_watchdog_in_lps = &rtl8723b_HalDmWatchDog_in_LPS; ++ ++ ++ pHalFunc->SetBeaconRelatedRegistersHandler = &rtl8723b_SetBeaconRelatedRegisters; ++ ++ pHalFunc->Add_RateATid = &rtl8723b_Add_RateATid; ++ ++ pHalFunc->run_thread = &rtl8723b_start_thread; ++ pHalFunc->cancel_thread = &rtl8723b_stop_thread; ++ ++ pHalFunc->read_bbreg = &PHY_QueryBBReg_8723B; ++ pHalFunc->write_bbreg = &PHY_SetBBReg_8723B; ++ pHalFunc->read_rfreg = &PHY_QueryRFReg_8723B; ++ pHalFunc->write_rfreg = &PHY_SetRFReg_8723B; ++ ++ /* Efuse related function */ ++ pHalFunc->BTEfusePowerSwitch = &Hal_BT_EfusePowerSwitch; ++ pHalFunc->EfusePowerSwitch = &Hal_EfusePowerSwitch; ++ pHalFunc->ReadEFuse = &Hal_ReadEFuse; ++ pHalFunc->EFUSEGetEfuseDefinition = &Hal_GetEfuseDefinition; ++ pHalFunc->EfuseGetCurrentSize = &Hal_EfuseGetCurrentSize; ++ pHalFunc->Efuse_PgPacketRead = &Hal_EfusePgPacketRead; ++ pHalFunc->Efuse_PgPacketWrite = &Hal_EfusePgPacketWrite; ++ pHalFunc->Efuse_WordEnableDataWrite = &Hal_EfuseWordEnableDataWrite; ++ pHalFunc->Efuse_PgPacketWrite_BT = &Hal_EfusePgPacketWrite_BT; ++ ++ pHalFunc->GetHalODMVarHandler = &rtl8723b_GetHalODMVar; ++ pHalFunc->SetHalODMVarHandler = &rtl8723b_SetHalODMVar; ++ ++ pHalFunc->xmit_thread_handler = &hal_xmit_handler; ++ pHalFunc->hal_notch_filter = &hal_notch_filter_8723b; ++ ++ pHalFunc->c2h_handler = c2h_handler_8723b; ++ pHalFunc->c2h_id_filter_ccx = c2h_id_filter_ccx_8723b; ++ ++ pHalFunc->fill_h2c_cmd = &FillH2CCmd8723B; ++} ++ ++void rtl8723b_InitAntenna_Selection(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData; ++ u8 val; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ ++ val = rtw_read8(padapter, REG_LEDCFG2); ++ /* Let 8051 take control antenna settting */ ++ val |= BIT(7); /* DPDT_SEL_EN, 0x4C[23] */ ++ rtw_write8(padapter, REG_LEDCFG2, val); ++} ++ ++void rtl8723b_init_default_value(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData; ++ struct dm_priv *pdmpriv; ++ u8 i; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ pdmpriv = &pHalData->dmpriv; ++ ++ padapter->registrypriv.wireless_mode = WIRELESS_11BG_24N; ++ ++ /* init default value */ ++ pHalData->fw_ractrl = false; ++ pHalData->bIQKInitialized = false; ++ if (!adapter_to_pwrctl(padapter)->bkeepfwalive) ++ pHalData->LastHMEBoxNum = 0; ++ ++ pHalData->bIQKInitialized = false; ++ ++ /* init dm default value */ ++ pdmpriv->TM_Trigger = 0;/* for IQK */ ++/* pdmpriv->binitialized = false; */ ++/* pdmpriv->prv_traffic_idx = 3; */ ++/* pdmpriv->initialize = 0; */ ++ ++ pdmpriv->ThermalValue_HP_index = 0; ++ for (i = 0; iThermalValue_HP[i] = 0; ++ ++ /* init Efuse variables */ ++ pHalData->EfuseUsedBytes = 0; ++ pHalData->EfuseUsedPercentage = 0; ++#ifdef HAL_EFUSE_MEMORY ++ pHalData->EfuseHal.fakeEfuseBank = 0; ++ pHalData->EfuseHal.fakeEfuseUsedBytes = 0; ++ memset(pHalData->EfuseHal.fakeEfuseContent, 0xFF, EFUSE_MAX_HW_SIZE); ++ memset(pHalData->EfuseHal.fakeEfuseInitMap, 0xFF, EFUSE_MAX_MAP_LEN); ++ memset(pHalData->EfuseHal.fakeEfuseModifiedMap, 0xFF, EFUSE_MAX_MAP_LEN); ++ pHalData->EfuseHal.BTEfuseUsedBytes = 0; ++ pHalData->EfuseHal.BTEfuseUsedPercentage = 0; ++ memset(pHalData->EfuseHal.BTEfuseContent, 0xFF, EFUSE_MAX_BT_BANK*EFUSE_MAX_HW_SIZE); ++ memset(pHalData->EfuseHal.BTEfuseInitMap, 0xFF, EFUSE_BT_MAX_MAP_LEN); ++ memset(pHalData->EfuseHal.BTEfuseModifiedMap, 0xFF, EFUSE_BT_MAX_MAP_LEN); ++ pHalData->EfuseHal.fakeBTEfuseUsedBytes = 0; ++ memset(pHalData->EfuseHal.fakeBTEfuseContent, 0xFF, EFUSE_MAX_BT_BANK*EFUSE_MAX_HW_SIZE); ++ memset(pHalData->EfuseHal.fakeBTEfuseInitMap, 0xFF, EFUSE_BT_MAX_MAP_LEN); ++ memset(pHalData->EfuseHal.fakeBTEfuseModifiedMap, 0xFF, EFUSE_BT_MAX_MAP_LEN); ++#endif ++} ++ ++u8 GetEEPROMSize8723B(struct adapter *padapter) ++{ ++ u8 size = 0; ++ u32 cr; ++ ++ cr = rtw_read16(padapter, REG_9346CR); ++ /* 6: EEPROM used is 93C46, 4: boot from E-Fuse. */ ++ size = (cr & BOOT_FROM_EEPROM) ? 6 : 4; ++ ++ MSG_8192C("EEPROM type is %s\n", size ==4 ? "E-FUSE" : "93C46"); ++ ++ return size; ++} ++ ++/* */ ++/* */ ++/* LLT R/W/Init function */ ++/* */ ++/* */ ++s32 rtl8723b_InitLLTTable(struct adapter *padapter) ++{ ++ unsigned long start, passing_time; ++ u32 val32; ++ s32 ret; ++ ++ ++ ret = _FAIL; ++ ++ val32 = rtw_read32(padapter, REG_AUTO_LLT); ++ val32 |= BIT_AUTO_INIT_LLT; ++ rtw_write32(padapter, REG_AUTO_LLT, val32); ++ ++ start = jiffies; ++ ++ do { ++ val32 = rtw_read32(padapter, REG_AUTO_LLT); ++ if (!(val32 & BIT_AUTO_INIT_LLT)) ++ { ++ ret = _SUCCESS; ++ break; ++ } ++ ++ passing_time = jiffies_to_msecs(jiffies - start); ++ if (passing_time > 1000) ++ { ++ DBG_8192C("%s: FAIL!! REG_AUTO_LLT(0x%X) =%08x\n", ++ __func__, REG_AUTO_LLT, val32); ++ break; ++ } ++ ++ msleep(1); ++ } while (1); ++ ++ return ret; ++} ++ ++static bool ++Hal_GetChnlGroup8723B( ++u8 Channel, ++ u8 *pGroup ++ ) ++{ ++ bool bIn24G =true; ++ ++ if (Channel <= 14) ++ { ++ bIn24G =true; ++ ++ if (1 <= Channel && Channel <= 2) *pGroup = 0; ++ else if (3 <= Channel && Channel <= 5) *pGroup = 1; ++ else if (6 <= Channel && Channel <= 8) *pGroup = 2; ++ else if (9 <= Channel && Channel <= 11) *pGroup = 3; ++ else if (12 <= Channel && Channel <= 14) *pGroup = 4; ++ else ++ { ++ RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("==>Hal_GetChnlGroup8723B in 2.4 G, but Channel %d in Group not found\n", Channel)); ++ } ++ } ++ else ++ { ++ bIn24G =false; ++ ++ if (36 <= Channel && Channel <= 42) *pGroup = 0; ++ else if (44 <= Channel && Channel <= 48) *pGroup = 1; ++ else if (50 <= Channel && Channel <= 58) *pGroup = 2; ++ else if (60 <= Channel && Channel <= 64) *pGroup = 3; ++ else if (100 <= Channel && Channel <= 106) *pGroup = 4; ++ else if (108 <= Channel && Channel <= 114) *pGroup = 5; ++ else if (116 <= Channel && Channel <= 122) *pGroup = 6; ++ else if (124 <= Channel && Channel <= 130) *pGroup = 7; ++ else if (132 <= Channel && Channel <= 138) *pGroup = 8; ++ else if (140 <= Channel && Channel <= 144) *pGroup = 9; ++ else if (149 <= Channel && Channel <= 155) *pGroup = 10; ++ else if (157 <= Channel && Channel <= 161) *pGroup = 11; ++ else if (165 <= Channel && Channel <= 171) *pGroup = 12; ++ else if (173 <= Channel && Channel <= 177) *pGroup = 13; ++ else ++ { ++ RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("==>Hal_GetChnlGroup8723B in 5G, but Channel %d in Group not found\n", Channel)); ++ } ++ ++ } ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("<==Hal_GetChnlGroup8723B, (%s) Channel = %d, Group =%d,\n", ++ (bIn24G) ? "2.4G" : "5G", Channel, *pGroup)); ++ return bIn24G; ++} ++ ++void ++Hal_InitPGData( ++ struct adapter *padapter, ++ u8 *PROMContent) ++{ ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ ++ if (false == pEEPROM->bautoload_fail_flag) ++ { /* autoload OK. */ ++ if (!pEEPROM->EepromOrEfuse) { ++ /* Read EFUSE real map to shadow. */ ++ EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false); ++ memcpy((void*)PROMContent, (void*)pEEPROM->efuse_eeprom_data, HWSET_MAX_SIZE_8723B); ++ } ++ } else {/* autoload fail */ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("AutoLoad Fail reported from CR9346!!\n")); ++ if (false == pEEPROM->EepromOrEfuse) ++ EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false); ++ memcpy((void*)PROMContent, (void*)pEEPROM->efuse_eeprom_data, HWSET_MAX_SIZE_8723B); ++ } ++} ++ ++void ++Hal_EfuseParseIDCode( ++struct adapter *padapter, ++u8 *hwinfo ++ ) ++{ ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++/* struct hal_com_data *pHalData = GET_HAL_DATA(padapter); */ ++ u16 EEPROMId; ++ ++ ++ /* Checl 0x8129 again for making sure autoload status!! */ ++ EEPROMId = le16_to_cpu(*((__le16*)hwinfo)); ++ if (EEPROMId != RTL_EEPROM_ID) ++ { ++ DBG_8192C("EEPROM ID(%#x) is invalid!!\n", EEPROMId); ++ pEEPROM->bautoload_fail_flag = true; ++ } ++ else ++ { ++ pEEPROM->bautoload_fail_flag = false; ++ } ++ ++ RT_TRACE(_module_hal_init_c_, _drv_notice_, ("EEPROM ID = 0x%04x\n", EEPROMId)); ++} ++ ++static void Hal_ReadPowerValueFromPROM_8723B(struct adapter *Adapter, ++ struct TxPowerInfo24G *pwrInfo24G, ++ u8 *PROMContent, bool AutoLoadFail) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ u32 rfPath, eeAddr =EEPROM_TX_PWR_INX_8723B, group, TxCount = 0; ++ ++ memset(pwrInfo24G, 0, sizeof(struct TxPowerInfo24G)); ++ ++ if (0xFF == PROMContent[eeAddr+1]) ++ AutoLoadFail = true; ++ ++ if (AutoLoadFail) ++ { ++ DBG_871X("%s(): Use Default value!\n", __func__); ++ for (rfPath = 0 ; rfPath < MAX_RF_PATH ; rfPath++) ++ { ++ /* 2.4G default value */ ++ for (group = 0 ; group < MAX_CHNL_GROUP_24G; group++) ++ { ++ pwrInfo24G->IndexCCK_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; ++ pwrInfo24G->IndexBW40_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; ++ } ++ for (TxCount = 0;TxCountBW20_Diff[rfPath][0] = EEPROM_DEFAULT_24G_HT20_DIFF; ++ pwrInfo24G->OFDM_Diff[rfPath][0] = EEPROM_DEFAULT_24G_OFDM_DIFF; ++ } ++ else ++ { ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ pwrInfo24G->BW40_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ pwrInfo24G->CCK_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ } ++ } ++ } ++ ++ return; ++ } ++ ++ pHalData->bTXPowerDataReadFromEEPORM = true; /* YJ, move, 120316 */ ++ ++ for (rfPath = 0 ; rfPath < MAX_RF_PATH ; rfPath++) ++ { ++ /* 2 2.4G default value */ ++ for (group = 0 ; group < MAX_CHNL_GROUP_24G; group++) ++ { ++ pwrInfo24G->IndexCCK_Base[rfPath][group] = PROMContent[eeAddr++]; ++ if (pwrInfo24G->IndexCCK_Base[rfPath][group] == 0xFF) ++ { ++ pwrInfo24G->IndexCCK_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; ++ } ++ } ++ for (group = 0 ; group < MAX_CHNL_GROUP_24G-1; group++) ++ { ++ pwrInfo24G->IndexBW40_Base[rfPath][group] = PROMContent[eeAddr++]; ++ if (pwrInfo24G->IndexBW40_Base[rfPath][group] == 0xFF) ++ pwrInfo24G->IndexBW40_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; ++ } ++ for (TxCount = 0;TxCountBW40_Diff[rfPath][TxCount] = 0; ++ if (PROMContent[eeAddr] == 0xFF) ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_24G_HT20_DIFF; ++ else ++ { ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4; ++ if (pwrInfo24G->BW20_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */ ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] |= 0xF0; ++ } ++ ++ if (PROMContent[eeAddr] == 0xFF) ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_24G_OFDM_DIFF; ++ else ++ { ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f); ++ if (pwrInfo24G->OFDM_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */ ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] |= 0xF0; ++ } ++ pwrInfo24G->CCK_Diff[rfPath][TxCount] = 0; ++ eeAddr++; ++ } ++ else ++ { ++ if (PROMContent[eeAddr] == 0xFF) ++ pwrInfo24G->BW40_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ else ++ { ++ pwrInfo24G->BW40_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4; ++ if (pwrInfo24G->BW40_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */ ++ pwrInfo24G->BW40_Diff[rfPath][TxCount] |= 0xF0; ++ } ++ ++ if (PROMContent[eeAddr] == 0xFF) ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ else ++ { ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f); ++ if (pwrInfo24G->BW20_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */ ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] |= 0xF0; ++ } ++ eeAddr++; ++ ++ if (PROMContent[eeAddr] == 0xFF) ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ else ++ { ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4; ++ if (pwrInfo24G->OFDM_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */ ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] |= 0xF0; ++ } ++ ++ if (PROMContent[eeAddr] == 0xFF) ++ pwrInfo24G->CCK_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ else ++ { ++ pwrInfo24G->CCK_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f); ++ if (pwrInfo24G->CCK_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */ ++ pwrInfo24G->CCK_Diff[rfPath][TxCount] |= 0xF0; ++ } ++ eeAddr++; ++ } ++ } ++ } ++} ++ ++ ++void ++Hal_EfuseParseTxPowerInfo_8723B( ++struct adapter * padapter, ++u8* PROMContent, ++bool AutoLoadFail ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ struct TxPowerInfo24G pwrInfo24G; ++ u8 rfPath, ch, TxCount = 1; ++ ++ Hal_ReadPowerValueFromPROM_8723B(padapter, &pwrInfo24G, PROMContent, AutoLoadFail); ++ for (rfPath = 0 ; rfPath < MAX_RF_PATH ; rfPath++) ++ { ++ for (ch = 0 ; ch < CHANNEL_MAX_NUMBER; ch++) ++ { ++ u8 group = 0; ++ ++ Hal_GetChnlGroup8723B(ch+1, &group); ++ ++ if (ch == 14-1) ++ { ++ pHalData->Index24G_CCK_Base[rfPath][ch] = pwrInfo24G.IndexCCK_Base[rfPath][5]; ++ pHalData->Index24G_BW40_Base[rfPath][ch] = pwrInfo24G.IndexBW40_Base[rfPath][group]; ++ } ++ else ++ { ++ pHalData->Index24G_CCK_Base[rfPath][ch] = pwrInfo24G.IndexCCK_Base[rfPath][group]; ++ pHalData->Index24G_BW40_Base[rfPath][ch] = pwrInfo24G.IndexBW40_Base[rfPath][group]; ++ } ++#ifdef CONFIG_DEBUG ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("======= Path %d, ChannelIndex %d, Group %d =======\n", rfPath, ch, group)); ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Index24G_CCK_Base[%d][%d] = 0x%x\n", rfPath, ch , pHalData->Index24G_CCK_Base[rfPath][ch])); ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Index24G_BW40_Base[%d][%d] = 0x%x\n", rfPath, ch, pHalData->Index24G_BW40_Base[rfPath][ch])); ++#endif ++ } ++ ++ for (TxCount = 0;TxCountCCK_24G_Diff[rfPath][TxCount]=pwrInfo24G.CCK_Diff[rfPath][TxCount]; ++ pHalData->OFDM_24G_Diff[rfPath][TxCount]=pwrInfo24G.OFDM_Diff[rfPath][TxCount]; ++ pHalData->BW20_24G_Diff[rfPath][TxCount]=pwrInfo24G.BW20_Diff[rfPath][TxCount]; ++ pHalData->BW40_24G_Diff[rfPath][TxCount]=pwrInfo24G.BW40_Diff[rfPath][TxCount]; ++ ++#ifdef CONFIG_DEBUG ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("--------------------------------------- 2.4G ---------------------------------------\n")); ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("CCK_24G_Diff[%d][%d]= %d\n", rfPath, TxCount, pHalData->CCK_24G_Diff[rfPath][TxCount])); ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("OFDM_24G_Diff[%d][%d]= %d\n", rfPath, TxCount, pHalData->OFDM_24G_Diff[rfPath][TxCount])); ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("BW20_24G_Diff[%d][%d]= %d\n", rfPath, TxCount, pHalData->BW20_24G_Diff[rfPath][TxCount])); ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("BW40_24G_Diff[%d][%d]= %d\n", rfPath, TxCount, pHalData->BW40_24G_Diff[rfPath][TxCount])); ++#endif ++ } ++ } ++ ++ /* 2010/10/19 MH Add Regulator recognize for CU. */ ++ if (!AutoLoadFail) ++ { ++ pHalData->EEPROMRegulatory = (PROMContent[EEPROM_RF_BOARD_OPTION_8723B]&0x7); /* bit0~2 */ ++ if (PROMContent[EEPROM_RF_BOARD_OPTION_8723B] == 0xFF) ++ pHalData->EEPROMRegulatory = (EEPROM_DEFAULT_BOARD_OPTION&0x7); /* bit0~2 */ ++ } ++ else ++ { ++ pHalData->EEPROMRegulatory = 0; ++ } ++ RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("EEPROMRegulatory = 0x%x\n", pHalData->EEPROMRegulatory)); ++} ++ ++void ++Hal_EfuseParseBTCoexistInfo_8723B( ++ struct adapter * padapter, ++ u8 *hwinfo, ++ bool AutoLoadFail ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ u8 tempval; ++ u32 tmpu4; ++ ++ if (!AutoLoadFail) { ++ tmpu4 = rtw_read32(padapter, REG_MULTI_FUNC_CTRL); ++ if (tmpu4 & BT_FUNC_EN) ++ pHalData->EEPROMBluetoothCoexist = true; ++ else ++ pHalData->EEPROMBluetoothCoexist = false; ++ ++ pHalData->EEPROMBluetoothType = BT_RTL8723B; ++ ++ tempval = hwinfo[EEPROM_RF_BT_SETTING_8723B]; ++ if (tempval != 0xFF) { ++ pHalData->EEPROMBluetoothAntNum = tempval & BIT(0); ++ /* EFUSE_0xC3[6] == 0, S1(Main)-ODM_RF_PATH_A; */ ++ /* EFUSE_0xC3[6] == 1, S0(Aux)-ODM_RF_PATH_B */ ++ pHalData->ant_path = (tempval & BIT(6))?ODM_RF_PATH_B:ODM_RF_PATH_A; ++ } ++ else { ++ pHalData->EEPROMBluetoothAntNum = Ant_x1; ++ pHalData->ant_path = ODM_RF_PATH_A; ++ } ++ } ++ else ++ { ++ pHalData->EEPROMBluetoothCoexist = false; ++ pHalData->EEPROMBluetoothType = BT_RTL8723B; ++ pHalData->EEPROMBluetoothAntNum = Ant_x1; ++ pHalData->ant_path = ODM_RF_PATH_A; ++ } ++ ++ if (padapter->registrypriv.ant_num > 0) { ++ DBG_8192C("%s: Apply driver defined antenna number(%d) to replace origin(%d)\n", ++ __func__, ++ padapter->registrypriv.ant_num, ++ pHalData->EEPROMBluetoothAntNum ==Ant_x2?2:1); ++ ++ switch (padapter->registrypriv.ant_num) { ++ case 1: ++ pHalData->EEPROMBluetoothAntNum = Ant_x1; ++ break; ++ case 2: ++ pHalData->EEPROMBluetoothAntNum = Ant_x2; ++ break; ++ default: ++ DBG_8192C("%s: Discard invalid driver defined antenna number(%d)!\n", ++ __func__, padapter->registrypriv.ant_num); ++ break; ++ } ++ } ++ ++ rtw_btcoex_SetBTCoexist(padapter, pHalData->EEPROMBluetoothCoexist); ++ rtw_btcoex_SetChipType(padapter, pHalData->EEPROMBluetoothType); ++ rtw_btcoex_SetPGAntNum(padapter, pHalData->EEPROMBluetoothAntNum ==Ant_x2?2:1); ++ if (pHalData->EEPROMBluetoothAntNum == Ant_x1) ++ { ++ rtw_btcoex_SetSingleAntPath(padapter, pHalData->ant_path); ++ } ++ ++ DBG_8192C("%s: %s BT-coex, ant_num =%d\n", ++ __func__, ++ pHalData->EEPROMBluetoothCoexist ==true?"Enable":"Disable", ++ pHalData->EEPROMBluetoothAntNum ==Ant_x2?2:1); ++} ++ ++void ++Hal_EfuseParseEEPROMVer_8723B( ++struct adapter * padapter, ++u8* hwinfo, ++bool AutoLoadFail ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ ++/* RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("%s(): AutoLoadFail = %d\n", __func__, AutoLoadFail)); */ ++ if (!AutoLoadFail) ++ pHalData->EEPROMVersion = hwinfo[EEPROM_VERSION_8723B]; ++ else ++ pHalData->EEPROMVersion = 1; ++ RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("Hal_EfuseParseEEPROMVer(), EEVer = %d\n", ++ pHalData->EEPROMVersion)); ++} ++ ++ ++ ++void ++Hal_EfuseParsePackageType_8723B( ++struct adapter * padapter, ++u8* hwinfo, ++bool AutoLoadFail ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ u8 package; ++ u8 efuseContent; ++ ++ Efuse_PowerSwitch(padapter, false, true); ++ efuse_OneByteRead(padapter, 0x1FB, &efuseContent, false); ++ DBG_871X("%s phy efuse read 0x1FB =%x\n", __func__, efuseContent); ++ Efuse_PowerSwitch(padapter, false, false); ++ ++ package = efuseContent & 0x7; ++ switch (package) ++ { ++ case 0x4: ++ pHalData->PackageType = PACKAGE_TFBGA79; ++ break; ++ case 0x5: ++ pHalData->PackageType = PACKAGE_TFBGA90; ++ break; ++ case 0x6: ++ pHalData->PackageType = PACKAGE_QFN68; ++ break; ++ case 0x7: ++ pHalData->PackageType = PACKAGE_TFBGA80; ++ break; ++ ++ default: ++ pHalData->PackageType = PACKAGE_DEFAULT; ++ break; ++ } ++ ++ DBG_871X("PackageType = 0x%X\n", pHalData->PackageType); ++} ++ ++ ++void ++Hal_EfuseParseVoltage_8723B( ++struct adapter * padapter, ++u8* hwinfo, ++bool AutoLoadFail ++ ) ++{ ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ ++ /* memcpy(pEEPROM->adjuseVoltageVal, &hwinfo[EEPROM_Voltage_ADDR_8723B], 1); */ ++ DBG_871X("%s hwinfo[EEPROM_Voltage_ADDR_8723B] =%02x\n", __func__, hwinfo[EEPROM_Voltage_ADDR_8723B]); ++ pEEPROM->adjuseVoltageVal = (hwinfo[EEPROM_Voltage_ADDR_8723B] & 0xf0) >> 4 ; ++ DBG_871X("%s pEEPROM->adjuseVoltageVal =%x\n", __func__, pEEPROM->adjuseVoltageVal); ++} ++ ++void ++Hal_EfuseParseChnlPlan_8723B( ++struct adapter * padapter, ++u8* hwinfo, ++bool AutoLoadFail ++ ) ++{ ++ padapter->mlmepriv.ChannelPlan = hal_com_config_channel_plan( ++ padapter ++ , hwinfo?hwinfo[EEPROM_ChannelPlan_8723B]:0xFF ++ , padapter->registrypriv.channel_plan ++ , RT_CHANNEL_DOMAIN_WORLD_NULL ++ , AutoLoadFail ++ ); ++ ++ Hal_ChannelPlanToRegulation(padapter, padapter->mlmepriv.ChannelPlan); ++ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("EEPROM ChannelPlan = 0x%02x\n", padapter->mlmepriv.ChannelPlan)); ++} ++ ++void ++Hal_EfuseParseCustomerID_8723B( ++struct adapter * padapter, ++u8* hwinfo, ++bool AutoLoadFail ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ ++/* RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("%s(): AutoLoadFail = %d\n", __func__, AutoLoadFail)); */ ++ if (!AutoLoadFail) ++ { ++ pHalData->EEPROMCustomerID = hwinfo[EEPROM_CustomID_8723B]; ++ } ++ else ++ { ++ pHalData->EEPROMCustomerID = 0; ++ } ++ RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("EEPROM Customer ID: 0x%2x\n", pHalData->EEPROMCustomerID)); ++} ++ ++void ++Hal_EfuseParseAntennaDiversity_8723B( ++struct adapter * padapter, ++u8 * hwinfo, ++bool AutoLoadFail ++ ) ++{ ++} ++ ++void ++Hal_EfuseParseXtal_8723B( ++struct adapter * padapter, ++u8 * hwinfo, ++bool AutoLoadFail ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ ++/* RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("%s(): AutoLoadFail = %d\n", __func__, AutoLoadFail)); */ ++ if (!AutoLoadFail) ++ { ++ pHalData->CrystalCap = hwinfo[EEPROM_XTAL_8723B]; ++ if (pHalData->CrystalCap == 0xFF) ++ pHalData->CrystalCap = EEPROM_Default_CrystalCap_8723B; /* what value should 8812 set? */ ++ } ++ else ++ { ++ pHalData->CrystalCap = EEPROM_Default_CrystalCap_8723B; ++ } ++ RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("EEPROM CrystalCap: 0x%2x\n", pHalData->CrystalCap)); ++} ++ ++ ++void ++Hal_EfuseParseThermalMeter_8723B( ++ struct adapter *padapter, ++ u8 *PROMContent, ++ u8 AutoLoadFail ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ ++/* RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("%s(): AutoLoadFail = %d\n", __func__, AutoLoadFail)); */ ++ /* */ ++ /* ThermalMeter from EEPROM */ ++ /* */ ++ if (false == AutoLoadFail) ++ pHalData->EEPROMThermalMeter = PROMContent[EEPROM_THERMAL_METER_8723B]; ++ else ++ pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_8723B; ++ ++ if ((pHalData->EEPROMThermalMeter == 0xff) || (true == AutoLoadFail)) ++ { ++ pHalData->bAPKThermalMeterIgnore = true; ++ pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_8723B; ++ } ++ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("EEPROM ThermalMeter = 0x%x\n", pHalData->EEPROMThermalMeter)); ++} ++ ++ ++void Hal_ReadRFGainOffset( ++ struct adapter * Adapter, ++ u8* PROMContent, ++ bool AutoloadFail) ++{ ++ /* */ ++ /* BB_RF Gain Offset from EEPROM */ ++ /* */ ++ ++ if (!AutoloadFail) { ++ Adapter->eeprompriv.EEPROMRFGainOffset =PROMContent[EEPROM_RF_GAIN_OFFSET]; ++ DBG_871X("AutoloadFail =%x,\n", AutoloadFail); ++ Adapter->eeprompriv.EEPROMRFGainVal =EFUSE_Read1Byte(Adapter, EEPROM_RF_GAIN_VAL); ++ DBG_871X("Adapter->eeprompriv.EEPROMRFGainVal =%x\n", Adapter->eeprompriv.EEPROMRFGainVal); ++ } ++ else { ++ Adapter->eeprompriv.EEPROMRFGainOffset = 0; ++ Adapter->eeprompriv.EEPROMRFGainVal = 0xFF; ++ DBG_871X("else AutoloadFail =%x,\n", AutoloadFail); ++ } ++ DBG_871X("EEPRORFGainOffset = 0x%02x\n", Adapter->eeprompriv.EEPROMRFGainOffset); ++} ++ ++u8 ++BWMapping_8723B( ++struct adapter * Adapter, ++struct pkt_attrib *pattrib ++) ++{ ++ u8 BWSettingOfDesc = 0; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++ /* DBG_871X("BWMapping pHalData->CurrentChannelBW %d, pattrib->bwmode %d\n", pHalData->CurrentChannelBW, pattrib->bwmode); */ ++ ++ if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_80) ++ { ++ if (pattrib->bwmode == CHANNEL_WIDTH_80) ++ BWSettingOfDesc = 2; ++ else if (pattrib->bwmode == CHANNEL_WIDTH_40) ++ BWSettingOfDesc = 1; ++ else ++ BWSettingOfDesc = 0; ++ } ++ else if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_40) ++ { ++ if ((pattrib->bwmode == CHANNEL_WIDTH_40) || (pattrib->bwmode == CHANNEL_WIDTH_80)) ++ BWSettingOfDesc = 1; ++ else ++ BWSettingOfDesc = 0; ++ } ++ else ++ BWSettingOfDesc = 0; ++ ++ /* if (pTcb->bBTTxPacket) */ ++ /* BWSettingOfDesc = 0; */ ++ ++ return BWSettingOfDesc; ++} ++ ++u8 SCMapping_8723B(struct adapter * Adapter, struct pkt_attrib *pattrib) ++{ ++ u8 SCSettingOfDesc = 0; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++ /* DBG_871X("SCMapping: pHalData->CurrentChannelBW %d, pHalData->nCur80MhzPrimeSC %d, pHalData->nCur40MhzPrimeSC %d\n", pHalData->CurrentChannelBW, pHalData->nCur80MhzPrimeSC, pHalData->nCur40MhzPrimeSC); */ ++ ++ if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_80) ++ { ++ if (pattrib->bwmode == CHANNEL_WIDTH_80) ++ { ++ SCSettingOfDesc = VHT_DATA_SC_DONOT_CARE; ++ } ++ else if (pattrib->bwmode == CHANNEL_WIDTH_40) ++ { ++ if (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) ++ SCSettingOfDesc = VHT_DATA_SC_40_LOWER_OF_80MHZ; ++ else if (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) ++ SCSettingOfDesc = VHT_DATA_SC_40_UPPER_OF_80MHZ; ++ else ++ DBG_871X("SCMapping: Not Correct Primary40MHz Setting\n"); ++ } ++ else ++ { ++ if ((pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) && (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER)) ++ SCSettingOfDesc = VHT_DATA_SC_20_LOWEST_OF_80MHZ; ++ else if ((pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) && (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER)) ++ SCSettingOfDesc = VHT_DATA_SC_20_LOWER_OF_80MHZ; ++ else if ((pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) && (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER)) ++ SCSettingOfDesc = VHT_DATA_SC_20_UPPER_OF_80MHZ; ++ else if ((pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) && (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER)) ++ SCSettingOfDesc = VHT_DATA_SC_20_UPPERST_OF_80MHZ; ++ else ++ DBG_871X("SCMapping: Not Correct Primary40MHz Setting\n"); ++ } ++ } ++ else if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_40) ++ { ++ /* DBG_871X("SCMapping: HT Case: pHalData->CurrentChannelBW %d, pHalData->nCur40MhzPrimeSC %d\n", pHalData->CurrentChannelBW, pHalData->nCur40MhzPrimeSC); */ ++ ++ if (pattrib->bwmode == CHANNEL_WIDTH_40) ++ { ++ SCSettingOfDesc = VHT_DATA_SC_DONOT_CARE; ++ } ++ else if (pattrib->bwmode == CHANNEL_WIDTH_20) ++ { ++ if (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) ++ { ++ SCSettingOfDesc = VHT_DATA_SC_20_UPPER_OF_80MHZ; ++ } ++ else if (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) ++ { ++ SCSettingOfDesc = VHT_DATA_SC_20_LOWER_OF_80MHZ; ++ } ++ else ++ { ++ SCSettingOfDesc = VHT_DATA_SC_DONOT_CARE; ++ } ++ } ++ } ++ else ++ { ++ SCSettingOfDesc = VHT_DATA_SC_DONOT_CARE; ++ } ++ ++ return SCSettingOfDesc; ++} ++ ++static void rtl8723b_cal_txdesc_chksum(struct tx_desc *ptxdesc) ++{ ++ u16 *usPtr = (u16*)ptxdesc; ++ u32 count; ++ u32 index; ++ u16 checksum = 0; ++ ++ ++ /* Clear first */ ++ ptxdesc->txdw7 &= cpu_to_le32(0xffff0000); ++ ++ /* checksume is always calculated by first 32 bytes, */ ++ /* and it doesn't depend on TX DESC length. */ ++ /* Thomas, Lucas@SD4, 20130515 */ ++ count = 16; ++ ++ for (index = 0; index < count; index++) { ++ checksum |= le16_to_cpu(*(__le16 *)(usPtr + index)); ++ } ++ ++ ptxdesc->txdw7 |= cpu_to_le32(checksum & 0x0000ffff); ++} ++ ++static u8 fill_txdesc_sectype(struct pkt_attrib *pattrib) ++{ ++ u8 sectype = 0; ++ if ((pattrib->encrypt > 0) && !pattrib->bswenc) ++ { ++ switch (pattrib->encrypt) ++ { ++ /* SEC_TYPE */ ++ case _WEP40_: ++ case _WEP104_: ++ case _TKIP_: ++ case _TKIP_WTMIC_: ++ sectype = 1; ++ break; ++ ++ case _AES_: ++ sectype = 3; ++ break; ++ ++ case _NO_PRIVACY_: ++ default: ++ break; ++ } ++ } ++ return sectype; ++} ++ ++static void fill_txdesc_vcs_8723b(struct adapter *padapter, struct pkt_attrib *pattrib, PTXDESC_8723B ptxdesc) ++{ ++ /* DBG_8192C("cvs_mode =%d\n", pattrib->vcs_mode); */ ++ ++ if (pattrib->vcs_mode) ++ { ++ switch (pattrib->vcs_mode) ++ { ++ case RTS_CTS: ++ ptxdesc->rtsen = 1; ++ /* ENABLE HW RTS */ ++ ptxdesc->hw_rts_en = 1; ++ break; ++ ++ case CTS_TO_SELF: ++ ptxdesc->cts2self = 1; ++ break; ++ ++ case NONE_VCS: ++ default: ++ break; ++ } ++ ++ ptxdesc->rtsrate = 8; /* RTS Rate =24M */ ++ ptxdesc->rts_ratefb_lmt = 0xF; ++ ++ if (padapter->mlmeextpriv.mlmext_info.preamble_mode == PREAMBLE_SHORT) ++ ptxdesc->rts_short = 1; ++ ++ /* Set RTS BW */ ++ if (pattrib->ht_en) ++ { ++ ptxdesc->rts_sc = SCMapping_8723B(padapter, pattrib); ++ } ++ } ++} ++ ++static void fill_txdesc_phy_8723b(struct adapter *padapter, struct pkt_attrib *pattrib, PTXDESC_8723B ptxdesc) ++{ ++ /* DBG_8192C("bwmode =%d, ch_off =%d\n", pattrib->bwmode, pattrib->ch_offset); */ ++ ++ if (pattrib->ht_en) ++ { ++ ptxdesc->data_bw = BWMapping_8723B(padapter, pattrib); ++ ++ ptxdesc->data_sc = SCMapping_8723B(padapter, pattrib); ++ } ++} ++ ++static void rtl8723b_fill_default_txdesc( ++ struct xmit_frame *pxmitframe, ++ u8 *pbuf) ++{ ++ struct adapter *padapter; ++ struct hal_com_data *pHalData; ++ struct dm_priv *pdmpriv; ++ struct mlme_ext_priv *pmlmeext; ++ struct mlme_ext_info *pmlmeinfo; ++ struct pkt_attrib *pattrib; ++ PTXDESC_8723B ptxdesc; ++ s32 bmcst; ++ ++ memset(pbuf, 0, TXDESC_SIZE); ++ ++ padapter = pxmitframe->padapter; ++ pHalData = GET_HAL_DATA(padapter); ++ pdmpriv = &pHalData->dmpriv; ++ pmlmeext = &padapter->mlmeextpriv; ++ pmlmeinfo = &(pmlmeext->mlmext_info); ++ ++ pattrib = &pxmitframe->attrib; ++ bmcst = IS_MCAST(pattrib->ra); ++ ++ ptxdesc = (PTXDESC_8723B)pbuf; ++ ++ if (pxmitframe->frame_tag == DATA_FRAMETAG) ++ { ++ u8 drv_userate = 0; ++ ++ ptxdesc->macid = pattrib->mac_id; /* CAM_ID(MAC_ID) */ ++ ptxdesc->rate_id = pattrib->raid; ++ ptxdesc->qsel = pattrib->qsel; ++ ptxdesc->seq = pattrib->seqnum; ++ ++ ptxdesc->sectype = fill_txdesc_sectype(pattrib); ++ fill_txdesc_vcs_8723b(padapter, pattrib, ptxdesc); ++ ++ if (pattrib->icmp_pkt == 1 && padapter->registrypriv.wifi_spec == 1) ++ drv_userate = 1; ++ ++ if ((pattrib->ether_type != 0x888e) && ++ (pattrib->ether_type != 0x0806) && ++ (pattrib->ether_type != 0x88B4) && ++ (pattrib->dhcp_pkt != 1) && ++ (drv_userate != 1) ++#ifdef CONFIG_AUTO_AP_MODE ++ && (pattrib->pctrl != true) ++#endif ++ ) ++ { ++ /* Non EAP & ARP & DHCP type data packet */ ++ ++ if (pattrib->ampdu_en == true) ++ { ++ ptxdesc->agg_en = 1; /* AGG EN */ ++ ptxdesc->max_agg_num = 0x1f; ++ ptxdesc->ampdu_density = pattrib->ampdu_spacing; ++ } ++ else ++ ptxdesc->bk = 1; /* AGG BK */ ++ ++ fill_txdesc_phy_8723b(padapter, pattrib, ptxdesc); ++ ++ ptxdesc->data_ratefb_lmt = 0x1F; ++ ++ if (pHalData->fw_ractrl == false) ++ { ++ ptxdesc->userate = 1; ++ ++ if (pHalData->dmpriv.INIDATA_RATE[pattrib->mac_id] & BIT(7)) ++ ptxdesc->data_short = 1; ++ ++ ptxdesc->datarate = pHalData->dmpriv.INIDATA_RATE[pattrib->mac_id] & 0x7F; ++ } ++ ++ if (padapter->fix_rate != 0xFF) { /* modify data rate by iwpriv */ ++ ptxdesc->userate = 1; ++ if (padapter->fix_rate & BIT(7)) ++ ptxdesc->data_short = 1; ++ ++ ptxdesc->datarate = (padapter->fix_rate & 0x7F); ++ ptxdesc->disdatafb = 1; ++ } ++ ++ if (pattrib->ldpc) ++ ptxdesc->data_ldpc = 1; ++ if (pattrib->stbc) ++ ptxdesc->data_stbc = 1; ++ ++#ifdef CONFIG_CMCC_TEST ++ ptxdesc->data_short = 1; /* use cck short premble */ ++#endif ++ } ++ else ++ { ++ /* EAP data packet and ARP packet. */ ++ /* Use the 1M data rate to send the EAP/ARP packet. */ ++ /* This will maybe make the handshake smooth. */ ++ ++ ptxdesc->bk = 1; /* AGG BK */ ++ ptxdesc->userate = 1; /* driver uses rate */ ++ if (pmlmeinfo->preamble_mode == PREAMBLE_SHORT) ++ ptxdesc->data_short = 1;/* DATA_SHORT */ ++ ptxdesc->datarate = MRateToHwRate(pmlmeext->tx_rate); ++ DBG_871X("YJ: %s(): ARP Data: userate =%d, datarate = 0x%x\n", __func__, ptxdesc->userate, ptxdesc->datarate); ++ } ++ ++ ptxdesc->usb_txagg_num = pxmitframe->agg_num; ++ } ++ else if (pxmitframe->frame_tag == MGNT_FRAMETAG) ++ { ++/* RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("%s: MGNT_FRAMETAG\n", __func__)); */ ++ ++ ptxdesc->macid = pattrib->mac_id; /* CAM_ID(MAC_ID) */ ++ ptxdesc->qsel = pattrib->qsel; ++ ptxdesc->rate_id = pattrib->raid; /* Rate ID */ ++ ptxdesc->seq = pattrib->seqnum; ++ ptxdesc->userate = 1; /* driver uses rate, 1M */ ++ ++ ptxdesc->mbssid = pattrib->mbssid & 0xF; ++ ++ ptxdesc->rty_lmt_en = 1; /* retry limit enable */ ++ if (pattrib->retry_ctrl == true) { ++ ptxdesc->data_rt_lmt = 6; ++ } else { ++ ptxdesc->data_rt_lmt = 12; ++ } ++ ++ ptxdesc->datarate = MRateToHwRate(pmlmeext->tx_rate); ++ ++ /* CCX-TXRPT ack for xmit mgmt frames. */ ++ if (pxmitframe->ack_report) { ++ #ifdef DBG_CCX ++ DBG_8192C("%s set spe_rpt\n", __func__); ++ #endif ++ ptxdesc->spe_rpt = 1; ++ ptxdesc->sw_define = (u8)(GET_PRIMARY_ADAPTER(padapter)->xmitpriv.seq_no); ++ } ++ } ++ else if (pxmitframe->frame_tag == TXAGG_FRAMETAG) ++ { ++ RT_TRACE(_module_hal_xmit_c_, _drv_warning_, ("%s: TXAGG_FRAMETAG\n", __func__)); ++ } ++ else ++ { ++ RT_TRACE(_module_hal_xmit_c_, _drv_warning_, ("%s: frame_tag = 0x%x\n", __func__, pxmitframe->frame_tag)); ++ ++ ptxdesc->macid = pattrib->mac_id; /* CAM_ID(MAC_ID) */ ++ ptxdesc->rate_id = pattrib->raid; /* Rate ID */ ++ ptxdesc->qsel = pattrib->qsel; ++ ptxdesc->seq = pattrib->seqnum; ++ ptxdesc->userate = 1; /* driver uses rate */ ++ ptxdesc->datarate = MRateToHwRate(pmlmeext->tx_rate); ++ } ++ ++ ptxdesc->pktlen = pattrib->last_txcmdsz; ++ ptxdesc->offset = TXDESC_SIZE + OFFSET_SZ; ++ ++ if (bmcst) ptxdesc->bmc = 1; ++ ++ /* 2009.11.05. tynli_test. Suggested by SD4 Filen for FW LPS. */ ++ /* (1) The sequence number of each non-Qos frame / broadcast / multicast / */ ++ /* mgnt frame should be controled by Hw because Fw will also send null data */ ++ /* which we cannot control when Fw LPS enable. */ ++ /* --> default enable non-Qos data sequense number. 2010.06.23. by tynli. */ ++ /* (2) Enable HW SEQ control for beacon packet, because we use Hw beacon. */ ++ /* (3) Use HW Qos SEQ to control the seq num of Ext port non-Qos packets. */ ++ /* 2010.06.23. Added by tynli. */ ++ if (!pattrib->qos_en) ++ { ++ /* Hw set sequence number */ ++ ptxdesc->en_hwseq = 1; /* HWSEQ_EN */ ++ } ++} ++ ++/* ++ *Description: ++ * ++ *Parameters: ++ * pxmitframe xmitframe ++ * pbuf where to fill tx desc ++ */ ++void rtl8723b_update_txdesc(struct xmit_frame *pxmitframe, u8 *pbuf) ++{ ++ struct tx_desc *pdesc; ++ ++ rtl8723b_fill_default_txdesc(pxmitframe, pbuf); ++ ++ pdesc = (struct tx_desc*)pbuf; ++ pdesc->txdw0 = pdesc->txdw0; ++ pdesc->txdw1 = pdesc->txdw1; ++ pdesc->txdw2 = pdesc->txdw2; ++ pdesc->txdw3 = pdesc->txdw3; ++ pdesc->txdw4 = pdesc->txdw4; ++ pdesc->txdw5 = pdesc->txdw5; ++ pdesc->txdw6 = pdesc->txdw6; ++ pdesc->txdw7 = pdesc->txdw7; ++ pdesc->txdw8 = pdesc->txdw8; ++ pdesc->txdw9 = pdesc->txdw9; ++ ++ rtl8723b_cal_txdesc_chksum(pdesc); ++} ++ ++/* */ ++/* Description: In normal chip, we should send some packet to Hw which will be used by Fw */ ++/* in FW LPS mode. The function is to fill the Tx descriptor of this packets, then */ ++/* Fw can tell Hw to send these packet derectly. */ ++/* Added by tynli. 2009.10.15. */ ++/* */ ++/* type1:pspoll, type2:null */ ++void rtl8723b_fill_fake_txdesc( ++ struct adapter *padapter, ++ u8* pDesc, ++ u32 BufferLen, ++ u8 IsPsPoll, ++ u8 IsBTQosNull, ++ u8 bDataFrame) ++{ ++ /* Clear all status */ ++ memset(pDesc, 0, TXDESC_SIZE); ++ ++ SET_TX_DESC_FIRST_SEG_8723B(pDesc, 1); /* bFirstSeg; */ ++ SET_TX_DESC_LAST_SEG_8723B(pDesc, 1); /* bLastSeg; */ ++ ++ SET_TX_DESC_OFFSET_8723B(pDesc, 0x28); /* Offset = 32 */ ++ ++ SET_TX_DESC_PKT_SIZE_8723B(pDesc, BufferLen); /* Buffer size + command header */ ++ SET_TX_DESC_QUEUE_SEL_8723B(pDesc, QSLT_MGNT); /* Fixed queue of Mgnt queue */ ++ ++ /* Set NAVUSEHDR to prevent Ps-poll AId filed to be changed to error vlaue by Hw. */ ++ if (true == IsPsPoll) ++ { ++ SET_TX_DESC_NAV_USE_HDR_8723B(pDesc, 1); ++ } ++ else ++ { ++ SET_TX_DESC_HWSEQ_EN_8723B(pDesc, 1); /* Hw set sequence number */ ++ SET_TX_DESC_HWSEQ_SEL_8723B(pDesc, 0); ++ } ++ ++ if (true ==IsBTQosNull) ++ { ++ SET_TX_DESC_BT_INT_8723B(pDesc, 1); ++ } ++ ++ SET_TX_DESC_USE_RATE_8723B(pDesc, 1); /* use data rate which is set by Sw */ ++ SET_TX_DESC_OWN_8723B((u8 *)pDesc, 1); ++ ++ SET_TX_DESC_TX_RATE_8723B(pDesc, DESC8723B_RATE1M); ++ ++ /* */ ++ /* Encrypt the data frame if under security mode excepct null data. Suggested by CCW. */ ++ /* */ ++ if (true ==bDataFrame) ++ { ++ u32 EncAlg; ++ ++ EncAlg = padapter->securitypriv.dot11PrivacyAlgrthm; ++ switch (EncAlg) ++ { ++ case _NO_PRIVACY_: ++ SET_TX_DESC_SEC_TYPE_8723B(pDesc, 0x0); ++ break; ++ case _WEP40_: ++ case _WEP104_: ++ case _TKIP_: ++ SET_TX_DESC_SEC_TYPE_8723B(pDesc, 0x1); ++ break; ++ case _SMS4_: ++ SET_TX_DESC_SEC_TYPE_8723B(pDesc, 0x2); ++ break; ++ case _AES_: ++ SET_TX_DESC_SEC_TYPE_8723B(pDesc, 0x3); ++ break; ++ default: ++ SET_TX_DESC_SEC_TYPE_8723B(pDesc, 0x0); ++ break; ++ } ++ } ++ ++ /* USB interface drop packet if the checksum of descriptor isn't correct. */ ++ /* Using this checksum can let hardware recovery from packet bulk out error (e.g. Cancel URC, Bulk out error.). */ ++ rtl8723b_cal_txdesc_chksum((struct tx_desc*)pDesc); ++} ++ ++static void hw_var_set_opmode(struct adapter *padapter, u8 variable, u8 *val) ++{ ++ u8 val8; ++ u8 mode = *((u8 *)val); ++ ++ { ++ /* disable Port0 TSF update */ ++ val8 = rtw_read8(padapter, REG_BCN_CTRL); ++ val8 |= DIS_TSF_UDT; ++ rtw_write8(padapter, REG_BCN_CTRL, val8); ++ ++ /* set net_type */ ++ Set_MSR(padapter, mode); ++ DBG_871X("#### %s() -%d iface_type(0) mode = %d ####\n", __func__, __LINE__, mode); ++ ++ if ((mode == _HW_STATE_STATION_) || (mode == _HW_STATE_NOLINK_)) ++ { ++ { ++ StopTxBeacon(padapter); ++#ifdef CONFIG_INTERRUPT_BASED_TXBCN ++#ifdef CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ rtw_write8(padapter, REG_DRVERLYINT, 0x05); /* restore early int time to 5ms */ ++ UpdateInterruptMask8812AU(padapter, true, 0, IMR_BCNDMAINT0_8723B); ++#endif /* CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT */ ++ ++#ifdef CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ UpdateInterruptMask8812AU(padapter, true , 0, (IMR_TXBCN0ERR_8723B|IMR_TXBCN0OK_8723B)); ++#endif /* CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR */ ++ ++#endif /* CONFIG_INTERRUPT_BASED_TXBCN */ ++ } ++ ++ /* disable atim wnd */ ++ rtw_write8(padapter, REG_BCN_CTRL, DIS_TSF_UDT|EN_BCN_FUNCTION|DIS_ATIM); ++ /* rtw_write8(padapter, REG_BCN_CTRL, 0x18); */ ++ } ++ else if ((mode == _HW_STATE_ADHOC_) /*|| (mode == _HW_STATE_AP_)*/) ++ { ++ ResumeTxBeacon(padapter); ++ rtw_write8(padapter, REG_BCN_CTRL, DIS_TSF_UDT|EN_BCN_FUNCTION|DIS_BCNQ_SUB); ++ } ++ else if (mode == _HW_STATE_AP_) ++ { ++#ifdef CONFIG_INTERRUPT_BASED_TXBCN ++#ifdef CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT ++ UpdateInterruptMask8723BU(padapter, true , IMR_BCNDMAINT0_8723B, 0); ++#endif /* CONFIG_INTERRUPT_BASED_TXBCN_EARLY_INT */ ++ ++#ifdef CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR ++ UpdateInterruptMask8723BU(padapter, true , (IMR_TXBCN0ERR_8723B|IMR_TXBCN0OK_8723B), 0); ++#endif /* CONFIG_INTERRUPT_BASED_TXBCN_BCN_OK_ERR */ ++ ++#endif /* CONFIG_INTERRUPT_BASED_TXBCN */ ++ ++ ResumeTxBeacon(padapter); ++ ++ rtw_write8(padapter, REG_BCN_CTRL, DIS_TSF_UDT|DIS_BCNQ_SUB); ++ ++ /* Set RCR */ ++ rtw_write32(padapter, REG_RCR, 0x7000208e);/* CBSSID_DATA must set to 0, reject ICV_ERR packet */ ++ /* enable to rx data frame */ ++ rtw_write16(padapter, REG_RXFLTMAP2, 0xFFFF); ++ /* enable to rx ps-poll */ ++ rtw_write16(padapter, REG_RXFLTMAP1, 0x0400); ++ ++ /* Beacon Control related register for first time */ ++ rtw_write8(padapter, REG_BCNDMATIM, 0x02); /* 2ms */ ++ ++ /* rtw_write8(padapter, REG_BCN_MAX_ERR, 0xFF); */ ++ rtw_write8(padapter, REG_ATIMWND, 0x0a); /* 10ms */ ++ rtw_write16(padapter, REG_BCNTCFG, 0x00); ++ rtw_write16(padapter, REG_TBTT_PROHIBIT, 0xff04); ++ rtw_write16(padapter, REG_TSFTR_SYN_OFFSET, 0x7fff);/* +32767 (~32ms) */ ++ ++ /* reset TSF */ ++ rtw_write8(padapter, REG_DUAL_TSF_RST, BIT(0)); ++ ++ /* enable BCN0 Function for if1 */ ++ /* don't enable update TSF0 for if1 (due to TSF update when beacon/probe rsp are received) */ ++ rtw_write8(padapter, REG_BCN_CTRL, (DIS_TSF_UDT|EN_BCN_FUNCTION|EN_TXBCN_RPT|DIS_BCNQ_SUB)); ++ ++ /* SW_BCN_SEL - Port0 */ ++ /* rtw_write8(Adapter, REG_DWBCN1_CTRL_8192E+2, rtw_read8(Adapter, REG_DWBCN1_CTRL_8192E+2) & ~BIT4); */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL); ++ ++ /* select BCN on port 0 */ ++ rtw_write8(padapter, REG_CCK_CHECK_8723B, ++ (rtw_read8(padapter, REG_CCK_CHECK_8723B)& ~BIT_BCN_PORT_SEL)); ++ ++ /* dis BCN1 ATIM WND if if2 is station */ ++ val8 = rtw_read8(padapter, REG_BCN_CTRL_1); ++ val8 |= DIS_ATIM; ++ rtw_write8(padapter, REG_BCN_CTRL_1, val8); ++ } ++ } ++} ++ ++static void hw_var_set_macaddr(struct adapter *padapter, u8 variable, u8 *val) ++{ ++ u8 idx = 0; ++ u32 reg_macid; ++ ++ reg_macid = REG_MACID; ++ ++ for (idx = 0 ; idx < 6; idx++) ++ { ++ rtw_write8(GET_PRIMARY_ADAPTER(padapter), (reg_macid+idx), val[idx]); ++ } ++} ++ ++static void hw_var_set_bssid(struct adapter *padapter, u8 variable, u8 *val) ++{ ++ u8 idx = 0; ++ u32 reg_bssid; ++ ++ reg_bssid = REG_BSSID; ++ ++ for (idx = 0 ; idx < 6; idx++) ++ { ++ rtw_write8(padapter, (reg_bssid+idx), val[idx]); ++ } ++} ++ ++static void hw_var_set_bcn_func(struct adapter *padapter, u8 variable, u8 *val) ++{ ++ u32 bcn_ctrl_reg; ++ ++ bcn_ctrl_reg = REG_BCN_CTRL; ++ ++ if (*(u8 *)val) ++ { ++ rtw_write8(padapter, bcn_ctrl_reg, (EN_BCN_FUNCTION | EN_TXBCN_RPT)); ++ } ++ else ++ { ++ u8 val8; ++ val8 = rtw_read8(padapter, bcn_ctrl_reg); ++ val8 &= ~(EN_BCN_FUNCTION | EN_TXBCN_RPT); ++ ++ /* Always enable port0 beacon function for PSTDMA */ ++ if (REG_BCN_CTRL == bcn_ctrl_reg) ++ val8 |= EN_BCN_FUNCTION; ++ ++ rtw_write8(padapter, bcn_ctrl_reg, val8); ++ } ++} ++ ++static void hw_var_set_correct_tsf(struct adapter *padapter, u8 variable, u8 *val) ++{ ++ u8 val8; ++ u64 tsf; ++ struct mlme_ext_priv *pmlmeext; ++ struct mlme_ext_info *pmlmeinfo; ++ ++ ++ pmlmeext = &padapter->mlmeextpriv; ++ pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ tsf = pmlmeext->TSFValue - rtw_modular64(pmlmeext->TSFValue, (pmlmeinfo->bcn_interval*1024)) -1024; /* us */ ++ ++ if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ++ ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) ++ { ++ StopTxBeacon(padapter); ++ } ++ ++ { ++ /* disable related TSF function */ ++ val8 = rtw_read8(padapter, REG_BCN_CTRL); ++ val8 &= ~EN_BCN_FUNCTION; ++ rtw_write8(padapter, REG_BCN_CTRL, val8); ++ ++ rtw_write32(padapter, REG_TSFTR, tsf); ++ rtw_write32(padapter, REG_TSFTR+4, tsf>>32); ++ ++ /* enable related TSF function */ ++ val8 = rtw_read8(padapter, REG_BCN_CTRL); ++ val8 |= EN_BCN_FUNCTION; ++ rtw_write8(padapter, REG_BCN_CTRL, val8); ++ } ++ ++ if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) ++ || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) ++ { ++ ResumeTxBeacon(padapter); ++ } ++} ++ ++static void hw_var_set_mlme_disconnect(struct adapter *padapter, u8 variable, u8 *val) ++{ ++ u8 val8; ++ ++ /* Set RCR to not to receive data frame when NO LINK state */ ++ /* rtw_write32(padapter, REG_RCR, rtw_read32(padapter, REG_RCR) & ~RCR_ADF); */ ++ /* reject all data frames */ ++ rtw_write16(padapter, REG_RXFLTMAP2, 0); ++ ++ /* reset TSF */ ++ rtw_write8(padapter, REG_DUAL_TSF_RST, BIT(0)); ++ ++ /* disable update TSF */ ++ val8 = rtw_read8(padapter, REG_BCN_CTRL); ++ val8 |= DIS_TSF_UDT; ++ rtw_write8(padapter, REG_BCN_CTRL, val8); ++} ++ ++static void hw_var_set_mlme_sitesurvey(struct adapter *padapter, u8 variable, u8 *val) ++{ ++ u32 value_rcr, rcr_clear_bit, reg_bcn_ctl; ++ u16 value_rxfltmap2; ++ u8 val8; ++ struct hal_com_data *pHalData; ++ struct mlme_priv *pmlmepriv; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ pmlmepriv = &padapter->mlmepriv; ++ ++ reg_bcn_ctl = REG_BCN_CTRL; ++ ++ rcr_clear_bit = RCR_CBSSID_BCN; ++ ++ /* config RCR to receive different BSSID & not to receive data frame */ ++ value_rxfltmap2 = 0; ++ ++ if ((check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)) ++ { ++ rcr_clear_bit = RCR_CBSSID_BCN; ++ } ++ value_rcr = rtw_read32(padapter, REG_RCR); ++ ++ if (*((u8 *)val)) ++ { ++ /* under sitesurvey */ ++ value_rcr &= ~(rcr_clear_bit); ++ rtw_write32(padapter, REG_RCR, value_rcr); ++ ++ rtw_write16(padapter, REG_RXFLTMAP2, value_rxfltmap2); ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE)) ++ { ++ /* disable update TSF */ ++ val8 = rtw_read8(padapter, reg_bcn_ctl); ++ val8 |= DIS_TSF_UDT; ++ rtw_write8(padapter, reg_bcn_ctl, val8); ++ } ++ ++ /* Save orignal RRSR setting. */ ++ pHalData->RegRRSR = rtw_read16(padapter, REG_RRSR); ++ } ++ else ++ { ++ /* sitesurvey done */ ++ if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE))) ++ { ++ /* enable to rx data frame */ ++ rtw_write16(padapter, REG_RXFLTMAP2, 0xFFFF); ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE)) ++ { ++ /* enable update TSF */ ++ val8 = rtw_read8(padapter, reg_bcn_ctl); ++ val8 &= ~DIS_TSF_UDT; ++ rtw_write8(padapter, reg_bcn_ctl, val8); ++ } ++ ++ value_rcr |= rcr_clear_bit; ++ rtw_write32(padapter, REG_RCR, value_rcr); ++ ++ /* Restore orignal RRSR setting. */ ++ rtw_write16(padapter, REG_RRSR, pHalData->RegRRSR); ++ } ++} ++ ++static void hw_var_set_mlme_join(struct adapter *padapter, u8 variable, u8 *val) ++{ ++ u8 val8; ++ u16 val16; ++ u32 val32; ++ u8 RetryLimit; ++ u8 type; ++ struct hal_com_data *pHalData; ++ struct mlme_priv *pmlmepriv; ++ struct eeprom_priv *pEEPROM; ++ ++ ++ RetryLimit = 0x30; ++ type = *(u8 *)val; ++ pHalData = GET_HAL_DATA(padapter); ++ pmlmepriv = &padapter->mlmepriv; ++ pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ ++ if (type == 0) /* prepare to join */ ++ { ++ /* enable to rx data frame.Accept all data frame */ ++ /* rtw_write32(padapter, REG_RCR, rtw_read32(padapter, REG_RCR)|RCR_ADF); */ ++ rtw_write16(padapter, REG_RXFLTMAP2, 0xFFFF); ++ ++ val32 = rtw_read32(padapter, REG_RCR); ++ if (padapter->in_cta_test) ++ val32 &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN);/* RCR_ADF */ ++ else ++ val32 |= RCR_CBSSID_DATA|RCR_CBSSID_BCN; ++ rtw_write32(padapter, REG_RCR, val32); ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) ++ { ++ RetryLimit = (pEEPROM->CustomerID == RT_CID_CCX) ? 7 : 48; ++ } ++ else /* Ad-hoc Mode */ ++ { ++ RetryLimit = 0x7; ++ } ++ } ++ else if (type == 1) /* joinbss_event call back when join res < 0 */ ++ { ++ rtw_write16(padapter, REG_RXFLTMAP2, 0x00); ++ } ++ else if (type == 2) /* sta add event call back */ ++ { ++ /* enable update TSF */ ++ val8 = rtw_read8(padapter, REG_BCN_CTRL); ++ val8 &= ~DIS_TSF_UDT; ++ rtw_write8(padapter, REG_BCN_CTRL, val8); ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) ++ { ++ RetryLimit = 0x7; ++ } ++ } ++ ++ val16 = (RetryLimit << RETRY_LIMIT_SHORT_SHIFT) | (RetryLimit << RETRY_LIMIT_LONG_SHIFT); ++ rtw_write16(padapter, REG_RL, val16); ++} ++ ++void CCX_FwC2HTxRpt_8723b(struct adapter *padapter, u8 *pdata, u8 len) ++{ ++ u8 seq_no; ++ ++#define GET_8723B_C2H_TX_RPT_LIFE_TIME_OVER(_Header) LE_BITS_TO_1BYTE((_Header + 0), 6, 1) ++#define GET_8723B_C2H_TX_RPT_RETRY_OVER(_Header) LE_BITS_TO_1BYTE((_Header + 0), 7, 1) ++ ++ /* DBG_871X("%s, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", __func__, */ ++ /* *pdata, *(pdata+1), *(pdata+2), *(pdata+3), *(pdata+4), *(pdata+5), *(pdata+6), *(pdata+7)); */ ++ ++ seq_no = *(pdata+6); ++ ++ if (GET_8723B_C2H_TX_RPT_RETRY_OVER(pdata) | GET_8723B_C2H_TX_RPT_LIFE_TIME_OVER(pdata)) { ++ rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_CCX_PKT_FAIL); ++ } ++/* ++ else if (seq_no != padapter->xmitpriv.seq_no) { ++ DBG_871X("tx_seq_no =%d, rpt_seq_no =%d\n", padapter->xmitpriv.seq_no, seq_no); ++ rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_CCX_PKT_FAIL); ++ } ++*/ ++ else { ++ rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_SUCCESS); ++ } ++} ++ ++s32 c2h_id_filter_ccx_8723b(u8 *buf) ++{ ++ struct c2h_evt_hdr_88xx *c2h_evt = (struct c2h_evt_hdr_88xx *)buf; ++ s32 ret = false; ++ if (c2h_evt->id == C2H_CCX_TX_RPT) ++ ret = true; ++ ++ return ret; ++} ++ ++ ++s32 c2h_handler_8723b(struct adapter *padapter, u8 *buf) ++{ ++ struct c2h_evt_hdr_88xx *pC2hEvent = (struct c2h_evt_hdr_88xx *)buf; ++ s32 ret = _SUCCESS; ++ u8 index = 0; ++ ++ if (pC2hEvent == NULL) { ++ DBG_8192C("%s(): pC2hEventis NULL\n", __func__); ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ switch (pC2hEvent->id) ++ { ++ case C2H_AP_RPT_RSP: ++ break; ++ case C2H_DBG: ++ { ++ RT_TRACE(_module_hal_init_c_, _drv_info_, ("c2h_handler_8723b: %s\n", pC2hEvent->payload)); ++ } ++ break; ++ ++ case C2H_CCX_TX_RPT: ++/* CCX_FwC2HTxRpt(padapter, QueueID, pC2hEvent->payload); */ ++ break; ++ ++ case C2H_EXT_RA_RPT: ++/* C2HExtRaRptHandler(padapter, pC2hEvent->payload, C2hEvent.CmdLen); */ ++ break; ++ ++ case C2H_HW_INFO_EXCH: ++ RT_TRACE(_module_hal_init_c_, _drv_info_, ("[BT], C2H_HW_INFO_EXCH\n")); ++ for (index = 0; index < pC2hEvent->plen; index++) ++ { ++ RT_TRACE(_module_hal_init_c_, _drv_info_, ("[BT], tmpBuf[%d]= 0x%x\n", index, pC2hEvent->payload[index])); ++ } ++ break; ++ ++ case C2H_8723B_BT_INFO: ++ rtw_btcoex_BtInfoNotify(padapter, pC2hEvent->plen, pC2hEvent->payload); ++ break; ++ ++ default: ++ break; ++ } ++ ++ /* Clear event to notify FW we have read the command. */ ++ /* Note: */ ++ /* If this field isn't clear, the FW won't update the next command message. */ ++/* rtw_write8(padapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE); */ ++exit: ++ return ret; ++} ++ ++static void process_c2h_event(struct adapter *padapter, PC2H_EVT_HDR pC2hEvent, u8 *c2hBuf) ++{ ++ u8 index = 0; ++ ++ if (c2hBuf == NULL) { ++ DBG_8192C("%s c2hbuff is NULL\n", __func__); ++ return; ++ } ++ ++ switch (pC2hEvent->CmdID) ++ { ++ case C2H_AP_RPT_RSP: ++ break; ++ case C2H_DBG: ++ { ++ RT_TRACE(_module_hal_init_c_, _drv_info_, ("C2HCommandHandler: %s\n", c2hBuf)); ++ } ++ break; ++ ++ case C2H_CCX_TX_RPT: ++/* CCX_FwC2HTxRpt(padapter, QueueID, tmpBuf); */ ++ break; ++ ++ case C2H_EXT_RA_RPT: ++/* C2HExtRaRptHandler(padapter, tmpBuf, C2hEvent.CmdLen); */ ++ break; ++ ++ case C2H_HW_INFO_EXCH: ++ RT_TRACE(_module_hal_init_c_, _drv_info_, ("[BT], C2H_HW_INFO_EXCH\n")); ++ for (index = 0; index < pC2hEvent->CmdLen; index++) ++ { ++ RT_TRACE(_module_hal_init_c_, _drv_info_, ("[BT], tmpBuf[%d]= 0x%x\n", index, c2hBuf[index])); ++ } ++ break; ++ ++ case C2H_8723B_BT_INFO: ++ rtw_btcoex_BtInfoNotify(padapter, pC2hEvent->CmdLen, c2hBuf); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++void C2HPacketHandler_8723B(struct adapter *padapter, u8 *pbuffer, u16 length) ++{ ++ C2H_EVT_HDR C2hEvent; ++ u8 *tmpBuf = NULL; ++#ifdef CONFIG_WOWLAN ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ ++ if (pwrpriv->wowlan_mode == true) ++ { ++ DBG_871X("%s(): return because wowolan_mode ==true! CMDID =%d\n", __func__, pbuffer[0]); ++ return; ++ } ++#endif ++ C2hEvent.CmdID = pbuffer[0]; ++ C2hEvent.CmdSeq = pbuffer[1]; ++ C2hEvent.CmdLen = length -2; ++ tmpBuf = pbuffer+2; ++ ++ /* DBG_871X("%s C2hEvent.CmdID:%x C2hEvent.CmdLen:%x C2hEvent.CmdSeq:%x\n", */ ++ /* __func__, C2hEvent.CmdID, C2hEvent.CmdLen, C2hEvent.CmdSeq); */ ++ RT_PRINT_DATA(_module_hal_init_c_, _drv_notice_, "C2HPacketHandler_8723B(): Command Content:\n", tmpBuf, C2hEvent.CmdLen); ++ ++ process_c2h_event(padapter,&C2hEvent, tmpBuf); ++ /* c2h_handler_8723b(padapter,&C2hEvent); */ ++ return; ++} ++ ++void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ u8 val8; ++ u32 val32; ++ ++ switch (variable) { ++ case HW_VAR_MEDIA_STATUS: ++ val8 = rtw_read8(padapter, MSR) & 0x0c; ++ val8 |= *val; ++ rtw_write8(padapter, MSR, val8); ++ break; ++ ++ case HW_VAR_MEDIA_STATUS1: ++ val8 = rtw_read8(padapter, MSR) & 0x03; ++ val8 |= *val << 2; ++ rtw_write8(padapter, MSR, val8); ++ break; ++ ++ case HW_VAR_SET_OPMODE: ++ hw_var_set_opmode(padapter, variable, val); ++ break; ++ ++ case HW_VAR_MAC_ADDR: ++ hw_var_set_macaddr(padapter, variable, val); ++ break; ++ ++ case HW_VAR_BSSID: ++ hw_var_set_bssid(padapter, variable, val); ++ break; ++ ++ case HW_VAR_BASIC_RATE: ++ { ++ struct mlme_ext_info *mlmext_info = &padapter->mlmeextpriv.mlmext_info; ++ u16 input_b = 0, masked = 0, ioted = 0, BrateCfg = 0; ++ u16 rrsr_2g_force_mask = (RRSR_11M|RRSR_5_5M|RRSR_1M); ++ u16 rrsr_2g_allow_mask = (RRSR_24M|RRSR_12M|RRSR_6M|RRSR_CCK_RATES); ++ ++ HalSetBrateCfg(padapter, val, &BrateCfg); ++ input_b = BrateCfg; ++ ++ /* apply force and allow mask */ ++ BrateCfg |= rrsr_2g_force_mask; ++ BrateCfg &= rrsr_2g_allow_mask; ++ masked = BrateCfg; ++ ++ #ifdef CONFIG_CMCC_TEST ++ BrateCfg |= (RRSR_11M|RRSR_5_5M|RRSR_1M); /* use 11M to send ACK */ ++ BrateCfg |= (RRSR_24M|RRSR_18M|RRSR_12M); /* CMCC_OFDM_ACK 12/18/24M */ ++ #endif ++ ++ /* IOT consideration */ ++ if (mlmext_info->assoc_AP_vendor == HT_IOT_PEER_CISCO) { ++ /* if peer is cisco and didn't use ofdm rate, we enable 6M ack */ ++ if ((BrateCfg & (RRSR_24M|RRSR_12M|RRSR_6M)) == 0) ++ BrateCfg |= RRSR_6M; ++ } ++ ioted = BrateCfg; ++ ++ pHalData->BasicRateSet = BrateCfg; ++ ++ DBG_8192C("HW_VAR_BASIC_RATE: %#x -> %#x -> %#x\n", input_b, masked, ioted); ++ ++ /* Set RRSR rate table. */ ++ rtw_write16(padapter, REG_RRSR, BrateCfg); ++ rtw_write8(padapter, REG_RRSR+2, rtw_read8(padapter, REG_RRSR+2)&0xf0); ++ } ++ break; ++ ++ case HW_VAR_TXPAUSE: ++ rtw_write8(padapter, REG_TXPAUSE, *val); ++ break; ++ ++ case HW_VAR_BCN_FUNC: ++ hw_var_set_bcn_func(padapter, variable, val); ++ break; ++ ++ case HW_VAR_CORRECT_TSF: ++ hw_var_set_correct_tsf(padapter, variable, val); ++ break; ++ ++ case HW_VAR_CHECK_BSSID: ++ { ++ u32 val32; ++ val32 = rtw_read32(padapter, REG_RCR); ++ if (*val) ++ val32 |= RCR_CBSSID_DATA|RCR_CBSSID_BCN; ++ else ++ val32 &= ~(RCR_CBSSID_DATA|RCR_CBSSID_BCN); ++ rtw_write32(padapter, REG_RCR, val32); ++ } ++ break; ++ ++ case HW_VAR_MLME_DISCONNECT: ++ hw_var_set_mlme_disconnect(padapter, variable, val); ++ break; ++ ++ case HW_VAR_MLME_SITESURVEY: ++ hw_var_set_mlme_sitesurvey(padapter, variable, val); ++ ++ rtw_btcoex_ScanNotify(padapter, *val?true:false); ++ break; ++ ++ case HW_VAR_MLME_JOIN: ++ hw_var_set_mlme_join(padapter, variable, val); ++ ++ switch (*val) ++ { ++ case 0: ++ /* prepare to join */ ++ rtw_btcoex_ConnectNotify(padapter, true); ++ break; ++ case 1: ++ /* joinbss_event callback when join res < 0 */ ++ rtw_btcoex_ConnectNotify(padapter, false); ++ break; ++ case 2: ++ /* sta add event callback */ ++/* rtw_btcoex_MediaStatusNotify(padapter, RT_MEDIA_CONNECT); */ ++ break; ++ } ++ break; ++ ++ case HW_VAR_ON_RCR_AM: ++ val32 = rtw_read32(padapter, REG_RCR); ++ val32 |= RCR_AM; ++ rtw_write32(padapter, REG_RCR, val32); ++ DBG_8192C("%s, %d, RCR = %x\n", __func__, __LINE__, rtw_read32(padapter, REG_RCR)); ++ break; ++ ++ case HW_VAR_OFF_RCR_AM: ++ val32 = rtw_read32(padapter, REG_RCR); ++ val32 &= ~RCR_AM; ++ rtw_write32(padapter, REG_RCR, val32); ++ DBG_8192C("%s, %d, RCR = %x\n", __func__, __LINE__, rtw_read32(padapter, REG_RCR)); ++ break; ++ ++ case HW_VAR_BEACON_INTERVAL: ++ rtw_write16(padapter, REG_BCN_INTERVAL, *((u16*)val)); ++ break; ++ ++ case HW_VAR_SLOT_TIME: ++ rtw_write8(padapter, REG_SLOT, *val); ++ break; ++ ++ case HW_VAR_RESP_SIFS: ++ /* SIFS_Timer = 0x0a0a0808; */ ++ /* RESP_SIFS for CCK */ ++ rtw_write8(padapter, REG_RESP_SIFS_CCK, val[0]); /* SIFS_T2T_CCK (0x08) */ ++ rtw_write8(padapter, REG_RESP_SIFS_CCK+1, val[1]); /* SIFS_R2T_CCK(0x08) */ ++ /* RESP_SIFS for OFDM */ ++ rtw_write8(padapter, REG_RESP_SIFS_OFDM, val[2]); /* SIFS_T2T_OFDM (0x0a) */ ++ rtw_write8(padapter, REG_RESP_SIFS_OFDM+1, val[3]); /* SIFS_R2T_OFDM(0x0a) */ ++ break; ++ ++ case HW_VAR_ACK_PREAMBLE: ++ { ++ u8 regTmp; ++ u8 bShortPreamble = *val; ++ ++ /* Joseph marked out for Netgear 3500 TKIP channel 7 issue.(Temporarily) */ ++ /* regTmp = (pHalData->nCur40MhzPrimeSC)<<5; */ ++ regTmp = 0; ++ if (bShortPreamble) regTmp |= 0x80; ++ rtw_write8(padapter, REG_RRSR+2, regTmp); ++ } ++ break; ++ ++ case HW_VAR_CAM_EMPTY_ENTRY: ++ { ++ u8 ucIndex = *val; ++ u8 i; ++ u32 ulCommand = 0; ++ u32 ulContent = 0; ++ u32 ulEncAlgo = CAM_AES; ++ ++ for (i = 0; iAcParam_BE = ((u32*)(val))[0]; ++ rtw_write32(padapter, REG_EDCA_BE_PARAM, *((u32*)val)); ++ break; ++ ++ case HW_VAR_AC_PARAM_BK: ++ rtw_write32(padapter, REG_EDCA_BK_PARAM, *((u32*)val)); ++ break; ++ ++ case HW_VAR_ACM_CTRL: ++ { ++ u8 ctrl = *((u8 *)val); ++ u8 hwctrl = 0; ++ ++ if (ctrl != 0) ++ { ++ hwctrl |= AcmHw_HwEn; ++ ++ if (ctrl & BIT(1)) /* BE */ ++ hwctrl |= AcmHw_BeqEn; ++ ++ if (ctrl & BIT(2)) /* VI */ ++ hwctrl |= AcmHw_ViqEn; ++ ++ if (ctrl & BIT(3)) /* VO */ ++ hwctrl |= AcmHw_VoqEn; ++ } ++ ++ DBG_8192C("[HW_VAR_ACM_CTRL] Write 0x%02X\n", hwctrl); ++ rtw_write8(padapter, REG_ACMHWCTRL, hwctrl); ++ } ++ break; ++ ++ case HW_VAR_AMPDU_FACTOR: ++ { ++ u32 AMPDULen = (*((u8 *)val)); ++ ++ if (AMPDULen < HT_AGG_SIZE_32K) ++ AMPDULen = (0x2000 << (*((u8 *)val))) -1; ++ else ++ AMPDULen = 0x7fff; ++ ++ rtw_write32(padapter, REG_AMPDU_MAX_LENGTH_8723B, AMPDULen); ++ } ++ break; ++ ++ case HW_VAR_H2C_FW_PWRMODE: ++ { ++ u8 psmode = *val; ++ ++ /* Forece leave RF low power mode for 1T1R to prevent conficting setting in Fw power */ ++ /* saving sequence. 2010.06.07. Added by tynli. Suggested by SD3 yschang. */ ++ if (psmode != PS_MODE_ACTIVE) ++ { ++ ODM_RF_Saving(&pHalData->odmpriv, true); ++ } ++ ++ /* if (psmode != PS_MODE_ACTIVE) { */ ++ /* rtl8723b_set_lowpwr_lps_cmd(padapter, true); */ ++ /* else { */ ++ /* rtl8723b_set_lowpwr_lps_cmd(padapter, false); */ ++ /* */ ++ rtl8723b_set_FwPwrMode_cmd(padapter, psmode); ++ } ++ break; ++ case HW_VAR_H2C_PS_TUNE_PARAM: ++ rtl8723b_set_FwPsTuneParam_cmd(padapter); ++ break; ++ ++ case HW_VAR_H2C_FW_JOINBSSRPT: ++ rtl8723b_set_FwJoinBssRpt_cmd(padapter, *val); ++ break; ++ ++ case HW_VAR_INITIAL_GAIN: ++ { ++ DIG_T *pDigTable = &pHalData->odmpriv.DM_DigTable; ++ u32 rx_gain = *(u32*)val; ++ ++ if (rx_gain == 0xff) {/* restore rx gain */ ++ ODM_Write_DIG(&pHalData->odmpriv, pDigTable->BackupIGValue); ++ } else { ++ pDigTable->BackupIGValue = pDigTable->CurIGValue; ++ ODM_Write_DIG(&pHalData->odmpriv, rx_gain); ++ } ++ } ++ break; ++ ++ case HW_VAR_EFUSE_USAGE: ++ pHalData->EfuseUsedPercentage = *val; ++ break; ++ ++ case HW_VAR_EFUSE_BYTES: ++ pHalData->EfuseUsedBytes = *((u16*)val); ++ break; ++ ++ case HW_VAR_EFUSE_BT_USAGE: ++#ifdef HAL_EFUSE_MEMORY ++ pHalData->EfuseHal.BTEfuseUsedPercentage = *val; ++#endif ++ break; ++ ++ case HW_VAR_EFUSE_BT_BYTES: ++#ifdef HAL_EFUSE_MEMORY ++ pHalData->EfuseHal.BTEfuseUsedBytes = *((u16*)val); ++#else ++ BTEfuseUsedBytes = *((u16*)val); ++#endif ++ break; ++ ++ case HW_VAR_FIFO_CLEARN_UP: ++ { ++ #define RW_RELEASE_EN BIT(18) ++ #define RXDMA_IDLE BIT(17) ++ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ u8 trycnt = 100; ++ ++ /* pause tx */ ++ rtw_write8(padapter, REG_TXPAUSE, 0xff); ++ ++ /* keep sn */ ++ padapter->xmitpriv.nqos_ssn = rtw_read16(padapter, REG_NQOS_SEQ); ++ ++ if (pwrpriv->bkeepfwalive != true) ++ { ++ /* RX DMA stop */ ++ val32 = rtw_read32(padapter, REG_RXPKT_NUM); ++ val32 |= RW_RELEASE_EN; ++ rtw_write32(padapter, REG_RXPKT_NUM, val32); ++ do { ++ val32 = rtw_read32(padapter, REG_RXPKT_NUM); ++ val32 &= RXDMA_IDLE; ++ if (val32) ++ break; ++ ++ DBG_871X("%s: [HW_VAR_FIFO_CLEARN_UP] val =%x times:%d\n", __func__, val32, trycnt); ++ } while (--trycnt); ++ if (trycnt == 0) { ++ DBG_8192C("[HW_VAR_FIFO_CLEARN_UP] Stop RX DMA failed......\n"); ++ } ++ ++ /* RQPN Load 0 */ ++ rtw_write16(padapter, REG_RQPN_NPQ, 0); ++ rtw_write32(padapter, REG_RQPN, 0x80000000); ++ mdelay(2); ++ } ++ } ++ break; ++ ++ case HW_VAR_APFM_ON_MAC: ++ pHalData->bMacPwrCtrlOn = *val; ++ DBG_8192C("%s: bMacPwrCtrlOn =%d\n", __func__, pHalData->bMacPwrCtrlOn); ++ break; ++ ++ case HW_VAR_NAV_UPPER: ++ { ++ u32 usNavUpper = *((u32*)val); ++ ++ if (usNavUpper > HAL_NAV_UPPER_UNIT_8723B * 0xFF) ++ { ++ RT_TRACE(_module_hal_init_c_, _drv_notice_, ("The setting value (0x%08X us) of NAV_UPPER is larger than (%d * 0xFF)!!!\n", usNavUpper, HAL_NAV_UPPER_UNIT_8723B)); ++ break; ++ } ++ ++ /* The value of ((usNavUpper + HAL_NAV_UPPER_UNIT_8723B - 1) / HAL_NAV_UPPER_UNIT_8723B) */ ++ /* is getting the upper integer. */ ++ usNavUpper = (usNavUpper + HAL_NAV_UPPER_UNIT_8723B - 1) / HAL_NAV_UPPER_UNIT_8723B; ++ rtw_write8(padapter, REG_NAV_UPPER, (u8)usNavUpper); ++ } ++ break; ++ ++ case HW_VAR_H2C_MEDIA_STATUS_RPT: ++ { ++ u16 mstatus_rpt = (*(u16 *)val); ++ u8 mstatus, macId; ++ ++ mstatus = (u8) (mstatus_rpt & 0xFF); ++ macId = (u8)(mstatus_rpt >> 8) ; ++ rtl8723b_set_FwMediaStatusRpt_cmd(padapter , mstatus, macId); ++ } ++ break; ++ case HW_VAR_BCN_VALID: ++ { ++ /* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2, write 1 to clear, Clear by sw */ ++ val8 = rtw_read8(padapter, REG_TDECTRL+2); ++ val8 |= BIT(0); ++ rtw_write8(padapter, REG_TDECTRL+2, val8); ++ } ++ break; ++ ++ case HW_VAR_DL_BCN_SEL: ++ { ++ /* SW_BCN_SEL - Port0 */ ++ val8 = rtw_read8(padapter, REG_DWBCN1_CTRL_8723B+2); ++ val8 &= ~BIT(4); ++ rtw_write8(padapter, REG_DWBCN1_CTRL_8723B+2, val8); ++ } ++ break; ++ ++ case HW_VAR_DO_IQK: ++ pHalData->bNeedIQK = true; ++ break; ++ ++ case HW_VAR_DL_RSVD_PAGE: ++ if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true) ++ { ++ rtl8723b_download_BTCoex_AP_mode_rsvd_page(padapter); ++ } ++ else ++ { ++ rtl8723b_download_rsvd_page(padapter, RT_MEDIA_CONNECT); ++ } ++ break; ++ ++ case HW_VAR_MACID_SLEEP: ++ /* Input is MACID */ ++ val32 = *(u32*)val; ++ if (val32 > 31) { ++ DBG_8192C(FUNC_ADPT_FMT ": [HW_VAR_MACID_SLEEP] Invalid macid(%d)\n", ++ FUNC_ADPT_ARG(padapter), val32); ++ break; ++ } ++ val8 = (u8)val32; /* macid is between 0~31 */ ++ ++ val32 = rtw_read32(padapter, REG_MACID_SLEEP); ++ DBG_8192C(FUNC_ADPT_FMT ": [HW_VAR_MACID_SLEEP] macid =%d, org MACID_SLEEP = 0x%08X\n", ++ FUNC_ADPT_ARG(padapter), val8, val32); ++ if (val32 & BIT(val8)) ++ break; ++ val32 |= BIT(val8); ++ rtw_write32(padapter, REG_MACID_SLEEP, val32); ++ break; ++ ++ case HW_VAR_MACID_WAKEUP: ++ /* Input is MACID */ ++ val32 = *(u32*)val; ++ if (val32 > 31) { ++ DBG_8192C(FUNC_ADPT_FMT ": [HW_VAR_MACID_WAKEUP] Invalid macid(%d)\n", ++ FUNC_ADPT_ARG(padapter), val32); ++ break; ++ } ++ val8 = (u8)val32; /* macid is between 0~31 */ ++ ++ val32 = rtw_read32(padapter, REG_MACID_SLEEP); ++ DBG_8192C(FUNC_ADPT_FMT ": [HW_VAR_MACID_WAKEUP] macid =%d, org MACID_SLEEP = 0x%08X\n", ++ FUNC_ADPT_ARG(padapter), val8, val32); ++ if (!(val32 & BIT(val8))) ++ break; ++ val32 &= ~BIT(val8); ++ rtw_write32(padapter, REG_MACID_SLEEP, val32); ++ break; ++ ++ default: ++ SetHwReg(padapter, variable, val); ++ break; ++ } ++} ++ ++void GetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ u8 val8; ++ u16 val16; ++ ++ switch (variable) { ++ case HW_VAR_TXPAUSE: ++ *val = rtw_read8(padapter, REG_TXPAUSE); ++ break; ++ ++ case HW_VAR_BCN_VALID: ++ { ++ /* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2 */ ++ val8 = rtw_read8(padapter, REG_TDECTRL+2); ++ *val = (BIT(0) & val8) ? true:false; ++ } ++ break; ++ ++ case HW_VAR_FWLPS_RF_ON: ++ { ++ /* When we halt NIC, we should check if FW LPS is leave. */ ++ u32 valRCR; ++ ++ if ((padapter->bSurpriseRemoved == true) || ++ (adapter_to_pwrctl(padapter)->rf_pwrstate == rf_off)) ++ { ++ /* If it is in HW/SW Radio OFF or IPS state, we do not check Fw LPS Leave, */ ++ /* because Fw is unload. */ ++ *val = true; ++ } ++ else ++ { ++ valRCR = rtw_read32(padapter, REG_RCR); ++ valRCR &= 0x00070000; ++ if (valRCR) ++ *val = false; ++ else ++ *val = true; ++ } ++ } ++ break; ++ ++ case HW_VAR_EFUSE_USAGE: ++ *val = pHalData->EfuseUsedPercentage; ++ break; ++ ++ case HW_VAR_EFUSE_BYTES: ++ *((u16*)val) = pHalData->EfuseUsedBytes; ++ break; ++ ++ case HW_VAR_EFUSE_BT_USAGE: ++#ifdef HAL_EFUSE_MEMORY ++ *val = pHalData->EfuseHal.BTEfuseUsedPercentage; ++#endif ++ break; ++ ++ case HW_VAR_EFUSE_BT_BYTES: ++#ifdef HAL_EFUSE_MEMORY ++ *((u16*)val) = pHalData->EfuseHal.BTEfuseUsedBytes; ++#else ++ *((u16*)val) = BTEfuseUsedBytes; ++#endif ++ break; ++ ++ case HW_VAR_APFM_ON_MAC: ++ *val = pHalData->bMacPwrCtrlOn; ++ break; ++ case HW_VAR_CHK_HI_QUEUE_EMPTY: ++ val16 = rtw_read16(padapter, REG_TXPKT_EMPTY); ++ *val = (val16 & BIT(10)) ? true:false; ++ break; ++#ifdef CONFIG_WOWLAN ++ case HW_VAR_RPWM_TOG: ++ *val = rtw_read8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1) & BIT7; ++ break; ++ case HW_VAR_WAKEUP_REASON: ++ *val = rtw_read8(padapter, REG_WOWLAN_WAKE_REASON); ++ if (*val == 0xEA) ++ *val = 0; ++ break; ++ case HW_VAR_SYS_CLKR: ++ *val = rtw_read8(padapter, REG_SYS_CLKR); ++ break; ++#endif ++ default: ++ GetHwReg(padapter, variable, val); ++ break; ++ } ++} ++ ++/* ++ *Description: ++ * Change default setting of specified variable. ++ */ ++u8 SetHalDefVar8723B(struct adapter *padapter, enum HAL_DEF_VARIABLE variable, void *pval) ++{ ++ struct hal_com_data *pHalData; ++ u8 bResult; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ bResult = _SUCCESS; ++ ++ switch (variable) ++ { ++ default: ++ bResult = SetHalDefVar(padapter, variable, pval); ++ break; ++ } ++ ++ return bResult; ++} ++ ++/* ++ *Description: ++ * Query setting of specified variable. ++ */ ++u8 GetHalDefVar8723B(struct adapter *padapter, enum HAL_DEF_VARIABLE variable, void *pval) ++{ ++ struct hal_com_data *pHalData; ++ u8 bResult; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ bResult = _SUCCESS; ++ ++ switch (variable) ++ { ++ case HAL_DEF_MAX_RECVBUF_SZ: ++ *((u32*)pval) = MAX_RECVBUF_SZ; ++ break; ++ ++ case HAL_DEF_RX_PACKET_OFFSET: ++ *((u32*)pval) = RXDESC_SIZE + DRVINFO_SZ*8; ++ break; ++ ++ case HW_VAR_MAX_RX_AMPDU_FACTOR: ++ /* Stanley@BB.SD3 suggests 16K can get stable performance */ ++ /* The experiment was done on SDIO interface */ ++ /* coding by Lucas@20130730 */ ++ *(u32*)pval = MAX_AMPDU_FACTOR_16K; ++ break; ++ case HAL_DEF_TX_LDPC: ++ case HAL_DEF_RX_LDPC: ++ *((u8 *)pval) = false; ++ break; ++ case HAL_DEF_TX_STBC: ++ *((u8 *)pval) = 0; ++ break; ++ case HAL_DEF_RX_STBC: ++ *((u8 *)pval) = 1; ++ break; ++ case HAL_DEF_EXPLICIT_BEAMFORMER: ++ case HAL_DEF_EXPLICIT_BEAMFORMEE: ++ *((u8 *)pval) = false; ++ break; ++ ++ case HW_DEF_RA_INFO_DUMP: ++ { ++ u8 mac_id = *(u8 *)pval; ++ u32 cmd; ++ u32 ra_info1, ra_info2; ++ u32 rate_mask1, rate_mask2; ++ u8 curr_tx_rate, curr_tx_sgi, hight_rate, lowest_rate; ++ ++ DBG_8192C("============ RA status check Mac_id:%d ===================\n", mac_id); ++ ++ cmd = 0x40000100 | mac_id; ++ rtw_write32(padapter, REG_HMEBOX_DBG_2_8723B, cmd); ++ msleep(10); ++ ra_info1 = rtw_read32(padapter, 0x2F0); ++ curr_tx_rate = ra_info1&0x7F; ++ curr_tx_sgi = (ra_info1>>7)&0x01; ++ DBG_8192C("[ ra_info1:0x%08x ] =>cur_tx_rate = %s, cur_sgi:%d, PWRSTS = 0x%02x \n", ++ ra_info1, ++ HDATA_RATE(curr_tx_rate), ++ curr_tx_sgi, ++ (ra_info1>>8) & 0x07); ++ ++ cmd = 0x40000400 | mac_id; ++ rtw_write32(padapter, REG_HMEBOX_DBG_2_8723B, cmd); ++ msleep(10); ++ ra_info1 = rtw_read32(padapter, 0x2F0); ++ ra_info2 = rtw_read32(padapter, 0x2F4); ++ rate_mask1 = rtw_read32(padapter, 0x2F8); ++ rate_mask2 = rtw_read32(padapter, 0x2FC); ++ hight_rate = ra_info2&0xFF; ++ lowest_rate = (ra_info2>>8) & 0xFF; ++ ++ DBG_8192C("[ ra_info1:0x%08x ] =>RSSI =%d, BW_setting = 0x%02x, DISRA = 0x%02x, VHT_EN = 0x%02x\n", ++ ra_info1, ++ ra_info1&0xFF, ++ (ra_info1>>8) & 0xFF, ++ (ra_info1>>16) & 0xFF, ++ (ra_info1>>24) & 0xFF); ++ ++ DBG_8192C("[ ra_info2:0x%08x ] =>hight_rate =%s, lowest_rate =%s, SGI = 0x%02x, RateID =%d\n", ++ ra_info2, ++ HDATA_RATE(hight_rate), ++ HDATA_RATE(lowest_rate), ++ (ra_info2>>16) & 0xFF, ++ (ra_info2>>24) & 0xFF); ++ ++ DBG_8192C("rate_mask2 = 0x%08x, rate_mask1 = 0x%08x\n", rate_mask2, rate_mask1); ++ ++ } ++ break; ++ ++ case HAL_DEF_TX_PAGE_BOUNDARY: ++ if (!padapter->registrypriv.wifi_spec) ++ { ++ *(u8 *)pval = TX_PAGE_BOUNDARY_8723B; ++ } ++ else ++ { ++ *(u8 *)pval = WMM_NORMAL_TX_PAGE_BOUNDARY_8723B; ++ } ++ break; ++ ++ case HAL_DEF_MACID_SLEEP: ++ *(u8 *)pval = true; /* support macid sleep */ ++ break; ++ ++ default: ++ bResult = GetHalDefVar(padapter, variable, pval); ++ break; ++ } ++ ++ return bResult; ++} ++ ++#ifdef CONFIG_WOWLAN ++void Hal_DetectWoWMode(struct adapter *padapter) ++{ ++ adapter_to_pwrctl(padapter)->bSupportRemoteWakeup = true; ++ DBG_871X("%s\n", __func__); ++} ++#endif /* CONFIG_WOWLAN */ ++ ++void rtl8723b_start_thread(struct adapter *padapter) ++{ ++#ifndef CONFIG_SDIO_TX_TASKLET ++ struct xmit_priv *xmitpriv = &padapter->xmitpriv; ++ ++ xmitpriv->SdioXmitThread = kthread_run(rtl8723bs_xmit_thread, padapter, "RTWHALXT"); ++ if (IS_ERR(xmitpriv->SdioXmitThread)) ++ { ++ RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("%s: start rtl8723bs_xmit_thread FAIL!!\n", __func__)); ++ } ++#endif ++} ++ ++void rtl8723b_stop_thread(struct adapter *padapter) ++{ ++#ifndef CONFIG_SDIO_TX_TASKLET ++ struct xmit_priv *xmitpriv = &padapter->xmitpriv; ++ ++ /* stop xmit_buf_thread */ ++ if (xmitpriv->SdioXmitThread) { ++ up(&xmitpriv->SdioXmitSema); ++ down(&xmitpriv->SdioXmitTerminateSema); ++ xmitpriv->SdioXmitThread = NULL; ++ } ++#endif ++} ++ ++#if defined(CONFIG_CHECK_BT_HANG) ++extern void check_bt_status_work(void *data); ++void rtl8723bs_init_checkbthang_workqueue(struct adapter * adapter) ++{ ++ adapter->priv_checkbt_wq = alloc_workqueue("sdio_wq", 0, 0); ++ INIT_DELAYED_WORK(&adapter->checkbt_work, (void*)check_bt_status_work); ++} ++ ++void rtl8723bs_free_checkbthang_workqueue(struct adapter * adapter) ++{ ++ if (adapter->priv_checkbt_wq) { ++ cancel_delayed_work_sync(&adapter->checkbt_work); ++ flush_workqueue(adapter->priv_checkbt_wq); ++ destroy_workqueue(adapter->priv_checkbt_wq); ++ adapter->priv_checkbt_wq = NULL; ++ } ++} ++ ++void rtl8723bs_cancle_checkbthang_workqueue(struct adapter * adapter) ++{ ++ if (adapter->priv_checkbt_wq) { ++ cancel_delayed_work_sync(&adapter->checkbt_work); ++ } ++} ++ ++void rtl8723bs_hal_check_bt_hang(struct adapter * adapter) ++{ ++ if (adapter->priv_checkbt_wq) ++ queue_delayed_work(adapter->priv_checkbt_wq, &(adapter->checkbt_work), 0); ++} ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/rtl8723b_phycfg.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/rtl8723b_phycfg.c +--- linux-4.3/3rdparty/rtl8723bs/hal/rtl8723b_phycfg.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/rtl8723b_phycfg.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,1070 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTL8723B_PHYCFG_C_ ++ ++#include ++#include ++#include ++ ++ ++/*---------------------------Define Local Constant---------------------------*/ ++/* Channel switch:The size of command tables for switch channel*/ ++#define MAX_PRECMD_CNT 16 ++#define MAX_RFDEPENDCMD_CNT 16 ++#define MAX_POSTCMD_CNT 16 ++ ++#define MAX_DOZE_WAITING_TIMES_9x 64 ++ ++/** ++* Function: phy_CalculateBitShift ++* ++* OverView: Get shifted position of the BitMask ++* ++* Input: ++* u32 BitMask, ++* ++* Output: none ++* Return: u32 Return the shift bit bit position of the mask ++*/ ++static u32 phy_CalculateBitShift(u32 BitMask) ++{ ++ u32 i; ++ ++ for (i = 0; i <=31; i++) { ++ if (((BitMask>>i) & 0x1) == 1) ++ break; ++ } ++ return i; ++} ++ ++ ++/** ++* Function: PHY_QueryBBReg ++* ++* OverView: Read "sepcific bits" from BB register ++* ++* Input: ++* struct adapter * Adapter, ++* u32 RegAddr, The target address to be readback ++* u32 BitMask The target bit position in the target address ++* to be readback ++* Output: None ++* Return: u32 Data The readback register value ++* Note: This function is equal to "GetRegSetting" in PHY programming guide ++*/ ++u32 ++PHY_QueryBBReg_8723B( ++struct adapter *Adapter, ++u32 RegAddr, ++u32 BitMask ++ ) ++{ ++ u32 ReturnValue = 0, OriginalValue, BitShift; ++ ++#if (DISABLE_BB_RF == 1) ++ return 0; ++#endif ++ ++ /* RT_TRACE(COMP_RF, DBG_TRACE, ("--->PHY_QueryBBReg(): RegAddr(%#lx), BitMask(%#lx)\n", RegAddr, BitMask)); */ ++ ++ OriginalValue = rtw_read32(Adapter, RegAddr); ++ BitShift = phy_CalculateBitShift(BitMask); ++ ReturnValue = (OriginalValue & BitMask) >> BitShift; ++ ++ return (ReturnValue); ++ ++} ++ ++ ++/** ++* Function: PHY_SetBBReg ++* ++* OverView: Write "Specific bits" to BB register (page 8~) ++* ++* Input: ++* struct adapter * Adapter, ++* u32 RegAddr, The target address to be modified ++* u32 BitMask The target bit position in the target address ++* to be modified ++* u32 Data The new register value in the target bit position ++* of the target address ++* ++* Output: None ++* Return: None ++* Note: This function is equal to "PutRegSetting" in PHY programming guide ++*/ ++ ++void ++PHY_SetBBReg_8723B( ++struct adapter *Adapter, ++u32 RegAddr, ++u32 BitMask, ++u32 Data ++ ) ++{ ++ /* u16 BBWaitCounter = 0; */ ++ u32 OriginalValue, BitShift; ++ ++#if (DISABLE_BB_RF == 1) ++ return; ++#endif ++ ++ /* RT_TRACE(COMP_RF, DBG_TRACE, ("--->PHY_SetBBReg(): RegAddr(%#lx), BitMask(%#lx), Data(%#lx)\n", RegAddr, BitMask, Data)); */ ++ ++ if (BitMask!= bMaskDWord) {/* if not "double word" write */ ++ OriginalValue = rtw_read32(Adapter, RegAddr); ++ BitShift = phy_CalculateBitShift(BitMask); ++ Data = ((OriginalValue & (~BitMask)) | ((Data << BitShift) & BitMask)); ++ } ++ ++ rtw_write32(Adapter, RegAddr, Data); ++ ++} ++ ++ ++/* */ ++/* 2. RF register R/W API */ ++/* */ ++ ++static u32 ++phy_RFSerialRead_8723B( ++struct adapter * Adapter, ++enum RF_PATH eRFPath, ++u32 Offset ++ ) ++{ ++ u32 retValue = 0; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ struct bb_register_def *pPhyReg = &pHalData->PHYRegDef[eRFPath]; ++ u32 NewOffset; ++ u32 tmplong2; ++ u8 RfPiEnable = 0; ++ u32 MaskforPhySet = 0; ++ int i = 0; ++ ++ /* */ ++ /* Make sure RF register offset is correct */ ++ /* */ ++ Offset &= 0xff; ++ ++ NewOffset = Offset; ++ ++ if (eRFPath == RF_PATH_A) ++ { ++ tmplong2 = PHY_QueryBBReg(Adapter, rFPGA0_XA_HSSIParameter2|MaskforPhySet, bMaskDWord);; ++ tmplong2 = (tmplong2 & (~bLSSIReadAddress)) | (NewOffset<<23) | bLSSIReadEdge; /* T65 RF */ ++ PHY_SetBBReg(Adapter, rFPGA0_XA_HSSIParameter2|MaskforPhySet, bMaskDWord, tmplong2&(~bLSSIReadEdge)); ++ } ++ else ++ { ++ tmplong2 = PHY_QueryBBReg(Adapter, rFPGA0_XB_HSSIParameter2|MaskforPhySet, bMaskDWord); ++ tmplong2 = (tmplong2 & (~bLSSIReadAddress)) | (NewOffset<<23) | bLSSIReadEdge; /* T65 RF */ ++ PHY_SetBBReg(Adapter, rFPGA0_XB_HSSIParameter2|MaskforPhySet, bMaskDWord, tmplong2&(~bLSSIReadEdge)); ++ } ++ ++ tmplong2 = PHY_QueryBBReg(Adapter, rFPGA0_XA_HSSIParameter2|MaskforPhySet, bMaskDWord); ++ PHY_SetBBReg(Adapter, rFPGA0_XA_HSSIParameter2|MaskforPhySet, bMaskDWord, tmplong2 & (~bLSSIReadEdge)); ++ PHY_SetBBReg(Adapter, rFPGA0_XA_HSSIParameter2|MaskforPhySet, bMaskDWord, tmplong2 | bLSSIReadEdge); ++ ++ udelay(10); ++ ++ for (i = 0;i<2;i++) ++ udelay(MAX_STALL_TIME); ++ udelay(10); ++ ++ if (eRFPath == RF_PATH_A) ++ RfPiEnable = (u8)PHY_QueryBBReg(Adapter, rFPGA0_XA_HSSIParameter1|MaskforPhySet, BIT8); ++ else if (eRFPath == RF_PATH_B) ++ RfPiEnable = (u8)PHY_QueryBBReg(Adapter, rFPGA0_XB_HSSIParameter1|MaskforPhySet, BIT8); ++ ++ if (RfPiEnable) ++ { /* Read from BBreg8b8, 12 bits for 8190, 20bits for T65 RF */ ++ retValue = PHY_QueryBBReg(Adapter, pPhyReg->rfLSSIReadBackPi|MaskforPhySet, bLSSIReadBackData); ++ ++ /* RT_DISP(FINIT, INIT_RF, ("Readback from RF-PI : 0x%x\n", retValue)); */ ++ } ++ else ++ { /* Read from BBreg8a0, 12 bits for 8190, 20 bits for T65 RF */ ++ retValue = PHY_QueryBBReg(Adapter, pPhyReg->rfLSSIReadBack|MaskforPhySet, bLSSIReadBackData); ++ ++ /* RT_DISP(FINIT, INIT_RF, ("Readback from RF-SI : 0x%x\n", retValue)); */ ++ } ++ return retValue; ++ ++} ++ ++/** ++* Function: phy_RFSerialWrite_8723B ++* ++* OverView: Write data to RF register (page 8~) ++* ++* Input: ++* struct adapter * Adapter, ++* RF_PATH eRFPath, Radio path of A/B/C/D ++* u32 Offset, The target address to be read ++* u32 Data The new register Data in the target bit position ++* of the target to be read ++* ++* Output: None ++* Return: None ++* Note: Threre are three types of serial operations: ++* 1. Software serial write ++* 2. Hardware LSSI-Low Speed Serial Interface ++* 3. Hardware HSSI-High speed ++* serial write. Driver need to implement (1) and (2). ++* This function is equal to the combination of RF_ReadReg() and RFLSSIRead() ++ * ++ * Note: For RF8256 only ++ * The total count of RTL8256(Zebra4) register is around 36 bit it only employs ++ * 4-bit RF address. RTL8256 uses "register mode control bit" (Reg00[12], Reg00[10]) ++ * to access register address bigger than 0xf. See "Appendix-4 in PHY Configuration ++ * programming guide" for more details. ++ * Thus, we define a sub-finction for RTL8526 register address conversion ++ * =========================================================== ++ * Register Mode RegCTL[1] RegCTL[0] Note ++ * (Reg00[12]) (Reg00[10]) ++ * =========================================================== ++ * Reg_Mode0 0 x Reg 0 ~15(0x0 ~ 0xf) ++ * ------------------------------------------------------------------ ++ * Reg_Mode1 1 0 Reg 16 ~30(0x1 ~ 0xf) ++ * ------------------------------------------------------------------ ++ * Reg_Mode2 1 1 Reg 31 ~ 45(0x1 ~ 0xf) ++ * ------------------------------------------------------------------ ++ * ++ *2008/09/02 MH Add 92S RF definition ++ * ++ * ++ * ++*/ ++static void ++phy_RFSerialWrite_8723B( ++struct adapter * Adapter, ++enum RF_PATH eRFPath, ++u32 Offset, ++u32 Data ++ ) ++{ ++ u32 DataAndAddr = 0; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ struct bb_register_def *pPhyReg = &pHalData->PHYRegDef[eRFPath]; ++ u32 NewOffset; ++ ++ Offset &= 0xff; ++ ++ /* */ ++ /* Switch page for 8256 RF IC */ ++ /* */ ++ NewOffset = Offset; ++ ++ /* */ ++ /* Put write addr in [5:0] and write data in [31:16] */ ++ /* */ ++ /* DataAndAddr = (Data<<16) | (NewOffset&0x3f); */ ++ DataAndAddr = ((NewOffset<<20) | (Data&0x000fffff)) & 0x0fffffff; /* T65 RF */ ++ ++ /* */ ++ /* Write Operation */ ++ /* */ ++ PHY_SetBBReg(Adapter, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr); ++ /* RTPRINT(FPHY, PHY_RFW, ("RFW-%d Addr[0x%lx]= 0x%lx\n", eRFPath, pPhyReg->rf3wireOffset, DataAndAddr)); */ ++ ++} ++ ++ ++/** ++* Function: PHY_QueryRFReg ++* ++* OverView: Query "Specific bits" to RF register (page 8~) ++* ++* Input: ++* struct adapter * Adapter, ++* RF_PATH eRFPath, Radio path of A/B/C/D ++* u32 RegAddr, The target address to be read ++* u32 BitMask The target bit position in the target address ++* to be read ++* ++* Output: None ++* Return: u32 Readback value ++* Note: This function is equal to "GetRFRegSetting" in PHY programming guide ++*/ ++u32 ++PHY_QueryRFReg_8723B( ++struct adapter * Adapter, ++u8 eRFPath, ++u32 RegAddr, ++u32 BitMask ++ ) ++{ ++ u32 Original_Value, Readback_Value, BitShift; ++ ++#if (DISABLE_BB_RF == 1) ++ return 0; ++#endif ++ ++ Original_Value = phy_RFSerialRead_8723B(Adapter, eRFPath, RegAddr); ++ ++ BitShift = phy_CalculateBitShift(BitMask); ++ Readback_Value = (Original_Value & BitMask) >> BitShift; ++ ++ return (Readback_Value); ++} ++ ++/** ++* Function: PHY_SetRFReg ++* ++* OverView: Write "Specific bits" to RF register (page 8~) ++* ++* Input: ++* struct adapter * Adapter, ++* RF_PATH eRFPath, Radio path of A/B/C/D ++* u32 RegAddr, The target address to be modified ++* u32 BitMask The target bit position in the target address ++* to be modified ++* u32 Data The new register Data in the target bit position ++* of the target address ++* ++* Output: None ++* Return: None ++* Note: This function is equal to "PutRFRegSetting" in PHY programming guide ++*/ ++void ++PHY_SetRFReg_8723B( ++struct adapter * Adapter, ++u8 eRFPath, ++u32 RegAddr, ++u32 BitMask, ++u32 Data ++ ) ++{ ++ u32 Original_Value, BitShift; ++ ++#if (DISABLE_BB_RF == 1) ++ return; ++#endif ++ ++ /* RF data is 12 bits only */ ++ if (BitMask != bRFRegOffsetMask) ++ { ++ Original_Value = phy_RFSerialRead_8723B(Adapter, eRFPath, RegAddr); ++ BitShift = phy_CalculateBitShift(BitMask); ++ Data = ((Original_Value & (~BitMask)) | (Data<< BitShift)); ++ } ++ ++ phy_RFSerialWrite_8723B(Adapter, eRFPath, RegAddr, Data); ++} ++ ++ ++/* */ ++/* 3. Initial MAC/BB/RF config by reading MAC/BB/RF txt. */ ++/* */ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: PHY_MACConfig8192C ++ * ++ * Overview: Condig MAC by header file or parameter file. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 08/12/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++s32 PHY_MACConfig8723B(struct adapter * Adapter) ++{ ++ int rtStatus = _SUCCESS; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ s8 *pszMACRegFile; ++ s8 sz8723MACRegFile[] = RTL8723B_PHY_MACREG; ++ ++ ++ pszMACRegFile = sz8723MACRegFile; ++ ++ /* */ ++ /* Config MAC */ ++ /* */ ++#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE ++ rtStatus = phy_ConfigMACWithParaFile(Adapter, pszMACRegFile); ++ if (rtStatus == _FAIL) ++#endif ++ { ++ ODM_ConfigMACWithHeaderFile(&pHalData->odmpriv); ++ rtStatus = _SUCCESS; ++ } ++ ++ return rtStatus; ++} ++ ++/** ++* Function: phy_InitBBRFRegisterDefinition ++* ++* OverView: Initialize Register definition offset for Radio Path A/B/C/D ++* ++* Input: ++* struct adapter * Adapter, ++* ++* Output: None ++* Return: None ++* Note: The initialization value is constant and it should never be changes ++*/ ++static void ++phy_InitBBRFRegisterDefinition( ++struct adapter * Adapter ++) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++ /* RF Interface Sowrtware Control */ ++ pHalData->PHYRegDef[ODM_RF_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; /* 16 LSBs if read 32-bit from 0x870 */ ++ pHalData->PHYRegDef[ODM_RF_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; /* 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872) */ ++ ++ /* RF Interface Output (and Enable) */ ++ pHalData->PHYRegDef[ODM_RF_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE; /* 16 LSBs if read 32-bit from 0x860 */ ++ pHalData->PHYRegDef[ODM_RF_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE; /* 16 LSBs if read 32-bit from 0x864 */ ++ ++ /* RF Interface (Output and) Enable */ ++ pHalData->PHYRegDef[ODM_RF_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE; /* 16 MSBs if read 32-bit from 0x860 (16-bit for 0x862) */ ++ pHalData->PHYRegDef[ODM_RF_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE; /* 16 MSBs if read 32-bit from 0x864 (16-bit for 0x866) */ ++ ++ pHalData->PHYRegDef[ODM_RF_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; /* LSSI Parameter */ ++ pHalData->PHYRegDef[ODM_RF_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter; ++ ++ pHalData->PHYRegDef[ODM_RF_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2; /* wire control parameter2 */ ++ pHalData->PHYRegDef[ODM_RF_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2; /* wire control parameter2 */ ++ ++ /* Tranceiver Readback LSSI/HSPI mode */ ++ pHalData->PHYRegDef[ODM_RF_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack; ++ pHalData->PHYRegDef[ODM_RF_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack; ++ pHalData->PHYRegDef[ODM_RF_PATH_A].rfLSSIReadBackPi = TransceiverA_HSPI_Readback; ++ pHalData->PHYRegDef[ODM_RF_PATH_B].rfLSSIReadBackPi = TransceiverB_HSPI_Readback; ++ ++} ++ ++static int ++phy_BB8723b_Config_ParaFile( ++struct adapter *Adapter ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ int rtStatus = _SUCCESS; ++ u8 sz8723BBRegFile[] = RTL8723B_PHY_REG; ++ u8 sz8723AGCTableFile[] = RTL8723B_AGC_TAB; ++ u8 sz8723BBBRegPgFile[] = RTL8723B_PHY_REG_PG; ++ u8 sz8723BBRegMpFile[] = RTL8723B_PHY_REG_MP; ++ u8 sz8723BRFTxPwrLmtFile[] = RTL8723B_TXPWR_LMT; ++ u8 *pszBBRegFile = NULL, *pszAGCTableFile = NULL, *pszBBRegPgFile = NULL, *pszBBRegMpFile = NULL, *pszRFTxPwrLmtFile = NULL; ++ ++ pszBBRegFile = sz8723BBRegFile ; ++ pszAGCTableFile = sz8723AGCTableFile; ++ pszBBRegPgFile = sz8723BBBRegPgFile; ++ pszBBRegMpFile = sz8723BBRegMpFile; ++ pszRFTxPwrLmtFile = sz8723BRFTxPwrLmtFile; ++ ++ /* Read Tx Power Limit File */ ++ PHY_InitTxPowerLimit(Adapter); ++ if (Adapter->registrypriv.RegEnableTxPowerLimit == 1 || ++ (Adapter->registrypriv.RegEnableTxPowerLimit == 2 && pHalData->EEPROMRegulatory == 1)) ++ { ++#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE ++ if (PHY_ConfigRFWithPowerLimitTableParaFile(Adapter, pszRFTxPwrLmtFile) == _FAIL) ++#endif ++ { ++ if (HAL_STATUS_SUCCESS != ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv, CONFIG_RF_TXPWR_LMT, (ODM_RF_RADIO_PATH_E)0)) ++ rtStatus = _FAIL; ++ } ++ ++ if (rtStatus != _SUCCESS) { ++ DBG_871X("%s():Read Tx power limit fail\n", __func__); ++ goto phy_BB8190_Config_ParaFile_Fail; ++ } ++ } ++ ++ /* */ ++ /* 1. Read PHY_REG.TXT BB INIT!! */ ++ /* */ ++#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE ++ if (phy_ConfigBBWithParaFile(Adapter, pszBBRegFile, CONFIG_BB_PHY_REG) == _FAIL) ++#endif ++ { ++ if (HAL_STATUS_SUCCESS != ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_PHY_REG)) ++ rtStatus = _FAIL; ++ } ++ ++ if (rtStatus != _SUCCESS) { ++ DBG_8192C("%s():Write BB Reg Fail!!", __func__); ++ goto phy_BB8190_Config_ParaFile_Fail; ++ } ++ ++ /* If EEPROM or EFUSE autoload OK, We must config by PHY_REG_PG.txt */ ++ PHY_InitTxPowerByRate(Adapter); ++ if (Adapter->registrypriv.RegEnableTxPowerByRate == 1 || ++ (Adapter->registrypriv.RegEnableTxPowerByRate == 2 && pHalData->EEPROMRegulatory != 2)) ++ { ++#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE ++ if (phy_ConfigBBWithPgParaFile(Adapter, pszBBRegPgFile) == _FAIL) ++#endif ++ { ++ if (HAL_STATUS_SUCCESS != ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_PHY_REG_PG)) ++ rtStatus = _FAIL; ++ } ++ ++ if (pHalData->odmpriv.PhyRegPgValueType == PHY_REG_PG_EXACT_VALUE) ++ PHY_TxPowerByRateConfiguration(Adapter); ++ ++ if (Adapter->registrypriv.RegEnableTxPowerLimit == 1 || ++ (Adapter->registrypriv.RegEnableTxPowerLimit == 2 && pHalData->EEPROMRegulatory == 1)) ++ PHY_ConvertTxPowerLimitToPowerIndex(Adapter); ++ ++ if (rtStatus != _SUCCESS) { ++ DBG_8192C("%s():BB_PG Reg Fail!!\n", __func__); ++ } ++ } ++ ++ /* */ ++ /* 2. Read BB AGC table Initialization */ ++ /* */ ++#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE ++ if (phy_ConfigBBWithParaFile(Adapter, pszAGCTableFile, CONFIG_BB_AGC_TAB) == _FAIL) ++#endif ++ { ++ if (HAL_STATUS_SUCCESS != ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_AGC_TAB)) ++ rtStatus = _FAIL; ++ } ++ ++ if (rtStatus != _SUCCESS) { ++ DBG_8192C("%s():AGC Table Fail\n", __func__); ++ goto phy_BB8190_Config_ParaFile_Fail; ++ } ++ ++phy_BB8190_Config_ParaFile_Fail: ++ ++ return rtStatus; ++} ++ ++ ++int ++PHY_BBConfig8723B( ++struct adapter *Adapter ++ ) ++{ ++ int rtStatus = _SUCCESS; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ u32 RegVal; ++ u8 CrystalCap; ++ ++ phy_InitBBRFRegisterDefinition(Adapter); ++ ++ /* Enable BB and RF */ ++ RegVal = rtw_read16(Adapter, REG_SYS_FUNC_EN); ++ rtw_write16(Adapter, REG_SYS_FUNC_EN, (u16)(RegVal|BIT13|BIT0|BIT1)); ++ ++ rtw_write32(Adapter, 0x948, 0x280); /* Others use Antenna S1 */ ++ ++ rtw_write8(Adapter, REG_RF_CTRL, RF_EN|RF_RSTB|RF_SDMRSTB); ++ ++ msleep(1); ++ ++ PHY_SetRFReg(Adapter, ODM_RF_PATH_A, 0x1, 0xfffff, 0x780); ++ ++ rtw_write8(Adapter, REG_SYS_FUNC_EN, FEN_PPLL|FEN_PCIEA|FEN_DIO_PCIE|FEN_BB_GLB_RSTn|FEN_BBRSTB); ++ ++ rtw_write8(Adapter, REG_AFE_XTAL_CTRL+1, 0x80); ++ ++ /* */ ++ /* Config BB and AGC */ ++ /* */ ++ rtStatus = phy_BB8723b_Config_ParaFile(Adapter); ++ ++ /* 0x2C[23:18] = 0x2C[17:12] = CrystalCap */ ++ CrystalCap = pHalData->CrystalCap & 0x3F; ++ PHY_SetBBReg(Adapter, REG_MAC_PHY_CTRL, 0xFFF000, (CrystalCap | (CrystalCap << 6))); ++ ++ return rtStatus; ++} ++ ++static void phy_LCK_8723B( ++struct adapter *Adapter ++ ) ++{ ++ PHY_SetRFReg(Adapter, RF_PATH_A, 0xB0, bRFRegOffsetMask, 0xDFBE0); ++ PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, 0x8C01); ++ mdelay(200); ++ PHY_SetRFReg(Adapter, RF_PATH_A, 0xB0, bRFRegOffsetMask, 0xDFFE0); ++} ++ ++int ++PHY_RFConfig8723B( ++struct adapter *Adapter ++ ) ++{ ++ int rtStatus = _SUCCESS; ++ ++ /* */ ++ /* RF config */ ++ /* */ ++ rtStatus = PHY_RF6052_Config8723B(Adapter); ++ ++ phy_LCK_8723B(Adapter); ++ /* PHY_BB8723B_Config_1T(Adapter); */ ++ ++ return rtStatus; ++} ++ ++/************************************************************************************************************** ++ * Description: ++ * The low-level interface to set TxAGC , called by both MP and Normal Driver. ++ * ++ * <20120830, Kordan> ++ **************************************************************************************************************/ ++ ++void ++PHY_SetTxPowerIndex_8723B( ++struct adapter * Adapter, ++u32 PowerIndex, ++u8 RFPath, ++u8 Rate ++ ) ++{ ++ if (RFPath == ODM_RF_PATH_A || RFPath == ODM_RF_PATH_B) ++ { ++ switch (Rate) ++ { ++ case MGN_1M: PHY_SetBBReg(Adapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, PowerIndex); break; ++ case MGN_2M: PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte1, PowerIndex); break; ++ case MGN_5_5M: PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte2, PowerIndex); break; ++ case MGN_11M: PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte3, PowerIndex); break; ++ ++ case MGN_6M: PHY_SetBBReg(Adapter, rTxAGC_A_Rate18_06, bMaskByte0, PowerIndex); break; ++ case MGN_9M: PHY_SetBBReg(Adapter, rTxAGC_A_Rate18_06, bMaskByte1, PowerIndex); break; ++ case MGN_12M: PHY_SetBBReg(Adapter, rTxAGC_A_Rate18_06, bMaskByte2, PowerIndex); break; ++ case MGN_18M: PHY_SetBBReg(Adapter, rTxAGC_A_Rate18_06, bMaskByte3, PowerIndex); break; ++ ++ case MGN_24M: PHY_SetBBReg(Adapter, rTxAGC_A_Rate54_24, bMaskByte0, PowerIndex); break; ++ case MGN_36M: PHY_SetBBReg(Adapter, rTxAGC_A_Rate54_24, bMaskByte1, PowerIndex); break; ++ case MGN_48M: PHY_SetBBReg(Adapter, rTxAGC_A_Rate54_24, bMaskByte2, PowerIndex); break; ++ case MGN_54M: PHY_SetBBReg(Adapter, rTxAGC_A_Rate54_24, bMaskByte3, PowerIndex); break; ++ ++ case MGN_MCS0: PHY_SetBBReg(Adapter, rTxAGC_A_Mcs03_Mcs00, bMaskByte0, PowerIndex); break; ++ case MGN_MCS1: PHY_SetBBReg(Adapter, rTxAGC_A_Mcs03_Mcs00, bMaskByte1, PowerIndex); break; ++ case MGN_MCS2: PHY_SetBBReg(Adapter, rTxAGC_A_Mcs03_Mcs00, bMaskByte2, PowerIndex); break; ++ case MGN_MCS3: PHY_SetBBReg(Adapter, rTxAGC_A_Mcs03_Mcs00, bMaskByte3, PowerIndex); break; ++ ++ case MGN_MCS4: PHY_SetBBReg(Adapter, rTxAGC_A_Mcs07_Mcs04, bMaskByte0, PowerIndex); break; ++ case MGN_MCS5: PHY_SetBBReg(Adapter, rTxAGC_A_Mcs07_Mcs04, bMaskByte1, PowerIndex); break; ++ case MGN_MCS6: PHY_SetBBReg(Adapter, rTxAGC_A_Mcs07_Mcs04, bMaskByte2, PowerIndex); break; ++ case MGN_MCS7: PHY_SetBBReg(Adapter, rTxAGC_A_Mcs07_Mcs04, bMaskByte3, PowerIndex); break; ++ ++ default: ++ DBG_871X("Invalid Rate!!\n"); ++ break; ++ } ++ } ++ else ++ { ++ RT_TRACE(_module_hal_init_c_, _drv_err_, ("Invalid RFPath!!\n")); ++ } ++} ++ ++u8 ++PHY_GetTxPowerIndex_8723B( ++struct adapter * padapter, ++u8 RFPath, ++u8 Rate, ++enum CHANNEL_WIDTH BandWidth, ++u8 Channel ++ ) ++{ ++ struct hal_com_data * pHalData = GET_HAL_DATA(padapter); ++ s8 txPower = 0, powerDiffByRate = 0, limit = 0; ++ bool bIn24G = false; ++ ++ /* DBG_871X("===>%s\n", __func__); */ ++ ++ txPower = (s8) PHY_GetTxPowerIndexBase(padapter, RFPath, Rate, BandWidth, Channel, &bIn24G); ++ powerDiffByRate = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, ODM_RF_PATH_A, RF_1TX, Rate); ++ ++ limit = PHY_GetTxPowerLimit(padapter, padapter->registrypriv.RegPwrTblSel, (u8)(!bIn24G), pHalData->CurrentChannelBW, RFPath, Rate, pHalData->CurrentChannel); ++ ++ powerDiffByRate = powerDiffByRate > limit ? limit : powerDiffByRate; ++ txPower += powerDiffByRate; ++ ++ txPower += PHY_GetTxPowerTrackingOffset(padapter, RFPath, Rate); ++ ++ if (txPower > MAX_POWER_INDEX) ++ txPower = MAX_POWER_INDEX; ++ ++ /* DBG_871X("Final Tx Power(RF-%c, Channel: %d) = %d(0x%X)\n", ((RFPath == 0)?'A':'B'), Channel, txPower, txPower)); */ ++ return (u8) txPower; ++} ++ ++void ++PHY_SetTxPowerLevel8723B( ++struct adapter * Adapter, ++u8 Channel ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; ++ u8 RFPath = ODM_RF_PATH_A; ++ ++ if (pHalData->AntDivCfg) {/* antenna diversity Enable */ ++ RFPath = ((pDM_FatTable->RxIdleAnt == MAIN_ANT) ? ODM_RF_PATH_A : ODM_RF_PATH_B); ++ } ++ else { /* antenna diversity disable */ ++ RFPath = pHalData->ant_path; ++ } ++ ++ RT_TRACE(_module_hal_init_c_, _drv_info_, ("==>PHY_SetTxPowerLevel8723B()\n")); ++ ++ PHY_SetTxPowerLevelByPath(Adapter, Channel, RFPath); ++ ++ RT_TRACE(_module_hal_init_c_, _drv_info_, ("<==PHY_SetTxPowerLevel8723B()\n")); ++} ++ ++void ++PHY_GetTxPowerLevel8723B( ++struct adapter * Adapter, ++ s32* powerlevel ++ ) ++{ ++} ++ ++static void ++phy_SetRegBW_8723B( ++struct adapter * Adapter, ++ enum CHANNEL_WIDTH CurrentBW ++) ++{ ++ u16 RegRfMod_BW, u2tmp = 0; ++ RegRfMod_BW = rtw_read16(Adapter, REG_TRXPTCL_CTL_8723B); ++ ++ switch (CurrentBW) ++ { ++ case CHANNEL_WIDTH_20: ++ rtw_write16(Adapter, REG_TRXPTCL_CTL_8723B, (RegRfMod_BW & 0xFE7F)); /* BIT 7 = 0, BIT 8 = 0 */ ++ break; ++ ++ case CHANNEL_WIDTH_40: ++ u2tmp = RegRfMod_BW | BIT7; ++ rtw_write16(Adapter, REG_TRXPTCL_CTL_8723B, (u2tmp & 0xFEFF)); /* BIT 7 = 1, BIT 8 = 0 */ ++ break; ++ ++ case CHANNEL_WIDTH_80: ++ u2tmp = RegRfMod_BW | BIT8; ++ rtw_write16(Adapter, REG_TRXPTCL_CTL_8723B, (u2tmp & 0xFF7F)); /* BIT 7 = 0, BIT 8 = 1 */ ++ break; ++ ++ default: ++ DBG_871X("phy_PostSetBWMode8723B(): unknown Bandwidth: %#X\n", CurrentBW); ++ break; ++ } ++} ++ ++static u8 ++phy_GetSecondaryChnl_8723B( ++struct adapter *Adapter ++) ++{ ++ u8 SCSettingOf40 = 0, SCSettingOf20 = 0; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++ RT_TRACE(_module_hal_init_c_, _drv_info_, ("SCMapping: VHT Case: pHalData->CurrentChannelBW %d, pHalData->nCur80MhzPrimeSC %d, pHalData->nCur40MhzPrimeSC %d\n", pHalData->CurrentChannelBW, pHalData->nCur80MhzPrimeSC, pHalData->nCur40MhzPrimeSC)); ++ if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_80) ++ { ++ if (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) ++ SCSettingOf40 = VHT_DATA_SC_40_LOWER_OF_80MHZ; ++ else if (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) ++ SCSettingOf40 = VHT_DATA_SC_40_UPPER_OF_80MHZ; ++ else ++ RT_TRACE(_module_hal_init_c_, _drv_err_, ("SCMapping: Not Correct Primary40MHz Setting\n")); ++ ++ if ((pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) && (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER)) ++ SCSettingOf20 = VHT_DATA_SC_20_LOWEST_OF_80MHZ; ++ else if ((pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) && (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER)) ++ SCSettingOf20 = VHT_DATA_SC_20_LOWER_OF_80MHZ; ++ else if ((pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) && (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER)) ++ SCSettingOf20 = VHT_DATA_SC_20_UPPER_OF_80MHZ; ++ else if ((pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) && (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER)) ++ SCSettingOf20 = VHT_DATA_SC_20_UPPERST_OF_80MHZ; ++ else ++ RT_TRACE(_module_hal_init_c_, _drv_err_, ("SCMapping: Not Correct Primary40MHz Setting\n")); ++ } ++ else if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_40) ++ { ++ RT_TRACE(_module_hal_init_c_, _drv_info_, ("SCMapping: VHT Case: pHalData->CurrentChannelBW %d, pHalData->nCur40MhzPrimeSC %d\n", pHalData->CurrentChannelBW, pHalData->nCur40MhzPrimeSC)); ++ ++ if (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) ++ SCSettingOf20 = VHT_DATA_SC_20_UPPER_OF_80MHZ; ++ else if (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) ++ SCSettingOf20 = VHT_DATA_SC_20_LOWER_OF_80MHZ; ++ else ++ RT_TRACE(_module_hal_init_c_, _drv_err_, ("SCMapping: Not Correct Primary40MHz Setting\n")); ++ } ++ ++ RT_TRACE(_module_hal_init_c_, _drv_info_, ("SCMapping: SC Value %x\n", ((SCSettingOf40 << 4) | SCSettingOf20))); ++ return ((SCSettingOf40 << 4) | SCSettingOf20); ++} ++ ++static void ++phy_PostSetBwMode8723B( ++struct adapter *Adapter ++) ++{ ++ u8 SubChnlNum = 0; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++ ++ /* 3 Set Reg668 Reg440 BW */ ++ phy_SetRegBW_8723B(Adapter, pHalData->CurrentChannelBW); ++ ++ /* 3 Set Reg483 */ ++ SubChnlNum = phy_GetSecondaryChnl_8723B(Adapter); ++ rtw_write8(Adapter, REG_DATA_SC_8723B, SubChnlNum); ++ ++ /* 3 */ ++ /* 3<2>Set PHY related register */ ++ /* 3 */ ++ switch (pHalData->CurrentChannelBW) ++ { ++ /* 20 MHz channel*/ ++ case CHANNEL_WIDTH_20: ++ PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bRFMOD, 0x0); ++ ++ PHY_SetBBReg(Adapter, rFPGA1_RFMOD, bRFMOD, 0x0); ++ ++/* PHY_SetBBReg(Adapter, rFPGA0_AnalogParameter2, BIT10, 1); */ ++ ++ PHY_SetBBReg(Adapter, rOFDM0_TxPseudoNoiseWgt, (BIT31|BIT30), 0x0); ++ break; ++ ++ ++ /* 40 MHz channel*/ ++ case CHANNEL_WIDTH_40: ++ PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bRFMOD, 0x1); ++ ++ PHY_SetBBReg(Adapter, rFPGA1_RFMOD, bRFMOD, 0x1); ++ ++ /* Set Control channel to upper or lower. These settings are required only for 40MHz */ ++ PHY_SetBBReg(Adapter, rCCK0_System, bCCKSideBand, (pHalData->nCur40MhzPrimeSC>>1)); ++ ++ PHY_SetBBReg(Adapter, rOFDM1_LSTF, 0xC00, pHalData->nCur40MhzPrimeSC); ++ ++/* PHY_SetBBReg(Adapter, rFPGA0_AnalogParameter2, BIT10, 0); */ ++ ++ PHY_SetBBReg(Adapter, 0x818, (BIT26|BIT27), (pHalData->nCur40MhzPrimeSC ==HAL_PRIME_CHNL_OFFSET_LOWER)?2:1); ++ ++ break; ++ ++ ++ ++ default: ++ /*RT_TRACE(COMP_DBG, DBG_LOUD, ("phy_SetBWMode8723B(): unknown Bandwidth: %#X\n"\ ++ , pHalData->CurrentChannelBW));*/ ++ break; ++ ++ } ++ ++ /* 3<3>Set RF related register */ ++ PHY_RF6052SetBandwidth8723B(Adapter, pHalData->CurrentChannelBW); ++} ++ ++static void ++phy_SwChnl8723B( ++struct adapter * padapter ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ u8 channelToSW = pHalData->CurrentChannel; ++ ++ if (pHalData->rf_chip == RF_PSEUDO_11N) ++ { ++ /* RT_TRACE(COMP_MLME, DBG_LOUD, ("phy_SwChnl8723B: return for PSEUDO\n")); */ ++ return; ++ } ++ pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff00) | channelToSW ); ++ PHY_SetRFReg(padapter, ODM_RF_PATH_A, RF_CHNLBW, 0x3FF, pHalData->RfRegChnlVal[0]); ++ PHY_SetRFReg(padapter, ODM_RF_PATH_B, RF_CHNLBW, 0x3FF, pHalData->RfRegChnlVal[0]); ++ ++ DBG_8192C("===>phy_SwChnl8723B: Channel = %d\n", channelToSW); ++} ++ ++static void ++phy_SwChnlAndSetBwMode8723B( ++ struct adapter * Adapter ++) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++ /* RT_TRACE(COMP_SCAN, DBG_LOUD, ("phy_SwChnlAndSetBwMode8723B(): bSwChnl %d, bSetChnlBW %d\n", pHalData->bSwChnl, pHalData->bSetChnlBW)); */ ++ if (Adapter->bNotifyChannelChange) ++ { ++ DBG_871X("[%s] bSwChnl =%d, ch =%d, bSetChnlBW =%d, bw =%d\n", ++ __func__, ++ pHalData->bSwChnl, ++ pHalData->CurrentChannel, ++ pHalData->bSetChnlBW, ++ pHalData->CurrentChannelBW); ++ } ++ ++ if ((Adapter->bDriverStopped) || (Adapter->bSurpriseRemoved)) ++ { ++ return; ++ } ++ ++ if (pHalData->bSwChnl) ++ { ++ phy_SwChnl8723B(Adapter); ++ pHalData->bSwChnl = false; ++ } ++ ++ if (pHalData->bSetChnlBW) ++ { ++ phy_PostSetBwMode8723B(Adapter); ++ pHalData->bSetChnlBW = false; ++ } ++ ++ PHY_SetTxPowerLevel8723B(Adapter, pHalData->CurrentChannel); ++} ++ ++static void ++PHY_HandleSwChnlAndSetBW8723B( ++struct adapter * Adapter, ++bool bSwitchChannel, ++bool bSetBandWidth, ++u8 ChannelNum, ++enum CHANNEL_WIDTH ChnlWidth, ++enum EXTCHNL_OFFSET ExtChnlOffsetOf40MHz, ++enum EXTCHNL_OFFSET ExtChnlOffsetOf80MHz, ++u8 CenterFrequencyIndex1 ++) ++{ ++ /* static bool bInitialzed = false; */ ++ struct hal_com_data * pHalData = GET_HAL_DATA(Adapter); ++ u8 tmpChannel = pHalData->CurrentChannel; ++ enum CHANNEL_WIDTH tmpBW = pHalData->CurrentChannelBW; ++ u8 tmpnCur40MhzPrimeSC = pHalData->nCur40MhzPrimeSC; ++ u8 tmpnCur80MhzPrimeSC = pHalData->nCur80MhzPrimeSC; ++ u8 tmpCenterFrequencyIndex1 =pHalData->CurrentCenterFrequencyIndex1; ++ ++ /* DBG_871X("=> PHY_HandleSwChnlAndSetBW8812: bSwitchChannel %d, bSetBandWidth %d\n", bSwitchChannel, bSetBandWidth); */ ++ ++ /* check is swchnl or setbw */ ++ if (!bSwitchChannel && !bSetBandWidth) ++ { ++ DBG_871X("PHY_HandleSwChnlAndSetBW8812: not switch channel and not set bandwidth\n"); ++ return; ++ } ++ ++ /* skip change for channel or bandwidth is the same */ ++ if (bSwitchChannel) ++ { ++ /* if (pHalData->CurrentChannel != ChannelNum) */ ++ { ++ if (HAL_IsLegalChannel(Adapter, ChannelNum)) ++ pHalData->bSwChnl = true; ++ } ++ } ++ ++ if (bSetBandWidth) ++ { ++ pHalData->bSetChnlBW = true; ++ } ++ ++ if (!pHalData->bSetChnlBW && !pHalData->bSwChnl) ++ { ++ /* DBG_871X("<= PHY_HandleSwChnlAndSetBW8812: bSwChnl %d, bSetChnlBW %d\n", pHalData->bSwChnl, pHalData->bSetChnlBW); */ ++ return; ++ } ++ ++ ++ if (pHalData->bSwChnl) ++ { ++ pHalData->CurrentChannel =ChannelNum; ++ pHalData->CurrentCenterFrequencyIndex1 = ChannelNum; ++ } ++ ++ ++ if (pHalData->bSetChnlBW) ++ { ++ pHalData->CurrentChannelBW = ChnlWidth; ++ pHalData->nCur40MhzPrimeSC = ExtChnlOffsetOf40MHz; ++ pHalData->nCur80MhzPrimeSC = ExtChnlOffsetOf80MHz; ++ pHalData->CurrentCenterFrequencyIndex1 = CenterFrequencyIndex1; ++ } ++ ++ /* Switch workitem or set timer to do switch channel or setbandwidth operation */ ++ if ((!Adapter->bDriverStopped) && (!Adapter->bSurpriseRemoved)) ++ { ++ phy_SwChnlAndSetBwMode8723B(Adapter); ++ } ++ else ++ { ++ if (pHalData->bSwChnl) ++ { ++ pHalData->CurrentChannel = tmpChannel; ++ pHalData->CurrentCenterFrequencyIndex1 = tmpChannel; ++ } ++ if (pHalData->bSetChnlBW) ++ { ++ pHalData->CurrentChannelBW = tmpBW; ++ pHalData->nCur40MhzPrimeSC = tmpnCur40MhzPrimeSC; ++ pHalData->nCur80MhzPrimeSC = tmpnCur80MhzPrimeSC; ++ pHalData->CurrentCenterFrequencyIndex1 = tmpCenterFrequencyIndex1; ++ } ++ } ++} ++ ++void ++PHY_SetBWMode8723B( ++struct adapter * Adapter, ++enum CHANNEL_WIDTH Bandwidth, /* 20M or 40M */ ++unsigned char Offset /* Upper, Lower, or Don't care */ ++) ++{ ++ struct hal_com_data * pHalData = GET_HAL_DATA(Adapter); ++ ++ PHY_HandleSwChnlAndSetBW8723B(Adapter, false, true, pHalData->CurrentChannel, Bandwidth, Offset, Offset, pHalData->CurrentChannel); ++} ++ ++void ++PHY_SwChnl8723B(/* Call after initialization */ ++struct adapter *Adapter, ++u8 channel ++ ) ++{ ++ PHY_HandleSwChnlAndSetBW8723B(Adapter, true, false, channel, 0, 0, 0, channel); ++} ++ ++void ++PHY_SetSwChnlBWMode8723B( ++struct adapter * Adapter, ++u8 channel, ++enum CHANNEL_WIDTH Bandwidth, ++u8 Offset40, ++u8 Offset80 ++) ++{ ++ /* DBG_871X("%s() ===>\n", __func__); */ ++ ++ PHY_HandleSwChnlAndSetBW8723B(Adapter, true, true, channel, Bandwidth, Offset40, Offset80, channel); ++ ++ /* DBG_871X("<==%s()\n", __func__); */ ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/rtl8723b_rf6052.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/rtl8723b_rf6052.c +--- linux-4.3/3rdparty/rtl8723bs/hal/rtl8723b_rf6052.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/rtl8723b_rf6052.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,241 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++/****************************************************************************** ++ * ++ * ++ * Module: rtl8192c_rf6052.c (Source C File) ++ * ++ * Note: Provide RF 6052 series relative API. ++ * ++ * Function: ++ * ++ * Export: ++ * ++ * Abbrev: ++ * ++ * History: ++ * Data Who Remark ++ * ++ * 09/25/2008 MHC Create initial version. ++ * 11/05/2008 MHC Add API for tw power setting. ++ * ++ * ++******************************************************************************/ ++ ++#include ++ ++/*---------------------------Define Local Constant---------------------------*/ ++/*---------------------------Define Local Constant---------------------------*/ ++ ++ ++/*------------------------Define global variable-----------------------------*/ ++/*------------------------Define global variable-----------------------------*/ ++ ++ ++/*------------------------Define local variable------------------------------*/ ++/* 2008/11/20 MH For Debug only, RF */ ++/*------------------------Define local variable------------------------------*/ ++ ++/*----------------------------------------------------------------------------- ++ * Function: PHY_RF6052SetBandwidth() ++ * ++ * Overview: This function is called by SetBWModeCallback8190Pci() only ++ * ++ * Input: struct adapter * Adapter ++ * WIRELESS_BANDWIDTH_E Bandwidth 20M or 40M ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Note: For RF type 0222D ++ *---------------------------------------------------------------------------*/ ++void ++PHY_RF6052SetBandwidth8723B( ++struct adapter * Adapter, ++enum CHANNEL_WIDTH Bandwidth) /* 20M or 40M */ ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++ switch (Bandwidth) ++ { ++ case CHANNEL_WIDTH_20: ++ pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff) | BIT10 | BIT11); ++ PHY_SetRFReg(Adapter, ODM_RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]); ++ PHY_SetRFReg(Adapter, ODM_RF_PATH_B, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]); ++ break; ++ ++ case CHANNEL_WIDTH_40: ++ pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff) | BIT10); ++ PHY_SetRFReg(Adapter, ODM_RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]); ++ PHY_SetRFReg(Adapter, ODM_RF_PATH_B, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]); ++ break; ++ ++ default: ++ /* RT_TRACE(COMP_DBG, DBG_LOUD, ("PHY_SetRF8225Bandwidth(): unknown Bandwidth: %#X\n", Bandwidth)); */ ++ break; ++ } ++ ++} ++ ++static int ++phy_RF6052_Config_ParaFile( ++struct adapter * Adapter ++ ) ++{ ++ u32 u4RegValue = 0; ++ u8 eRFPath; ++ struct bb_register_def *pPhyReg; ++ ++ int rtStatus = _SUCCESS; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++ static char sz8723RadioAFile[] = RTL8723B_PHY_RADIO_A; ++ static char sz8723RadioBFile[] = RTL8723B_PHY_RADIO_B; ++ static s8 sz8723BTxPwrTrackFile[] = RTL8723B_TXPWR_TRACK; ++ char *pszRadioAFile, *pszRadioBFile, *pszTxPwrTrackFile; ++ ++ pszRadioAFile = sz8723RadioAFile; ++ pszRadioBFile = sz8723RadioBFile; ++ pszTxPwrTrackFile = sz8723BTxPwrTrackFile; ++ ++ /* 3----------------------------------------------------------------- */ ++ /* 3 <2> Initialize RF */ ++ /* 3----------------------------------------------------------------- */ ++ /* for (eRFPath = RF_PATH_A; eRFPath NumTotalRFPath; eRFPath++) */ ++ for (eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) ++ { ++ ++ pPhyReg = &pHalData->PHYRegDef[eRFPath]; ++ ++ /*----Store original RFENV control type----*/ ++ switch (eRFPath) ++ { ++ case RF_PATH_A: ++ case RF_PATH_C: ++ u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV); ++ break; ++ case RF_PATH_B : ++ case RF_PATH_D: ++ u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16); ++ break; ++ } ++ ++ /*----Set RF_ENV enable----*/ ++ PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1); ++ udelay(1);/* PlatformStallExecution(1); */ ++ ++ /*----Set RF_ENV output high----*/ ++ PHY_SetBBReg(Adapter, pPhyReg->rfintfo, bRFSI_RFENV, 0x1); ++ udelay(1);/* PlatformStallExecution(1); */ ++ ++ /* Set bit number of Address and Data for RF register */ ++ PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0); /* Set 1 to 4 bits for 8255 */ ++ udelay(1);/* PlatformStallExecution(1); */ ++ ++ PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0); /* Set 0 to 12 bits for 8255 */ ++ udelay(1);/* PlatformStallExecution(1); */ ++ ++ /*----Initialize RF fom connfiguration file----*/ ++ switch (eRFPath) ++ { ++ case RF_PATH_A: ++#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE ++ if (PHY_ConfigRFWithParaFile(Adapter, pszRadioAFile, eRFPath) == _FAIL) ++#endif ++ { ++ if (HAL_STATUS_FAILURE ==ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv, CONFIG_RF_RADIO, (ODM_RF_RADIO_PATH_E)eRFPath)) ++ rtStatus = _FAIL; ++ } ++ break; ++ case RF_PATH_B: ++#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE ++ if (PHY_ConfigRFWithParaFile(Adapter, pszRadioBFile, eRFPath) == _FAIL) ++#endif ++ { ++ if (HAL_STATUS_FAILURE ==ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv, CONFIG_RF_RADIO, (ODM_RF_RADIO_PATH_E)eRFPath)) ++ rtStatus = _FAIL; ++ } ++ break; ++ case RF_PATH_C: ++ break; ++ case RF_PATH_D: ++ break; ++ } ++ ++ /*----Restore RFENV control type----*/; ++ switch (eRFPath) ++ { ++ case RF_PATH_A: ++ case RF_PATH_C: ++ PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue); ++ break; ++ case RF_PATH_B : ++ case RF_PATH_D: ++ PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue); ++ break; ++ } ++ ++ if (rtStatus != _SUCCESS) { ++ /* RT_TRACE(COMP_FPGA, DBG_LOUD, ("phy_RF6052_Config_ParaFile():Radio[%d] Fail!!", eRFPath)); */ ++ goto phy_RF6052_Config_ParaFile_Fail; ++ } ++ ++ } ++ ++ /* 3 ----------------------------------------------------------------- */ ++ /* 3 Configuration of Tx Power Tracking */ ++ /* 3 ----------------------------------------------------------------- */ ++ ++#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE ++ if (PHY_ConfigRFWithTxPwrTrackParaFile(Adapter, pszTxPwrTrackFile) == _FAIL) ++#endif ++ { ++ ODM_ConfigRFWithTxPwrTrackHeaderFile(&pHalData->odmpriv); ++ } ++ ++ /* RT_TRACE(COMP_INIT, DBG_LOUD, ("<---phy_RF6052_Config_ParaFile()\n")); */ ++ return rtStatus; ++ ++phy_RF6052_Config_ParaFile_Fail: ++ return rtStatus; ++} ++ ++ ++int ++PHY_RF6052_Config8723B( ++struct adapter * Adapter) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ int rtStatus = _SUCCESS; ++ ++ /* */ ++ /* Initialize general global value */ ++ /* */ ++ /* TODO: Extend RF_PATH_C and RF_PATH_D in the future */ ++ if (pHalData->rf_type == RF_1T1R) ++ pHalData->NumTotalRFPath = 1; ++ else ++ pHalData->NumTotalRFPath = 2; ++ ++ /* */ ++ /* Config BB and RF */ ++ /* */ ++ rtStatus = phy_RF6052_Config_ParaFile(Adapter); ++ return rtStatus; ++ ++} ++ ++/* End of HalRf6052.c */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/rtl8723b_rxdesc.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/rtl8723b_rxdesc.c +--- linux-4.3/3rdparty/rtl8723bs/hal/rtl8723b_rxdesc.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/rtl8723b_rxdesc.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,87 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTL8723B_REDESC_C_ ++ ++#include ++ ++static void process_rssi(struct adapter *padapter, union recv_frame *prframe) ++{ ++ struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; ++ struct signal_stat * signal_stat = &padapter->recvpriv.signal_strength_data; ++ ++ /* DBG_8192C("process_rssi => pattrib->rssil(%d) signal_strength(%d)\n ", pattrib->RecvSignalPower, pattrib->signal_strength); */ ++ /* if (pRfd->Status.bPacketToSelf || pRfd->Status.bPacketBeacon) */ ++ { ++ if (signal_stat->update_req) { ++ signal_stat->total_num = 0; ++ signal_stat->total_val = 0; ++ signal_stat->update_req = 0; ++ } ++ ++ signal_stat->total_num++; ++ signal_stat->total_val += pattrib->phy_info.SignalStrength; ++ signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num; ++ } ++ ++}/* Process_UI_RSSI_8192C */ ++ ++static void process_link_qual(struct adapter *padapter, union recv_frame *prframe) ++{ ++ struct rx_pkt_attrib *pattrib; ++ struct signal_stat * signal_stat; ++ ++ if (prframe == NULL || padapter == NULL) { ++ return; ++ } ++ ++ pattrib = &prframe->u.hdr.attrib; ++ signal_stat = &padapter->recvpriv.signal_qual_data; ++ ++ /* DBG_8192C("process_link_qual => pattrib->signal_qual(%d)\n ", pattrib->signal_qual); */ ++ ++ if (signal_stat->update_req) { ++ signal_stat->total_num = 0; ++ signal_stat->total_val = 0; ++ signal_stat->update_req = 0; ++ } ++ ++ signal_stat->total_num++; ++ signal_stat->total_val += pattrib->phy_info.SignalQuality; ++ signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num; ++}/* Process_UiLinkQuality8192S */ ++ ++ ++void rtl8723b_process_phy_info(struct adapter *padapter, void *prframe) ++{ ++ union recv_frame *precvframe = (union recv_frame *)prframe; ++ /* */ ++ /* Check RSSI */ ++ /* */ ++ process_rssi(padapter, precvframe); ++ /* */ ++ /* Check PWDB. */ ++ /* */ ++ /* process_PWDB(padapter, precvframe); */ ++ ++ /* UpdateRxSignalStatistics8192C(Adapter, pRfd); */ ++ /* */ ++ /* Check EVM */ ++ /* */ ++ process_link_qual(padapter, precvframe); ++ #ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA ++ rtw_store_phy_info(padapter, prframe); ++ #endif ++ ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/rtl8723bs_recv.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/rtl8723bs_recv.c +--- linux-4.3/3rdparty/rtl8723bs/hal/rtl8723bs_recv.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/rtl8723bs_recv.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,528 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTL8723BS_RECV_C_ ++ ++#include ++#include ++#include ++ ++ ++static s32 initrecvbuf(struct recv_buf *precvbuf, struct adapter *padapter) ++{ ++ INIT_LIST_HEAD(&precvbuf->list); ++ spin_lock_init(&precvbuf->recvbuf_lock); ++ ++ precvbuf->adapter = padapter; ++ ++ return _SUCCESS; ++} ++ ++static void update_recvframe_attrib( ++ struct adapter *padapter, ++ union recv_frame *precvframe, ++ struct recv_stat *prxstat) ++{ ++ struct rx_pkt_attrib *pattrib; ++ struct recv_stat report; ++ PRXREPORT prxreport = (PRXREPORT)&report; ++ ++ report.rxdw0 = prxstat->rxdw0; ++ report.rxdw1 = prxstat->rxdw1; ++ report.rxdw2 = prxstat->rxdw2; ++ report.rxdw3 = prxstat->rxdw3; ++ report.rxdw4 = prxstat->rxdw4; ++ report.rxdw5 = prxstat->rxdw5; ++ ++ pattrib = &precvframe->u.hdr.attrib; ++ memset(pattrib, 0, sizeof(struct rx_pkt_attrib)); ++ ++ /* update rx report to recv_frame attribute */ ++ pattrib->pkt_rpt_type = prxreport->c2h_ind?C2H_PACKET:NORMAL_RX; ++/* DBG_871X("%s: pkt_rpt_type =%d\n", __func__, pattrib->pkt_rpt_type); */ ++ ++ if (pattrib->pkt_rpt_type == NORMAL_RX) ++ { ++ /* Normal rx packet */ ++ /* update rx report to recv_frame attribute */ ++ pattrib->pkt_len = (u16)prxreport->pktlen; ++ pattrib->drvinfo_sz = (u8)(prxreport->drvinfosize << 3); ++ pattrib->physt = (u8)prxreport->physt; ++ ++ pattrib->crc_err = (u8)prxreport->crc32; ++ pattrib->icv_err = (u8)prxreport->icverr; ++ ++ pattrib->bdecrypted = (u8)(prxreport->swdec ? 0 : 1); ++ pattrib->encrypt = (u8)prxreport->security; ++ ++ pattrib->qos = (u8)prxreport->qos; ++ pattrib->priority = (u8)prxreport->tid; ++ ++ pattrib->amsdu = (u8)prxreport->amsdu; ++ ++ pattrib->seq_num = (u16)prxreport->seq; ++ pattrib->frag_num = (u8)prxreport->frag; ++ pattrib->mfrag = (u8)prxreport->mf; ++ pattrib->mdata = (u8)prxreport->md; ++ ++ pattrib->data_rate = (u8)prxreport->rx_rate; ++ } ++ else ++ { ++ pattrib->pkt_len = (u16)prxreport->pktlen; ++ } ++} ++ ++/* ++ * Notice: ++ *Before calling this function, ++ *precvframe->u.hdr.rx_data should be ready! ++ */ ++static void update_recvframe_phyinfo( ++ union recv_frame *precvframe, ++ struct phy_stat *pphy_status) ++{ ++ struct adapter * padapter = precvframe->u.hdr.adapter; ++ struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib; ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PODM_PHY_INFO_T pPHYInfo = (PODM_PHY_INFO_T)(&pattrib->phy_info); ++ ++ u8 *wlanhdr; ++ ODM_PACKET_INFO_T pkt_info; ++ u8 *sa = NULL; ++ /* _irqL irqL; */ ++ struct sta_priv *pstapriv; ++ struct sta_info *psta; ++ ++ pkt_info.bPacketMatchBSSID =false; ++ pkt_info.bPacketToSelf = false; ++ pkt_info.bPacketBeacon = false; ++ ++ ++ wlanhdr = get_recvframe_data(precvframe); ++ ++ pkt_info.bPacketMatchBSSID = ((!IsFrameTypeCtrl(wlanhdr)) && ++ !pattrib->icv_err && !pattrib->crc_err && ++ !memcmp(get_hdr_bssid(wlanhdr), get_bssid(&padapter->mlmepriv), ETH_ALEN)); ++ ++ pkt_info.bPacketToSelf = pkt_info.bPacketMatchBSSID && (!memcmp(get_ra(wlanhdr), myid(&padapter->eeprompriv), ETH_ALEN)); ++ ++ pkt_info.bPacketBeacon = pkt_info.bPacketMatchBSSID && (GetFrameSubType(wlanhdr) == WIFI_BEACON); ++ ++ sa = get_ta(wlanhdr); ++ ++ pkt_info.StationID = 0xFF; ++ ++ pstapriv = &padapter->stapriv; ++ psta = rtw_get_stainfo(pstapriv, sa); ++ if (psta) ++ { ++ pkt_info.StationID = psta->mac_id; ++ /* DBG_8192C("%s ==> StationID(%d)\n", __func__, pkt_info.StationID); */ ++ } ++ pkt_info.DataRate = pattrib->data_rate; ++ ++ /* rtl8723b_query_rx_phy_status(precvframe, pphy_status); */ ++ /* spin_lock_bh(&pHalData->odm_stainfo_lock); */ ++ ODM_PhyStatusQuery(&pHalData->odmpriv, pPHYInfo, (u8 *)pphy_status,&(pkt_info)); ++ if (psta) psta->rssi = pattrib->phy_info.RecvSignalPower; ++ /* spin_unlock_bh(&pHalData->odm_stainfo_lock); */ ++ precvframe->u.hdr.psta = NULL; ++ if (pkt_info.bPacketMatchBSSID && ++ (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true)) ++ { ++ if (psta) ++ { ++ precvframe->u.hdr.psta = psta; ++ rtl8723b_process_phy_info(padapter, precvframe); ++ } ++ } ++ else if (pkt_info.bPacketToSelf || pkt_info.bPacketBeacon) ++ { ++ if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE) == true) ++ { ++ if (psta) ++ { ++ precvframe->u.hdr.psta = psta; ++ } ++ } ++ rtl8723b_process_phy_info(padapter, precvframe); ++ } ++} ++ ++static void rtl8723bs_c2h_packet_handler(struct adapter *padapter, u8 *pbuf, u16 length) ++{ ++ u8 *tmpBuf = NULL; ++ u8 res = false; ++ ++ if (length == 0) ++ return; ++ ++ /* DBG_871X("+%s() length =%d\n", __func__, length); */ ++ ++ tmpBuf = rtw_zmalloc(length); ++ if (tmpBuf == NULL) ++ return; ++ ++ memcpy(tmpBuf, pbuf, length); ++ ++ res = rtw_c2h_packet_wk_cmd(padapter, tmpBuf, length); ++ ++ if (res == false) ++ kfree(tmpBuf); ++ ++ /* DBG_871X("-%s res(%d)\n", __func__, res); */ ++ ++ return; ++} ++ ++static void rtl8723bs_recv_tasklet(void *priv) ++{ ++ struct adapter * padapter; ++ struct hal_com_data * pHalData; ++ struct recv_priv *precvpriv; ++ struct recv_buf *precvbuf; ++ union recv_frame *precvframe; ++ struct rx_pkt_attrib *pattrib; ++ u8 *ptr; ++ u32 pkt_offset, skb_len, alloc_sz; ++ _pkt *pkt_copy = NULL; ++ u8 shift_sz = 0, rx_report_sz = 0; ++ ++ ++ padapter = (struct adapter *)priv; ++ pHalData = GET_HAL_DATA(padapter); ++ precvpriv = &padapter->recvpriv; ++ ++ do { ++ precvbuf = rtw_dequeue_recvbuf(&precvpriv->recv_buf_pending_queue); ++ if (NULL == precvbuf) break; ++ ++ ptr = precvbuf->pdata; ++ ++ while (ptr < precvbuf->ptail) ++ { ++ precvframe = rtw_alloc_recvframe(&precvpriv->free_recv_queue); ++ if (precvframe == NULL) ++ { ++ DBG_8192C("%s: no enough recv frame!\n", __func__); ++ rtw_enqueue_recvbuf_to_head(precvbuf, &precvpriv->recv_buf_pending_queue); ++ ++ /* The case of can't allocte recvframe should be temporary, */ ++ /* schedule again and hope recvframe is available next time. */ ++ tasklet_schedule(&precvpriv->recv_tasklet); ++ return; ++ } ++ ++ /* rx desc parsing */ ++ update_recvframe_attrib(padapter, precvframe, (struct recv_stat*)ptr); ++ ++ pattrib = &precvframe->u.hdr.attrib; ++ ++ /* fix Hardware RX data error, drop whole recv_buffer */ ++ if ((!(pHalData->ReceiveConfig & RCR_ACRC32)) && pattrib->crc_err) ++ { ++ DBG_8192C("%s()-%d: RX Warning! rx CRC ERROR !!\n", __func__, __LINE__); ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ break; ++ } ++ ++ rx_report_sz = RXDESC_SIZE + pattrib->drvinfo_sz; ++ pkt_offset = rx_report_sz + pattrib->shift_sz + pattrib->pkt_len; ++ ++ if ((ptr + pkt_offset) > precvbuf->ptail) { ++ DBG_8192C("%s()-%d: : next pkt len(%p,%d) exceed ptail(%p)!\n", __func__, __LINE__, ptr, pkt_offset, precvbuf->ptail); ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ break; ++ } ++ ++ if ((pattrib->crc_err) || (pattrib->icv_err)) ++ { ++ { ++ DBG_8192C("%s: crc_err =%d icv_err =%d, skip!\n", __func__, pattrib->crc_err, pattrib->icv_err); ++ } ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ } ++ else ++ { ++ /* Modified by Albert 20101213 */ ++ /* For 8 bytes IP header alignment. */ ++ if (pattrib->qos) /* Qos data, wireless lan header length is 26 */ ++ { ++ shift_sz = 6; ++ } ++ else ++ { ++ shift_sz = 0; ++ } ++ ++ skb_len = pattrib->pkt_len; ++ ++ /* for first fragment packet, driver need allocate 1536+drvinfo_sz+RXDESC_SIZE to defrag packet. */ ++ /* modify alloc_sz for recvive crc error packet by thomas 2011-06-02 */ ++ if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) { ++ if (skb_len <= 1650) ++ alloc_sz = 1664; ++ else ++ alloc_sz = skb_len + 14; ++ } ++ else { ++ alloc_sz = skb_len; ++ /* 6 is for IP header 8 bytes alignment in QoS packet case. */ ++ /* 8 is for skb->data 4 bytes alignment. */ ++ alloc_sz += 14; ++ } ++ ++ pkt_copy = rtw_skb_alloc(alloc_sz); ++ ++ if (pkt_copy) ++ { ++ pkt_copy->dev = padapter->pnetdev; ++ precvframe->u.hdr.pkt = pkt_copy; ++ skb_reserve(pkt_copy, 8 - ((SIZE_PTR)(pkt_copy->data) & 7));/* force pkt_copy->data at 8-byte alignment address */ ++ skb_reserve(pkt_copy, shift_sz);/* force ip_hdr at 8-byte alignment address according to shift_sz. */ ++ memcpy(pkt_copy->data, (ptr + rx_report_sz + pattrib->shift_sz), skb_len); ++ precvframe->u.hdr.rx_head = pkt_copy->head; ++ precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail = pkt_copy->data; ++ precvframe->u.hdr.rx_end = skb_end_pointer(pkt_copy); ++ } ++ else ++ { ++ if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) ++ { ++ DBG_8192C("%s: alloc_skb fail, drop frag frame\n", __func__); ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ break; ++ } ++ ++ precvframe->u.hdr.pkt = rtw_skb_clone(precvbuf->pskb); ++ if (precvframe->u.hdr.pkt) ++ { ++ _pkt *pkt_clone = precvframe->u.hdr.pkt; ++ ++ pkt_clone->data = ptr + rx_report_sz + pattrib->shift_sz; ++ skb_reset_tail_pointer(pkt_clone); ++ precvframe->u.hdr.rx_head = precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail ++ = pkt_clone->data; ++ precvframe->u.hdr.rx_end = pkt_clone->data + skb_len; ++ } ++ else ++ { ++ DBG_8192C("%s: rtw_skb_clone fail\n", __func__); ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ break; ++ } ++ } ++ ++ recvframe_put(precvframe, skb_len); ++ /* recvframe_pull(precvframe, drvinfo_sz + RXDESC_SIZE); */ ++ ++ if (pHalData->ReceiveConfig & RCR_APPFCS) ++ recvframe_pull_tail(precvframe, IEEE80211_FCS_LEN); ++ ++ /* move to drv info position */ ++ ptr += RXDESC_SIZE; ++ ++ /* update drv info */ ++ if (pHalData->ReceiveConfig & RCR_APP_BA_SSN) { ++ /* rtl8723s_update_bassn(padapter, pdrvinfo); */ ++ ptr += 4; ++ } ++ ++ if (pattrib->pkt_rpt_type == NORMAL_RX)/* Normal rx packet */ ++ { ++ if (pattrib->physt) ++ update_recvframe_phyinfo(precvframe, (struct phy_stat*)ptr); ++ ++ if (rtw_recv_entry(precvframe) != _SUCCESS) ++ { ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_dump_, ("%s: rtw_recv_entry(precvframe) != _SUCCESS\n", __func__)); ++ } ++ } ++ else if (pattrib->pkt_rpt_type == C2H_PACKET) ++ { ++ C2H_EVT_HDR C2hEvent; ++ ++ u16 len_c2h = pattrib->pkt_len; ++ u8 *pbuf_c2h = precvframe->u.hdr.rx_data; ++ u8 *pdata_c2h; ++ ++ C2hEvent.CmdID = pbuf_c2h[0]; ++ C2hEvent.CmdSeq = pbuf_c2h[1]; ++ C2hEvent.CmdLen = (len_c2h -2); ++ pdata_c2h = pbuf_c2h+2; ++ ++ if (C2hEvent.CmdID == C2H_CCX_TX_RPT) ++ { ++ CCX_FwC2HTxRpt_8723b(padapter, pdata_c2h, C2hEvent.CmdLen); ++ } ++ else ++ { ++ rtl8723bs_c2h_packet_handler(padapter, precvframe->u.hdr.rx_data, pattrib->pkt_len); ++ } ++ ++ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); ++ ++ } ++ } ++ ++ pkt_offset = _RND8(pkt_offset); ++ precvbuf->pdata += pkt_offset; ++ ptr = precvbuf->pdata; ++ precvframe = NULL; ++ pkt_copy = NULL; ++ } ++ ++ rtw_enqueue_recvbuf(precvbuf, &precvpriv->free_recv_buf_queue); ++ } while (1); ++ ++} ++ ++/* ++ * Initialize recv private variable for hardware dependent ++ * 1. recv buf ++ * 2. recv tasklet ++ * ++ */ ++s32 rtl8723bs_init_recv_priv(struct adapter *padapter) ++{ ++ s32 res; ++ u32 i, n; ++ struct recv_priv *precvpriv; ++ struct recv_buf *precvbuf; ++ ++ ++ res = _SUCCESS; ++ precvpriv = &padapter->recvpriv; ++ ++ /* 3 1. init recv buffer */ ++ _rtw_init_queue(&precvpriv->free_recv_buf_queue); ++ _rtw_init_queue(&precvpriv->recv_buf_pending_queue); ++ ++ n = NR_RECVBUFF * sizeof(struct recv_buf) + 4; ++ precvpriv->pallocated_recv_buf = rtw_zmalloc(n); ++ if (precvpriv->pallocated_recv_buf == NULL) { ++ res = _FAIL; ++ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("alloc recv_buf fail!\n")); ++ goto exit; ++ } ++ ++ precvpriv->precv_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_recv_buf), 4); ++ ++ /* init each recv buffer */ ++ precvbuf = (struct recv_buf*)precvpriv->precv_buf; ++ for (i = 0; i < NR_RECVBUFF; i++) ++ { ++ res = initrecvbuf(precvbuf, padapter); ++ if (res == _FAIL) ++ break; ++ ++ if (precvbuf->pskb == NULL) { ++ SIZE_PTR tmpaddr = 0; ++ SIZE_PTR alignment = 0; ++ ++ precvbuf->pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); ++ ++ if (precvbuf->pskb) ++ { ++ precvbuf->pskb->dev = padapter->pnetdev; ++ ++ tmpaddr = (SIZE_PTR)precvbuf->pskb->data; ++ alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); ++ skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment)); ++ } ++ ++ if (precvbuf->pskb == NULL) { ++ DBG_871X("%s: alloc_skb fail!\n", __func__); ++ } ++ } ++ ++ list_add_tail(&precvbuf->list, &precvpriv->free_recv_buf_queue.queue); ++ ++ precvbuf++; ++ } ++ precvpriv->free_recv_buf_queue_cnt = i; ++ ++ if (res == _FAIL) ++ goto initbuferror; ++ ++ /* 3 2. init tasklet */ ++ tasklet_init(&precvpriv->recv_tasklet, ++ (void(*)(unsigned long))rtl8723bs_recv_tasklet, ++ (unsigned long)padapter); ++ ++ goto exit; ++ ++initbuferror: ++ precvbuf = (struct recv_buf*)precvpriv->precv_buf; ++ if (precvbuf) { ++ n = precvpriv->free_recv_buf_queue_cnt; ++ precvpriv->free_recv_buf_queue_cnt = 0; ++ for (i = 0; i < n ; i++) ++ { ++ list_del_init(&precvbuf->list); ++ rtw_os_recvbuf_resource_free(padapter, precvbuf); ++ precvbuf++; ++ } ++ precvpriv->precv_buf = NULL; ++ } ++ ++ if (precvpriv->pallocated_recv_buf) { ++ n = NR_RECVBUFF * sizeof(struct recv_buf) + 4; ++ kfree(precvpriv->pallocated_recv_buf); ++ precvpriv->pallocated_recv_buf = NULL; ++ } ++ ++exit: ++ return res; ++} ++ ++/* ++ * Free recv private variable of hardware dependent ++ * 1. recv buf ++ * 2. recv tasklet ++ * ++ */ ++void rtl8723bs_free_recv_priv(struct adapter *padapter) ++{ ++ u32 i, n; ++ struct recv_priv *precvpriv; ++ struct recv_buf *precvbuf; ++ ++ ++ precvpriv = &padapter->recvpriv; ++ ++ /* 3 1. kill tasklet */ ++ tasklet_kill(&precvpriv->recv_tasklet); ++ ++ /* 3 2. free all recv buffers */ ++ precvbuf = (struct recv_buf*)precvpriv->precv_buf; ++ if (precvbuf) { ++ n = NR_RECVBUFF; ++ precvpriv->free_recv_buf_queue_cnt = 0; ++ for (i = 0; i < n ; i++) ++ { ++ list_del_init(&precvbuf->list); ++ rtw_os_recvbuf_resource_free(padapter, precvbuf); ++ precvbuf++; ++ } ++ precvpriv->precv_buf = NULL; ++ } ++ ++ if (precvpriv->pallocated_recv_buf) { ++ n = NR_RECVBUFF * sizeof(struct recv_buf) + 4; ++ kfree(precvpriv->pallocated_recv_buf); ++ precvpriv->pallocated_recv_buf = NULL; ++ } ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/rtl8723bs_xmit.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/rtl8723bs_xmit.c +--- linux-4.3/3rdparty/rtl8723bs/hal/rtl8723bs_xmit.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/rtl8723bs_xmit.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,652 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RTL8723BS_XMIT_C_ ++ ++#include ++#include ++#include ++ ++static u8 rtw_sdio_wait_enough_TxOQT_space(struct adapter *padapter, u8 agg_num) ++{ ++ u32 n = 0; ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ ++ while (pHalData->SdioTxOQTFreeSpace < agg_num) ++ { ++ if ((padapter->bSurpriseRemoved == true) ++ || (padapter->bDriverStopped == true)) { ++ DBG_871X("%s: bSurpriseRemoved or bDriverStopped (wait TxOQT)\n", __func__); ++ return false; ++ } ++ ++ HalQueryTxOQTBufferStatus8723BSdio(padapter); ++ ++ if ((++n % 60) == 0) { ++ if ((n % 300) == 0) { ++ DBG_871X("%s(%d): QOT free space(%d), agg_num: %d\n", ++ __func__, n, pHalData->SdioTxOQTFreeSpace, agg_num); ++ } ++ msleep(1); ++ /* yield(); */ ++ } ++ } ++ ++ pHalData->SdioTxOQTFreeSpace -= agg_num; ++ ++ /* if (n > 1) */ ++ /* ++priv->pshare->nr_out_of_txoqt_space; */ ++ ++ return true; ++} ++ ++static s32 rtl8723_dequeue_writeport(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ struct xmit_buf *pxmitbuf; ++ struct adapter * pri_padapter = padapter; ++ s32 ret = 0; ++ u8 PageIdx = 0; ++ u32 deviceId; ++ u8 bUpdatePageNum = false; ++ ++ ret = ret || check_fwstate(pmlmepriv, _FW_UNDER_SURVEY); ++ ++ if (true == ret) ++ pxmitbuf = dequeue_pending_xmitbuf_under_survey(pxmitpriv); ++ else ++ pxmitbuf = dequeue_pending_xmitbuf(pxmitpriv); ++ ++ if (pxmitbuf == NULL) ++ return true; ++ ++ deviceId = ffaddr2deviceId(pdvobjpriv, pxmitbuf->ff_hwaddr); ++ ++ /* translate fifo addr to queue index */ ++ switch (deviceId) { ++ case WLAN_TX_HIQ_DEVICE_ID: ++ PageIdx = HI_QUEUE_IDX; ++ break; ++ ++ case WLAN_TX_MIQ_DEVICE_ID: ++ PageIdx = MID_QUEUE_IDX; ++ break; ++ ++ case WLAN_TX_LOQ_DEVICE_ID: ++ PageIdx = LOW_QUEUE_IDX; ++ break; ++ } ++ ++query_free_page: ++ /* check if hardware tx fifo page is enough */ ++ if (false == rtw_hal_sdio_query_tx_freepage(pri_padapter, PageIdx, pxmitbuf->pg_num)) ++ { ++ if (!bUpdatePageNum) { ++ /* Total number of page is NOT available, so update current FIFO status */ ++ HalQueryTxBufferStatus8723BSdio(padapter); ++ bUpdatePageNum = true; ++ goto query_free_page; ++ } else { ++ bUpdatePageNum = false; ++ enqueue_pending_xmitbuf_to_head(pxmitpriv, pxmitbuf); ++ return true; ++ } ++ } ++ ++ if ((padapter->bSurpriseRemoved == true) ++ || (padapter->bDriverStopped == true)) { ++ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ++ ("%s: bSurpriseRemoved(wirte port)\n", __func__)); ++ goto free_xmitbuf; ++ } ++ ++ if (rtw_sdio_wait_enough_TxOQT_space(padapter, pxmitbuf->agg_num) == false) ++ { ++ goto free_xmitbuf; ++ } ++ ++ traffic_check_for_leave_lps(padapter, true, pxmitbuf->agg_num); ++ ++ rtw_write_port(padapter, deviceId, pxmitbuf->len, (u8 *)pxmitbuf); ++ ++ rtw_hal_sdio_update_tx_freepage(pri_padapter, PageIdx, pxmitbuf->pg_num); ++ ++free_xmitbuf: ++ /* rtw_free_xmitframe(pxmitpriv, pframe); */ ++ /* pxmitbuf->priv_data = NULL; */ ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++ ++#ifdef CONFIG_SDIO_TX_TASKLET ++ tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); ++#endif ++ ++ return _FAIL; ++} ++ ++/* ++ * Description ++ *Transmit xmitbuf to hardware tx fifo ++ * ++ * Return ++ *_SUCCESS ok ++ *_FAIL something error ++ */ ++s32 rtl8723bs_xmit_buf_handler(struct adapter *padapter) ++{ ++ struct xmit_priv *pxmitpriv; ++ u8 queue_empty, queue_pending; ++ s32 ret; ++ ++ ++ pxmitpriv = &padapter->xmitpriv; ++ ++ if (down_interruptible(&pxmitpriv->xmit_sema)) { ++ DBG_871X_LEVEL(_drv_emerg_, "%s: down SdioXmitBufSema fail!\n", __func__); ++ return _FAIL; ++ } ++ ++ ret = (padapter->bDriverStopped == true) || (padapter->bSurpriseRemoved == true); ++ if (ret) { ++ RT_TRACE(_module_hal_xmit_c_, _drv_err_, ++ ("%s: bDriverStopped(%d) bSurpriseRemoved(%d)!\n", ++ __func__, padapter->bDriverStopped, padapter->bSurpriseRemoved)); ++ return _FAIL; ++ } ++ ++ queue_pending = check_pending_xmitbuf(pxmitpriv); ++ ++ if (queue_pending == false) ++ return _SUCCESS; ++ ++ ret = rtw_register_tx_alive(padapter); ++ if (ret != _SUCCESS) { ++ return _SUCCESS; ++ } ++ ++ do { ++ queue_empty = rtl8723_dequeue_writeport(padapter); ++/* dump secondary adapter xmitbuf */ ++ } while (!queue_empty); ++ ++ rtw_unregister_tx_alive(padapter); ++ ++ return _SUCCESS; ++} ++ ++/* ++ * Description: ++ *Aggregation packets and send to hardware ++ * ++ * Return: ++ *0 Success ++ *-1 Hardware resource(TX FIFO) not ready ++ *-2 Software resource(xmitbuf) not ready ++ */ ++static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv) ++{ ++ s32 err, ret; ++ u32 k = 0; ++ struct hw_xmit *hwxmits, *phwxmit; ++ u8 no_res, idx, hwentry; ++ struct tx_servq *ptxservq; ++ struct list_head *sta_plist, *sta_phead, *frame_plist, *frame_phead; ++ struct xmit_frame *pxmitframe; ++ struct __queue *pframe_queue; ++ struct xmit_buf *pxmitbuf; ++ u32 txlen, max_xmit_len; ++ u8 txdesc_size = TXDESC_SIZE; ++ int inx[4]; ++ ++ err = 0; ++ no_res = false; ++ hwxmits = pxmitpriv->hwxmits; ++ hwentry = pxmitpriv->hwxmit_entry; ++ ptxservq = NULL; ++ pxmitframe = NULL; ++ pframe_queue = NULL; ++ pxmitbuf = NULL; ++ ++ if (padapter->registrypriv.wifi_spec == 1) { ++ for (idx = 0; idx<4; idx++) ++ inx[idx] = pxmitpriv->wmm_para_seq[idx]; ++ } else { ++ inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3; ++ } ++ ++ /* 0(VO), 1(VI), 2(BE), 3(BK) */ ++ for (idx = 0; idx < hwentry; idx++) ++ { ++ phwxmit = hwxmits + inx[idx]; ++ ++ if ((check_pending_xmitbuf(pxmitpriv) == true) && (padapter->mlmepriv.LinkDetectInfo.bHigherBusyTxTraffic == true)) { ++ if ((phwxmit->accnt > 0) && (phwxmit->accnt < 5)) { ++ err = -2; ++ break; ++ } ++ } ++ ++ max_xmit_len = rtw_hal_get_sdio_tx_max_length(padapter, inx[idx]); ++ ++ spin_lock_bh(&pxmitpriv->lock); ++ ++ sta_phead = get_list_head(phwxmit->sta_queue); ++ sta_plist = get_next(sta_phead); ++ /* because stop_sta_xmit may delete sta_plist at any time */ ++ /* so we should add lock here, or while loop can not exit */ ++ while (sta_phead != sta_plist) ++ { ++ ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending); ++ sta_plist = get_next(sta_plist); ++ ++#ifdef DBG_XMIT_BUF ++ DBG_871X("%s idx:%d hwxmit_pkt_num:%d ptxservq_pkt_num:%d\n", __func__, idx, phwxmit->accnt, ptxservq->qcnt); ++ DBG_871X("%s free_xmit_extbuf_cnt =%d free_xmitbuf_cnt =%d free_xmitframe_cnt =%d\n", ++ __func__, pxmitpriv->free_xmit_extbuf_cnt, pxmitpriv->free_xmitbuf_cnt, ++ pxmitpriv->free_xmitframe_cnt); ++#endif ++ pframe_queue = &ptxservq->sta_pending; ++ ++ frame_phead = get_list_head(pframe_queue); ++ ++ while (list_empty(frame_phead) == false) ++ { ++ frame_plist = get_next(frame_phead); ++ pxmitframe = LIST_CONTAINOR(frame_plist, struct xmit_frame, list); ++ ++ /* check xmit_buf size enough or not */ ++ txlen = txdesc_size + rtw_wlan_pkt_size(pxmitframe); ++ if ((NULL == pxmitbuf) || ++ ((_RND(pxmitbuf->len, 8) + txlen) > max_xmit_len) ++ || (k >= (rtw_hal_sdio_max_txoqt_free_space(padapter)-1)) ++ ) ++ { ++ if (pxmitbuf) ++ { ++ /* pxmitbuf->priv_data will be NULL, and will crash here */ ++ if (pxmitbuf->len > 0 && pxmitbuf->priv_data) ++ { ++ struct xmit_frame *pframe; ++ pframe = (struct xmit_frame*)pxmitbuf->priv_data; ++ pframe->agg_num = k; ++ pxmitbuf->agg_num = k; ++ rtl8723b_update_txdesc(pframe, pframe->buf_addr); ++ rtw_free_xmitframe(pxmitpriv, pframe); ++ pxmitbuf->priv_data = NULL; ++ enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf); ++ /* can not yield under lock */ ++ /* yield(); */ ++ } else { ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++ } ++ } ++ ++ pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); ++ if (pxmitbuf == NULL) { ++#ifdef DBG_XMIT_BUF ++ DBG_871X_LEVEL(_drv_err_, "%s: xmit_buf is not enough!\n", __func__); ++#endif ++ err = -2; ++ up(&(pxmitpriv->xmit_sema)); ++ break; ++ } ++ k = 0; ++ } ++ ++ /* ok to send, remove frame from queue */ ++ if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true) { ++ if ((pxmitframe->attrib.psta->state & WIFI_SLEEP_STATE) && ++ (pxmitframe->attrib.triggered == 0)) { ++ DBG_871X("%s: one not triggered pkt in queue when this STA sleep," ++ " break and goto next sta\n", __func__); ++ break; ++ } ++ } ++ ++ list_del_init(&pxmitframe->list); ++ ptxservq->qcnt--; ++ phwxmit->accnt--; ++ ++ if (k == 0) { ++ pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe); ++ pxmitbuf->priv_data = (u8 *)pxmitframe; ++ } ++ ++ /* coalesce the xmitframe to xmitbuf */ ++ pxmitframe->pxmitbuf = pxmitbuf; ++ pxmitframe->buf_addr = pxmitbuf->ptail; ++ ++ ret = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); ++ if (ret == _FAIL) { ++ DBG_871X_LEVEL(_drv_err_, "%s: coalesce FAIL!", __func__); ++ /* Todo: error handler */ ++ } else { ++ k++; ++ if (k != 1) ++ rtl8723b_update_txdesc(pxmitframe, pxmitframe->buf_addr); ++ rtw_count_tx_stats(padapter, pxmitframe, pxmitframe->attrib.last_txcmdsz); ++ ++ txlen = txdesc_size + pxmitframe->attrib.last_txcmdsz; ++ pxmitframe->pg_num = (txlen + 127)/128; ++ pxmitbuf->pg_num += (txlen + 127)/128; ++ /* if (k != 1) */ ++ /* ((struct xmit_frame*)pxmitbuf->priv_data)->pg_num += pxmitframe->pg_num; */ ++ pxmitbuf->ptail += _RND(txlen, 8); /* round to 8 bytes alignment */ ++ pxmitbuf->len = _RND(pxmitbuf->len, 8) + txlen; ++ } ++ ++ if (k != 1) ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ pxmitframe = NULL; ++ } ++ ++ if (list_empty(&pframe_queue->queue)) ++ list_del_init(&ptxservq->tx_pending); ++ ++ if (err) break; ++ } ++ spin_unlock_bh(&pxmitpriv->lock); ++ ++ /* dump xmit_buf to hw tx fifo */ ++ if (pxmitbuf) ++ { ++ RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("pxmitbuf->len =%d enqueue\n", pxmitbuf->len)); ++ ++ if (pxmitbuf->len > 0) { ++ struct xmit_frame *pframe; ++ pframe = (struct xmit_frame*)pxmitbuf->priv_data; ++ pframe->agg_num = k; ++ pxmitbuf->agg_num = k; ++ rtl8723b_update_txdesc(pframe, pframe->buf_addr); ++ rtw_free_xmitframe(pxmitpriv, pframe); ++ pxmitbuf->priv_data = NULL; ++ enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf); ++ yield(); ++ } ++ else ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++ pxmitbuf = NULL; ++ } ++ ++ if (err) break; ++ } ++ ++ return err; ++} ++ ++/* ++ * Description ++ *Transmit xmitframe from queue ++ * ++ * Return ++ *_SUCCESS ok ++ *_FAIL something error ++ */ ++static s32 rtl8723bs_xmit_handler(struct adapter *padapter) ++{ ++ struct xmit_priv *pxmitpriv; ++ s32 ret; ++ ++ ++ pxmitpriv = &padapter->xmitpriv; ++ ++ if (down_interruptible(&pxmitpriv->SdioXmitSema)) { ++ DBG_871X_LEVEL(_drv_emerg_, "%s: down sema fail!\n", __func__); ++ return _FAIL; ++ } ++ ++next: ++ if ((padapter->bDriverStopped == true) || ++ (padapter->bSurpriseRemoved == true)) { ++ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ++ ("%s: bDriverStopped(%d) bSurpriseRemoved(%d)\n", ++ __func__, padapter->bDriverStopped, padapter->bSurpriseRemoved)); ++ return _FAIL; ++ } ++ ++ spin_lock_bh(&pxmitpriv->lock); ++ ret = rtw_txframes_pending(padapter); ++ spin_unlock_bh(&pxmitpriv->lock); ++ if (ret == 0) { ++ return _SUCCESS; ++ } ++ ++ /* dequeue frame and write to hardware */ ++ ++ ret = xmit_xmitframes(padapter, pxmitpriv); ++ if (ret == -2) { ++ /* here sleep 1ms will cause big TP loss of TX */ ++ /* from 50+ to 40+ */ ++ if (padapter->registrypriv.wifi_spec) ++ msleep(1); ++ else ++ yield(); ++ goto next; ++ } ++ ++ spin_lock_bh(&pxmitpriv->lock); ++ ret = rtw_txframes_pending(padapter); ++ spin_unlock_bh(&pxmitpriv->lock); ++ if (ret == 1) { ++ goto next; ++ } ++ ++ return _SUCCESS; ++} ++ ++int rtl8723bs_xmit_thread(void *context) ++{ ++ s32 ret; ++ struct adapter *padapter; ++ struct xmit_priv *pxmitpriv; ++ u8 thread_name[20] = "RTWHALXT"; ++ ++ ++ ret = _SUCCESS; ++ padapter = (struct adapter *)context; ++ pxmitpriv = &padapter->xmitpriv; ++ ++ rtw_sprintf(thread_name, 20, "%s-"ADPT_FMT, thread_name, ADPT_ARG(padapter)); ++ thread_enter(thread_name); ++ ++ DBG_871X("start "FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); ++ ++ /* For now, no one would down sema to check thread is running, */ ++ /* so mark this temporary, Lucas@20130820 */ ++/* up(&pxmitpriv->SdioXmitTerminateSema); */ ++ ++ do { ++ ret = rtl8723bs_xmit_handler(padapter); ++ if (signal_pending(current)) { ++ flush_signals(current); ++ } ++ } while (_SUCCESS == ret); ++ ++ up(&pxmitpriv->SdioXmitTerminateSema); ++ ++ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("-%s\n", __func__)); ++ ++ thread_exit(); ++} ++ ++s32 rtl8723bs_mgnt_xmit(struct adapter *padapter, struct xmit_frame *pmgntframe) ++{ ++ s32 ret = _SUCCESS; ++ struct pkt_attrib *pattrib; ++ struct xmit_buf *pxmitbuf; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ u8 *pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ u8 txdesc_size = TXDESC_SIZE; ++ ++ RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("+%s\n", __func__)); ++ ++ pattrib = &pmgntframe->attrib; ++ pxmitbuf = pmgntframe->pxmitbuf; ++ ++ rtl8723b_update_txdesc(pmgntframe, pmgntframe->buf_addr); ++ ++ pxmitbuf->len = txdesc_size + pattrib->last_txcmdsz; ++ pxmitbuf->pg_num = (pxmitbuf->len + 127)/128; /* 128 is tx page size */ ++ pxmitbuf->ptail = pmgntframe->buf_addr + pxmitbuf->len; ++ pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pmgntframe); ++ ++ rtw_count_tx_stats(padapter, pmgntframe, pattrib->last_txcmdsz); ++ ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ ++ pxmitbuf->priv_data = NULL; ++ ++ if (GetFrameSubType(pframe) ==WIFI_BEACON) /* dump beacon directly */ ++ { ++ ret = rtw_write_port(padapter, pdvobjpriv->Queue2Pipe[pxmitbuf->ff_hwaddr], pxmitbuf->len, (u8 *)pxmitbuf); ++ if (ret != _SUCCESS) ++ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR); ++ ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++ } ++ else ++ { ++ enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf); ++ } ++ ++ return ret; ++} ++ ++/* ++ * Description: ++ *Handle xmitframe(packet) come from rtw_xmit() ++ * ++ * Return: ++ *true dump packet directly ok ++ *false enqueue, temporary can't transmit packets to hardware ++ */ ++s32 rtl8723bs_hal_xmit(struct adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ struct xmit_priv *pxmitpriv; ++ s32 err; ++ ++ ++ pxmitframe->attrib.qsel = pxmitframe->attrib.priority; ++ pxmitpriv = &padapter->xmitpriv; ++ ++ if ((pxmitframe->frame_tag == DATA_FRAMETAG) && ++ (pxmitframe->attrib.ether_type != 0x0806) && ++ (pxmitframe->attrib.ether_type != 0x888e) && ++ (pxmitframe->attrib.dhcp_pkt != 1)) ++ { ++ if (padapter->mlmepriv.LinkDetectInfo.bBusyTraffic == true) ++ rtw_issue_addbareq_cmd(padapter, pxmitframe); ++ } ++ ++ spin_lock_bh(&pxmitpriv->lock); ++ err = rtw_xmitframe_enqueue(padapter, pxmitframe); ++ spin_unlock_bh(&pxmitpriv->lock); ++ if (err != _SUCCESS) { ++ RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("rtl8723bs_hal_xmit: enqueue xmitframe fail\n")); ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ ++ pxmitpriv->tx_drop++; ++ return true; ++ } ++ ++ up(&pxmitpriv->SdioXmitSema); ++ ++ return false; ++} ++ ++s32 rtl8723bs_hal_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ s32 err; ++ ++ if ((err =rtw_xmitframe_enqueue(padapter, pxmitframe)) != _SUCCESS) ++ { ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ ++ pxmitpriv->tx_drop++; ++ } ++ else ++ { ++#ifdef CONFIG_SDIO_TX_TASKLET ++ tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); ++#else ++ up(&pxmitpriv->SdioXmitSema); ++#endif ++ } ++ ++ return err; ++ ++} ++ ++/* ++ * Return ++ *_SUCCESS start thread ok ++ *_FAIL start thread fail ++ * ++ */ ++s32 rtl8723bs_init_xmit_priv(struct adapter *padapter) ++{ ++ struct xmit_priv *xmitpriv = &padapter->xmitpriv; ++ struct hal_com_data *phal; ++ ++ ++ phal = GET_HAL_DATA(padapter); ++ ++ spin_lock_init(&phal->SdioTxFIFOFreePageLock); ++ sema_init(&xmitpriv->SdioXmitSema, 0); ++ sema_init(&xmitpriv->SdioXmitTerminateSema, 0); ++ ++ return _SUCCESS; ++} ++ ++void rtl8723bs_free_xmit_priv(struct adapter *padapter) ++{ ++ struct hal_com_data *phal; ++ struct xmit_priv *pxmitpriv; ++ struct xmit_buf *pxmitbuf; ++ struct __queue *pqueue; ++ struct list_head *plist, *phead; ++ struct list_head tmplist; ++ ++ ++ phal = GET_HAL_DATA(padapter); ++ pxmitpriv = &padapter->xmitpriv; ++ pqueue = &pxmitpriv->pending_xmitbuf_queue; ++ phead = get_list_head(pqueue); ++ INIT_LIST_HEAD(&tmplist); ++ ++ spin_lock_bh(&pqueue->lock); ++ if (!list_empty(&pqueue->queue)) ++ { ++ /* Insert tmplist to end of queue, and delete phead */ ++ /* then tmplist become head of queue. */ ++ list_add_tail(&tmplist, phead); ++ list_del_init(phead); ++ } ++ spin_unlock_bh(&pqueue->lock); ++ ++ phead = &tmplist; ++ while (list_empty(phead) == false) ++ { ++ plist = get_next(phead); ++ list_del_init(plist); ++ ++ pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); ++ rtw_free_xmitframe(pxmitpriv, (struct xmit_frame*)pxmitbuf->priv_data); ++ pxmitbuf->priv_data = NULL; ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++ } ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/sdio_halinit.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/sdio_halinit.c +--- linux-4.3/3rdparty/rtl8723bs/hal/sdio_halinit.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/sdio_halinit.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,1959 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _SDIO_HALINIT_C_ ++ ++#include ++#include ++#include ++ ++#include "hal_com_h2c.h" ++/* ++ * Description: ++ *Call power on sequence to enable card ++ * ++ * Return: ++ *_SUCCESS enable success ++ *_FAIL enable fail ++ */ ++static u8 CardEnable(struct adapter *padapter) ++{ ++ u8 bMacPwrCtrlOn; ++ u8 ret = _FAIL; ++ ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if (bMacPwrCtrlOn == false) ++ { ++ /* RSV_CTRL 0x1C[7:0] = 0x00 */ ++ /* unlock ISO/CLK/Power control register */ ++ rtw_write8(padapter, REG_RSV_CTRL, 0x0); ++ ++ ret = HalPwrSeqCmdParsing(padapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, rtl8723B_card_enable_flow); ++ if (ret == _SUCCESS) { ++ u8 bMacPwrCtrlOn = true; ++ rtw_hal_set_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ } ++ } else ++ ret = _SUCCESS; ++ ++ return ret; ++} ++ ++#ifdef CONFIG_GPIO_WAKEUP ++/* we set it high under init and fw will */ ++/* give us Low Pulse when host wake up */ ++void HostWakeUpGpioClear(struct adapter * Adapter) ++{ ++ u32 value32; ++ ++ value32 = rtw_read32(Adapter, REG_GPIO_PIN_CTRL_2); ++ ++ /* set GPIO 12 1 */ ++ value32 |= BIT(12);/* 4+8 */ ++ /* GPIO 12 out put */ ++ value32 |= BIT(20);/* 4+16 */ ++ ++ rtw_write32(Adapter, REG_GPIO_PIN_CTRL_2, value32); ++} /* HostWakeUpGpioClear */ ++ ++void HalSetOutPutGPIO(struct adapter *padapter, u8 index, u8 OutPutValue) ++{ ++ if (index <= 7) { ++ /* config GPIO mode */ ++ rtw_write8(padapter, REG_GPIO_PIN_CTRL + 3, rtw_read8(padapter, REG_GPIO_PIN_CTRL + 3) & ~BIT(index)); ++ ++ /* config GPIO Sel */ ++ /* 0: input */ ++ /* 1: output */ ++ rtw_write8(padapter, REG_GPIO_PIN_CTRL + 2, rtw_read8(padapter, REG_GPIO_PIN_CTRL + 2) | BIT(index)); ++ ++ /* set output value */ ++ if (OutPutValue) { ++ rtw_write8(padapter, REG_GPIO_PIN_CTRL + 1, rtw_read8(padapter, REG_GPIO_PIN_CTRL + 1) | BIT(index)); ++ } else { ++ rtw_write8(padapter, REG_GPIO_PIN_CTRL + 1, rtw_read8(padapter, REG_GPIO_PIN_CTRL + 1) & ~BIT(index)); ++ } ++ } else { ++ /* 88C Series: */ ++ /* index: 11~8 transform to 3~0 */ ++ /* 8723 Series: */ ++ /* index: 12~8 transform to 4~0 */ ++ index -= 8; ++ ++ /* config GPIO mode */ ++ rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 3, rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 3) & ~BIT(index)); ++ ++ /* config GPIO Sel */ ++ /* 0: input */ ++ /* 1: output */ ++ rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 2, rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 2) | BIT(index)); ++ ++ /* set output value */ ++ if (OutPutValue) { ++ rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 1, rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 1) | BIT(index)); ++ } else { ++ rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 1, rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 1) & ~BIT(index)); ++ } ++ } ++} ++#endif ++ ++static ++u8 _InitPowerOn_8723BS(struct adapter *padapter) ++{ ++ u8 value8; ++ u16 value16; ++ u32 value32; ++ u8 ret; ++/* u8 bMacPwrCtrlOn; */ ++ ++ ++ /* all of these MUST be configured before power on */ ++#ifdef CONFIG_EXT_CLK ++ /* Use external crystal(XTAL) */ ++ value8 = rtw_read8(padapter, REG_PAD_CTRL1_8723B+2); ++ value8 |= BIT(7); ++ rtw_write8(padapter, REG_PAD_CTRL1_8723B+2, value8); ++ ++ /* CLK_REQ High active or Low Active */ ++ /* Request GPIO polarity: */ ++ /* 0: low active */ ++ /* 1: high active */ ++ value8 = rtw_read8(padapter, REG_MULTI_FUNC_CTRL+1); ++ value8 |= BIT(5); ++ rtw_write8(padapter, REG_MULTI_FUNC_CTRL+1, value8); ++#endif /* CONFIG_EXT_CLK */ ++ ++ /* only cmd52 can be used before power on(card enable) */ ++ ret = CardEnable(padapter); ++ if (ret == false) { ++ RT_TRACE(_module_hci_hal_init_c_, _drv_emerg_, ++ ("%s: run power on flow fail\n", __func__)); ++ return _FAIL; ++ } ++ ++ /* Radio-Off Pin Trigger */ ++ value8 = rtw_read8(padapter, REG_GPIO_INTM+1); ++ value8 |= BIT(1); /* Enable falling edge triggering interrupt */ ++ rtw_write8(padapter, REG_GPIO_INTM+1, value8); ++ value8 = rtw_read8(padapter, REG_GPIO_IO_SEL_2+1); ++ value8 |= BIT(1); ++ rtw_write8(padapter, REG_GPIO_IO_SEL_2+1, value8); ++ ++ /* Enable power down and GPIO interrupt */ ++ value16 = rtw_read16(padapter, REG_APS_FSMCO); ++ value16 |= EnPDN; /* Enable HW power down and RF on */ ++ rtw_write16(padapter, REG_APS_FSMCO, value16); ++ ++ /* Enable CMD53 R/W Operation */ ++/* bMacPwrCtrlOn = true; */ ++/* rtw_hal_set_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); */ ++ ++ rtw_write8(padapter, REG_CR, 0x00); ++ /* Enable MAC DMA/WMAC/SCHEDULE/SEC block */ ++ value16 = rtw_read16(padapter, REG_CR); ++ value16 |= (HCI_TXDMA_EN | HCI_RXDMA_EN | TXDMA_EN | RXDMA_EN ++ | PROTOCOL_EN | SCHEDULE_EN | ENSEC | CALTMR_EN); ++ rtw_write16(padapter, REG_CR, value16); ++ ++ rtw_btcoex_PowerOnSetting(padapter); ++ ++ /* external switch to S1 */ ++ /* 0x38[11] = 0x1 */ ++ /* 0x4c[23] = 0x1 */ ++ /* 0x64[0] = 0 */ ++ value16 = rtw_read16(padapter, REG_PWR_DATA); ++ /* Switch the control of EESK, EECS to RFC for DPDT or Antenna switch */ ++ value16 |= BIT(11); /* BIT_EEPRPAD_RFE_CTRL_EN */ ++ rtw_write16(padapter, REG_PWR_DATA, value16); ++/* DBG_8192C("%s: REG_PWR_DATA(0x%x) = 0x%04X\n", __func__, REG_PWR_DATA, rtw_read16(padapter, REG_PWR_DATA)); */ ++ ++ value32 = rtw_read32(padapter, REG_LEDCFG0); ++ value32 |= BIT(23); /* DPDT_SEL_EN, 1 for SW control */ ++ rtw_write32(padapter, REG_LEDCFG0, value32); ++/* DBG_8192C("%s: REG_LEDCFG0(0x%x) = 0x%08X\n", __func__, REG_LEDCFG0, rtw_read32(padapter, REG_LEDCFG0)); */ ++ ++ value8 = rtw_read8(padapter, REG_PAD_CTRL1_8723B); ++ value8 &= ~BIT(0); /* BIT_SW_DPDT_SEL_DATA, DPDT_SEL default configuration */ ++ rtw_write8(padapter, REG_PAD_CTRL1_8723B, value8); ++/* DBG_8192C("%s: REG_PAD_CTRL1(0x%x) = 0x%02X\n", __func__, REG_PAD_CTRL1_8723B, rtw_read8(padapter, REG_PAD_CTRL1_8723B)); */ ++ ++#ifdef CONFIG_GPIO_WAKEUP ++ HostWakeUpGpioClear(padapter); ++#endif ++ ++ return _SUCCESS; ++} ++ ++/* Tx Page FIFO threshold */ ++static void _init_available_page_threshold(struct adapter *padapter, u8 numHQ, u8 numNQ, u8 numLQ, u8 numPubQ) ++{ ++ u16 HQ_threshold, NQ_threshold, LQ_threshold; ++ ++ HQ_threshold = (numPubQ + numHQ + 1) >> 1; ++ HQ_threshold |= (HQ_threshold<<8); ++ ++ NQ_threshold = (numPubQ + numNQ + 1) >> 1; ++ NQ_threshold |= (NQ_threshold<<8); ++ ++ LQ_threshold = (numPubQ + numLQ + 1) >> 1; ++ LQ_threshold |= (LQ_threshold<<8); ++ ++ rtw_write16(padapter, 0x218, HQ_threshold); ++ rtw_write16(padapter, 0x21A, NQ_threshold); ++ rtw_write16(padapter, 0x21C, LQ_threshold); ++ DBG_8192C("%s(): Enable Tx FIFO Page Threshold H:0x%x, N:0x%x, L:0x%x\n", __func__, HQ_threshold, NQ_threshold, LQ_threshold); ++} ++ ++static void _InitQueueReservedPage(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ u32 numHQ = 0; ++ u32 numLQ = 0; ++ u32 numNQ = 0; ++ u32 numPubQ; ++ u32 value32; ++ u8 value8; ++ bool bWiFiConfig = pregistrypriv->wifi_spec; ++ ++ if (pHalData->OutEpQueueSel & TX_SELE_HQ) ++ { ++ numHQ = bWiFiConfig ? WMM_NORMAL_PAGE_NUM_HPQ_8723B : NORMAL_PAGE_NUM_HPQ_8723B; ++ } ++ ++ if (pHalData->OutEpQueueSel & TX_SELE_LQ) ++ { ++ numLQ = bWiFiConfig ? WMM_NORMAL_PAGE_NUM_LPQ_8723B : NORMAL_PAGE_NUM_LPQ_8723B; ++ } ++ ++ /* NOTE: This step shall be proceed before writting REG_RQPN. */ ++ if (pHalData->OutEpQueueSel & TX_SELE_NQ) { ++ numNQ = bWiFiConfig ? WMM_NORMAL_PAGE_NUM_NPQ_8723B : NORMAL_PAGE_NUM_NPQ_8723B; ++ } ++ ++ numPubQ = TX_TOTAL_PAGE_NUMBER_8723B - numHQ - numLQ - numNQ; ++ ++ value8 = (u8)_NPQ(numNQ); ++ rtw_write8(padapter, REG_RQPN_NPQ, value8); ++ ++ /* TX DMA */ ++ value32 = _HPQ(numHQ) | _LPQ(numLQ) | _PUBQ(numPubQ) | LD_RQPN; ++ rtw_write32(padapter, REG_RQPN, value32); ++ ++ rtw_hal_set_sdio_tx_max_length(padapter, numHQ, numNQ, numLQ, numPubQ); ++ ++ _init_available_page_threshold(padapter, numHQ, numNQ, numLQ, numPubQ); ++} ++ ++static void _InitTxBufferBoundary(struct adapter *padapter) ++{ ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ ++ /* u16 txdmactrl; */ ++ u8 txpktbuf_bndy; ++ ++ if (!pregistrypriv->wifi_spec) { ++ txpktbuf_bndy = TX_PAGE_BOUNDARY_8723B; ++ } else { ++ /* for WMM */ ++ txpktbuf_bndy = WMM_NORMAL_TX_PAGE_BOUNDARY_8723B; ++ } ++ ++ rtw_write8(padapter, REG_TXPKTBUF_BCNQ_BDNY_8723B, txpktbuf_bndy); ++ rtw_write8(padapter, REG_TXPKTBUF_MGQ_BDNY_8723B, txpktbuf_bndy); ++ rtw_write8(padapter, REG_TXPKTBUF_WMAC_LBK_BF_HD_8723B, txpktbuf_bndy); ++ rtw_write8(padapter, REG_TRXFF_BNDY, txpktbuf_bndy); ++ rtw_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy); ++} ++ ++static void ++_InitNormalChipRegPriority( ++struct adapter *Adapter, ++u16 beQ, ++u16 bkQ, ++u16 viQ, ++u16 voQ, ++u16 mgtQ, ++u16 hiQ ++ ) ++{ ++ u16 value16 = (rtw_read16(Adapter, REG_TRXDMA_CTRL) & 0x7); ++ ++ value16 |= _TXDMA_BEQ_MAP(beQ) | _TXDMA_BKQ_MAP(bkQ) | ++ _TXDMA_VIQ_MAP(viQ) | _TXDMA_VOQ_MAP(voQ) | ++ _TXDMA_MGQ_MAP(mgtQ)| _TXDMA_HIQ_MAP(hiQ); ++ ++ rtw_write16(Adapter, REG_TRXDMA_CTRL, value16); ++} ++ ++static void ++_InitNormalChipOneOutEpPriority( ++struct adapter * Adapter ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++ u16 value = 0; ++ switch (pHalData->OutEpQueueSel) ++ { ++ case TX_SELE_HQ: ++ value = QUEUE_HIGH; ++ break; ++ case TX_SELE_LQ: ++ value = QUEUE_LOW; ++ break; ++ case TX_SELE_NQ: ++ value = QUEUE_NORMAL; ++ break; ++ default: ++ /* RT_ASSERT(false, ("Shall not reach here!\n")); */ ++ break; ++ } ++ ++ _InitNormalChipRegPriority(Adapter, ++ value, ++ value, ++ value, ++ value, ++ value, ++ value ++ ); ++ ++} ++ ++static void ++_InitNormalChipTwoOutEpPriority( ++struct adapter * Adapter ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ struct registry_priv *pregistrypriv = &Adapter->registrypriv; ++ u16 beQ, bkQ, viQ, voQ, mgtQ, hiQ; ++ ++ ++ u16 valueHi = 0; ++ u16 valueLow = 0; ++ ++ switch (pHalData->OutEpQueueSel) ++ { ++ case (TX_SELE_HQ | TX_SELE_LQ): ++ valueHi = QUEUE_HIGH; ++ valueLow = QUEUE_LOW; ++ break; ++ case (TX_SELE_NQ | TX_SELE_LQ): ++ valueHi = QUEUE_NORMAL; ++ valueLow = QUEUE_LOW; ++ break; ++ case (TX_SELE_HQ | TX_SELE_NQ): ++ valueHi = QUEUE_HIGH; ++ valueLow = QUEUE_NORMAL; ++ break; ++ default: ++ /* RT_ASSERT(false, ("Shall not reach here!\n")); */ ++ break; ++ } ++ ++ if (!pregistrypriv->wifi_spec) { ++ beQ = valueLow; ++ bkQ = valueLow; ++ viQ = valueHi; ++ voQ = valueHi; ++ mgtQ = valueHi; ++ hiQ = valueHi; ++ } ++ else {/* for WMM , CONFIG_OUT_EP_WIFI_MODE */ ++ beQ = valueLow; ++ bkQ = valueHi; ++ viQ = valueHi; ++ voQ = valueLow; ++ mgtQ = valueHi; ++ hiQ = valueHi; ++ } ++ ++ _InitNormalChipRegPriority(Adapter, beQ, bkQ, viQ, voQ, mgtQ, hiQ); ++ ++} ++ ++static void ++_InitNormalChipThreeOutEpPriority( ++struct adapter *padapter ++ ) ++{ ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ u16 beQ, bkQ, viQ, voQ, mgtQ, hiQ; ++ ++ if (!pregistrypriv->wifi_spec) {/* typical setting */ ++ beQ = QUEUE_LOW; ++ bkQ = QUEUE_LOW; ++ viQ = QUEUE_NORMAL; ++ voQ = QUEUE_HIGH; ++ mgtQ = QUEUE_HIGH; ++ hiQ = QUEUE_HIGH; ++ } ++ else {/* for WMM */ ++ beQ = QUEUE_LOW; ++ bkQ = QUEUE_NORMAL; ++ viQ = QUEUE_NORMAL; ++ voQ = QUEUE_HIGH; ++ mgtQ = QUEUE_HIGH; ++ hiQ = QUEUE_HIGH; ++ } ++ _InitNormalChipRegPriority(padapter, beQ, bkQ, viQ, voQ, mgtQ, hiQ); ++} ++ ++static void ++_InitNormalChipQueuePriority( ++struct adapter * Adapter ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++ switch (pHalData->OutEpNumber) ++ { ++ case 1: ++ _InitNormalChipOneOutEpPriority(Adapter); ++ break; ++ case 2: ++ _InitNormalChipTwoOutEpPriority(Adapter); ++ break; ++ case 3: ++ _InitNormalChipThreeOutEpPriority(Adapter); ++ break; ++ default: ++ /* RT_ASSERT(false, ("Shall not reach here!\n")); */ ++ break; ++ } ++ ++ ++} ++ ++static void _InitQueuePriority(struct adapter *padapter) ++{ ++ _InitNormalChipQueuePriority(padapter); ++} ++ ++static void _InitPageBoundary(struct adapter *padapter) ++{ ++ /* RX Page Boundary */ ++ u16 rxff_bndy = RX_DMA_BOUNDARY_8723B; ++ ++ rtw_write16(padapter, (REG_TRXFF_BNDY + 2), rxff_bndy); ++} ++ ++static void _InitTransferPageSize(struct adapter *padapter) ++{ ++ /* Tx page size is always 128. */ ++ ++ u8 value8; ++ value8 = _PSRX(PBP_128) | _PSTX(PBP_128); ++ rtw_write8(padapter, REG_PBP, value8); ++} ++ ++static void _InitDriverInfoSize(struct adapter *padapter, u8 drvInfoSize) ++{ ++ rtw_write8(padapter, REG_RX_DRVINFO_SZ, drvInfoSize); ++} ++ ++static void _InitNetworkType(struct adapter *padapter) ++{ ++ u32 value32; ++ ++ value32 = rtw_read32(padapter, REG_CR); ++ ++ /* TODO: use the other function to set network type */ ++/* value32 = (value32 & ~MASK_NETTYPE) | _NETTYPE(NT_LINK_AD_HOC); */ ++ value32 = (value32 & ~MASK_NETTYPE) | _NETTYPE(NT_LINK_AP); ++ ++ rtw_write32(padapter, REG_CR, value32); ++} ++ ++static void _InitWMACSetting(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData; ++ u16 value16; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ ++ pHalData->ReceiveConfig = 0; ++ pHalData->ReceiveConfig |= RCR_APM | RCR_AM | RCR_AB; ++ pHalData->ReceiveConfig |= RCR_CBSSID_DATA | RCR_CBSSID_BCN | RCR_AMF; ++ pHalData->ReceiveConfig |= RCR_HTC_LOC_CTRL; ++ pHalData->ReceiveConfig |= RCR_APP_PHYST_RXFF | RCR_APP_ICV | RCR_APP_MIC; ++ rtw_write32(padapter, REG_RCR, pHalData->ReceiveConfig); ++ ++ /* Accept all multicast address */ ++ rtw_write32(padapter, REG_MAR, 0xFFFFFFFF); ++ rtw_write32(padapter, REG_MAR + 4, 0xFFFFFFFF); ++ ++ /* Accept all data frames */ ++ value16 = 0xFFFF; ++ rtw_write16(padapter, REG_RXFLTMAP2, value16); ++ ++ /* 2010.09.08 hpfan */ ++ /* Since ADF is removed from RCR, ps-poll will not be indicate to driver, */ ++ /* RxFilterMap should mask ps-poll to gurantee AP mode can rx ps-poll. */ ++ value16 = 0x400; ++ rtw_write16(padapter, REG_RXFLTMAP1, value16); ++ ++ /* Accept all management frames */ ++ value16 = 0xFFFF; ++ rtw_write16(padapter, REG_RXFLTMAP0, value16); ++} ++ ++static void _InitAdaptiveCtrl(struct adapter *padapter) ++{ ++ u16 value16; ++ u32 value32; ++ ++ /* Response Rate Set */ ++ value32 = rtw_read32(padapter, REG_RRSR); ++ value32 &= ~RATE_BITMAP_ALL; ++ value32 |= RATE_RRSR_CCK_ONLY_1M; ++ rtw_write32(padapter, REG_RRSR, value32); ++ ++ /* CF-END Threshold */ ++ /* m_spIoBase->rtw_write8(REG_CFEND_TH, 0x1); */ ++ ++ /* SIFS (used in NAV) */ ++ value16 = _SPEC_SIFS_CCK(0x10) | _SPEC_SIFS_OFDM(0x10); ++ rtw_write16(padapter, REG_SPEC_SIFS, value16); ++ ++ /* Retry Limit */ ++ value16 = _LRL(0x30) | _SRL(0x30); ++ rtw_write16(padapter, REG_RL, value16); ++} ++ ++static void _InitEDCA(struct adapter *padapter) ++{ ++ /* Set Spec SIFS (used in NAV) */ ++ rtw_write16(padapter, REG_SPEC_SIFS, 0x100a); ++ rtw_write16(padapter, REG_MAC_SPEC_SIFS, 0x100a); ++ ++ /* Set SIFS for CCK */ ++ rtw_write16(padapter, REG_SIFS_CTX, 0x100a); ++ ++ /* Set SIFS for OFDM */ ++ rtw_write16(padapter, REG_SIFS_TRX, 0x100a); ++ ++ /* TXOP */ ++ rtw_write32(padapter, REG_EDCA_BE_PARAM, 0x005EA42B); ++ rtw_write32(padapter, REG_EDCA_BK_PARAM, 0x0000A44F); ++ rtw_write32(padapter, REG_EDCA_VI_PARAM, 0x005EA324); ++ rtw_write32(padapter, REG_EDCA_VO_PARAM, 0x002FA226); ++} ++ ++static void _InitRetryFunction(struct adapter *padapter) ++{ ++ u8 value8; ++ ++ value8 = rtw_read8(padapter, REG_FWHW_TXQ_CTRL); ++ value8 |= EN_AMPDU_RTY_NEW; ++ rtw_write8(padapter, REG_FWHW_TXQ_CTRL, value8); ++ ++ /* Set ACK timeout */ ++ rtw_write8(padapter, REG_ACKTO, 0x40); ++} ++ ++static void HalRxAggr8723BSdio(struct adapter *padapter) ++{ ++ struct registry_priv *pregistrypriv; ++ u8 valueDMATimeout; ++ u8 valueDMAPageCount; ++ ++ ++ pregistrypriv = &padapter->registrypriv; ++ ++ if (pregistrypriv->wifi_spec) ++ { ++ /* 2010.04.27 hpfan */ ++ /* Adjust RxAggrTimeout to close to zero disable RxAggr, suggested by designer */ ++ /* Timeout value is calculated by 34 / (2^n) */ ++ valueDMATimeout = 0x06; ++ valueDMAPageCount = 0x06; ++ } ++ else ++ { ++ /* 20130530, Isaac@SD1 suggest 3 kinds of parameter */ ++ /* TX/RX Balance */ ++ valueDMATimeout = 0x06; ++ valueDMAPageCount = 0x06; ++ } ++ ++ rtw_write8(padapter, REG_RXDMA_AGG_PG_TH+1, valueDMATimeout); ++ rtw_write8(padapter, REG_RXDMA_AGG_PG_TH, valueDMAPageCount); ++} ++ ++static void sdio_AggSettingRxUpdate(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData; ++ u8 valueDMA; ++ u8 valueRxAggCtrl = 0; ++ u8 aggBurstNum = 3; /* 0:1, 1:2, 2:3, 3:4 */ ++ u8 aggBurstSize = 0; /* 0:1K, 1:512Byte, 2:256Byte... */ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ ++ valueDMA = rtw_read8(padapter, REG_TRXDMA_CTRL); ++ valueDMA |= RXDMA_AGG_EN; ++ rtw_write8(padapter, REG_TRXDMA_CTRL, valueDMA); ++ ++ valueRxAggCtrl |= RXDMA_AGG_MODE_EN; ++ valueRxAggCtrl |= ((aggBurstNum<<2) & 0x0C); ++ valueRxAggCtrl |= ((aggBurstSize<<4) & 0x30); ++ rtw_write8(padapter, REG_RXDMA_MODE_CTRL_8723B, valueRxAggCtrl);/* RxAggLowThresh = 4*1K */ ++} ++ ++static void _initSdioAggregationSetting(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ ++ /* Tx aggregation setting */ ++/* sdio_AggSettingTxUpdate(padapter); */ ++ ++ /* Rx aggregation setting */ ++ HalRxAggr8723BSdio(padapter); ++ ++ sdio_AggSettingRxUpdate(padapter); ++ ++ /* 201/12/10 MH Add for USB agg mode dynamic switch. */ ++ pHalData->UsbRxHighSpeedMode = false; ++} ++ ++static void _InitOperationMode(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData; ++ struct mlme_ext_priv *pmlmeext; ++ u8 regBwOpMode = 0; ++ u32 regRATR = 0, regRRSR = 0; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ pmlmeext = &padapter->mlmeextpriv; ++ ++ /* 1 This part need to modified according to the rate set we filtered!! */ ++ /* */ ++ /* Set RRSR, RATR, and REG_BWOPMODE registers */ ++ /* */ ++ switch (pmlmeext->cur_wireless_mode) ++ { ++ case WIRELESS_MODE_B: ++ regBwOpMode = BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_CCK; ++ regRRSR = RATE_ALL_CCK; ++ break; ++ case WIRELESS_MODE_A: ++/* RT_ASSERT(false, ("Error wireless a mode\n")); */ ++ break; ++ case WIRELESS_MODE_G: ++ regBwOpMode = BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ break; ++ case WIRELESS_MODE_AUTO: ++ regBwOpMode = BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; ++ regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ break; ++ case WIRELESS_MODE_N_24G: ++ /* It support CCK rate by default. */ ++ /* CCK rate will be filtered out only when associated AP does not support it. */ ++ regBwOpMode = BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; ++ regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ break; ++ case WIRELESS_MODE_N_5G: ++/* RT_ASSERT(false, ("Error wireless mode")); */ ++ regBwOpMode = BW_OPMODE_5G; ++ regRATR = RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; ++ regRRSR = RATE_ALL_OFDM_AG; ++ break; ++ ++ default: /* for MacOSX compiler warning. */ ++ break; ++ } ++ ++ rtw_write8(padapter, REG_BWOPMODE, regBwOpMode); ++ ++} ++ ++static void _InitInterrupt(struct adapter *padapter) ++{ ++ /* HISR - turn all off */ ++ rtw_write32(padapter, REG_HISR, 0); ++ ++ /* HIMR - turn all off */ ++ rtw_write32(padapter, REG_HIMR, 0); ++ ++ /* */ ++ /* Initialize and enable SDIO Host Interrupt. */ ++ /* */ ++ InitInterrupt8723BSdio(padapter); ++ ++ /* */ ++ /* Initialize system Host Interrupt. */ ++ /* */ ++ InitSysInterrupt8723BSdio(padapter); ++} ++ ++static void _InitRFType(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ ++#if DISABLE_BB_RF ++ pHalData->rf_chip = RF_PSEUDO_11N; ++ return; ++#endif ++ ++ pHalData->rf_chip = RF_6052; ++ ++ pHalData->rf_type = RF_1T1R; ++ DBG_8192C("Set RF Chip ID to RF_6052 and RF type to 1T1R.\n"); ++} ++ ++static void _RfPowerSave(struct adapter *padapter) ++{ ++/* YJ, TODO */ ++} ++ ++/* */ ++/* 2010/08/09 MH Add for power down check. */ ++/* */ ++static bool HalDetectPwrDownMode(struct adapter * Adapter) ++{ ++ u8 tmpvalue; ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(Adapter); ++ ++ ++ EFUSE_ShadowRead(Adapter, 1, 0x7B/*EEPROM_RF_OPT3_92C*/, (u32 *)&tmpvalue); ++ ++ /* 2010/08/25 MH INF priority > PDN Efuse value. */ ++ if (tmpvalue & BIT4 && pwrctrlpriv->reg_pdnmode) ++ { ++ pHalData->pwrdown = true; ++ } ++ else ++ { ++ pHalData->pwrdown = false; ++ } ++ ++ DBG_8192C("HalDetectPwrDownMode(): PDN =%d\n", pHalData->pwrdown); ++ ++ return pHalData->pwrdown; ++} /* HalDetectPwrDownMode */ ++ ++static u32 rtl8723bs_hal_init(struct adapter *padapter) ++{ ++ s32 ret; ++ struct hal_com_data *pHalData; ++ struct pwrctrl_priv *pwrctrlpriv; ++ struct registry_priv *pregistrypriv; ++ u32 NavUpper = WiFiNavUpperUs; ++ u8 u1bTmp; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ pwrctrlpriv = adapter_to_pwrctl(padapter); ++ pregistrypriv = &padapter->registrypriv; ++ ++ if (adapter_to_pwrctl(padapter)->bips_processing == true ++ && adapter_to_pwrctl(padapter)->pre_ips_type == 0) ++ { ++ unsigned long start_time; ++ u8 cpwm_orig, cpwm_now; ++ u8 val8, bMacPwrCtrlOn = true; ++ ++ DBG_871X("%s: Leaving IPS in FWLPS state\n", __func__); ++ ++ /* for polling cpwm */ ++ cpwm_orig = 0; ++ rtw_hal_get_hwreg(padapter, HW_VAR_CPWM, &cpwm_orig); ++ ++ /* ser rpwm */ ++ val8 = rtw_read8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1); ++ val8 &= 0x80; ++ val8 += 0x80; ++ val8 |= BIT(6); ++ rtw_write8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1, val8); ++ DBG_871X("%s: write rpwm =%02x\n", __func__, val8); ++ adapter_to_pwrctl(padapter)->tog = (val8 + 0x80) & 0x80; ++ ++ /* do polling cpwm */ ++ start_time = jiffies; ++ do { ++ ++ mdelay(1); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_CPWM, &cpwm_now); ++ if ((cpwm_orig ^ cpwm_now) & 0x80) ++ { ++ break; ++ } ++ ++ if (jiffies_to_msecs(jiffies - start_time) > 100) ++ { ++ DBG_871X("%s: polling cpwm timeout when leaving IPS in FWLPS state\n", __func__); ++ break; ++ } ++ } while (1); ++ ++ rtl8723b_set_FwPwrModeInIPS_cmd(padapter, 0); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ ++ rtw_btcoex_HAL_Initialize(padapter, false); ++ ++ return _SUCCESS; ++ } ++ ++#ifdef CONFIG_WOWLAN ++ if (rtw_read8(padapter, REG_MCUFWDL)&BIT7) { ++ u8 reg_val = 0; ++ DBG_871X("+Reset Entry+\n"); ++ rtw_write8(padapter, REG_MCUFWDL, 0x00); ++ _8051Reset8723(padapter); ++ /* reset BB */ ++ reg_val = rtw_read8(padapter, REG_SYS_FUNC_EN); ++ reg_val &= ~(BIT(0) | BIT(1)); ++ rtw_write8(padapter, REG_SYS_FUNC_EN, reg_val); ++ /* reset RF */ ++ rtw_write8(padapter, REG_RF_CTRL, 0); ++ /* reset TRX path */ ++ rtw_write16(padapter, REG_CR, 0); ++ /* reset MAC, Digital Core */ ++ reg_val = rtw_read8(padapter, REG_SYS_FUNC_EN+1); ++ reg_val &= ~(BIT(4) | BIT(7)); ++ rtw_write8(padapter, REG_SYS_FUNC_EN+1, reg_val); ++ reg_val = rtw_read8(padapter, REG_SYS_FUNC_EN+1); ++ reg_val |= BIT(4) | BIT(7); ++ rtw_write8(padapter, REG_SYS_FUNC_EN+1, reg_val); ++ DBG_871X("-Reset Entry-\n"); ++ } ++#endif /* CONFIG_WOWLAN */ ++ /* Disable Interrupt first. */ ++/* rtw_hal_disable_interrupt(padapter); */ ++ ++ ret = _InitPowerOn_8723BS(padapter); ++ if (_FAIL == ret) { ++ RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("Failed to init Power On!\n")); ++ return _FAIL; ++ } ++ ++ rtw_write8(padapter, REG_EARLY_MODE_CONTROL, 0); ++ ++ ret = rtl8723b_FirmwareDownload(padapter, false); ++ if (ret != _SUCCESS) { ++ RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("%s: Download Firmware failed!!\n", __func__)); ++ padapter->bFWReady = false; ++ pHalData->fw_ractrl = false; ++ return ret; ++ } else { ++ RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("rtl8723bs_hal_init(): Download Firmware Success!!\n")); ++ padapter->bFWReady = true; ++ pHalData->fw_ractrl = true; ++ } ++ ++ rtl8723b_InitializeFirmwareVars(padapter); ++ ++/* SIC_Init(padapter); */ ++ ++ if (pwrctrlpriv->reg_rfoff == true) { ++ pwrctrlpriv->rf_pwrstate = rf_off; ++ } ++ ++ /* 2010/08/09 MH We need to check if we need to turnon or off RF after detecting */ ++ /* HW GPIO pin. Before PHY_RFConfig8192C. */ ++ HalDetectPwrDownMode(padapter); ++ ++ /* Set RF type for BB/RF configuration */ ++ _InitRFType(padapter); ++ ++ /* Save target channel */ ++ /* Current Channel will be updated again later. */ ++ pHalData->CurrentChannel = 6; ++ ++#if (HAL_MAC_ENABLE == 1) ++ ret = PHY_MACConfig8723B(padapter); ++ if (ret != _SUCCESS) { ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Initializepadapter8192CSdio(): Fail to configure MAC!!\n")); ++ return ret; ++ } ++#endif ++ /* */ ++ /* d. Initialize BB related configurations. */ ++ /* */ ++#if (HAL_BB_ENABLE == 1) ++ ret = PHY_BBConfig8723B(padapter); ++ if (ret != _SUCCESS) { ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Initializepadapter8192CSdio(): Fail to configure BB!!\n")); ++ return ret; ++ } ++#endif ++ ++ /* If RF is on, we need to init RF. Otherwise, skip the procedure. */ ++ /* We need to follow SU method to change the RF cfg.txt. Default disable RF TX/RX mode. */ ++ /* if (pHalData->eRFPowerState == eRfOn) */ ++ { ++#if (HAL_RF_ENABLE == 1) ++ ret = PHY_RFConfig8723B(padapter); ++ if (ret != _SUCCESS) { ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Initializepadapter8192CSdio(): Fail to configure RF!!\n")); ++ return ret; ++ } ++#endif ++ } ++ ++ /* */ ++ /* Joseph Note: Keep RfRegChnlVal for later use. */ ++ /* */ ++ pHalData->RfRegChnlVal[0] = PHY_QueryRFReg(padapter, (enum RF_PATH)0, RF_CHNLBW, bRFRegOffsetMask); ++ pHalData->RfRegChnlVal[1] = PHY_QueryRFReg(padapter, (enum RF_PATH)1, RF_CHNLBW, bRFRegOffsetMask); ++ ++ ++ /* if (!pHalData->bMACFuncEnable) { */ ++ _InitQueueReservedPage(padapter); ++ _InitTxBufferBoundary(padapter); ++ ++ /* init LLT after tx buffer boundary is defined */ ++ ret = rtl8723b_InitLLTTable(padapter); ++ if (_SUCCESS != ret) { ++ DBG_8192C("%s: Failed to init LLT Table!\n", __func__); ++ return _FAIL; ++ } ++ /* */ ++ _InitQueuePriority(padapter); ++ _InitPageBoundary(padapter); ++ _InitTransferPageSize(padapter); ++ ++ /* Get Rx PHY status in order to report RSSI and others. */ ++ _InitDriverInfoSize(padapter, DRVINFO_SZ); ++ hal_init_macaddr(padapter); ++ _InitNetworkType(padapter); ++ _InitWMACSetting(padapter); ++ _InitAdaptiveCtrl(padapter); ++ _InitEDCA(padapter); ++ _InitRetryFunction(padapter); ++ _initSdioAggregationSetting(padapter); ++ _InitOperationMode(padapter); ++ rtl8723b_InitBeaconParameters(padapter); ++ _InitInterrupt(padapter); ++ _InitBurstPktLen_8723BS(padapter); ++ ++ /* YJ, TODO */ ++ rtw_write8(padapter, REG_SECONDARY_CCA_CTRL_8723B, 0x3); /* CCA */ ++ rtw_write8(padapter, 0x976, 0); /* hpfan_todo: 2nd CCA related */ ++ ++ rtw_write16(padapter, REG_PKT_VO_VI_LIFE_TIME, 0x0400); /* unit: 256us. 256ms */ ++ rtw_write16(padapter, REG_PKT_BE_BK_LIFE_TIME, 0x0400); /* unit: 256us. 256ms */ ++ ++ invalidate_cam_all(padapter); ++ ++ rtw_hal_set_chnl_bw(padapter, padapter->registrypriv.channel, ++ CHANNEL_WIDTH_20, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HAL_PRIME_CHNL_OFFSET_DONT_CARE); ++ ++ /* Record original value for template. This is arough data, we can only use the data */ ++ /* for power adjust. The value can not be adjustde according to different power!!! */ ++/* pHalData->OriginalCckTxPwrIdx = pHalData->CurrentCckTxPwrIdx; */ ++/* pHalData->OriginalOfdm24GTxPwrIdx = pHalData->CurrentOfdm24GTxPwrIdx; */ ++ ++ rtl8723b_InitAntenna_Selection(padapter); ++ ++ /* */ ++ /* Disable BAR, suggested by Scott */ ++ /* 2010.04.09 add by hpfan */ ++ /* */ ++ rtw_write32(padapter, REG_BAR_MODE_CTRL, 0x0201ffff); ++ ++ /* HW SEQ CTRL */ ++ /* set 0x0 to 0xFF by tynli. Default enable HW SEQ NUM. */ ++ rtw_write8(padapter, REG_HWSEQ_CTRL, 0xFF); ++ ++ ++ /* */ ++ /* Configure SDIO TxRx Control to enable Rx DMA timer masking. */ ++ /* 2010.02.24. */ ++ /* */ ++ rtw_write32(padapter, SDIO_LOCAL_BASE|SDIO_REG_TX_CTRL, 0); ++ ++ _RfPowerSave(padapter); ++ ++ ++ rtl8723b_InitHalDm(padapter); ++ ++ /* DbgPrint("pHalData->DefaultTxPwrDbm = %d\n", pHalData->DefaultTxPwrDbm); */ ++ ++ /* */ ++ /* Update current Tx FIFO page status. */ ++ /* */ ++ HalQueryTxBufferStatus8723BSdio(padapter); ++ HalQueryTxOQTBufferStatus8723BSdio(padapter); ++ pHalData->SdioTxOQTMaxFreeSpace = pHalData->SdioTxOQTFreeSpace; ++ ++ /* Enable MACTXEN/MACRXEN block */ ++ u1bTmp = rtw_read8(padapter, REG_CR); ++ u1bTmp |= (MACTXEN | MACRXEN); ++ rtw_write8(padapter, REG_CR, u1bTmp); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_NAV_UPPER, (u8 *)&NavUpper); ++ ++ /* ack for xmit mgmt frames. */ ++ rtw_write32(padapter, REG_FWHW_TXQ_CTRL, rtw_read32(padapter, REG_FWHW_TXQ_CTRL)|BIT(12)); ++ ++/* pHalData->PreRpwmVal = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_HRPWM1) & 0x80; */ ++ ++ { ++ pwrctrlpriv->rf_pwrstate = rf_on; ++ ++ if (pwrctrlpriv->rf_pwrstate == rf_on) ++ { ++ struct pwrctrl_priv *pwrpriv; ++ unsigned long start_time; ++ u8 restore_iqk_rst; ++ u8 b2Ant; ++ u8 h2cCmdBuf; ++ ++ pwrpriv = adapter_to_pwrctl(padapter); ++ ++ PHY_LCCalibrate_8723B(&pHalData->odmpriv); ++ ++ /* Inform WiFi FW that it is the beginning of IQK */ ++ h2cCmdBuf = 1; ++ FillH2CCmd8723B(padapter, H2C_8723B_BT_WLAN_CALIBRATION, 1, &h2cCmdBuf); ++ ++ start_time = jiffies; ++ do { ++ if (rtw_read8(padapter, 0x1e7) & 0x01) ++ break; ++ ++ msleep(50); ++ } while (jiffies_to_msecs(jiffies - start_time) <= 400); ++ ++ rtw_btcoex_IQKNotify(padapter, true); ++ ++ restore_iqk_rst = (pwrpriv->bips_processing ==true)?true:false; ++ b2Ant = pHalData->EEPROMBluetoothAntNum ==Ant_x2?true:false; ++ PHY_IQCalibrate_8723B(padapter, false, restore_iqk_rst, b2Ant, pHalData->ant_path); ++ pHalData->odmpriv.RFCalibrateInfo.bIQKInitialized = true; ++ ++ rtw_btcoex_IQKNotify(padapter, false); ++ ++ /* Inform WiFi FW that it is the finish of IQK */ ++ h2cCmdBuf = 0; ++ FillH2CCmd8723B(padapter, H2C_8723B_BT_WLAN_CALIBRATION, 1, &h2cCmdBuf); ++ ++ ODM_TXPowerTrackingCheck(&pHalData->odmpriv); ++ } ++ } ++ ++ /* Init BT hw config. */ ++ rtw_btcoex_HAL_Initialize(padapter, false); ++ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("-%s\n", __func__)); ++ ++ return _SUCCESS; ++} ++ ++/* */ ++/* Description: */ ++/* RTL8723e card disable power sequence v003 which suggested by Scott. */ ++/* */ ++/* First created by tynli. 2011.01.28. */ ++/* */ ++static void CardDisableRTL8723BSdio(struct adapter *padapter) ++{ ++ u8 u1bTmp; ++ u8 bMacPwrCtrlOn; ++ u8 ret = _FAIL; ++ ++ /* Run LPS WL RFOFF flow */ ++ ret = HalPwrSeqCmdParsing(padapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, rtl8723B_enter_lps_flow); ++ if (ret == _FAIL) { ++ DBG_8192C(KERN_ERR "%s: run RF OFF flow fail!\n", __func__); ++ } ++ ++ /* ==== Reset digital sequence ====== */ ++ ++ u1bTmp = rtw_read8(padapter, REG_MCUFWDL); ++ if ((u1bTmp & RAM_DL_SEL) && padapter->bFWReady) /* 8051 RAM code */ ++ rtl8723b_FirmwareSelfReset(padapter); ++ ++ /* Reset MCU 0x2[10]= 0. Suggested by Filen. 2011.01.26. by tynli. */ ++ u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN+1); ++ u1bTmp &= ~BIT(2); /* 0x2[10], FEN_CPUEN */ ++ rtw_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp); ++ ++ /* MCUFWDL 0x80[1:0]= 0 */ ++ /* reset MCU ready status */ ++ rtw_write8(padapter, REG_MCUFWDL, 0); ++ ++ /* Reset MCU IO Wrapper, added by Roger, 2011.08.30 */ ++ u1bTmp = rtw_read8(padapter, REG_RSV_CTRL+1); ++ u1bTmp &= ~BIT(0); ++ rtw_write8(padapter, REG_RSV_CTRL+1, u1bTmp); ++ u1bTmp = rtw_read8(padapter, REG_RSV_CTRL+1); ++ u1bTmp |= BIT(0); ++ rtw_write8(padapter, REG_RSV_CTRL+1, u1bTmp); ++ ++ /* ==== Reset digital sequence end ====== */ ++ ++ bMacPwrCtrlOn = false; /* Disable CMD53 R/W */ ++ ret = false; ++ rtw_hal_set_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ ret = HalPwrSeqCmdParsing(padapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, rtl8723B_card_disable_flow); ++ if (ret == false) { ++ DBG_8192C(KERN_ERR "%s: run CARD DISABLE flow fail!\n", __func__); ++ } ++} ++ ++static u32 rtl8723bs_hal_deinit(struct adapter *padapter) ++{ ++ struct dvobj_priv *psdpriv = padapter->dvobj; ++ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; ++ ++ if (padapter->hw_init_completed == true) ++ { ++ if (adapter_to_pwrctl(padapter)->bips_processing == true) ++ { ++ if (padapter->netif_up == true) ++ { ++ int cnt = 0; ++ u8 val8 = 0; ++ ++ DBG_871X("%s: issue H2C to FW when entering IPS\n", __func__); ++ ++ rtl8723b_set_FwPwrModeInIPS_cmd(padapter, 0x3); ++ /* poll 0x1cc to make sure H2C command already finished by FW; MAC_0x1cc = 0 means H2C done by FW. */ ++ do{ ++ val8 = rtw_read8(padapter, REG_HMETFR); ++ cnt++; ++ DBG_871X("%s polling REG_HMETFR = 0x%x, cnt =%d\n", __func__, val8, cnt); ++ mdelay(10); ++ }while (cnt<100 && (val8!= 0)); ++ /* H2C done, enter 32k */ ++ if (val8 == 0) ++ { ++ /* ser rpwm to enter 32k */ ++ val8 = rtw_read8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1); ++ val8 += 0x80; ++ val8 |= BIT(0); ++ rtw_write8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1, val8); ++ DBG_871X("%s: write rpwm =%02x\n", __func__, val8); ++ adapter_to_pwrctl(padapter)->tog = (val8 + 0x80) & 0x80; ++ cnt = val8 = 0; ++ do{ ++ val8 = rtw_read8(padapter, REG_CR); ++ cnt++; ++ DBG_871X("%s polling 0x100 = 0x%x, cnt =%d\n", __func__, val8, cnt); ++ mdelay(10); ++ }while (cnt<100 && (val8!= 0xEA)); ++ } ++ else ++ { ++ DBG_871X("MAC_1C0 =%08x, MAC_1C4 =%08x, MAC_1C8 =%08x, MAC_1CC =%08x\n", rtw_read32(padapter, 0x1c0), rtw_read32(padapter, 0x1c4) ++ , rtw_read32(padapter, 0x1c8), rtw_read32(padapter, 0x1cc)); ++ } ++ ++ DBG_871X("polling done when entering IPS, check result : 0x100 = 0x%x, cnt =%d, MAC_1cc = 0x%02x\n" ++ , rtw_read8(padapter, REG_CR), cnt, rtw_read8(padapter, REG_HMETFR)); ++ ++ adapter_to_pwrctl(padapter)->pre_ips_type = 0; ++ ++ } ++ else ++ { ++ pdbgpriv->dbg_carddisable_cnt++; ++ CardDisableRTL8723BSdio(padapter); ++ ++ adapter_to_pwrctl(padapter)->pre_ips_type = 1; ++ } ++ ++ } ++ else ++ { ++ pdbgpriv->dbg_carddisable_cnt++; ++ CardDisableRTL8723BSdio(padapter); ++ } ++ } ++ else ++ { ++ pdbgpriv->dbg_deinit_fail_cnt++; ++ } ++ ++ return _SUCCESS; ++} ++ ++static u32 rtl8723bs_inirp_init(struct adapter *padapter) ++{ ++ return _SUCCESS; ++} ++ ++static u32 rtl8723bs_inirp_deinit(struct adapter *padapter) ++{ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("+rtl8723bs_inirp_deinit\n")); ++ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("-rtl8723bs_inirp_deinit\n")); ++ ++ return _SUCCESS; ++} ++ ++static void rtl8723bs_init_default_value(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ ++ rtl8723b_init_default_value(padapter); ++ ++ /* interface related variable */ ++ pHalData->SdioRxFIFOCnt = 0; ++} ++ ++static void rtl8723bs_interface_configure(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ bool bWiFiConfig = pregistrypriv->wifi_spec; ++ ++ ++ pdvobjpriv->RtOutPipe[0] = WLAN_TX_HIQ_DEVICE_ID; ++ pdvobjpriv->RtOutPipe[1] = WLAN_TX_MIQ_DEVICE_ID; ++ pdvobjpriv->RtOutPipe[2] = WLAN_TX_LOQ_DEVICE_ID; ++ ++ if (bWiFiConfig) ++ pHalData->OutEpNumber = 2; ++ else ++ pHalData->OutEpNumber = SDIO_MAX_TX_QUEUE; ++ ++ switch (pHalData->OutEpNumber) { ++ case 3: ++ pHalData->OutEpQueueSel =TX_SELE_HQ| TX_SELE_LQ|TX_SELE_NQ; ++ break; ++ case 2: ++ pHalData->OutEpQueueSel =TX_SELE_HQ| TX_SELE_NQ; ++ break; ++ case 1: ++ pHalData->OutEpQueueSel =TX_SELE_HQ; ++ break; ++ default: ++ break; ++ } ++ ++ Hal_MappingOutPipe(padapter, pHalData->OutEpNumber); ++} ++ ++/* */ ++/* Description: */ ++/* We should set Efuse cell selection to WiFi cell in default. */ ++/* */ ++/* Assumption: */ ++/* PASSIVE_LEVEL */ ++/* */ ++/* Added by Roger, 2010.11.23. */ ++/* */ ++static void ++_EfuseCellSel( ++struct adapter *padapter ++ ) ++{ ++ u32 value32; ++ ++ value32 = rtw_read32(padapter, EFUSE_TEST); ++ value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); ++ rtw_write32(padapter, EFUSE_TEST, value32); ++} ++ ++static void ++_ReadRFType( ++struct adapter *Adapter ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); ++ ++#if DISABLE_BB_RF ++ pHalData->rf_chip = RF_PSEUDO_11N; ++#else ++ pHalData->rf_chip = RF_6052; ++#endif ++} ++ ++ ++static void ++Hal_EfuseParseMACAddr_8723BS( ++struct adapter * padapter, ++u8* hwinfo, ++bool AutoLoadFail ++ ) ++{ ++ u16 i; ++ u8 sMacAddr[6] = {0x00, 0xE0, 0x4C, 0xb7, 0x23, 0x00}; ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ ++ if (AutoLoadFail) ++ { ++/* sMacAddr[5] = (u8)GetRandomNumber(1, 254); */ ++ for (i = 0; i<6; i++) ++ pEEPROM->mac_addr[i] = sMacAddr[i]; ++ } ++ else ++ { ++ /* Read Permanent MAC address */ ++ memcpy(pEEPROM->mac_addr, &hwinfo[EEPROM_MAC_ADDR_8723BS], ETH_ALEN); ++ } ++/* NicIFSetMacAddress(padapter, padapter->PermanentAddress); */ ++ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ++ ("Hal_EfuseParseMACAddr_8723BS: Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n", ++ pEEPROM->mac_addr[0], pEEPROM->mac_addr[1], ++ pEEPROM->mac_addr[2], pEEPROM->mac_addr[3], ++ pEEPROM->mac_addr[4], pEEPROM->mac_addr[5])); ++} ++ ++static void ++Hal_EfuseParseBoardType_8723BS( ++struct adapter * padapter, ++u8* hwinfo, ++bool AutoLoadFail ++ ) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ ++ if (!AutoLoadFail) ++ { ++ pHalData->BoardType = (hwinfo[EEPROM_RF_BOARD_OPTION_8723B] & 0xE0) >> 5; ++ if (pHalData->BoardType == 0xFF) ++ pHalData->BoardType = (EEPROM_DEFAULT_BOARD_OPTION&0xE0)>>5; ++ } ++ else ++ pHalData->BoardType = 0; ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Board Type: 0x%2x\n", pHalData->BoardType)); ++} ++ ++static void ++_ReadEfuseInfo8723BS( ++ struct adapter * padapter ++ ) ++{ ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ u8* hwinfo = NULL; ++ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("====>_ReadEfuseInfo8723BS()\n")); ++ ++ /* */ ++ /* This part read and parse the eeprom/efuse content */ ++ /* */ ++ ++ if (sizeof(pEEPROM->efuse_eeprom_data) < HWSET_MAX_SIZE_8723B) ++ DBG_871X("[WARNING] size of efuse_eeprom_data is less than HWSET_MAX_SIZE_8723B!\n"); ++ ++ hwinfo = pEEPROM->efuse_eeprom_data; ++ ++ Hal_InitPGData(padapter, hwinfo); ++ ++ Hal_EfuseParseIDCode(padapter, hwinfo); ++ Hal_EfuseParseEEPROMVer_8723B(padapter, hwinfo, pEEPROM->bautoload_fail_flag); ++ ++ Hal_EfuseParseMACAddr_8723BS(padapter, hwinfo, pEEPROM->bautoload_fail_flag); ++ ++ Hal_EfuseParseTxPowerInfo_8723B(padapter, hwinfo, pEEPROM->bautoload_fail_flag); ++ Hal_EfuseParseBoardType_8723BS(padapter, hwinfo, pEEPROM->bautoload_fail_flag); ++ ++ /* */ ++ /* Read Bluetooth co-exist and initialize */ ++ /* */ ++ Hal_EfuseParseBTCoexistInfo_8723B(padapter, hwinfo, pEEPROM->bautoload_fail_flag); ++ Hal_EfuseParseChnlPlan_8723B(padapter, hwinfo, pEEPROM->bautoload_fail_flag); ++ Hal_EfuseParseXtal_8723B(padapter, hwinfo, pEEPROM->bautoload_fail_flag); ++ Hal_EfuseParsePackageType_8723B(padapter, hwinfo, pEEPROM->bautoload_fail_flag); ++ Hal_EfuseParseThermalMeter_8723B(padapter, hwinfo, pEEPROM->bautoload_fail_flag); ++ Hal_EfuseParseAntennaDiversity_8723B(padapter, hwinfo, pEEPROM->bautoload_fail_flag); ++ Hal_EfuseParseCustomerID_8723B(padapter, hwinfo, pEEPROM->bautoload_fail_flag); ++ ++ Hal_EfuseParseVoltage_8723B(padapter, hwinfo, pEEPROM->bautoload_fail_flag); ++ ++#ifdef CONFIG_WOWLAN ++ Hal_DetectWoWMode(padapter); ++#endif ++ ++ Hal_ReadRFGainOffset(padapter, hwinfo, pEEPROM->bautoload_fail_flag); ++ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("<==== _ReadEfuseInfo8723BS()\n")); ++} ++ ++static void _ReadPROMContent( ++ struct adapter * padapter ++ ) ++{ ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ u8 eeValue; ++ ++ eeValue = rtw_read8(padapter, REG_9346CR); ++ /* To check system boot selection. */ ++ pEEPROM->EepromOrEfuse = (eeValue & BOOT_FROM_EEPROM) ? true : false; ++ pEEPROM->bautoload_fail_flag = (eeValue & EEPROM_EN) ? false : true; ++ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ++ ("%s: 9346CR = 0x%02X, Boot from %s, Autoload %s\n", ++ __func__, eeValue, ++ (pEEPROM->EepromOrEfuse ? "EEPROM" : "EFUSE"), ++ (pEEPROM->bautoload_fail_flag ? "Fail" : "OK"))); ++ ++/* pHalData->EEType = IS_BOOT_FROM_EEPROM(Adapter) ? EEPROM_93C46 : EEPROM_BOOT_EFUSE; */ ++ ++ _ReadEfuseInfo8723BS(padapter); ++} ++ ++static void ++_InitOtherVariable( ++ struct adapter * Adapter ++ ) ++{ ++} ++ ++/* */ ++/* Description: */ ++/* Read HW adapter information by E-Fuse or EEPROM according CR9346 reported. */ ++/* */ ++/* Assumption: */ ++/* PASSIVE_LEVEL (SDIO interface) */ ++/* */ ++/* */ ++static s32 _ReadAdapterInfo8723BS(struct adapter *padapter) ++{ ++ u8 val8; ++ unsigned long start; ++ ++ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("+_ReadAdapterInfo8723BS\n")); ++ ++ /* before access eFuse, make sure card enable has been called */ ++ if (padapter->hw_init_completed == false) ++ _InitPowerOn_8723BS(padapter); ++ ++ ++ val8 = rtw_read8(padapter, 0x4e); ++ MSG_8192C("%s, 0x4e = 0x%x\n", __func__, val8); ++ val8 |= BIT(6); ++ rtw_write8(padapter, 0x4e, val8); ++ ++ ++ start = jiffies; ++ ++ _EfuseCellSel(padapter); ++ _ReadRFType(padapter); ++ _ReadPROMContent(padapter); ++ _InitOtherVariable(padapter); ++ ++ if (padapter->hw_init_completed == false) ++ { ++ rtw_write8(padapter, 0x67, 0x00); /* for BT, Switch Ant control to BT */ ++ CardDisableRTL8723BSdio(padapter);/* for the power consumption issue, wifi ko module is loaded during booting, but wifi GUI is off */ ++ } ++ ++ ++ MSG_8192C("<==== _ReadAdapterInfo8723BS in %d ms\n", jiffies_to_msecs(jiffies - start)); ++ ++ return _SUCCESS; ++} ++ ++static void ReadAdapterInfo8723BS(struct adapter *padapter) ++{ ++ /* Read EEPROM size before call any EEPROM function */ ++ padapter->EepromAddressSize = GetEEPROMSize8723B(padapter); ++ ++ _ReadAdapterInfo8723BS(padapter); ++} ++ ++/* ++ * If variable not handled here, ++ * some variables will be processed in SetHwReg8723B() ++ */ ++static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val) ++{ ++ struct hal_com_data *pHalData; ++ u8 val8; ++ ++#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) ++ struct wowlan_ioctl_param *poidparam; ++ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); ++ int res; ++ u32 tmp; ++ u16 len = 0; ++ u8 trycnt = 100; ++ u32 himr = 0; ++#if defined(CONFIG_WOWLAN) ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct sta_info *psta = NULL; ++ u64 iv_low = 0, iv_high = 0; ++ u8 mstatus = (*(u8 *)val); ++#endif ++#endif ++ ++ pHalData = GET_HAL_DATA(padapter); ++ ++ switch (variable) ++ { ++ case HW_VAR_SET_RPWM: ++ /* rpwm value only use BIT0(clock bit) , BIT6(Ack bit), and BIT7(Toggle bit) */ ++ /* BIT0 value - 1: 32k, 0:40MHz. */ ++ /* BIT6 value - 1: report cpwm value after success set, 0:do not report. */ ++ /* BIT7 value - Toggle bit change. */ ++ { ++ val8 = *val; ++ val8 &= 0xC1; ++ rtw_write8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1, val8); ++ } ++ break; ++ case HW_VAR_SET_REQ_FW_PS: ++ { ++ u8 req_fw_ps = 0; ++ req_fw_ps = rtw_read8(padapter, 0x8f); ++ req_fw_ps |= 0x10; ++ rtw_write8(padapter, 0x8f, req_fw_ps); ++ } ++ break; ++ case HW_VAR_RXDMA_AGG_PG_TH: ++ val8 = *val; ++ break; ++ ++#ifdef CONFIG_WOWLAN ++ case HW_VAR_WOWLAN: ++ { ++ poidparam = (struct wowlan_ioctl_param *)val; ++ switch (poidparam->subcode) { ++ case WOWLAN_ENABLE: ++ DBG_871X_LEVEL(_drv_always_, "WOWLAN_ENABLE\n"); ++ ++ /* backup data rate to register 0x8b for wowlan FW */ ++ rtw_write8(padapter, 0x8d, 1); ++ rtw_write8(padapter, 0x8c, 0); ++ rtw_write8(padapter, 0x8f, 0x40); ++ rtw_write8(padapter, 0x8b, ++ rtw_read8(padapter, 0x2f0)); ++ ++ /* 1. Download WOWLAN FW */ ++ DBG_871X_LEVEL(_drv_always_, "Re-download WoWlan FW!\n"); ++ SetFwRelatedForWoWLAN8723b(padapter, true); ++ ++ /* 2. RX DMA stop */ ++ DBG_871X_LEVEL(_drv_always_, "Pause DMA\n"); ++ rtw_write32(padapter, REG_RXPKT_NUM, (rtw_read32(padapter, REG_RXPKT_NUM)|RW_RELEASE_EN)); ++ do{ ++ if ((rtw_read32(padapter, REG_RXPKT_NUM)&RXDMA_IDLE)) { ++ DBG_871X_LEVEL(_drv_always_, "RX_DMA_IDLE is true\n"); ++ break; ++ } else { ++ /* If RX_DMA is not idle, receive one pkt from DMA */ ++ res = sdio_local_read(padapter, SDIO_REG_RX0_REQ_LEN, 4, (u8 *)&tmp); ++ len = le16_to_cpu(tmp); ++ DBG_871X_LEVEL(_drv_always_, "RX len:%d\n", len); ++ if (len > 0) ++ res = RecvOnePkt(padapter, len); ++ else ++ DBG_871X_LEVEL(_drv_always_, "read length fail %d\n", len); ++ ++ DBG_871X_LEVEL(_drv_always_, "RecvOnePkt Result: %d\n", res); ++ } ++ }while (trycnt--); ++ if (trycnt == 0) ++ DBG_871X_LEVEL(_drv_always_, "Stop RX DMA failed......\n"); ++ ++ /* 3. Clear IMR and ISR */ ++ DBG_871X_LEVEL(_drv_always_, "Clear IMR and ISR\n"); ++ tmp = 0; ++ sdio_local_write(padapter, SDIO_REG_HIMR_ON, 4, (u8 *)&tmp); ++ sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp); ++ sdio_local_read(padapter, SDIO_REG_HISR, 4, (u8 *)&tmp); ++ sdio_local_write(padapter, SDIO_REG_HISR, 4, (u8 *)&tmp); ++ ++ /* 4. Enable CPWM2 only */ ++ DBG_871X_LEVEL(_drv_always_, "Enable only CPWM2\n"); ++ sdio_local_read(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp); ++ DBG_871X("DisableInterruptButCpwm28723BSdio(): Read SDIO_REG_HIMR: 0x%08x\n", tmp); ++ ++ himr = cpu_to_le32(SDIO_HIMR_DISABLED)|SDIO_HIMR_CPWM2_MSK; ++ sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&himr); ++ ++ sdio_local_read(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp); ++ DBG_871X("DisableInterruptButCpwm28723BSdio(): Read again SDIO_REG_HIMR: 0x%08x\n", tmp); ++ ++ /* 5. Set Enable WOWLAN H2C command. */ ++ DBG_871X_LEVEL(_drv_always_, "Set Enable WOWLan cmd\n"); ++ rtl8723b_set_wowlan_cmd(padapter, 1); ++ ++ /* 6. Check EnableWoWlan CMD is ready */ ++ if (!pwrctl->wowlan_pno_enable) { ++ DBG_871X_LEVEL(_drv_always_, "Check EnableWoWlan CMD is ready\n"); ++ mstatus = rtw_read8(padapter, REG_WOW_CTRL); ++ trycnt = 10; ++ while (!(mstatus&BIT1) && trycnt>1) { ++ mstatus = rtw_read8(padapter, REG_WOW_CTRL); ++ DBG_871X("Loop index: %d :0x%02x\n", trycnt, mstatus); ++ trycnt --; ++ msleep(2); ++ } ++ } ++ break; ++ ++ case WOWLAN_DISABLE: ++ DBG_871X_LEVEL(_drv_always_, "WOWLAN_DISABLE\n"); ++ ++ psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(pmlmepriv)); ++ if (psta != NULL) ++ rtl8723b_set_FwMediaStatusRpt_cmd(padapter, RT_MEDIA_DISCONNECT, psta->mac_id); ++ else ++ DBG_871X("psta is null\n"); ++ ++ /* 1. Read wakeup reason */ ++ pwrctl->wowlan_wake_reason = rtw_read8(padapter, REG_WOWLAN_WAKE_REASON); ++ DBG_871X_LEVEL(_drv_always_, "wakeup_reason: 0x%02x, mac_630 = 0x%08x, mac_634 = 0x%08x, mac_1c0 = 0x%08x, mac_1c4 = 0x%08x" ++ ", mac_494 = 0x%08x, , mac_498 = 0x%08x, mac_49c = 0x%08x, mac_608 = 0x%08x, mac_4a0 = 0x%08x, mac_4a4 = 0x%08x\n" ++ ", mac_1cc = 0x%08x, mac_2f0 = 0x%08x, mac_2f4 = 0x%08x, mac_2f8 = 0x%08x, mac_2fc = 0x%08x, mac_8c = 0x%08x" ++ , pwrctl->wowlan_wake_reason, rtw_read32(padapter, REG_WOWLAN_GTK_DBG1), rtw_read32(padapter, REG_WOWLAN_GTK_DBG2) ++ , rtw_read32(padapter, 0x1c0), rtw_read32(padapter, 0x1c4) ++ , rtw_read32(padapter, 0x494), rtw_read32(padapter, 0x498), rtw_read32(padapter, 0x49c), rtw_read32(padapter, 0x608) ++ , rtw_read32(padapter, 0x4a0), rtw_read32(padapter, 0x4a4) ++ , rtw_read32(padapter, 0x1cc), rtw_read32(padapter, 0x2f0), rtw_read32(padapter, 0x2f4), rtw_read32(padapter, 0x2f8) ++ , rtw_read32(padapter, 0x2fc), rtw_read32(padapter, 0x8c)); ++#ifdef CONFIG_PNO_SET_DEBUG ++ DBG_871X("0x1b9: 0x%02x, 0x632: 0x%02x\n", rtw_read8(padapter, 0x1b9), rtw_read8(padapter, 0x632)); ++ DBG_871X("0x4fc: 0x%02x, 0x4fd: 0x%02x\n", rtw_read8(padapter, 0x4fc), rtw_read8(padapter, 0x4fd)); ++ DBG_871X("TXDMA STATUS: 0x%08x\n", rtw_read32(padapter, REG_TXDMA_STATUS)); ++#endif ++ ++ { ++ /* 2. Set Disable WOWLAN H2C command. */ ++ DBG_871X_LEVEL(_drv_always_, "Set Disable WOWLan cmd\n"); ++ rtl8723b_set_wowlan_cmd(padapter, 0); ++ ++ /* 3. Check Disable WoWlan CMD ready. */ ++ DBG_871X_LEVEL(_drv_always_, "Check DisableWoWlan CMD is ready\n"); ++ mstatus = rtw_read8(padapter, REG_WOW_CTRL); ++ trycnt = 50; ++ while (mstatus&BIT1 && trycnt>1) { ++ mstatus = rtw_read8(padapter, REG_WOW_CTRL); ++ DBG_871X_LEVEL(_drv_always_, "Loop index: %d :0x%02x\n", trycnt, mstatus); ++ trycnt --; ++ msleep(10); ++ } ++ ++ if (mstatus & BIT1) { ++ DBG_871X_LEVEL(_drv_always_, "Disable WOW mode fail!!\n"); ++ DBG_871X("Set 0x690 = 0x00\n"); ++ rtw_write8(padapter, REG_WOW_CTRL, (rtw_read8(padapter, REG_WOW_CTRL)&0xf0)); ++ DBG_871X_LEVEL(_drv_always_, "Release RXDMA\n"); ++ rtw_write32(padapter, REG_RXPKT_NUM, (rtw_read32(padapter, REG_RXPKT_NUM)&(~RW_RELEASE_EN))); ++ } ++ ++ /* 3.1 read fw iv */ ++ iv_low = rtw_read32(padapter, REG_TXPKTBUF_IV_LOW); ++ /* only low two bytes is PN, check AES_IV macro for detail */ ++ iv_low &= 0xffff; ++ iv_high = rtw_read32(padapter, REG_TXPKTBUF_IV_HIGH); ++ /* get the real packet number */ ++ pwrctl->wowlan_fw_iv = iv_high << 16 | iv_low; ++ DBG_871X_LEVEL(_drv_always_, "fw_iv: 0x%016llx\n", pwrctl->wowlan_fw_iv); ++ /* Update TX iv data. */ ++ rtw_set_sec_pn(padapter); ++ ++ /* 3.2 read GTK index and key */ ++ if (psecuritypriv->binstallKCK_KEK == true && psecuritypriv->dot11PrivacyAlgrthm == _AES_) ++ { ++ u8 gtk_keyindex = 0; ++ u8 get_key[16]; ++ /* read gtk key index */ ++ gtk_keyindex = rtw_read8(padapter, 0x48c); ++ ++ if (gtk_keyindex < 4) ++ { ++ psecuritypriv->dot118021XGrpKeyid = gtk_keyindex; ++ read_cam(padapter , gtk_keyindex, get_key); ++ memcpy(psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, get_key, 16); ++ DBG_871X_LEVEL(_drv_always_, "GTK (%d) = 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", gtk_keyindex, ++ psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].lkey[0], ++ psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].lkey[1], ++ psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].lkey[2], ++ psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].lkey[3]); ++ } ++ else ++ DBG_871X_LEVEL(_drv_always_, "GTK index =%d\n", gtk_keyindex); ++ } ++ ++ /* 4. Re-download Normal FW. */ ++ DBG_871X_LEVEL(_drv_always_, "Re-download Normal FW!\n"); ++ SetFwRelatedForWoWLAN8723b(padapter, false); ++ } ++#ifdef CONFIG_GPIO_WAKEUP ++ DBG_871X_LEVEL(_drv_always_, "Set Wake GPIO to high for default.\n"); ++ HalSetOutPutGPIO(padapter, WAKEUP_GPIO_IDX, 1); ++#endif ++ ++ /* 5. Download reserved pages and report media status if needed. */ ++ if ((pwrctl->wowlan_wake_reason != FWDecisionDisconnect) && ++ (pwrctl->wowlan_wake_reason != Rx_Pairwisekey) && ++ (pwrctl->wowlan_wake_reason != Rx_DisAssoc) && ++ (pwrctl->wowlan_wake_reason != Rx_DeAuth)) ++ { ++ rtl8723b_set_FwJoinBssRpt_cmd(padapter, RT_MEDIA_CONNECT); ++ if (psta != NULL) ++ rtl8723b_set_FwMediaStatusRpt_cmd(padapter, RT_MEDIA_CONNECT, psta->mac_id); ++ } ++#ifdef CONFIG_PNO_SUPPORT ++ rtw_write8(padapter, 0x1b8, 0); ++ DBG_871X("reset 0x1b8: %d\n", rtw_read8(padapter, 0x1b8)); ++ rtw_write8(padapter, 0x1b9, 0); ++ DBG_871X("reset 0x1b9: %d\n", rtw_read8(padapter, 0x1b9)); ++ rtw_write8(padapter, REG_PNO_STATUS, 0); ++ DBG_871X("reset REG_PNO_STATUS: %d\n", rtw_read8(padapter, REG_PNO_STATUS)); ++#endif ++ break; ++ ++ default: ++ break; ++ } ++ } ++ break; ++#endif /* CONFIG_WOWLAN */ ++#ifdef CONFIG_AP_WOWLAN ++ case HW_VAR_AP_WOWLAN: ++ { ++ poidparam = (struct wowlan_ioctl_param *)val; ++ switch (poidparam->subcode) { ++ case WOWLAN_AP_ENABLE: ++ DBG_871X("%s, WOWLAN_AP_ENABLE\n", __func__); ++ /* 1. Download WOWLAN FW */ ++ DBG_871X_LEVEL(_drv_always_, "Re-download WoWlan FW!\n"); ++ SetFwRelatedForWoWLAN8723b(padapter, true); ++ ++ /* 2. RX DMA stop */ ++ DBG_871X_LEVEL(_drv_always_, "Pause DMA\n"); ++ rtw_write32(padapter, REG_RXPKT_NUM, ++ (rtw_read32(padapter, REG_RXPKT_NUM)|RW_RELEASE_EN)); ++ do { ++ if ((rtw_read32(padapter, REG_RXPKT_NUM)&RXDMA_IDLE)) { ++ DBG_871X_LEVEL(_drv_always_, "RX_DMA_IDLE is true\n"); ++ break; ++ } else { ++ /* If RX_DMA is not idle, receive one pkt from DMA */ ++ res = sdio_local_read(padapter, SDIO_REG_RX0_REQ_LEN, 4, (u8 *)&tmp); ++ len = le16_to_cpu(tmp); ++ ++ DBG_871X_LEVEL(_drv_always_, "RX len:%d\n", len); ++ if (len > 0) ++ res = RecvOnePkt(padapter, len); ++ else ++ DBG_871X_LEVEL(_drv_always_, "read length fail %d\n", len); ++ ++ DBG_871X_LEVEL(_drv_always_, "RecvOnePkt Result: %d\n", res); ++ } ++ } while (trycnt--); ++ ++ if (trycnt == 0) ++ DBG_871X_LEVEL(_drv_always_, "Stop RX DMA failed......\n"); ++ ++ /* 3. Clear IMR and ISR */ ++ DBG_871X_LEVEL(_drv_always_, "Clear IMR and ISR\n"); ++ tmp = 0; ++ sdio_local_write(padapter, SDIO_REG_HIMR_ON, 4, (u8 *)&tmp); ++ sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp); ++ sdio_local_read(padapter, SDIO_REG_HISR, 4, (u8 *)&tmp); ++ sdio_local_write(padapter, SDIO_REG_HISR, 4, (u8 *)&tmp); ++ ++ /* 4. Enable CPWM2 only */ ++ DBG_871X_LEVEL(_drv_always_, "Enable only CPWM2\n"); ++ sdio_local_read(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp); ++ DBG_871X("DisableInterruptButCpwm28723BSdio(): Read SDIO_REG_HIMR: 0x%08x\n", tmp); ++ ++ himr = cpu_to_le32(SDIO_HIMR_DISABLED)|SDIO_HIMR_CPWM2_MSK; ++ sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&himr); ++ ++ sdio_local_read(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp); ++ DBG_871X("DisableInterruptButCpwm28723BSdio(): Read again SDIO_REG_HIMR: 0x%08x\n", tmp); ++ ++ /* 5. Set Enable WOWLAN H2C command. */ ++ DBG_871X_LEVEL(_drv_always_, "Set Enable AP WOWLan cmd\n"); ++ rtl8723b_set_ap_wowlan_cmd(padapter, 1); ++ /* 6. add some delay for H2C cmd ready */ ++ msleep(10); ++ ++ rtw_write8(padapter, REG_WOWLAN_WAKE_REASON, 0); ++ break; ++ case WOWLAN_AP_DISABLE: ++ DBG_871X("%s, WOWLAN_AP_DISABLE\n", __func__); ++ /* 1. Read wakeup reason */ ++ pwrctl->wowlan_wake_reason = ++ rtw_read8(padapter, REG_WOWLAN_WAKE_REASON); ++ ++ DBG_871X_LEVEL(_drv_always_, "wakeup_reason: 0x%02x\n", ++ pwrctl->wowlan_wake_reason); ++ ++ /* 2. Set Disable WOWLAN H2C command. */ ++ DBG_871X_LEVEL(_drv_always_, "Set Disable WOWLan cmd\n"); ++ rtl8723b_set_ap_wowlan_cmd(padapter, 0); ++ /* 6. add some delay for H2C cmd ready */ ++ msleep(2); ++ ++ DBG_871X_LEVEL(_drv_always_, "Release RXDMA\n"); ++ ++ rtw_write32(padapter, REG_RXPKT_NUM, ++ (rtw_read32(padapter, REG_RXPKT_NUM) & (~RW_RELEASE_EN))); ++ ++ SetFwRelatedForWoWLAN8723b(padapter, false); ++ ++#ifdef CONFIG_GPIO_WAKEUP ++ DBG_871X_LEVEL(_drv_always_, "Set Wake GPIO to high for default.\n"); ++ HalSetOutPutGPIO(padapter, WAKEUP_GPIO_IDX, 1); ++#endif /* CONFIG_GPIO_WAKEUP */ ++ rtl8723b_set_FwJoinBssRpt_cmd(padapter, RT_MEDIA_CONNECT); ++ issue_beacon(padapter, 0); ++ break; ++ default: ++ break; ++ } ++ } ++ break; ++#endif /* CONFIG_AP_WOWLAN */ ++ case HW_VAR_DM_IN_LPS: ++ rtl8723b_hal_dm_in_lps(padapter); ++ break; ++ default: ++ SetHwReg8723B(padapter, variable, val); ++ break; ++ } ++} ++ ++/* ++ * If variable not handled here, ++ * some variables will be processed in GetHwReg8723B() ++ */ ++static void GetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val) ++{ ++ switch (variable) { ++ case HW_VAR_CPWM: ++ *val = rtw_read8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HCPWM1_8723B); ++ break; ++ ++ case HW_VAR_FW_PS_STATE: ++ { ++ /* 3. read dword 0x88 driver read fw ps state */ ++ *((u16*)val) = rtw_read16(padapter, 0x88); ++ } ++ break; ++ default: ++ GetHwReg8723B(padapter, variable, val); ++ break; ++ } ++} ++ ++static void SetHwRegWithBuf8723B(struct adapter *padapter, u8 variable, u8 *pbuf, int len) ++{ ++ switch (variable) { ++ case HW_VAR_C2H_HANDLE: ++ /* DBG_8192C("%s len =%d\n", __func__, len); */ ++ C2HPacketHandler_8723B(padapter, pbuf, len); ++ break; ++ default: ++ break; ++ } ++} ++ ++/* */ ++/* Description: */ ++/* Query setting of specified variable. */ ++/* */ ++static u8 ++GetHalDefVar8723BSDIO( ++struct adapter * Adapter, ++enum HAL_DEF_VARIABLE eVariable, ++void * pValue ++ ) ++{ ++ u8 bResult = _SUCCESS; ++ ++ switch (eVariable) ++ { ++ case HAL_DEF_IS_SUPPORT_ANT_DIV: ++ break; ++ case HAL_DEF_CURRENT_ANTENNA: ++ break; ++ case HW_VAR_MAX_RX_AMPDU_FACTOR: ++ /* Stanley@BB.SD3 suggests 16K can get stable performance */ ++ /* coding by Lucas@20130730 */ ++ *(u32*)pValue = MAX_AMPDU_FACTOR_16K; ++ break; ++ default: ++ bResult = GetHalDefVar8723B(Adapter, eVariable, pValue); ++ break; ++ } ++ ++ return bResult; ++} ++ ++/* */ ++/* Description: */ ++/* Change default setting of specified variable. */ ++/* */ ++static u8 SetHalDefVar8723BSDIO(struct adapter *Adapter, ++ enum HAL_DEF_VARIABLE eVariable, void *pValue) ++{ ++ return SetHalDefVar8723B(Adapter, eVariable, pValue); ++} ++ ++void rtl8723bs_set_hal_ops(struct adapter *padapter) ++{ ++ struct hal_ops *pHalFunc = &padapter->HalFunc; ++ ++ rtl8723b_set_hal_ops(pHalFunc); ++ ++ pHalFunc->hal_init = &rtl8723bs_hal_init; ++ pHalFunc->hal_deinit = &rtl8723bs_hal_deinit; ++ ++ pHalFunc->inirp_init = &rtl8723bs_inirp_init; ++ pHalFunc->inirp_deinit = &rtl8723bs_inirp_deinit; ++ ++ pHalFunc->init_xmit_priv = &rtl8723bs_init_xmit_priv; ++ pHalFunc->free_xmit_priv = &rtl8723bs_free_xmit_priv; ++ ++ pHalFunc->init_recv_priv = &rtl8723bs_init_recv_priv; ++ pHalFunc->free_recv_priv = &rtl8723bs_free_recv_priv; ++ ++ pHalFunc->init_default_value = &rtl8723bs_init_default_value; ++ pHalFunc->intf_chip_configure = &rtl8723bs_interface_configure; ++ pHalFunc->read_adapter_info = &ReadAdapterInfo8723BS; ++ ++ pHalFunc->enable_interrupt = &EnableInterrupt8723BSdio; ++ pHalFunc->disable_interrupt = &DisableInterrupt8723BSdio; ++ pHalFunc->check_ips_status = &CheckIPSStatus; ++#ifdef CONFIG_WOWLAN ++ pHalFunc->clear_interrupt = &ClearInterrupt8723BSdio; ++#endif ++ pHalFunc->SetHwRegHandler = &SetHwReg8723BS; ++ pHalFunc->GetHwRegHandler = &GetHwReg8723BS; ++ pHalFunc->SetHwRegHandlerWithBuf = &SetHwRegWithBuf8723B; ++ pHalFunc->GetHalDefVarHandler = &GetHalDefVar8723BSDIO; ++ pHalFunc->SetHalDefVarHandler = &SetHalDefVar8723BSDIO; ++ ++ pHalFunc->hal_xmit = &rtl8723bs_hal_xmit; ++ pHalFunc->mgnt_xmit = &rtl8723bs_mgnt_xmit; ++ pHalFunc->hal_xmitframe_enqueue = &rtl8723bs_hal_xmitframe_enqueue; ++ ++#if defined(CONFIG_CHECK_BT_HANG) ++ pHalFunc->hal_init_checkbthang_workqueue = &rtl8723bs_init_checkbthang_workqueue; ++ pHalFunc->hal_free_checkbthang_workqueue = &rtl8723bs_free_checkbthang_workqueue; ++ pHalFunc->hal_cancle_checkbthang_workqueue = &rtl8723bs_cancle_checkbthang_workqueue; ++ pHalFunc->hal_checke_bt_hang = &rtl8723bs_hal_check_bt_hang; ++#endif ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/hal/sdio_ops.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/sdio_ops.c +--- linux-4.3/3rdparty/rtl8723bs/hal/sdio_ops.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/hal/sdio_ops.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,1262 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ *******************************************************************************/ ++#define _SDIO_OPS_C_ ++ ++#include ++#include ++#include ++ ++/* define SDIO_DEBUG_IO 1 */ ++ ++ ++/* */ ++/* Description: */ ++/* The following mapping is for SDIO host local register space. */ ++/* */ ++/* Creadted by Roger, 2011.01.31. */ ++/* */ ++static void HalSdioGetCmdAddr8723BSdio( ++struct adapter * padapter, ++u8 DeviceID, ++u32 Addr, ++ u32* pCmdAddr ++ ) ++{ ++ switch (DeviceID) ++ { ++ case SDIO_LOCAL_DEVICE_ID: ++ *pCmdAddr = ((SDIO_LOCAL_DEVICE_ID << 13) | (Addr & SDIO_LOCAL_MSK)); ++ break; ++ ++ case WLAN_IOREG_DEVICE_ID: ++ *pCmdAddr = ((WLAN_IOREG_DEVICE_ID << 13) | (Addr & WLAN_IOREG_MSK)); ++ break; ++ ++ case WLAN_TX_HIQ_DEVICE_ID: ++ *pCmdAddr = ((WLAN_TX_HIQ_DEVICE_ID << 13) | (Addr & WLAN_FIFO_MSK)); ++ break; ++ ++ case WLAN_TX_MIQ_DEVICE_ID: ++ *pCmdAddr = ((WLAN_TX_MIQ_DEVICE_ID << 13) | (Addr & WLAN_FIFO_MSK)); ++ break; ++ ++ case WLAN_TX_LOQ_DEVICE_ID: ++ *pCmdAddr = ((WLAN_TX_LOQ_DEVICE_ID << 13) | (Addr & WLAN_FIFO_MSK)); ++ break; ++ ++ case WLAN_RX0FF_DEVICE_ID: ++ *pCmdAddr = ((WLAN_RX0FF_DEVICE_ID << 13) | (Addr & WLAN_RX0FF_MSK)); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++static u8 get_deviceid(u32 addr) ++{ ++ u8 devideId; ++ u16 pseudoId; ++ ++ ++ pseudoId = (u16)(addr >> 16); ++ switch (pseudoId) ++ { ++ case 0x1025: ++ devideId = SDIO_LOCAL_DEVICE_ID; ++ break; ++ ++ case 0x1026: ++ devideId = WLAN_IOREG_DEVICE_ID; ++ break; ++ ++/* case 0x1027: */ ++/* devideId = SDIO_FIRMWARE_FIFO; */ ++/* break; */ ++ ++ case 0x1031: ++ devideId = WLAN_TX_HIQ_DEVICE_ID; ++ break; ++ ++ case 0x1032: ++ devideId = WLAN_TX_MIQ_DEVICE_ID; ++ break; ++ ++ case 0x1033: ++ devideId = WLAN_TX_LOQ_DEVICE_ID; ++ break; ++ ++ case 0x1034: ++ devideId = WLAN_RX0FF_DEVICE_ID; ++ break; ++ ++ default: ++/* devideId = (u8)((addr >> 13) & 0xF); */ ++ devideId = WLAN_IOREG_DEVICE_ID; ++ break; ++ } ++ ++ return devideId; ++} ++ ++/* ++ * Ref: ++ *HalSdioGetCmdAddr8723BSdio() ++ */ ++static u32 _cvrt2ftaddr(const u32 addr, u8 *pdeviceId, u16 *poffset) ++{ ++ u8 deviceId; ++ u16 offset; ++ u32 ftaddr; ++ ++ ++ deviceId = get_deviceid(addr); ++ offset = 0; ++ ++ switch (deviceId) ++ { ++ case SDIO_LOCAL_DEVICE_ID: ++ offset = addr & SDIO_LOCAL_MSK; ++ break; ++ ++ case WLAN_TX_HIQ_DEVICE_ID: ++ case WLAN_TX_MIQ_DEVICE_ID: ++ case WLAN_TX_LOQ_DEVICE_ID: ++ offset = addr & WLAN_FIFO_MSK; ++ break; ++ ++ case WLAN_RX0FF_DEVICE_ID: ++ offset = addr & WLAN_RX0FF_MSK; ++ break; ++ ++ case WLAN_IOREG_DEVICE_ID: ++ default: ++ deviceId = WLAN_IOREG_DEVICE_ID; ++ offset = addr & WLAN_IOREG_MSK; ++ break; ++ } ++ ftaddr = (deviceId << 13) | offset; ++ ++ if (pdeviceId) *pdeviceId = deviceId; ++ if (poffset) *poffset = offset; ++ ++ return ftaddr; ++} ++ ++static u8 sdio_read8(struct intf_hdl *pintfhdl, u32 addr) ++{ ++ u32 ftaddr; ++ u8 val; ++ ++ ftaddr = _cvrt2ftaddr(addr, NULL, NULL); ++ val = sd_read8(pintfhdl, ftaddr, NULL); ++ return val; ++} ++ ++static u16 sdio_read16(struct intf_hdl *pintfhdl, u32 addr) ++{ ++ u32 ftaddr; ++ u16 val; ++ __le16 le_tmp; ++ ++ ftaddr = _cvrt2ftaddr(addr, NULL, NULL); ++ sd_cmd52_read(pintfhdl, ftaddr, 2, (u8 *)&le_tmp); ++ val = le16_to_cpu(le_tmp); ++ return val; ++} ++ ++static u32 sdio_read32(struct intf_hdl *pintfhdl, u32 addr) ++{ ++ struct adapter *padapter; ++ u8 bMacPwrCtrlOn; ++ u8 deviceId; ++ u16 offset; ++ u32 ftaddr; ++ u8 shift; ++ u32 val; ++ s32 err; ++ __le32 le_tmp; ++ ++ padapter = pintfhdl->padapter; ++ ftaddr = _cvrt2ftaddr(addr, &deviceId, &offset); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if (((deviceId == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ++ || (false == bMacPwrCtrlOn) ++ || (true == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)) ++ { ++ err = sd_cmd52_read(pintfhdl, ftaddr, 4, (u8 *)&le_tmp); ++#ifdef SDIO_DEBUG_IO ++ if (!err) { ++#endif ++ val = le32_to_cpu(le_tmp); ++ return val; ++#ifdef SDIO_DEBUG_IO ++ } ++ ++ DBG_8192C(KERN_ERR "%s: Mac Power off, Read FAIL(%d)! addr = 0x%x\n", __func__, err, addr); ++ return SDIO_ERR_VAL32; ++#endif ++ } ++ ++ /* 4 bytes alignment */ ++ shift = ftaddr & 0x3; ++ if (shift == 0) { ++ val = sd_read32(pintfhdl, ftaddr, NULL); ++ } else { ++ u8 *ptmpbuf; ++ ++ ptmpbuf = (u8 *)rtw_malloc(8); ++ if (NULL == ptmpbuf) { ++ DBG_8192C(KERN_ERR "%s: Allocate memory FAIL!(size =8) addr = 0x%x\n", __func__, addr); ++ return SDIO_ERR_VAL32; ++ } ++ ++ ftaddr &= ~(u16)0x3; ++ sd_read(pintfhdl, ftaddr, 8, ptmpbuf); ++ memcpy(&le_tmp, ptmpbuf+shift, 4); ++ val = le32_to_cpu(le_tmp); ++ ++ kfree(ptmpbuf); ++ } ++ return val; ++} ++ ++static s32 sdio_readN(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pbuf) ++{ ++ struct adapter *padapter; ++ u8 bMacPwrCtrlOn; ++ u8 deviceId; ++ u16 offset; ++ u32 ftaddr; ++ u8 shift; ++ s32 err; ++ ++ padapter = pintfhdl->padapter; ++ err = 0; ++ ++ ftaddr = _cvrt2ftaddr(addr, &deviceId, &offset); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if (((deviceId == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ++ || (false == bMacPwrCtrlOn) ++ || (true == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)) ++ { ++ err = sd_cmd52_read(pintfhdl, ftaddr, cnt, pbuf); ++ return err; ++ } ++ ++ /* 4 bytes alignment */ ++ shift = ftaddr & 0x3; ++ if (shift == 0) { ++ err = sd_read(pintfhdl, ftaddr, cnt, pbuf); ++ } else { ++ u8 *ptmpbuf; ++ u32 n; ++ ++ ftaddr &= ~(u16)0x3; ++ n = cnt + shift; ++ ptmpbuf = rtw_malloc(n); ++ if (NULL == ptmpbuf) return -1; ++ err = sd_read(pintfhdl, ftaddr, n, ptmpbuf); ++ if (!err) ++ memcpy(pbuf, ptmpbuf+shift, cnt); ++ kfree(ptmpbuf); ++ } ++ return err; ++} ++ ++static s32 sdio_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val) ++{ ++ u32 ftaddr; ++ s32 err; ++ ++ ftaddr = _cvrt2ftaddr(addr, NULL, NULL); ++ sd_write8(pintfhdl, ftaddr, val, &err); ++ ++ return err; ++} ++ ++static s32 sdio_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val) ++{ ++ u32 ftaddr; ++ s32 err; ++ __le16 le_tmp; ++ ++ ftaddr = _cvrt2ftaddr(addr, NULL, NULL); ++ le_tmp = cpu_to_le16(val); ++ err = sd_cmd52_write(pintfhdl, ftaddr, 2, (u8 *)&le_tmp); ++ ++ return err; ++} ++ ++static s32 sdio_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val) ++{ ++ struct adapter *padapter; ++ u8 bMacPwrCtrlOn; ++ u8 deviceId; ++ u16 offset; ++ u32 ftaddr; ++ u8 shift; ++ s32 err; ++ __le32 le_tmp; ++ ++ padapter = pintfhdl->padapter; ++ err = 0; ++ ++ ftaddr = _cvrt2ftaddr(addr, &deviceId, &offset); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if (((deviceId == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) || ++ (!bMacPwrCtrlOn) || (adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)) { ++ le_tmp = cpu_to_le32(val); ++ err = sd_cmd52_write(pintfhdl, ftaddr, 4, (u8 *)&le_tmp); ++ return err; ++ } ++ ++ /* 4 bytes alignment */ ++ shift = ftaddr & 0x3; ++ if (shift == 0) ++ { ++ sd_write32(pintfhdl, ftaddr, val, &err); ++ } else { ++ le_tmp = cpu_to_le32(val); ++ err = sd_cmd52_write(pintfhdl, ftaddr, 4, (u8 *)&le_tmp); ++ } ++ return err; ++} ++ ++static s32 sdio_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pbuf) ++{ ++ struct adapter *padapter; ++ u8 bMacPwrCtrlOn; ++ u8 deviceId; ++ u16 offset; ++ u32 ftaddr; ++ u8 shift; ++ s32 err; ++ ++ padapter = pintfhdl->padapter; ++ err = 0; ++ ++ ftaddr = _cvrt2ftaddr(addr, &deviceId, &offset); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if (((deviceId == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ++ || (false == bMacPwrCtrlOn) ++ || (true == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)) ++ { ++ err = sd_cmd52_write(pintfhdl, ftaddr, cnt, pbuf); ++ return err; ++ } ++ ++ shift = ftaddr & 0x3; ++ if (shift == 0) { ++ err = sd_write(pintfhdl, ftaddr, cnt, pbuf); ++ } else { ++ u8 *ptmpbuf; ++ u32 n; ++ ++ ftaddr &= ~(u16)0x3; ++ n = cnt + shift; ++ ptmpbuf = rtw_malloc(n); ++ if (NULL == ptmpbuf) return -1; ++ err = sd_read(pintfhdl, ftaddr, 4, ptmpbuf); ++ if (err) { ++ kfree(ptmpbuf); ++ return err; ++ } ++ memcpy(ptmpbuf+shift, pbuf, cnt); ++ err = sd_write(pintfhdl, ftaddr, n, ptmpbuf); ++ kfree(ptmpbuf); ++ } ++ return err; ++} ++ ++static u8 sdio_f0_read8(struct intf_hdl *pintfhdl, u32 addr) ++{ ++ return sd_f0_read8(pintfhdl, addr, NULL); ++} ++ ++static void sdio_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem) ++{ ++ s32 err; ++ ++ err = sdio_readN(pintfhdl, addr, cnt, rmem); ++ /* TODO: Report error is err not zero */ ++} ++ ++static void sdio_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) ++{ ++ sdio_writeN(pintfhdl, addr, cnt, wmem); ++} ++ ++/* ++ * Description: ++ *Read from RX FIFO ++ *Round read size to block size, ++ *and make sure data transfer will be done in one command. ++ * ++ * Parameters: ++ *pintfhdl a pointer of intf_hdl ++ *addr port ID ++ *cnt size to read ++ *rmem address to put data ++ * ++ * Return: ++ *_SUCCESS(1) Success ++ *_FAIL(0) Fail ++ */ ++static u32 sdio_read_port( ++ struct intf_hdl *pintfhdl, ++ u32 addr, ++ u32 cnt, ++ u8 *mem) ++{ ++ struct adapter *padapter; ++ PSDIO_DATA psdio; ++ struct hal_com_data *phal; ++ u32 oldcnt; ++#ifdef SDIO_DYNAMIC_ALLOC_MEM ++ u8 *oldmem; ++#endif ++ s32 err; ++ ++ ++ padapter = pintfhdl->padapter; ++ psdio = &adapter_to_dvobj(padapter)->intf_data; ++ phal = GET_HAL_DATA(padapter); ++ ++ HalSdioGetCmdAddr8723BSdio(padapter, addr, phal->SdioRxFIFOCnt++, &addr); ++ ++ oldcnt = cnt; ++ if (cnt > psdio->block_transfer_len) ++ cnt = _RND(cnt, psdio->block_transfer_len); ++/* cnt = sdio_align_size(cnt); */ ++ ++ if (oldcnt != cnt) { ++#ifdef SDIO_DYNAMIC_ALLOC_MEM ++ oldmem = mem; ++ mem = rtw_malloc(cnt); ++ if (mem == NULL) { ++ DBG_8192C(KERN_WARNING "%s: allocate memory %d bytes fail!\n", __func__, cnt); ++ mem = oldmem; ++ oldmem == NULL; ++ } ++#else ++ /* in this case, caller should gurante the buffer is big enough */ ++ /* to receive data after alignment */ ++#endif ++ } ++ ++ err = _sd_read(pintfhdl, addr, cnt, mem); ++ ++#ifdef SDIO_DYNAMIC_ALLOC_MEM ++ if ((oldcnt != cnt) && (oldmem)) { ++ memcpy(oldmem, mem, oldcnt); ++ kfree(mem); ++ } ++#endif ++ ++ if (err) return _FAIL; ++ return _SUCCESS; ++} ++ ++/* ++ * Description: ++ *Write to TX FIFO ++ *Align write size block size, ++ *and make sure data could be written in one command. ++ * ++ * Parameters: ++ *pintfhdl a pointer of intf_hdl ++ *addr port ID ++ *cnt size to write ++ *wmem data pointer to write ++ * ++ * Return: ++ *_SUCCESS(1) Success ++ *_FAIL(0) Fail ++ */ ++static u32 sdio_write_port( ++ struct intf_hdl *pintfhdl, ++ u32 addr, ++ u32 cnt, ++ u8 *mem) ++{ ++ struct adapter *padapter; ++ PSDIO_DATA psdio; ++ s32 err; ++ struct xmit_buf *xmitbuf = (struct xmit_buf *)mem; ++ ++ padapter = pintfhdl->padapter; ++ psdio = &adapter_to_dvobj(padapter)->intf_data; ++ ++ if (padapter->hw_init_completed == false) { ++ DBG_871X("%s [addr = 0x%x cnt =%d] padapter->hw_init_completed == false\n", __func__, addr, cnt); ++ return _FAIL; ++ } ++ ++ cnt = _RND4(cnt); ++ HalSdioGetCmdAddr8723BSdio(padapter, addr, cnt >> 2, &addr); ++ ++ if (cnt > psdio->block_transfer_len) ++ cnt = _RND(cnt, psdio->block_transfer_len); ++/* cnt = sdio_align_size(cnt); */ ++ ++ err = sd_write(pintfhdl, addr, cnt, xmitbuf->pdata); ++ ++ rtw_sctx_done_err(&xmitbuf->sctx, ++ err ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS); ++ ++ if (err) return _FAIL; ++ return _SUCCESS; ++} ++ ++void sdio_set_intf_ops(struct adapter *padapter, struct _io_ops *pops) ++{ ++ pops->_read8 = &sdio_read8; ++ pops->_read16 = &sdio_read16; ++ pops->_read32 = &sdio_read32; ++ pops->_read_mem = &sdio_read_mem; ++ pops->_read_port = &sdio_read_port; ++ ++ pops->_write8 = &sdio_write8; ++ pops->_write16 = &sdio_write16; ++ pops->_write32 = &sdio_write32; ++ pops->_writeN = &sdio_writeN; ++ pops->_write_mem = &sdio_write_mem; ++ pops->_write_port = &sdio_write_port; ++ ++ pops->_sd_f0_read8 = sdio_f0_read8; ++} ++ ++/* ++ * Todo: align address to 4 bytes. ++ */ ++static s32 _sdio_local_read( ++ struct adapter *padapter, ++ u32 addr, ++ u32 cnt, ++ u8 *pbuf) ++{ ++ struct intf_hdl * pintfhdl; ++ u8 bMacPwrCtrlOn; ++ s32 err; ++ u8 *ptmpbuf; ++ u32 n; ++ ++ ++ pintfhdl =&padapter->iopriv.intf; ++ ++ HalSdioGetCmdAddr8723BSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if (false == bMacPwrCtrlOn) ++ { ++ err = _sd_cmd52_read(pintfhdl, addr, cnt, pbuf); ++ return err; ++ } ++ ++ n = RND4(cnt); ++ ptmpbuf = (u8 *)rtw_malloc(n); ++ if (!ptmpbuf) ++ return (-1); ++ ++ err = _sd_read(pintfhdl, addr, n, ptmpbuf); ++ if (!err) ++ memcpy(pbuf, ptmpbuf, cnt); ++ ++ if (ptmpbuf) ++ kfree(ptmpbuf); ++ ++ return err; ++} ++ ++/* ++ * Todo: align address to 4 bytes. ++ */ ++s32 sdio_local_read( ++ struct adapter *padapter, ++ u32 addr, ++ u32 cnt, ++ u8 *pbuf) ++{ ++ struct intf_hdl * pintfhdl; ++ u8 bMacPwrCtrlOn; ++ s32 err; ++ u8 *ptmpbuf; ++ u32 n; ++ ++ pintfhdl =&padapter->iopriv.intf; ++ ++ HalSdioGetCmdAddr8723BSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if ((false == bMacPwrCtrlOn) ++ || (true == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)) ++ { ++ err = sd_cmd52_read(pintfhdl, addr, cnt, pbuf); ++ return err; ++ } ++ ++ n = RND4(cnt); ++ ptmpbuf = (u8 *)rtw_malloc(n); ++ if (!ptmpbuf) ++ return (-1); ++ ++ err = sd_read(pintfhdl, addr, n, ptmpbuf); ++ if (!err) ++ memcpy(pbuf, ptmpbuf, cnt); ++ ++ if (ptmpbuf) ++ kfree(ptmpbuf); ++ ++ return err; ++} ++ ++/* ++ * Todo: align address to 4 bytes. ++ */ ++s32 sdio_local_write( ++ struct adapter *padapter, ++ u32 addr, ++ u32 cnt, ++ u8 *pbuf) ++{ ++ struct intf_hdl * pintfhdl; ++ u8 bMacPwrCtrlOn; ++ s32 err; ++ u8 *ptmpbuf; ++ ++ if (addr & 0x3) ++ DBG_8192C("%s, address must be 4 bytes alignment\n", __func__); ++ ++ if (cnt & 0x3) ++ DBG_8192C("%s, size must be the multiple of 4\n", __func__); ++ ++ pintfhdl =&padapter->iopriv.intf; ++ ++ HalSdioGetCmdAddr8723BSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if ((false == bMacPwrCtrlOn) ++ || (true == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)) ++ { ++ err = sd_cmd52_write(pintfhdl, addr, cnt, pbuf); ++ return err; ++ } ++ ++ ptmpbuf = (u8 *)rtw_malloc(cnt); ++ if (!ptmpbuf) ++ return (-1); ++ ++ memcpy(ptmpbuf, pbuf, cnt); ++ ++ err = sd_write(pintfhdl, addr, cnt, ptmpbuf); ++ ++ kfree(ptmpbuf); ++ ++ return err; ++} ++ ++u8 SdioLocalCmd52Read1Byte(struct adapter *padapter, u32 addr) ++{ ++ u8 val = 0; ++ struct intf_hdl * pintfhdl =&padapter->iopriv.intf; ++ ++ HalSdioGetCmdAddr8723BSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ sd_cmd52_read(pintfhdl, addr, 1, &val); ++ ++ return val; ++} ++ ++static u16 SdioLocalCmd52Read2Byte(struct adapter *padapter, u32 addr) ++{ ++ __le16 val = 0; ++ struct intf_hdl * pintfhdl =&padapter->iopriv.intf; ++ ++ HalSdioGetCmdAddr8723BSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ sd_cmd52_read(pintfhdl, addr, 2, (u8 *)&val); ++ ++ return le16_to_cpu(val); ++} ++ ++static u32 SdioLocalCmd53Read4Byte(struct adapter *padapter, u32 addr) ++{ ++ ++ u8 bMacPwrCtrlOn; ++ u32 val = 0; ++ struct intf_hdl * pintfhdl =&padapter->iopriv.intf; ++ __le32 le_tmp; ++ ++ HalSdioGetCmdAddr8723BSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); ++ if (!bMacPwrCtrlOn || adapter_to_pwrctl(padapter)->bFwCurrentInPSMode) { ++ sd_cmd52_read(pintfhdl, addr, 4, (u8 *)&le_tmp); ++ val = le32_to_cpu(le_tmp); ++ } else { ++ val = sd_read32(pintfhdl, addr, NULL); ++ } ++ return val; ++} ++ ++void SdioLocalCmd52Write1Byte(struct adapter *padapter, u32 addr, u8 v) ++{ ++ struct intf_hdl * pintfhdl =&padapter->iopriv.intf; ++ ++ HalSdioGetCmdAddr8723BSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ sd_cmd52_write(pintfhdl, addr, 1, &v); ++} ++ ++static void SdioLocalCmd52Write4Byte(struct adapter *padapter, u32 addr, u32 v) ++{ ++ struct intf_hdl * pintfhdl =&padapter->iopriv.intf; ++ __le32 le_tmp; ++ ++ HalSdioGetCmdAddr8723BSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); ++ le_tmp = cpu_to_le32(v); ++ sd_cmd52_write(pintfhdl, addr, 4, (u8 *)&le_tmp); ++} ++ ++static s32 ReadInterrupt8723BSdio(struct adapter *padapter, u32 *phisr) ++{ ++ u32 hisr, himr; ++ u8 val8, hisr_len; ++ ++ ++ if (phisr == NULL) ++ return false; ++ ++ himr = GET_HAL_DATA(padapter)->sdio_himr; ++ ++ /* decide how many bytes need to be read */ ++ hisr_len = 0; ++ while (himr) ++ { ++ hisr_len++; ++ himr >>= 8; ++ } ++ ++ hisr = 0; ++ while (hisr_len != 0) ++ { ++ hisr_len--; ++ val8 = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_HISR+hisr_len); ++ hisr |= (val8 << (8*hisr_len)); ++ } ++ ++ *phisr = hisr; ++ ++ return true; ++} ++ ++/* */ ++/* Description: */ ++/* Initialize SDIO Host Interrupt Mask configuration variables for future use. */ ++/* */ ++/* Assumption: */ ++/* Using SDIO Local register ONLY for configuration. */ ++/* */ ++/* Created by Roger, 2011.02.11. */ ++/* */ ++void InitInterrupt8723BSdio(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ pHalData->sdio_himr = (u32)( \ ++ SDIO_HIMR_RX_REQUEST_MSK | ++ SDIO_HIMR_AVAL_MSK | ++/* SDIO_HIMR_TXERR_MSK | */ ++/* SDIO_HIMR_RXERR_MSK | */ ++/* SDIO_HIMR_TXFOVW_MSK | */ ++/* SDIO_HIMR_RXFOVW_MSK | */ ++/* SDIO_HIMR_TXBCNOK_MSK | */ ++/* SDIO_HIMR_TXBCNERR_MSK | */ ++/* SDIO_HIMR_BCNERLY_INT_MSK | */ ++/* SDIO_HIMR_C2HCMD_MSK | */ ++/* SDIO_HIMR_HSISR_IND_MSK | */ ++/* SDIO_HIMR_GTINT3_IND_MSK | */ ++/* SDIO_HIMR_GTINT4_IND_MSK | */ ++/* SDIO_HIMR_PSTIMEOUT_MSK | */ ++/* SDIO_HIMR_OCPINT_MSK | */ ++/* SDIO_HIMR_ATIMEND_MSK | */ ++/* SDIO_HIMR_ATIMEND_E_MSK | */ ++/* SDIO_HIMR_CTWEND_MSK | */ ++ 0); ++} ++ ++/* */ ++/* Description: */ ++/* Initialize System Host Interrupt Mask configuration variables for future use. */ ++/* */ ++/* Created by Roger, 2011.08.03. */ ++/* */ ++void InitSysInterrupt8723BSdio(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData; ++ ++ ++ pHalData = GET_HAL_DATA(padapter); ++ ++ pHalData->SysIntrMask = ( \ ++/* HSIMR_GPIO12_0_INT_EN | */ ++/* HSIMR_SPS_OCP_INT_EN | */ ++/* HSIMR_RON_INT_EN | */ ++/* HSIMR_PDNINT_EN | */ ++/* HSIMR_GPIO9_INT_EN | */ ++ 0); ++} ++ ++#ifdef CONFIG_WOWLAN ++/* */ ++/* Description: */ ++/* Clear corresponding SDIO Host ISR interrupt service. */ ++/* */ ++/* Assumption: */ ++/* Using SDIO Local register ONLY for configuration. */ ++/* */ ++/* Created by Roger, 2011.02.11. */ ++/* */ ++void ClearInterrupt8723BSdio(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData; ++ u8 *clear; ++ ++ ++ if (true == padapter->bSurpriseRemoved) ++ return; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ clear = rtw_zmalloc(4); ++ ++ /* Clear corresponding HISR Content if needed */ ++ *(__le32*)clear = cpu_to_le32(pHalData->sdio_hisr & MASK_SDIO_HISR_CLEAR); ++ if (*(__le32*)clear) { ++ /* Perform write one clear operation */ ++ sdio_local_write(padapter, SDIO_REG_HISR, 4, clear); ++ } ++ ++ kfree(clear); ++} ++#endif ++ ++/* */ ++/* Description: */ ++/* Enalbe SDIO Host Interrupt Mask configuration on SDIO local domain. */ ++/* */ ++/* Assumption: */ ++/* 1. Using SDIO Local register ONLY for configuration. */ ++/* 2. PASSIVE LEVEL */ ++/* */ ++/* Created by Roger, 2011.02.11. */ ++/* */ ++void EnableInterrupt8723BSdio(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData; ++ __le32 himr; ++ u32 tmp; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ ++ himr = cpu_to_le32(pHalData->sdio_himr); ++ sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&himr); ++ ++ RT_TRACE(_module_hci_ops_c_, _drv_notice_, ++ ("%s: enable SDIO HIMR = 0x%08X\n", __func__, pHalData->sdio_himr)); ++ ++ /* Update current system IMR settings */ ++ tmp = rtw_read32(padapter, REG_HSIMR); ++ rtw_write32(padapter, REG_HSIMR, tmp | pHalData->SysIntrMask); ++ ++ RT_TRACE(_module_hci_ops_c_, _drv_notice_, ++ ("%s: enable HSIMR = 0x%08X\n", __func__, pHalData->SysIntrMask)); ++ ++ /* */ ++ /* There are some C2H CMDs have been sent before system interrupt is enabled, e.g., C2H, CPWM. */ ++ /* So we need to clear all C2H events that FW has notified, otherwise FW won't schedule any commands anymore. */ ++ /* 2011.10.19. */ ++ /* */ ++ rtw_write8(padapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE); ++} ++ ++/* */ ++/* Description: */ ++/* Disable SDIO Host IMR configuration to mask unnecessary interrupt service. */ ++/* */ ++/* Assumption: */ ++/* Using SDIO Local register ONLY for configuration. */ ++/* */ ++/* Created by Roger, 2011.02.11. */ ++/* */ ++void DisableInterrupt8723BSdio(struct adapter *padapter) ++{ ++ __le32 himr; ++ ++ himr = cpu_to_le32(SDIO_HIMR_DISABLED); ++ sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&himr); ++} ++ ++/* */ ++/* Description: */ ++/* Using 0x100 to check the power status of FW. */ ++/* */ ++/* Assumption: */ ++/* Using SDIO Local register ONLY for configuration. */ ++/* */ ++/* Created by Isaac, 2013.09.10. */ ++/* */ ++u8 CheckIPSStatus(struct adapter *padapter) ++{ ++ DBG_871X("%s(): Read 0x100 = 0x%02x 0x86 = 0x%02x\n", __func__, ++ rtw_read8(padapter, 0x100), rtw_read8(padapter, 0x86)); ++ ++ if (rtw_read8(padapter, 0x100) == 0xEA) ++ return true; ++ else ++ return false; ++} ++ ++static struct recv_buf* sd_recv_rxfifo(struct adapter *padapter, u32 size) ++{ ++ u32 readsize, ret; ++ u8 *preadbuf; ++ struct recv_priv *precvpriv; ++ struct recv_buf *precvbuf; ++ ++ ++ /* Patch for some SDIO Host 4 bytes issue */ ++ /* ex. RK3188 */ ++ readsize = RND4(size); ++ ++ /* 3 1. alloc recvbuf */ ++ precvpriv = &padapter->recvpriv; ++ precvbuf = rtw_dequeue_recvbuf(&precvpriv->free_recv_buf_queue); ++ if (precvbuf == NULL) { ++ DBG_871X_LEVEL(_drv_err_, "%s: alloc recvbuf FAIL!\n", __func__); ++ return NULL; ++ } ++ ++ /* 3 2. alloc skb */ ++ if (precvbuf->pskb == NULL) { ++ SIZE_PTR tmpaddr = 0; ++ SIZE_PTR alignment = 0; ++ ++ precvbuf->pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); ++ ++ if (precvbuf->pskb) ++ { ++ precvbuf->pskb->dev = padapter->pnetdev; ++ ++ tmpaddr = (SIZE_PTR)precvbuf->pskb->data; ++ alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); ++ skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment)); ++ } ++ ++ if (precvbuf->pskb == NULL) { ++ DBG_871X("%s: alloc_skb fail! read =%d\n", __func__, readsize); ++ return NULL; ++ } ++ } ++ ++ /* 3 3. read data from rxfifo */ ++ preadbuf = precvbuf->pskb->data; ++ ret = sdio_read_port(&padapter->iopriv.intf, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf); ++ if (ret == _FAIL) { ++ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: read port FAIL!\n", __func__)); ++ return NULL; ++ } ++ ++ ++ /* 3 4. init recvbuf */ ++ precvbuf->len = size; ++ precvbuf->phead = precvbuf->pskb->head; ++ precvbuf->pdata = precvbuf->pskb->data; ++ skb_set_tail_pointer(precvbuf->pskb, size); ++ precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); ++ precvbuf->pend = skb_end_pointer(precvbuf->pskb); ++ ++ return precvbuf; ++} ++ ++static void sd_rxhandler(struct adapter *padapter, struct recv_buf *precvbuf) ++{ ++ struct recv_priv *precvpriv; ++ struct __queue *ppending_queue; ++ ++ precvpriv = &padapter->recvpriv; ++ ppending_queue = &precvpriv->recv_buf_pending_queue; ++ ++ /* 3 1. enqueue recvbuf */ ++ rtw_enqueue_recvbuf(precvbuf, ppending_queue); ++ ++ /* 3 2. schedule tasklet */ ++ tasklet_schedule(&precvpriv->recv_tasklet); ++} ++ ++void sd_int_dpc(struct adapter *padapter) ++{ ++ struct hal_com_data *phal; ++ struct dvobj_priv *dvobj; ++ struct intf_hdl * pintfhdl =&padapter->iopriv.intf; ++ struct pwrctrl_priv *pwrctl; ++ ++ ++ phal = GET_HAL_DATA(padapter); ++ dvobj = adapter_to_dvobj(padapter); ++ pwrctl = dvobj_to_pwrctl(dvobj); ++ ++ if (phal->sdio_hisr & SDIO_HISR_AVAL) ++ { ++ u8 freepage[4]; ++ ++ _sdio_local_read(padapter, SDIO_REG_FREE_TXPG, 4, freepage); ++ up(&(padapter->xmitpriv.xmit_sema)); ++ } ++ if (phal->sdio_hisr & SDIO_HISR_CPWM1) ++ { ++ struct reportpwrstate_parm report; ++ ++ u8 bcancelled; ++ _cancel_timer(&(pwrctl->pwr_rpwm_timer), &bcancelled); ++ ++ report.state = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_HCPWM1_8723B); ++ ++ /* cpwm_int_hdl(padapter, &report); */ ++ _set_workitem(&(pwrctl->cpwm_event)); ++ } ++ ++ if (phal->sdio_hisr & SDIO_HISR_TXERR) ++ { ++ u8 *status; ++ u32 addr; ++ ++ status = rtw_malloc(4); ++ if (status) ++ { ++ addr = REG_TXDMA_STATUS; ++ HalSdioGetCmdAddr8723BSdio(padapter, WLAN_IOREG_DEVICE_ID, addr, &addr); ++ _sd_read(pintfhdl, addr, 4, status); ++ _sd_write(pintfhdl, addr, 4, status); ++ DBG_8192C("%s: SDIO_HISR_TXERR (0x%08x)\n", __func__, le32_to_cpu(*(u32*)status)); ++ kfree(status); ++ } else { ++ DBG_8192C("%s: SDIO_HISR_TXERR, but can't allocate memory to read status!\n", __func__); ++ } ++ } ++ ++ if (phal->sdio_hisr & SDIO_HISR_TXBCNOK) ++ { ++ DBG_8192C("%s: SDIO_HISR_TXBCNOK\n", __func__); ++ } ++ ++ if (phal->sdio_hisr & SDIO_HISR_TXBCNERR) ++ { ++ DBG_8192C("%s: SDIO_HISR_TXBCNERR\n", __func__); ++ } ++#ifndef CONFIG_C2H_PACKET_EN ++ if (phal->sdio_hisr & SDIO_HISR_C2HCMD) ++ { ++ struct c2h_evt_hdr_88xx *c2h_evt; ++ ++ DBG_8192C("%s: C2H Command\n", __func__); ++ if ((c2h_evt = (struct c2h_evt_hdr_88xx*)rtw_zmalloc(16)) != NULL) { ++ if (rtw_hal_c2h_evt_read(padapter, (u8 *)c2h_evt) == _SUCCESS) { ++ if (c2h_id_filter_ccx_8723b((u8 *)c2h_evt)) { ++ /* Handle CCX report here */ ++ rtw_hal_c2h_handler(padapter, (u8 *)c2h_evt); ++ kfree((u8 *)c2h_evt); ++ } else { ++ rtw_c2h_wk_cmd(padapter, (u8 *)c2h_evt); ++ } ++ } ++ } else { ++ /* Error handling for malloc fail */ ++ if (rtw_cbuf_push(padapter->evtpriv.c2h_queue, (void*)NULL) != _SUCCESS) ++ DBG_871X("%s rtw_cbuf_push fail\n", __func__); ++ _set_workitem(&padapter->evtpriv.c2h_wk); ++ } ++ } ++#endif ++ ++ if (phal->sdio_hisr & SDIO_HISR_RXFOVW) ++ { ++ DBG_8192C("%s: Rx Overflow\n", __func__); ++ } ++ if (phal->sdio_hisr & SDIO_HISR_RXERR) ++ { ++ DBG_8192C("%s: Rx Error\n", __func__); ++ } ++ ++ if (phal->sdio_hisr & SDIO_HISR_RX_REQUEST) ++ { ++ struct recv_buf *precvbuf; ++ int alloc_fail_time = 0; ++ u32 hisr; ++ ++/* DBG_8192C("%s: RX Request, size =%d\n", __func__, phal->SdioRxFIFOSize); */ ++ phal->sdio_hisr ^= SDIO_HISR_RX_REQUEST; ++ do { ++ phal->SdioRxFIFOSize = SdioLocalCmd52Read2Byte(padapter, SDIO_REG_RX0_REQ_LEN); ++ if (phal->SdioRxFIFOSize != 0) ++ { ++ precvbuf = sd_recv_rxfifo(padapter, phal->SdioRxFIFOSize); ++ if (precvbuf) ++ sd_rxhandler(padapter, precvbuf); ++ else ++ { ++ alloc_fail_time++; ++ DBG_871X("precvbuf is Null for %d times because alloc memory failed\n", alloc_fail_time); ++ if (alloc_fail_time >= 10) ++ break; ++ } ++ phal->SdioRxFIFOSize = 0; ++ } ++ else ++ break; ++ ++ hisr = 0; ++ ReadInterrupt8723BSdio(padapter, &hisr); ++ hisr &= SDIO_HISR_RX_REQUEST; ++ if (!hisr) ++ break; ++ } while (1); ++ ++ if (alloc_fail_time == 10) ++ DBG_871X("exit because alloc memory failed more than 10 times\n"); ++ ++ } ++} ++ ++void sd_int_hdl(struct adapter *padapter) ++{ ++ struct hal_com_data *phal; ++ ++ ++ if ((padapter->bDriverStopped == true) || ++ (padapter->bSurpriseRemoved == true)) ++ return; ++ ++ phal = GET_HAL_DATA(padapter); ++ ++ phal->sdio_hisr = 0; ++ ReadInterrupt8723BSdio(padapter, &phal->sdio_hisr); ++ ++ if (phal->sdio_hisr & phal->sdio_himr) ++ { ++ u32 v32; ++ ++ phal->sdio_hisr &= phal->sdio_himr; ++ ++ /* clear HISR */ ++ v32 = phal->sdio_hisr & MASK_SDIO_HISR_CLEAR; ++ if (v32) { ++ SdioLocalCmd52Write4Byte(padapter, SDIO_REG_HISR, v32); ++ } ++ ++ sd_int_dpc(padapter); ++ } else { ++ RT_TRACE(_module_hci_ops_c_, _drv_err_, ++ ("%s: HISR(0x%08x) and HIMR(0x%08x) not match!\n", ++ __func__, phal->sdio_hisr, phal->sdio_himr)); ++ } ++} ++ ++/* */ ++/* Description: */ ++/* Query SDIO Local register to query current the number of Free TxPacketBuffer page. */ ++/* */ ++/* Assumption: */ ++/* 1. Running at PASSIVE_LEVEL */ ++/* 2. RT_TX_SPINLOCK is NOT acquired. */ ++/* */ ++/* Created by Roger, 2011.01.28. */ ++/* */ ++u8 HalQueryTxBufferStatus8723BSdio(struct adapter *padapter) ++{ ++ struct hal_com_data *phal; ++ u32 NumOfFreePage; ++ /* _irqL irql; */ ++ ++ ++ phal = GET_HAL_DATA(padapter); ++ ++ NumOfFreePage = SdioLocalCmd53Read4Byte(padapter, SDIO_REG_FREE_TXPG); ++ ++ /* spin_lock_bh(&phal->SdioTxFIFOFreePageLock); */ ++ memcpy(phal->SdioTxFIFOFreePage, &NumOfFreePage, 4); ++ RT_TRACE(_module_hci_ops_c_, _drv_notice_, ++ ("%s: Free page for HIQ(%#x), MIDQ(%#x), LOWQ(%#x), PUBQ(%#x)\n", ++ __func__, ++ phal->SdioTxFIFOFreePage[HI_QUEUE_IDX], ++ phal->SdioTxFIFOFreePage[MID_QUEUE_IDX], ++ phal->SdioTxFIFOFreePage[LOW_QUEUE_IDX], ++ phal->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX])); ++ /* spin_unlock_bh(&phal->SdioTxFIFOFreePageLock); */ ++ ++ return true; ++} ++ ++/* */ ++/* Description: */ ++/* Query SDIO Local register to get the current number of TX OQT Free Space. */ ++/* */ ++u8 HalQueryTxOQTBufferStatus8723BSdio(struct adapter *padapter) ++{ ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ pHalData->SdioTxOQTFreeSpace = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_OQT_FREE_PG); ++ return true; ++} ++ ++#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) ++u8 RecvOnePkt(struct adapter *padapter, u32 size) ++{ ++ struct recv_buf *precvbuf; ++ struct dvobj_priv *psddev; ++ PSDIO_DATA psdio_data; ++ struct sdio_func *func; ++ ++ u8 res = false; ++ ++ DBG_871X("+%s: size: %d+\n", __func__, size); ++ ++ if (padapter == NULL) { ++ DBG_871X(KERN_ERR "%s: padapter is NULL!\n", __func__); ++ return false; ++ } ++ ++ psddev = adapter_to_dvobj(padapter); ++ psdio_data = &psddev->intf_data; ++ func = psdio_data->func; ++ ++ if (size) { ++ sdio_claim_host(func); ++ precvbuf = sd_recv_rxfifo(padapter, size); ++ ++ if (precvbuf) { ++ /* printk("Completed Recv One Pkt.\n"); */ ++ sd_rxhandler(padapter, precvbuf); ++ res = true; ++ } else { ++ res = false; ++ } ++ sdio_release_host(func); ++ } ++ DBG_871X("-%s-\n", __func__); ++ return res; ++} ++#endif /* CONFIG_WOWLAN */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/autoconf.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/autoconf.h +--- linux-4.3/3rdparty/rtl8723bs/include/autoconf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/autoconf.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,67 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++ ++/* ++ * Automatically generated C config: don't edit ++ */ ++ ++/* ++ * Functions Config ++ */ ++/* define CONFIG_DEBUG_CFG80211 */ ++ ++/* ++ * Auto Config Section ++ */ ++#define LPS_RPWM_WAIT_MS 300 ++#ifndef DISABLE_BB_RF ++#define DISABLE_BB_RF 0 ++#endif ++ ++#if DISABLE_BB_RF ++ #define HAL_MAC_ENABLE 0 ++ #define HAL_BB_ENABLE 0 ++ #define HAL_RF_ENABLE 0 ++#else ++ #define HAL_MAC_ENABLE 1 ++ #define HAL_BB_ENABLE 1 ++ #define HAL_RF_ENABLE 1 ++#endif ++ ++/* ++ * Platform dependent ++ */ ++#define WAKEUP_GPIO_IDX 12 /* WIFI Chip Side */ ++#ifdef CONFIG_WOWLAN ++#define CONFIG_GTK_OL ++#endif /* CONFIG_WOWLAN */ ++ ++/* ++ * Debug Related Config ++ */ ++#undef CONFIG_DEBUG ++ ++#ifdef CONFIG_DEBUG ++#define DBG 1 /* for ODM & BTCOEX debug */ ++/*#define CONFIG_DEBUG_RTL871X */ ++#else /* !CONFIG_DEBUG */ ++#define DBG 0 /* for ODM & BTCOEX debug */ ++#endif /* !CONFIG_DEBUG */ ++ ++#define CONFIG_PROC_DEBUG ++ ++/* define DBG_XMIT_BUF */ ++/* define DBG_XMIT_BUF_EXT */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/basic_types.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/basic_types.h +--- linux-4.3/3rdparty/rtl8723bs/include/basic_types.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/basic_types.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,209 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __BASIC_TYPES_H__ ++#define __BASIC_TYPES_H__ ++ ++ ++#define SUCCESS 0 ++#define FAIL (-1) ++ ++#include ++ ++typedef signed int sint; ++ ++#define FIELD_OFFSET(s, field) ((__kernel_ssize_t)&((s*)(0))->field) ++ ++#define SIZE_PTR __kernel_size_t ++#define SSIZE_PTR __kernel_ssize_t ++ ++/* port from fw by thomas */ ++/* TODO: Belows are Sync from SD7-Driver. It is necessary to check correctness */ ++ ++/* ++ *Call endian free function when ++ * 1. Read/write packet content. ++ * 2. Before write integer to IO. ++ * 3. After read integer from IO. ++*/ ++ ++/* */ ++/* Byte Swapping routine. */ ++/* */ ++#define EF1Byte (u8) ++#define EF2Byte le16_to_cpu ++#define EF4Byte le32_to_cpu ++ ++/* Convert little data endian to host ordering */ ++#define EF1BYTE(_val) \ ++ ((u8)(_val)) ++#define EF2BYTE(_val) \ ++ (le16_to_cpu(_val)) ++#define EF4BYTE(_val) \ ++ (le32_to_cpu(_val)) ++ ++/* Read data from memory */ ++#define READEF1BYTE(_ptr) \ ++ EF1BYTE(*((u8 *)(_ptr))) ++/* Read le16 data from memory and convert to host ordering */ ++#define READEF2BYTE(_ptr) \ ++ EF2BYTE(*(_ptr)) ++#define READEF4BYTE(_ptr) \ ++ EF4BYTE(*(_ptr)) ++ ++/* Write data to memory */ ++#define WRITEEF1BYTE(_ptr, _val) \ ++ do { \ ++ (*((u8 *)(_ptr))) = EF1BYTE(_val); \ ++ } while (0) ++/* Write le data to memory in host ordering */ ++#define WRITEEF2BYTE(_ptr, _val) \ ++ do { \ ++ (*((u16 *)(_ptr))) = EF2BYTE(_val); \ ++ } while (0) ++ ++#define WRITEEF4BYTE(_ptr, _val) \ ++ do { \ ++ (*((u32 *)(_ptr))) = EF2BYTE(_val); \ ++ } while (0) ++ ++/* Create a bit mask ++ * Examples: ++ * BIT_LEN_MASK_32(0) => 0x00000000 ++ * BIT_LEN_MASK_32(1) => 0x00000001 ++ * BIT_LEN_MASK_32(2) => 0x00000003 ++ * BIT_LEN_MASK_32(32) => 0xFFFFFFFF ++ */ ++#define BIT_LEN_MASK_32(__bitlen) \ ++ (0xFFFFFFFF >> (32 - (__bitlen))) ++#define BIT_LEN_MASK_16(__bitlen) \ ++ (0xFFFF >> (16 - (__bitlen))) ++#define BIT_LEN_MASK_8(__bitlen) \ ++ (0xFF >> (8 - (__bitlen))) ++ ++/* Create an offset bit mask ++ * Examples: ++ * BIT_OFFSET_LEN_MASK_32(0, 2) => 0x00000003 ++ * BIT_OFFSET_LEN_MASK_32(16, 2) => 0x00030000 ++ */ ++#define BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen) \ ++ (BIT_LEN_MASK_32(__bitlen) << (__bitoffset)) ++#define BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen) \ ++ (BIT_LEN_MASK_16(__bitlen) << (__bitoffset)) ++#define BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen) \ ++ (BIT_LEN_MASK_8(__bitlen) << (__bitoffset)) ++ ++/*Description: ++ * Return 4-byte value in host byte ordering from ++ * 4-byte pointer in little-endian system. ++ */ ++#define LE_P4BYTE_TO_HOST_4BYTE(__pstart) \ ++ (EF4BYTE(*((__le32 *)(__pstart)))) ++#define LE_P2BYTE_TO_HOST_2BYTE(__pstart) \ ++ (EF2BYTE(*((__le16 *)(__pstart)))) ++#define LE_P1BYTE_TO_HOST_1BYTE(__pstart) \ ++ (EF1BYTE(*((u8 *)(__pstart)))) ++ ++/* */ ++/* Description: */ ++/* Translate subfield (continuous bits in little-endian) of 4-byte value in litten byte to */ ++/* 4-byte value in host byte ordering. */ ++/* */ ++#define LE_BITS_TO_4BYTE(__pstart, __bitoffset, __bitlen) \ ++ (\ ++ (LE_P4BYTE_TO_HOST_4BYTE(__pstart) >> (__bitoffset)) & \ ++ BIT_LEN_MASK_32(__bitlen) \ ++ ) ++#define LE_BITS_TO_2BYTE(__pstart, __bitoffset, __bitlen) \ ++ (\ ++ (LE_P2BYTE_TO_HOST_2BYTE(__pstart) >> (__bitoffset)) & \ ++ BIT_LEN_MASK_16(__bitlen) \ ++ ) ++#define LE_BITS_TO_1BYTE(__pstart, __bitoffset, __bitlen) \ ++ (\ ++ (LE_P1BYTE_TO_HOST_1BYTE(__pstart) >> (__bitoffset)) & \ ++ BIT_LEN_MASK_8(__bitlen) \ ++ ) ++ ++/* */ ++/* Description: */ ++/* Mask subfield (continuous bits in little-endian) of 4-byte value in litten byte oredering */ ++/* and return the result in 4-byte value in host byte ordering. */ ++/* */ ++#define LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) \ ++ (\ ++ LE_P4BYTE_TO_HOST_4BYTE(__pstart) & \ ++ (~BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)) \ ++ ) ++#define LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) \ ++ (\ ++ LE_P2BYTE_TO_HOST_2BYTE(__pstart) & \ ++ (~BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen)) \ ++ ) ++#define LE_BITS_CLEARED_TO_1BYTE(__pstart, __bitoffset, __bitlen) \ ++ (\ ++ LE_P1BYTE_TO_HOST_1BYTE(__pstart) & \ ++ (~BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen)) \ ++ ) ++ ++/* */ ++/* Description: */ ++/* Set subfield of little-endian 4-byte value to specified value. */ ++/* */ ++#define SET_BITS_TO_LE_4BYTE(__pstart, __bitoffset, __bitlen, __val) \ ++ *((u32 *)(__pstart)) = \ ++ ( \ ++ LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) | \ ++ ((((u32)__val) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset)) \ ++ ) ++ ++#define SET_BITS_TO_LE_2BYTE(__pstart, __bitoffset, __bitlen, __val) \ ++ *((u16 *)(__pstart)) = \ ++ ( \ ++ LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) | \ ++ ((((u16)__val) & BIT_LEN_MASK_16(__bitlen)) << (__bitoffset)) \ ++ ); ++ ++#define SET_BITS_TO_LE_1BYTE(__pstart, __bitoffset, __bitlen, __val) \ ++ *((u8 *)(__pstart)) = EF1BYTE \ ++ ( \ ++ LE_BITS_CLEARED_TO_1BYTE(__pstart, __bitoffset, __bitlen) | \ ++ ((((u8)__val) & BIT_LEN_MASK_8(__bitlen)) << (__bitoffset)) \ ++ ) ++ ++#define LE_BITS_CLEARED_TO_1BYTE_8BIT(__pStart, __BitOffset, __BitLen) \ ++ (\ ++ LE_P1BYTE_TO_HOST_1BYTE(__pStart) \ ++ ) ++ ++#define SET_BITS_TO_LE_1BYTE_8BIT(__pStart, __BitOffset, __BitLen, __Value) \ ++{ \ ++ *((u8 *)(__pStart)) = \ ++ EF1Byte(\ ++ LE_BITS_CLEARED_TO_1BYTE_8BIT(__pStart, __BitOffset, __BitLen) \ ++ | \ ++ ((u8)__Value) \ ++ ); \ ++} ++ ++/* Get the N-bytes aligment offset from the current length */ ++#define N_BYTE_ALIGMENT(__Value, __Aligment) ((__Aligment == 1) ? (__Value) : (((__Value + __Aligment - 1) / __Aligment) * __Aligment)) ++ ++#define TEST_FLAG(__Flag, __testFlag) (((__Flag) & (__testFlag)) != 0) ++#define SET_FLAG(__Flag, __setFlag) ((__Flag) |= __setFlag) ++#define CLEAR_FLAG(__Flag, __clearFlag) ((__Flag) &= ~(__clearFlag)) ++#define CLEAR_FLAGS(__Flag) ((__Flag) = 0) ++#define TEST_FLAGS(__Flag, __testFlags) (((__Flag) & (__testFlags)) == (__testFlags)) ++ ++#endif /* __BASIC_TYPES_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/cmd_osdep.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/cmd_osdep.h +--- linux-4.3/3rdparty/rtl8723bs/include/cmd_osdep.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/cmd_osdep.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,26 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __CMD_OSDEP_H_ ++#define __CMD_OSDEP_H_ ++ ++ ++extern sint _rtw_init_cmd_priv (struct cmd_priv *pcmdpriv); ++extern sint _rtw_init_evt_priv(struct evt_priv *pevtpriv); ++extern void _rtw_free_evt_priv (struct evt_priv *pevtpriv); ++extern void _rtw_free_cmd_priv (struct cmd_priv *pcmdpriv); ++extern sint _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj); ++extern struct cmd_obj *_rtw_dequeue_cmd(struct __queue *queue); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/drv_conf.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/drv_conf.h +--- linux-4.3/3rdparty/rtl8723bs/include/drv_conf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/drv_conf.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,37 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __DRV_CONF_H__ ++#define __DRV_CONF_H__ ++#include "autoconf.h" ++ ++//About USB VENDOR REQ ++#if defined(CONFIG_USB_VENDOR_REQ_BUFFER_PREALLOC) && !defined(CONFIG_USB_VENDOR_REQ_MUTEX) ++ #warning "define CONFIG_USB_VENDOR_REQ_MUTEX for CONFIG_USB_VENDOR_REQ_BUFFER_PREALLOC automatically" ++ #define CONFIG_USB_VENDOR_REQ_MUTEX ++#endif ++#if defined(CONFIG_VENDOR_REQ_RETRY) && !defined(CONFIG_USB_VENDOR_REQ_MUTEX) ++ #warning "define CONFIG_USB_VENDOR_REQ_MUTEX for CONFIG_VENDOR_REQ_RETRY automatically" ++ #define CONFIG_USB_VENDOR_REQ_MUTEX ++#endif ++ ++#define DYNAMIC_CAMID_ALLOC ++ ++#ifndef CONFIG_RTW_HIQ_FILTER ++ #define CONFIG_RTW_HIQ_FILTER 1 ++#endif ++ ++//#include ++ ++#endif // __DRV_CONF_H__ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/drv_types.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/drv_types.h +--- linux-4.3/3rdparty/rtl8723bs/include/drv_types.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/drv_types.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,720 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++/*------------------------------------------------------------------------------- ++ ++ For type defines and data structure defines ++ ++--------------------------------------------------------------------------------*/ ++ ++ ++#ifndef __DRV_TYPES_H__ ++#define __DRV_TYPES_H__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++enum _NIC_VERSION { ++ ++ RTL8711_NIC, ++ RTL8712_NIC, ++ RTL8713_NIC, ++ RTL8716_NIC ++ ++}; ++ ++#include ++ ++#include ++ ++#ifdef CONFIG_INTEL_WIDI ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ioctl_cfg80211.h" ++ ++#include ++#include ++#include ++ ++#define SPEC_DEV_ID_NONE BIT(0) ++#define SPEC_DEV_ID_DISABLE_HT BIT(1) ++#define SPEC_DEV_ID_ENABLE_PS BIT(2) ++#define SPEC_DEV_ID_RF_CONFIG_1T1R BIT(3) ++#define SPEC_DEV_ID_RF_CONFIG_2T2R BIT(4) ++#define SPEC_DEV_ID_ASSIGN_IFNAME BIT(5) ++ ++struct specific_device_id{ ++ ++ u32 flags; ++ ++ u16 idVendor; ++ u16 idProduct; ++ ++}; ++ ++struct registry_priv ++{ ++ u8 chip_version; ++ u8 rfintfs; ++ u8 lbkmode; ++ u8 hci; ++ struct ndis_802_11_ssid ssid; ++ u8 network_mode; /* infra, ad-hoc, auto */ ++ u8 channel;/* ad-hoc support requirement */ ++ u8 wireless_mode;/* A, B, G, auto */ ++ u8 scan_mode;/* active, passive */ ++ u8 radio_enable; ++ u8 preamble;/* long, short, auto */ ++ u8 vrtl_carrier_sense;/* Enable, Disable, Auto */ ++ u8 vcs_type;/* RTS/CTS, CTS-to-self */ ++ u16 rts_thresh; ++ u16 frag_thresh; ++ u8 adhoc_tx_pwr; ++ u8 soft_ap; ++ u8 power_mgnt; ++ u8 ips_mode; ++ u8 smart_ps; ++ u8 usb_rxagg_mode; ++ u8 long_retry_lmt; ++ u8 short_retry_lmt; ++ u16 busy_thresh; ++ u8 ack_policy; ++ u8 mp_dm; ++ u8 software_encrypt; ++ u8 software_decrypt; ++ u8 acm_method; ++ /* UAPSD */ ++ u8 wmm_enable; ++ u8 uapsd_enable; ++ u8 uapsd_max_sp; ++ u8 uapsd_acbk_en; ++ u8 uapsd_acbe_en; ++ u8 uapsd_acvi_en; ++ u8 uapsd_acvo_en; ++ ++ struct wlan_bssid_ex dev_network; ++ ++ u8 ht_enable; ++ /* 0: 20 MHz, 1: 40 MHz, 2: 80 MHz, 3: 160MHz */ ++ /* 2.4G use bit 0 ~ 3, 5G use bit 4 ~ 7 */ ++ /* 0x21 means enable 2.4G 40MHz & 5G 80MHz */ ++ u8 bw_mode; ++ u8 ampdu_enable;/* for tx */ ++ u8 rx_stbc; ++ u8 ampdu_amsdu;/* A-MPDU Supports A-MSDU is permitted */ ++ /* Short GI support Bit Map */ ++ /* BIT0 - 20MHz, 1: support, 0: non-support */ ++ /* BIT1 - 40MHz, 1: support, 0: non-support */ ++ /* BIT2 - 80MHz, 1: support, 0: non-support */ ++ /* BIT3 - 160MHz, 1: support, 0: non-support */ ++ u8 short_gi; ++ /* BIT0: Enable VHT LDPC Rx, BIT1: Enable VHT LDPC Tx, BIT4: Enable HT LDPC Rx, BIT5: Enable HT LDPC Tx */ ++ u8 ldpc_cap; ++ /* BIT0: Enable VHT STBC Rx, BIT1: Enable VHT STBC Tx, BIT4: Enable HT STBC Rx, BIT5: Enable HT STBC Tx */ ++ u8 stbc_cap; ++ /* BIT0: Enable VHT Beamformer, BIT1: Enable VHT Beamformee, BIT4: Enable HT Beamformer, BIT5: Enable HT Beamformee */ ++ u8 beamform_cap; ++ ++ u8 lowrate_two_xmit; ++ ++ u8 rf_config ; ++ u8 low_power ; ++ ++ u8 wifi_spec;/* !turbo_mode */ ++ ++ u8 channel_plan; ++ ++ u8 btcoex; ++ u8 bt_iso; ++ u8 bt_sco; ++ u8 bt_ampdu; ++ s8 ant_num; ++ ++ bool bAcceptAddbaReq; ++ ++ u8 antdiv_cfg; ++ u8 antdiv_type; ++ ++ u8 usbss_enable;/* 0:disable, 1:enable */ ++ u8 hwpdn_mode;/* 0:disable, 1:enable, 2:decide by EFUSE config */ ++ u8 hwpwrp_detect;/* 0:disable, 1:enable */ ++ ++ u8 hw_wps_pbc;/* 0:disable, 1:enable */ ++ ++ u8 max_roaming_times; /* the max number driver will try to roaming */ ++ ++ u8 enable80211d; ++ ++ u8 ifname[16]; ++ ++ u8 notch_filter; ++ ++ /* define for tx power adjust */ ++ u8 RegEnableTxPowerLimit; ++ u8 RegEnableTxPowerByRate; ++ u8 RegPowerBase; ++ u8 RegPwrTblSel; ++ s8 TxBBSwing_2G; ++ s8 TxBBSwing_5G; ++ u8 AmplifierType_2G; ++ u8 AmplifierType_5G; ++ u8 bEn_RFE; ++ u8 RFE_Type; ++ u8 check_fw_ps; ++ ++#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE ++ u8 load_phy_file; ++ u8 RegDecryptCustomFile; ++#endif ++ ++#ifdef CONFIG_MULTI_VIR_IFACES ++ u8 ext_iface_num;/* primary/secondary iface is excluded */ ++#endif ++ u8 qos_opt_enable; ++ ++ u8 hiq_filter; ++}; ++ ++ ++/* For registry parameters */ ++#define RGTRY_OFT(field) ((u32)FIELD_OFFSET(struct registry_priv, field)) ++#define RGTRY_SZ(field) sizeof(((struct registry_priv*) 0)->field) ++#define BSSID_OFT(field) ((u32)FIELD_OFFSET(struct wlan_bssid_ex, field)) ++#define BSSID_SZ(field) sizeof(((struct wlan_bssid_ex *) 0)->field) ++ ++#include ++#define INTF_DATA SDIO_DATA ++ ++#define is_primary_adapter(adapter) (1) ++#define get_iface_type(adapter) (IFACE_PORT0) ++#define GET_PRIMARY_ADAPTER(padapter) (((struct adapter *)padapter)->dvobj->if1) ++#define GET_IFACE_NUMS(padapter) (((struct adapter *)padapter)->dvobj->iface_nums) ++#define GET_ADAPTER(padapter, iface_id) (((struct adapter *)padapter)->dvobj->padapters[iface_id]) ++ ++#ifdef CONFIG_DBG_COUNTER ++ ++struct rx_logs { ++ u32 intf_rx; ++ u32 intf_rx_err_recvframe; ++ u32 intf_rx_err_skb; ++ u32 intf_rx_report; ++ u32 core_rx; ++ u32 core_rx_pre; ++ u32 core_rx_pre_ver_err; ++ u32 core_rx_pre_mgmt; ++ u32 core_rx_pre_mgmt_err_80211w; ++ u32 core_rx_pre_mgmt_err; ++ u32 core_rx_pre_ctrl; ++ u32 core_rx_pre_ctrl_err; ++ u32 core_rx_pre_data; ++ u32 core_rx_pre_data_wapi_seq_err; ++ u32 core_rx_pre_data_wapi_key_err; ++ u32 core_rx_pre_data_handled; ++ u32 core_rx_pre_data_err; ++ u32 core_rx_pre_data_unknown; ++ u32 core_rx_pre_unknown; ++ u32 core_rx_enqueue; ++ u32 core_rx_dequeue; ++ u32 core_rx_post; ++ u32 core_rx_post_decrypt; ++ u32 core_rx_post_decrypt_wep; ++ u32 core_rx_post_decrypt_tkip; ++ u32 core_rx_post_decrypt_aes; ++ u32 core_rx_post_decrypt_wapi; ++ u32 core_rx_post_decrypt_hw; ++ u32 core_rx_post_decrypt_unknown; ++ u32 core_rx_post_decrypt_err; ++ u32 core_rx_post_defrag_err; ++ u32 core_rx_post_portctrl_err; ++ u32 core_rx_post_indicate; ++ u32 core_rx_post_indicate_in_oder; ++ u32 core_rx_post_indicate_reoder; ++ u32 core_rx_post_indicate_err; ++ u32 os_indicate; ++ u32 os_indicate_ap_mcast; ++ u32 os_indicate_ap_forward; ++ u32 os_indicate_ap_self; ++ u32 os_indicate_err; ++ u32 os_netif_ok; ++ u32 os_netif_err; ++}; ++ ++struct tx_logs { ++ u32 os_tx; ++ u32 os_tx_err_up; ++ u32 os_tx_err_xmit; ++ u32 os_tx_m2u; ++ u32 os_tx_m2u_ignore_fw_linked; ++ u32 os_tx_m2u_ignore_self; ++ u32 os_tx_m2u_entry; ++ u32 os_tx_m2u_entry_err_xmit; ++ u32 os_tx_m2u_entry_err_skb; ++ u32 os_tx_m2u_stop; ++ u32 core_tx; ++ u32 core_tx_err_pxmitframe; ++ u32 core_tx_err_brtx; ++ u32 core_tx_upd_attrib; ++ u32 core_tx_upd_attrib_adhoc; ++ u32 core_tx_upd_attrib_sta; ++ u32 core_tx_upd_attrib_ap; ++ u32 core_tx_upd_attrib_unknown; ++ u32 core_tx_upd_attrib_dhcp; ++ u32 core_tx_upd_attrib_icmp; ++ u32 core_tx_upd_attrib_active; ++ u32 core_tx_upd_attrib_err_ucast_sta; ++ u32 core_tx_upd_attrib_err_ucast_ap_link; ++ u32 core_tx_upd_attrib_err_sta; ++ u32 core_tx_upd_attrib_err_link; ++ u32 core_tx_upd_attrib_err_sec; ++ u32 core_tx_ap_enqueue_warn_fwstate; ++ u32 core_tx_ap_enqueue_warn_sta; ++ u32 core_tx_ap_enqueue_warn_nosta; ++ u32 core_tx_ap_enqueue_warn_link; ++ u32 core_tx_ap_enqueue_warn_trigger; ++ u32 core_tx_ap_enqueue_mcast; ++ u32 core_tx_ap_enqueue_ucast; ++ u32 core_tx_ap_enqueue; ++ u32 intf_tx; ++ u32 intf_tx_pending_ac; ++ u32 intf_tx_pending_fw_under_survey; ++ u32 intf_tx_pending_fw_under_linking; ++ u32 intf_tx_pending_xmitbuf; ++ u32 intf_tx_enqueue; ++ u32 core_tx_enqueue; ++ u32 core_tx_enqueue_class; ++ u32 core_tx_enqueue_class_err_sta; ++ u32 core_tx_enqueue_class_err_nosta; ++ u32 core_tx_enqueue_class_err_fwlink; ++ u32 intf_tx_direct; ++ u32 intf_tx_direct_err_coalesce; ++ u32 intf_tx_dequeue; ++ u32 intf_tx_dequeue_err_coalesce; ++ u32 intf_tx_dump_xframe; ++ u32 intf_tx_dump_xframe_err_txdesc; ++ u32 intf_tx_dump_xframe_err_port; ++}; ++ ++struct int_logs { ++ u32 all; ++ u32 err; ++ u32 tbdok; ++ u32 tbder; ++ u32 bcnderr; ++ u32 bcndma; ++ u32 bcndma_e; ++ u32 rx; ++ u32 rx_rdu; ++ u32 rx_fovw; ++ u32 txfovw; ++ u32 mgntok; ++ u32 highdok; ++ u32 bkdok; ++ u32 bedok; ++ u32 vidok; ++ u32 vodok; ++}; ++ ++#endif /* CONFIG_DBG_COUNTER */ ++ ++struct debug_priv { ++ u32 dbg_sdio_free_irq_error_cnt; ++ u32 dbg_sdio_alloc_irq_error_cnt; ++ u32 dbg_sdio_free_irq_cnt; ++ u32 dbg_sdio_alloc_irq_cnt; ++ u32 dbg_sdio_deinit_error_cnt; ++ u32 dbg_sdio_init_error_cnt; ++ u32 dbg_suspend_error_cnt; ++ u32 dbg_suspend_cnt; ++ u32 dbg_resume_cnt; ++ u32 dbg_resume_error_cnt; ++ u32 dbg_deinit_fail_cnt; ++ u32 dbg_carddisable_cnt; ++ u32 dbg_carddisable_error_cnt; ++ u32 dbg_ps_insuspend_cnt; ++ u32 dbg_dev_unload_inIPS_cnt; ++ u32 dbg_wow_leave_ps_fail_cnt; ++ u32 dbg_scan_pwr_state_cnt; ++ u32 dbg_downloadfw_pwr_state_cnt; ++ u32 dbg_fw_read_ps_state_fail_cnt; ++ u32 dbg_leave_ips_fail_cnt; ++ u32 dbg_leave_lps_fail_cnt; ++ u32 dbg_h2c_leave32k_fail_cnt; ++ u32 dbg_diswow_dload_fw_fail_cnt; ++ u32 dbg_enwow_dload_fw_fail_cnt; ++ u32 dbg_ips_drvopen_fail_cnt; ++ u32 dbg_poll_fail_cnt; ++ u32 dbg_rpwm_toogle_cnt; ++ u32 dbg_rpwm_timeout_fail_cnt; ++ u64 dbg_rx_fifo_last_overflow; ++ u64 dbg_rx_fifo_curr_overflow; ++ u64 dbg_rx_fifo_diff_overflow; ++ u64 dbg_rx_ampdu_drop_count; ++ u64 dbg_rx_ampdu_forced_indicate_count; ++ u64 dbg_rx_ampdu_loss_count; ++ u64 dbg_rx_dup_mgt_frame_drop_count; ++ u64 dbg_rx_ampdu_window_shift_cnt; ++}; ++ ++struct rtw_traffic_statistics { ++ /* tx statistics */ ++ u64 tx_bytes; ++ u64 tx_pkts; ++ u64 tx_drop; ++ u64 cur_tx_bytes; ++ u64 last_tx_bytes; ++ u32 cur_tx_tp; /* Tx throughput in MBps. */ ++ ++ /* rx statistics */ ++ u64 rx_bytes; ++ u64 rx_pkts; ++ u64 rx_drop; ++ u64 cur_rx_bytes; ++ u64 last_rx_bytes; ++ u32 cur_rx_tp; /* Rx throughput in MBps. */ ++}; ++ ++struct cam_ctl_t { ++ _lock lock; ++ u64 bitmap; ++}; ++ ++struct cam_entry_cache { ++ u16 ctrl; ++ u8 mac[ETH_ALEN]; ++ u8 key[16]; ++}; ++ ++#define KEY_FMT "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" ++#define KEY_ARG(x) ((u8 *)(x))[0], ((u8 *)(x))[1], ((u8 *)(x))[2], ((u8 *)(x))[3], ((u8 *)(x))[4], ((u8 *)(x))[5], \ ++ ((u8 *)(x))[6], ((u8 *)(x))[7], ((u8 *)(x))[8], ((u8 *)(x))[9], ((u8 *)(x))[10], ((u8 *)(x))[11], \ ++ ((u8 *)(x))[12], ((u8 *)(x))[13], ((u8 *)(x))[14], ((u8 *)(x))[15] ++ ++struct dvobj_priv ++{ ++ /*-------- below is common data --------*/ ++ struct adapter *if1; /* PRIMARY_ADAPTER */ ++ struct adapter *if2; /* SECONDARY_ADAPTER */ ++ ++ s32 processing_dev_remove; ++ ++ struct debug_priv drv_dbg; ++ ++ /* for local/global synchronization */ ++ /* */ ++ _lock lock; ++ int macid[NUM_STA]; ++ ++ _mutex hw_init_mutex; ++ _mutex h2c_fwcmd_mutex; ++ _mutex setch_mutex; ++ _mutex setbw_mutex; ++ ++ unsigned char oper_channel; /* saved channel info when call set_channel_bw */ ++ unsigned char oper_bwmode; ++ unsigned char oper_ch_offset;/* PRIME_CHNL_OFFSET */ ++ unsigned long on_oper_ch_time; ++ ++ struct adapter *padapters; ++ ++ struct cam_ctl_t cam_ctl; ++ struct cam_entry_cache cam_cache[TOTAL_CAM_ENTRY]; ++ ++ /* For 92D, DMDP have 2 interface. */ ++ u8 InterfaceNumber; ++ u8 NumInterfaces; ++ ++ /* In /Out Pipe information */ ++ int RtInPipe[2]; ++ int RtOutPipe[4]; ++ u8 Queue2Pipe[HW_QUEUE_ENTRY];/* for out pipe mapping */ ++ ++ u8 irq_alloc; ++ atomic_t continual_io_error; ++ ++ atomic_t disable_func; ++ ++ struct pwrctrl_priv pwrctl_priv; ++ ++ struct rtw_traffic_statistics traffic_stat; ++ ++/*-------- below is for SDIO INTERFACE --------*/ ++ ++#ifdef INTF_DATA ++ INTF_DATA intf_data; ++#endif ++}; ++ ++#define dvobj_to_pwrctl(dvobj) (&(dvobj->pwrctl_priv)) ++#define pwrctl_to_dvobj(pwrctl) container_of(pwrctl, struct dvobj_priv, pwrctl_priv) ++ ++__inline static struct device *dvobj_to_dev(struct dvobj_priv *dvobj) ++{ ++ /* todo: get interface type from dvobj and the return the dev accordingly */ ++#ifdef RTW_DVOBJ_CHIP_HW_TYPE ++#endif ++ ++ return &dvobj->intf_data.func->dev; ++} ++ ++struct adapter *dvobj_get_port0_adapter(struct dvobj_priv *dvobj); ++ ++enum _IFACE_TYPE { ++ IFACE_PORT0, /* mapping to port0 for C/D series chips */ ++ IFACE_PORT1, /* mapping to port1 for C/D series chip */ ++ MAX_IFACE_PORT, ++}; ++ ++enum ADAPTER_TYPE { ++ PRIMARY_ADAPTER, ++ SECONDARY_ADAPTER, ++ MAX_ADAPTER = 0xFF, ++}; ++ ++typedef enum _DRIVER_STATE{ ++ DRIVER_NORMAL = 0, ++ DRIVER_DISAPPEAR = 1, ++ DRIVER_REPLACE_DONGLE = 2, ++}DRIVER_STATE; ++ ++struct adapter { ++ int DriverState;/* for disable driver using module, use dongle to replace module. */ ++ int pid[3];/* process id from UI, 0:wps, 1:hostapd, 2:dhcpcd */ ++ int bDongle;/* build-in module or external dongle */ ++ ++ struct dvobj_priv *dvobj; ++ struct mlme_priv mlmepriv; ++ struct mlme_ext_priv mlmeextpriv; ++ struct cmd_priv cmdpriv; ++ struct evt_priv evtpriv; ++ /* struct io_queue *pio_queue; */ ++ struct io_priv iopriv; ++ struct xmit_priv xmitpriv; ++ struct recv_priv recvpriv; ++ struct sta_priv stapriv; ++ struct security_priv securitypriv; ++ _lock security_key_mutex; /* add for CONFIG_IEEE80211W, none 11w also can use */ ++ struct registry_priv registrypriv; ++ struct eeprom_priv eeprompriv; ++ ++ struct hostapd_priv *phostapdpriv; ++ ++ u32 setband; ++ ++ void * HalData; ++ u32 hal_data_sz; ++ struct hal_ops HalFunc; ++ ++ s32 bDriverStopped; ++ s32 bSurpriseRemoved; ++ s32 bCardDisableWOHSM; ++ ++ u32 IsrContent; ++ u32 ImrContent; ++ ++ u8 EepromAddressSize; ++ u8 hw_init_completed; ++ u8 bDriverIsGoingToUnload; ++ u8 init_adpt_in_progress; ++ u8 bHaltInProgress; ++ ++ void *cmdThread; ++ void *evtThread; ++ void *xmitThread; ++ void *recvThread; ++ ++ u32 (*intf_init)(struct dvobj_priv *dvobj); ++ void (*intf_deinit)(struct dvobj_priv *dvobj); ++ int (*intf_alloc_irq)(struct dvobj_priv *dvobj); ++ void (*intf_free_irq)(struct dvobj_priv *dvobj); ++ ++ ++ void (*intf_start)(struct adapter * adapter); ++ void (*intf_stop)(struct adapter * adapter); ++ ++ _nic_hdl pnetdev; ++ char old_ifname[IFNAMSIZ]; ++ ++ /* used by rtw_rereg_nd_name related function */ ++ struct rereg_nd_name_data { ++ _nic_hdl old_pnetdev; ++ char old_ifname[IFNAMSIZ]; ++ u8 old_ips_mode; ++ u8 old_bRegUseLed; ++ } rereg_nd_name_priv; ++ ++ int bup; ++ struct net_device_stats stats; ++ struct iw_statistics iwstats; ++ struct proc_dir_entry *dir_dev;/* for proc directory */ ++ struct proc_dir_entry *dir_odm; ++ ++ struct wireless_dev *rtw_wdev; ++ struct rtw_wdev_priv wdev_data; ++ ++ int net_closed; ++ ++ u8 netif_up; ++ ++ u8 bFWReady; ++ u8 bBTFWReady; ++ u8 bLinkInfoDump; ++ u8 bRxRSSIDisplay; ++ /* Added by Albert 2012/10/26 */ ++ /* The driver will show up the desired channel number when this flag is 1. */ ++ u8 bNotifyChannelChange; ++ ++ /* pbuddystruct adapter is used only in two inteface case, (iface_nums =2 in struct dvobj_priv) */ ++ /* PRIMARY ADAPTER's buddy is SECONDARY_ADAPTER */ ++ /* SECONDARY_ADAPTER's buddy is PRIMARY_ADAPTER */ ++ /* for iface_id > SECONDARY_ADAPTER(IFACE_ID1), refer to padapters[iface_id] in struct dvobj_priv */ ++ /* and their pbuddystruct adapter is PRIMARY_ADAPTER. */ ++ /* for PRIMARY_ADAPTER(IFACE_ID0) can directly refer to if1 in struct dvobj_priv */ ++ struct adapter *pbuddy_adapter; ++ ++ /* extend to support multi interface */ ++ /* IFACE_ID0 is equals to PRIMARY_ADAPTER */ ++ /* IFACE_ID1 is equals to SECONDARY_ADAPTER */ ++ u8 iface_id; ++ ++ /* for debug purpose */ ++ u8 fix_rate; ++ u8 driver_vcs_en; /* Enable = 1, Disable = 0 driver control vrtl_carrier_sense for tx */ ++ u8 driver_vcs_type;/* force 0:disable VCS, 1:RTS-CTS, 2:CTS-to-self when vcs_en = 1. */ ++ u8 driver_ampdu_spacing;/* driver control AMPDU Density for peer sta's rx */ ++ u8 driver_rx_ampdu_factor;/* 0xff: disable drv ctrl, 0:8k, 1:16k, 2:32k, 3:64k; */ ++ ++ unsigned char in_cta_test; ++ ++#ifdef CONFIG_DBG_COUNTER ++ struct rx_logs rx_logs; ++ struct tx_logs tx_logs; ++ struct int_logs int_logs; ++#endif ++}; ++ ++#define adapter_to_dvobj(adapter) (adapter->dvobj) ++#define adapter_to_pwrctl(adapter) (dvobj_to_pwrctl(adapter->dvobj)) ++#define adapter_wdev_data(adapter) (&((adapter)->wdev_data)) ++ ++/* */ ++/* Function disabled. */ ++/* */ ++#define DF_TX_BIT BIT0 ++#define DF_RX_BIT BIT1 ++#define DF_IO_BIT BIT2 ++ ++/* define RTW_DISABLE_FUNC(padapter, func) (atomic_add(&adapter_to_dvobj(padapter)->disable_func, (func))) */ ++/* define RTW_ENABLE_FUNC(padapter, func) (atomic_sub(&adapter_to_dvobj(padapter)->disable_func, (func))) */ ++__inline static void RTW_DISABLE_FUNC(struct adapter *padapter, int func_bit) ++{ ++ int df = atomic_read(&adapter_to_dvobj(padapter)->disable_func); ++ df |= func_bit; ++ atomic_set(&adapter_to_dvobj(padapter)->disable_func, df); ++} ++ ++__inline static void RTW_ENABLE_FUNC(struct adapter *padapter, int func_bit) ++{ ++ int df = atomic_read(&adapter_to_dvobj(padapter)->disable_func); ++ df &= ~(func_bit); ++ atomic_set(&adapter_to_dvobj(padapter)->disable_func, df); ++} ++ ++#define RTW_IS_FUNC_DISABLED(padapter, func_bit) (atomic_read(&adapter_to_dvobj(padapter)->disable_func) & (func_bit)) ++ ++#define RTW_CANNOT_IO(padapter) \ ++ ((padapter)->bSurpriseRemoved || \ ++ RTW_IS_FUNC_DISABLED((padapter), DF_IO_BIT)) ++ ++#define RTW_CANNOT_RX(padapter) \ ++ ((padapter)->bDriverStopped || \ ++ (padapter)->bSurpriseRemoved || \ ++ RTW_IS_FUNC_DISABLED((padapter), DF_RX_BIT)) ++ ++#define RTW_CANNOT_TX(padapter) \ ++ ((padapter)->bDriverStopped || \ ++ (padapter)->bSurpriseRemoved || \ ++ RTW_IS_FUNC_DISABLED((padapter), DF_TX_BIT)) ++ ++#ifdef CONFIG_GPIO_API ++int rtw_get_gpio(struct net_device *netdev, int gpio_num); ++int rtw_set_gpio_output_value(struct net_device *netdev, int gpio_num, bool isHigh); ++int rtw_config_gpio(struct net_device *netdev, int gpio_num, bool isOutput); ++#endif ++ ++#ifdef CONFIG_WOWLAN ++int rtw_suspend_wow(struct adapter *padapter); ++int rtw_resume_process_wow(struct adapter *padapter); ++#endif ++ ++__inline static u8 *myid(struct eeprom_priv *peepriv) ++{ ++ return (peepriv->mac_addr); ++} ++ ++/* HCI Related header file */ ++#include ++#include ++#include ++ ++#include ++ ++void rtw_indicate_wx_disassoc_event(struct adapter *padapter); ++void rtw_indicate_wx_assoc_event(struct adapter *padapter); ++void rtw_indicate_wx_disassoc_event(struct adapter *padapter); ++void indicate_wx_scan_complete_event(struct adapter *padapter); ++int rtw_change_ifname(struct adapter *padapter, const char *ifname); ++ ++extern char *rtw_phy_file_path; ++extern char *rtw_initmac; ++extern int rtw_mc2u_disable; ++extern int rtw_ht_enable; ++extern u32 g_wait_hiq_empty; ++extern u8 g_fwdl_wintint_rdy_fail; ++extern u8 g_fwdl_chksum_fail; ++ ++#endif /* __DRV_TYPES_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/drv_types_sdio.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/drv_types_sdio.h +--- linux-4.3/3rdparty/rtl8723bs/include/drv_types_sdio.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/drv_types_sdio.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,39 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __DRV_TYPES_SDIO_H__ ++#define __DRV_TYPES_SDIO_H__ ++ ++/* SDIO Header Files */ ++ #include ++ #include ++ ++#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) ++ #include ++ #include ++#endif ++ ++typedef struct sdio_data ++{ ++ u8 func_number; ++ ++ u8 tx_block_mode; ++ u8 rx_block_mode; ++ u32 block_transfer_len; ++ ++ struct sdio_func *func; ++ void *sys_sdio_irq_thd; ++} SDIO_DATA, *PSDIO_DATA; ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/ethernet.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/ethernet.h +--- linux-4.3/3rdparty/rtl8723bs/include/ethernet.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/ethernet.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,22 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++/*! \file */ ++#ifndef __INC_ETHERNET_H ++#define __INC_ETHERNET_H ++ ++#define ETHERNET_HEADER_SIZE 14 /* Ethernet Header Length */ ++#define LLC_HEADER_SIZE 6 /* LLC Header Length */ ++ ++#endif /* #ifndef __INC_ETHERNET_H */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/Hal8192CPhyReg.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/Hal8192CPhyReg.h +--- linux-4.3/3rdparty/rtl8723bs/include/Hal8192CPhyReg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/Hal8192CPhyReg.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,1126 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++/***************************************************************************** ++ * ++ * Module: __INC_HAL8192CPHYREG_H ++ * ++ * ++ * Note: 1. Define PMAC/BB register map ++ * 2. Define RF register map ++ * 3. PMAC/BB register bit mask. ++ * 4. RF reg bit mask. ++ * 5. Other BB/RF relative definition. ++ * ++ * ++ * Export: Constants, macro, functions(API), global variables(None). ++ * ++ * Abbrev: ++ * ++ * History: ++ * Data Who Remark ++ * 08/07/2007 MHC 1. Porting from 9x series PHYCFG.h. ++ * 2. Reorganize code architecture. ++ *09/25/2008 MH 1. Add RL6052 register definition ++ * ++ *****************************************************************************/ ++#ifndef __INC_HAL8192CPHYREG_H ++#define __INC_HAL8192CPHYREG_H ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++/* */ ++/* 8192S Regsiter offset definition */ ++/* */ ++ ++/* */ ++/* BB-PHY register PMAC 0x100 PHY 0x800 - 0xEFF */ ++/* 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF */ ++/* 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 */ ++/* 3. RF register 0x00-2E */ ++/* 4. Bit Mask for BB/RF register */ ++/* 5. Other defintion for BB/RF R/W */ ++/* */ ++ ++ ++/* */ ++/* 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF */ ++/* 1. Page1(0x100) */ ++/* */ ++#define rPMAC_Reset 0x100 ++#define rPMAC_TxStart 0x104 ++#define rPMAC_TxLegacySIG 0x108 ++#define rPMAC_TxHTSIG1 0x10c ++#define rPMAC_TxHTSIG2 0x110 ++#define rPMAC_PHYDebug 0x114 ++#define rPMAC_TxPacketNum 0x118 ++#define rPMAC_TxIdle 0x11c ++#define rPMAC_TxMACHeader0 0x120 ++#define rPMAC_TxMACHeader1 0x124 ++#define rPMAC_TxMACHeader2 0x128 ++#define rPMAC_TxMACHeader3 0x12c ++#define rPMAC_TxMACHeader4 0x130 ++#define rPMAC_TxMACHeader5 0x134 ++#define rPMAC_TxDataType 0x138 ++#define rPMAC_TxRandomSeed 0x13c ++#define rPMAC_CCKPLCPPreamble 0x140 ++#define rPMAC_CCKPLCPHeader 0x144 ++#define rPMAC_CCKCRC16 0x148 ++#define rPMAC_OFDMRxCRC32OK 0x170 ++#define rPMAC_OFDMRxCRC32Er 0x174 ++#define rPMAC_OFDMRxParityEr 0x178 ++#define rPMAC_OFDMRxCRC8Er 0x17c ++#define rPMAC_CCKCRxRC16Er 0x180 ++#define rPMAC_CCKCRxRC32Er 0x184 ++#define rPMAC_CCKCRxRC32OK 0x188 ++#define rPMAC_TxStatus 0x18c ++ ++/* */ ++/* 2. Page2(0x200) */ ++/* */ ++/* The following two definition are only used for USB interface. */ ++#define RF_BB_CMD_ADDR 0x02c0 /* RF/BB read/write command address. */ ++#define RF_BB_CMD_DATA 0x02c4 /* RF/BB read/write command data. */ ++ ++/* */ ++/* 3. Page8(0x800) */ ++/* */ ++#define rFPGA0_RFMOD 0x800 /* RF mode & CCK TxSC RF BW Setting?? */ ++ ++#define rFPGA0_TxInfo 0x804 /* Status report?? */ ++#define rFPGA0_PSDFunction 0x808 ++ ++#define rFPGA0_TxGainStage 0x80c /* Set TX PWR init gain? */ ++ ++#define rFPGA0_RFTiming1 0x810 /* Useless now */ ++#define rFPGA0_RFTiming2 0x814 ++ ++#define rFPGA0_XA_HSSIParameter1 0x820 /* RF 3 wire register */ ++#define rFPGA0_XA_HSSIParameter2 0x824 ++#define rFPGA0_XB_HSSIParameter1 0x828 ++#define rFPGA0_XB_HSSIParameter2 0x82c ++#define rTxAGC_B_Rate18_06 0x830 ++#define rTxAGC_B_Rate54_24 0x834 ++#define rTxAGC_B_CCK1_55_Mcs32 0x838 ++#define rTxAGC_B_Mcs03_Mcs00 0x83c ++ ++#define rTxAGC_B_Mcs07_Mcs04 0x848 ++#define rTxAGC_B_Mcs11_Mcs08 0x84c ++ ++#define rFPGA0_XA_LSSIParameter 0x840 ++#define rFPGA0_XB_LSSIParameter 0x844 ++ ++#define rFPGA0_RFWakeUpParameter 0x850 /* Useless now */ ++#define rFPGA0_RFSleepUpParameter 0x854 ++ ++#define rFPGA0_XAB_SwitchControl 0x858 /* RF Channel switch */ ++#define rFPGA0_XCD_SwitchControl 0x85c ++ ++#define rFPGA0_XA_RFInterfaceOE 0x860 /* RF Channel switch */ ++#define rFPGA0_XB_RFInterfaceOE 0x864 ++ ++#define rTxAGC_B_Mcs15_Mcs12 0x868 ++#define rTxAGC_B_CCK11_A_CCK2_11 0x86c ++ ++#define rFPGA0_XAB_RFInterfaceSW 0x870 /* RF Interface Software Control */ ++#define rFPGA0_XCD_RFInterfaceSW 0x874 ++ ++#define rFPGA0_XAB_RFParameter 0x878 /* RF Parameter */ ++#define rFPGA0_XCD_RFParameter 0x87c ++ ++#define rFPGA0_AnalogParameter1 0x880 /* Crystal cap setting RF-R/W protection for parameter4?? */ ++#define rFPGA0_AnalogParameter2 0x884 ++#define rFPGA0_AnalogParameter3 0x888 /* Useless now */ ++#define rFPGA0_AnalogParameter4 0x88c ++ ++#define rFPGA0_XA_LSSIReadBack 0x8a0 /* Tranceiver LSSI Readback */ ++#define rFPGA0_XB_LSSIReadBack 0x8a4 ++#define rFPGA0_XC_LSSIReadBack 0x8a8 ++#define rFPGA0_XD_LSSIReadBack 0x8ac ++ ++#define rFPGA0_PSDReport 0x8b4 /* Useless now */ ++#define TransceiverA_HSPI_Readback 0x8b8 /* Transceiver A HSPI Readback */ ++#define TransceiverB_HSPI_Readback 0x8bc /* Transceiver B HSPI Readback */ ++#define rFPGA0_XAB_RFInterfaceRB 0x8e0 /* Useless now RF Interface Readback Value */ ++#define rFPGA0_XCD_RFInterfaceRB 0x8e4 /* Useless now */ ++ ++/* */ ++/* 4. Page9(0x900) */ ++/* */ ++#define rFPGA1_RFMOD 0x900 /* RF mode & OFDM TxSC RF BW Setting?? */ ++ ++#define rFPGA1_TxBlock 0x904 /* Useless now */ ++#define rFPGA1_DebugSelect 0x908 /* Useless now */ ++#define rFPGA1_TxInfo 0x90c /* Useless now Status report?? */ ++#define rS0S1_PathSwitch 0x948 ++ ++/* */ ++/* 5. PageA(0xA00) */ ++/* */ ++/* Set Control channel to upper or lower. These settings are required only for 40MHz */ ++#define rCCK0_System 0xa00 ++ ++#define rCCK0_AFESetting 0xa04 /* Disable init gain now Select RX path by RSSI */ ++#define rCCK0_CCA 0xa08 /* Disable init gain now Init gain */ ++ ++#define rCCK0_RxAGC1 0xa0c /* AGC default value, saturation level Antenna Diversity, RX AGC, LNA Threshold, RX LNA Threshold useless now. Not the same as 90 series */ ++#define rCCK0_RxAGC2 0xa10 /* AGC & DAGC */ ++ ++#define rCCK0_RxHP 0xa14 ++ ++#define rCCK0_DSPParameter1 0xa18 /* Timing recovery & Channel estimation threshold */ ++#define rCCK0_DSPParameter2 0xa1c /* SQ threshold */ ++ ++#define rCCK0_TxFilter1 0xa20 ++#define rCCK0_TxFilter2 0xa24 ++#define rCCK0_DebugPort 0xa28 /* debug port and Tx filter3 */ ++#define rCCK0_FalseAlarmReport 0xa2c /* 0xa2d useless now 0xa30-a4f channel report */ ++#define rCCK0_TRSSIReport 0xa50 ++#define rCCK0_RxReport 0xa54 /* 0xa57 */ ++#define rCCK0_FACounterLower 0xa5c /* 0xa5b */ ++#define rCCK0_FACounterUpper 0xa58 /* 0xa5c */ ++/* */ ++/* PageB(0xB00) */ ++/* */ ++#define rPdp_AntA 0xb00 ++#define rPdp_AntA_4 0xb04 ++#define rConfig_Pmpd_AntA 0xb28 ++#define rConfig_AntA 0xb68 ++#define rConfig_AntB 0xb6c ++#define rPdp_AntB 0xb70 ++#define rPdp_AntB_4 0xb74 ++#define rConfig_Pmpd_AntB 0xb98 ++#define rAPK 0xbd8 ++ ++/* */ ++/* 6. PageC(0xC00) */ ++/* */ ++#define rOFDM0_LSTF 0xc00 ++ ++#define rOFDM0_TRxPathEnable 0xc04 ++#define rOFDM0_TRMuxPar 0xc08 ++#define rOFDM0_TRSWIsolation 0xc0c ++ ++#define rOFDM0_XARxAFE 0xc10 /* RxIQ DC offset, Rx digital filter, DC notch filter */ ++#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imblance matrix */ ++#define rOFDM0_XBRxAFE 0xc18 ++#define rOFDM0_XBRxIQImbalance 0xc1c ++#define rOFDM0_XCRxAFE 0xc20 ++#define rOFDM0_XCRxIQImbalance 0xc24 ++#define rOFDM0_XDRxAFE 0xc28 ++#define rOFDM0_XDRxIQImbalance 0xc2c ++ ++#define rOFDM0_RxDetector1 0xc30 /* PD, BW & SBD DM tune init gain */ ++#define rOFDM0_RxDetector2 0xc34 /* SBD & Fame Sync. */ ++#define rOFDM0_RxDetector3 0xc38 /* Frame Sync. */ ++#define rOFDM0_RxDetector4 0xc3c /* PD, SBD, Frame Sync & Short-GI */ ++ ++#define rOFDM0_RxDSP 0xc40 /* Rx Sync Path */ ++#define rOFDM0_CFOandDAGC 0xc44 /* CFO & DAGC */ ++#define rOFDM0_CCADropThreshold 0xc48 /* CCA Drop threshold */ ++#define rOFDM0_ECCAThreshold 0xc4c /* energy CCA */ ++ ++#define rOFDM0_XAAGCCore1 0xc50 /* DIG */ ++#define rOFDM0_XAAGCCore2 0xc54 ++#define rOFDM0_XBAGCCore1 0xc58 ++#define rOFDM0_XBAGCCore2 0xc5c ++#define rOFDM0_XCAGCCore1 0xc60 ++#define rOFDM0_XCAGCCore2 0xc64 ++#define rOFDM0_XDAGCCore1 0xc68 ++#define rOFDM0_XDAGCCore2 0xc6c ++ ++#define rOFDM0_AGCParameter1 0xc70 ++#define rOFDM0_AGCParameter2 0xc74 ++#define rOFDM0_AGCRSSITable 0xc78 ++#define rOFDM0_HTSTFAGC 0xc7c ++ ++#define rOFDM0_XATxIQImbalance 0xc80 /* TX PWR TRACK and DIG */ ++#define rOFDM0_XATxAFE 0xc84 ++#define rOFDM0_XBTxIQImbalance 0xc88 ++#define rOFDM0_XBTxAFE 0xc8c ++#define rOFDM0_XCTxIQImbalance 0xc90 ++#define rOFDM0_XCTxAFE 0xc94 ++#define rOFDM0_XDTxIQImbalance 0xc98 ++#define rOFDM0_XDTxAFE 0xc9c ++ ++#define rOFDM0_RxIQExtAnta 0xca0 ++#define rOFDM0_TxCoeff1 0xca4 ++#define rOFDM0_TxCoeff2 0xca8 ++#define rOFDM0_TxCoeff3 0xcac ++#define rOFDM0_TxCoeff4 0xcb0 ++#define rOFDM0_TxCoeff5 0xcb4 ++#define rOFDM0_TxCoeff6 0xcb8 ++#define rOFDM0_RxHPParameter 0xce0 ++#define rOFDM0_TxPseudoNoiseWgt 0xce4 ++#define rOFDM0_FrameSync 0xcf0 ++#define rOFDM0_DFSReport 0xcf4 ++ ++/* */ ++/* 7. PageD(0xD00) */ ++/* */ ++#define rOFDM1_LSTF 0xd00 ++#define rOFDM1_TRxPathEnable 0xd04 ++ ++#define rOFDM1_CFO 0xd08 /* No setting now */ ++#define rOFDM1_CSI1 0xd10 ++#define rOFDM1_SBD 0xd14 ++#define rOFDM1_CSI2 0xd18 ++#define rOFDM1_CFOTracking 0xd2c ++#define rOFDM1_TRxMesaure1 0xd34 ++#define rOFDM1_IntfDet 0xd3c ++#define rOFDM1_PseudoNoiseStateAB 0xd50 ++#define rOFDM1_PseudoNoiseStateCD 0xd54 ++#define rOFDM1_RxPseudoNoiseWgt 0xd58 ++ ++#define rOFDM_PHYCounter1 0xda0 /* cca, parity fail */ ++#define rOFDM_PHYCounter2 0xda4 /* rate illegal, crc8 fail */ ++#define rOFDM_PHYCounter3 0xda8 /* MCS not support */ ++ ++#define rOFDM_ShortCFOAB 0xdac /* No setting now */ ++#define rOFDM_ShortCFOCD 0xdb0 ++#define rOFDM_LongCFOAB 0xdb4 ++#define rOFDM_LongCFOCD 0xdb8 ++#define rOFDM_TailCFOAB 0xdbc ++#define rOFDM_TailCFOCD 0xdc0 ++#define rOFDM_PWMeasure1 0xdc4 ++#define rOFDM_PWMeasure2 0xdc8 ++#define rOFDM_BWReport 0xdcc ++#define rOFDM_AGCReport 0xdd0 ++#define rOFDM_RxSNR 0xdd4 ++#define rOFDM_RxEVMCSI 0xdd8 ++#define rOFDM_SIGReport 0xddc ++ ++ ++/* */ ++/* 8. PageE(0xE00) */ ++/* */ ++#define rTxAGC_A_Rate18_06 0xe00 ++#define rTxAGC_A_Rate54_24 0xe04 ++#define rTxAGC_A_CCK1_Mcs32 0xe08 ++#define rTxAGC_A_Mcs03_Mcs00 0xe10 ++#define rTxAGC_A_Mcs07_Mcs04 0xe14 ++#define rTxAGC_A_Mcs11_Mcs08 0xe18 ++#define rTxAGC_A_Mcs15_Mcs12 0xe1c ++ ++#define rFPGA0_IQK 0xe28 ++#define rTx_IQK_Tone_A 0xe30 ++#define rRx_IQK_Tone_A 0xe34 ++#define rTx_IQK_PI_A 0xe38 ++#define rRx_IQK_PI_A 0xe3c ++ ++#define rTx_IQK 0xe40 ++#define rRx_IQK 0xe44 ++#define rIQK_AGC_Pts 0xe48 ++#define rIQK_AGC_Rsp 0xe4c ++#define rTx_IQK_Tone_B 0xe50 ++#define rRx_IQK_Tone_B 0xe54 ++#define rTx_IQK_PI_B 0xe58 ++#define rRx_IQK_PI_B 0xe5c ++#define rIQK_AGC_Cont 0xe60 ++ ++#define rBlue_Tooth 0xe6c ++#define rRx_Wait_CCA 0xe70 ++#define rTx_CCK_RFON 0xe74 ++#define rTx_CCK_BBON 0xe78 ++#define rTx_OFDM_RFON 0xe7c ++#define rTx_OFDM_BBON 0xe80 ++#define rTx_To_Rx 0xe84 ++#define rTx_To_Tx 0xe88 ++#define rRx_CCK 0xe8c ++ ++#define rTx_Power_Before_IQK_A 0xe94 ++#define rTx_Power_After_IQK_A 0xe9c ++ ++#define rRx_Power_Before_IQK_A 0xea0 ++#define rRx_Power_Before_IQK_A_2 0xea4 ++#define rRx_Power_After_IQK_A 0xea8 ++#define rRx_Power_After_IQK_A_2 0xeac ++ ++#define rTx_Power_Before_IQK_B 0xeb4 ++#define rTx_Power_After_IQK_B 0xebc ++ ++#define rRx_Power_Before_IQK_B 0xec0 ++#define rRx_Power_Before_IQK_B_2 0xec4 ++#define rRx_Power_After_IQK_B 0xec8 ++#define rRx_Power_After_IQK_B_2 0xecc ++ ++#define rRx_OFDM 0xed0 ++#define rRx_Wait_RIFS 0xed4 ++#define rRx_TO_Rx 0xed8 ++#define rStandby 0xedc ++#define rSleep 0xee0 ++#define rPMPD_ANAEN 0xeec ++ ++/* */ ++/* 7. RF Register 0x00-0x2E (RF 8256) */ ++/* RF-0222D 0x00-3F */ ++/* */ ++/* Zebra1 */ ++#define rZebra1_HSSIEnable 0x0 /* Useless now */ ++#define rZebra1_TRxEnable1 0x1 ++#define rZebra1_TRxEnable2 0x2 ++#define rZebra1_AGC 0x4 ++#define rZebra1_ChargePump 0x5 ++#define rZebra1_Channel 0x7 /* RF channel switch */ ++ ++/* endif */ ++#define rZebra1_TxGain 0x8 /* Useless now */ ++#define rZebra1_TxLPF 0x9 ++#define rZebra1_RxLPF 0xb ++#define rZebra1_RxHPFCorner 0xc ++ ++/* Zebra4 */ ++#define rGlobalCtrl 0 /* Useless now */ ++#define rRTL8256_TxLPF 19 ++#define rRTL8256_RxLPF 11 ++ ++/* RTL8258 */ ++#define rRTL8258_TxLPF 0x11 /* Useless now */ ++#define rRTL8258_RxLPF 0x13 ++#define rRTL8258_RSSILPF 0xa ++ ++/* */ ++/* RL6052 Register definition */ ++/* */ ++#define RF_AC 0x00 /* */ ++ ++#define RF_IQADJ_G1 0x01 /* */ ++#define RF_IQADJ_G2 0x02 /* */ ++#define RF_BS_PA_APSET_G1_G4 0x03 ++#define RF_BS_PA_APSET_G5_G8 0x04 ++#define RF_POW_TRSW 0x05 /* */ ++ ++#define RF_GAIN_RX 0x06 /* */ ++#define RF_GAIN_TX 0x07 /* */ ++ ++#define RF_TXM_IDAC 0x08 /* */ ++#define RF_IPA_G 0x09 /* */ ++#define RF_TXBIAS_G 0x0A ++#define RF_TXPA_AG 0x0B ++#define RF_IPA_A 0x0C /* */ ++#define RF_TXBIAS_A 0x0D ++#define RF_BS_PA_APSET_G9_G11 0x0E ++#define RF_BS_IQGEN 0x0F /* */ ++ ++#define RF_MODE1 0x10 /* */ ++#define RF_MODE2 0x11 /* */ ++ ++#define RF_RX_AGC_HP 0x12 /* */ ++#define RF_TX_AGC 0x13 /* */ ++#define RF_BIAS 0x14 /* */ ++#define RF_IPA 0x15 /* */ ++#define RF_TXBIAS 0x16 /* */ ++#define RF_POW_ABILITY 0x17 /* */ ++#define RF_MODE_AG 0x18 /* */ ++#define rRfChannel 0x18 /* RF channel and BW switch */ ++#define RF_CHNLBW 0x18 /* RF channel and BW switch */ ++#define RF_TOP 0x19 /* */ ++ ++#define RF_RX_G1 0x1A /* */ ++#define RF_RX_G2 0x1B /* */ ++ ++#define RF_RX_BB2 0x1C /* */ ++#define RF_RX_BB1 0x1D /* */ ++ ++#define RF_RCK1 0x1E /* */ ++#define RF_RCK2 0x1F /* */ ++ ++#define RF_TX_G1 0x20 /* */ ++#define RF_TX_G2 0x21 /* */ ++#define RF_TX_G3 0x22 /* */ ++ ++#define RF_TX_BB1 0x23 /* */ ++ ++#define RF_T_METER 0x24 /* */ ++ ++#define RF_SYN_G1 0x25 /* RF TX Power control */ ++#define RF_SYN_G2 0x26 /* RF TX Power control */ ++#define RF_SYN_G3 0x27 /* RF TX Power control */ ++#define RF_SYN_G4 0x28 /* RF TX Power control */ ++#define RF_SYN_G5 0x29 /* RF TX Power control */ ++#define RF_SYN_G6 0x2A /* RF TX Power control */ ++#define RF_SYN_G7 0x2B /* RF TX Power control */ ++#define RF_SYN_G8 0x2C /* RF TX Power control */ ++ ++#define RF_RCK_OS 0x30 /* RF TX PA control */ ++ ++#define RF_TXPA_G1 0x31 /* RF TX PA control */ ++#define RF_TXPA_G2 0x32 /* RF TX PA control */ ++#define RF_TXPA_G3 0x33 /* RF TX PA control */ ++#define RF_TX_BIAS_A 0x35 ++#define RF_TX_BIAS_D 0x36 ++#define RF_LOBF_9 0x38 ++#define RF_RXRF_A3 0x3C /* */ ++#define RF_TRSW 0x3F ++ ++#define RF_TXRF_A2 0x41 ++#define RF_TXPA_G4 0x46 ++#define RF_TXPA_A4 0x4B ++#define RF_0x52 0x52 ++#define RF_WE_LUT 0xEF ++#define RF_S0S1 0xB0 ++ ++/* */ ++/* Bit Mask */ ++/* */ ++/* 1. Page1(0x100) */ ++#define bBBResetB 0x100 /* Useless now? */ ++#define bGlobalResetB 0x200 ++#define bOFDMTxStart 0x4 ++#define bCCKTxStart 0x8 ++#define bCRC32Debug 0x100 ++#define bPMACLoopback 0x10 ++#define bTxLSIG 0xffffff ++#define bOFDMTxRate 0xf ++#define bOFDMTxReserved 0x10 ++#define bOFDMTxLength 0x1ffe0 ++#define bOFDMTxParity 0x20000 ++#define bTxHTSIG1 0xffffff ++#define bTxHTMCSRate 0x7f ++#define bTxHTBW 0x80 ++#define bTxHTLength 0xffff00 ++#define bTxHTSIG2 0xffffff ++#define bTxHTSmoothing 0x1 ++#define bTxHTSounding 0x2 ++#define bTxHTReserved 0x4 ++#define bTxHTAggreation 0x8 ++#define bTxHTSTBC 0x30 ++#define bTxHTAdvanceCoding 0x40 ++#define bTxHTShortGI 0x80 ++#define bTxHTNumberHT_LTF 0x300 ++#define bTxHTCRC8 0x3fc00 ++#define bCounterReset 0x10000 ++#define bNumOfOFDMTx 0xffff ++#define bNumOfCCKTx 0xffff0000 ++#define bTxIdleInterval 0xffff ++#define bOFDMService 0xffff0000 ++#define bTxMACHeader 0xffffffff ++#define bTxDataInit 0xff ++#define bTxHTMode 0x100 ++#define bTxDataType 0x30000 ++#define bTxRandomSeed 0xffffffff ++#define bCCKTxPreamble 0x1 ++#define bCCKTxSFD 0xffff0000 ++#define bCCKTxSIG 0xff ++#define bCCKTxService 0xff00 ++#define bCCKLengthExt 0x8000 ++#define bCCKTxLength 0xffff0000 ++#define bCCKTxCRC16 0xffff ++#define bCCKTxStatus 0x1 ++#define bOFDMTxStatus 0x2 ++ ++#define IS_BB_REG_OFFSET_92S(_Offset) ((_Offset >= 0x800) && (_Offset <= 0xfff)) ++ ++/* 2. Page8(0x800) */ ++#define bRFMOD 0x1 /* Reg 0x800 rFPGA0_RFMOD */ ++#define bJapanMode 0x2 ++#define bCCKTxSC 0x30 ++#define bCCKEn 0x1000000 ++#define bOFDMEn 0x2000000 ++ ++#define bOFDMRxADCPhase 0x10000 /* Useless now */ ++#define bOFDMTxDACPhase 0x40000 ++#define bXATxAGC 0x3f ++ ++#define bAntennaSelect 0x0300 ++ ++#define bXBTxAGC 0xf00 /* Reg 80c rFPGA0_TxGainStage */ ++#define bXCTxAGC 0xf000 ++#define bXDTxAGC 0xf0000 ++ ++#define bPAStart 0xf0000000 /* Useless now */ ++#define bTRStart 0x00f00000 ++#define bRFStart 0x0000f000 ++#define bBBStart 0x000000f0 ++#define bBBCCKStart 0x0000000f ++#define bPAEnd 0xf /* Reg0x814 */ ++#define bTREnd 0x0f000000 ++#define bRFEnd 0x000f0000 ++#define bCCAMask 0x000000f0 /* T2R */ ++#define bR2RCCAMask 0x00000f00 ++#define bHSSI_R2TDelay 0xf8000000 ++#define bHSSI_T2RDelay 0xf80000 ++#define bContTxHSSI 0x400 /* chane gain at continue Tx */ ++#define bIGFromCCK 0x200 ++#define bAGCAddress 0x3f ++#define bRxHPTx 0x7000 ++#define bRxHPT2R 0x38000 ++#define bRxHPCCKIni 0xc0000 ++#define bAGCTxCode 0xc00000 ++#define bAGCRxCode 0x300000 ++ ++#define b3WireDataLength 0x800 /* Reg 0x820~84f rFPGA0_XA_HSSIParameter1 */ ++#define b3WireAddressLength 0x400 ++ ++#define b3WireRFPowerDown 0x1 /* Useless now */ ++/* define bHWSISelect 0x8 */ ++#define b5GPAPEPolarity 0x40000000 ++#define b2GPAPEPolarity 0x80000000 ++#define bRFSW_TxDefaultAnt 0x3 ++#define bRFSW_TxOptionAnt 0x30 ++#define bRFSW_RxDefaultAnt 0x300 ++#define bRFSW_RxOptionAnt 0x3000 ++#define bRFSI_3WireData 0x1 ++#define bRFSI_3WireClock 0x2 ++#define bRFSI_3WireLoad 0x4 ++#define bRFSI_3WireRW 0x8 ++#define bRFSI_3Wire 0xf ++ ++#define bRFSI_RFENV 0x10 /* Reg 0x870 rFPGA0_XAB_RFInterfaceSW */ ++ ++#define bRFSI_TRSW 0x20 /* Useless now */ ++#define bRFSI_TRSWB 0x40 ++#define bRFSI_ANTSW 0x100 ++#define bRFSI_ANTSWB 0x200 ++#define bRFSI_PAPE 0x400 ++#define bRFSI_PAPE5G 0x800 ++#define bBandSelect 0x1 ++#define bHTSIG2_GI 0x80 ++#define bHTSIG2_Smoothing 0x01 ++#define bHTSIG2_Sounding 0x02 ++#define bHTSIG2_Aggreaton 0x08 ++#define bHTSIG2_STBC 0x30 ++#define bHTSIG2_AdvCoding 0x40 ++#define bHTSIG2_NumOfHTLTF 0x300 ++#define bHTSIG2_CRC8 0x3fc ++#define bHTSIG1_MCS 0x7f ++#define bHTSIG1_BandWidth 0x80 ++#define bHTSIG1_HTLength 0xffff ++#define bLSIG_Rate 0xf ++#define bLSIG_Reserved 0x10 ++#define bLSIG_Length 0x1fffe ++#define bLSIG_Parity 0x20 ++#define bCCKRxPhase 0x4 ++ ++#define bLSSIReadAddress 0x7f800000 /* T65 RF */ ++ ++#define bLSSIReadEdge 0x80000000 /* LSSI "Read" edge signal */ ++ ++#define bLSSIReadBackData 0xfffff /* T65 RF */ ++ ++#define bLSSIReadOKFlag 0x1000 /* Useless now */ ++#define bCCKSampleRate 0x8 /* 0: 44MHz, 1:88MHz */ ++#define bRegulator0Standby 0x1 ++#define bRegulatorPLLStandby 0x2 ++#define bRegulator1Standby 0x4 ++#define bPLLPowerUp 0x8 ++#define bDPLLPowerUp 0x10 ++#define bDA10PowerUp 0x20 ++#define bAD7PowerUp 0x200 ++#define bDA6PowerUp 0x2000 ++#define bXtalPowerUp 0x4000 ++#define b40MDClkPowerUP 0x8000 ++#define bDA6DebugMode 0x20000 ++#define bDA6Swing 0x380000 ++ ++#define bADClkPhase 0x4000000 /* Reg 0x880 rFPGA0_AnalogParameter1 20/40 CCK support switch 40/80 BB MHZ */ ++ ++#define b80MClkDelay 0x18000000 /* Useless */ ++#define bAFEWatchDogEnable 0x20000000 ++ ++#define bXtalCap01 0xc0000000 /* Reg 0x884 rFPGA0_AnalogParameter2 Crystal cap */ ++#define bXtalCap23 0x3 ++#define bXtalCap92x 0x0f000000 ++#define bXtalCap 0x0f000000 ++ ++#define bIntDifClkEnable 0x400 /* Useless */ ++#define bExtSigClkEnable 0x800 ++#define bBandgapMbiasPowerUp 0x10000 ++#define bAD11SHGain 0xc0000 ++#define bAD11InputRange 0x700000 ++#define bAD11OPCurrent 0x3800000 ++#define bIPathLoopback 0x4000000 ++#define bQPathLoopback 0x8000000 ++#define bAFELoopback 0x10000000 ++#define bDA10Swing 0x7e0 ++#define bDA10Reverse 0x800 ++#define bDAClkSource 0x1000 ++#define bAD7InputRange 0x6000 ++#define bAD7Gain 0x38000 ++#define bAD7OutputCMMode 0x40000 ++#define bAD7InputCMMode 0x380000 ++#define bAD7Current 0xc00000 ++#define bRegulatorAdjust 0x7000000 ++#define bAD11PowerUpAtTx 0x1 ++#define bDA10PSAtTx 0x10 ++#define bAD11PowerUpAtRx 0x100 ++#define bDA10PSAtRx 0x1000 ++#define bCCKRxAGCFormat 0x200 ++#define bPSDFFTSamplepPoint 0xc000 ++#define bPSDAverageNum 0x3000 ++#define bIQPathControl 0xc00 ++#define bPSDFreq 0x3ff ++#define bPSDAntennaPath 0x30 ++#define bPSDIQSwitch 0x40 ++#define bPSDRxTrigger 0x400000 ++#define bPSDTxTrigger 0x80000000 ++#define bPSDSineToneScale 0x7f000000 ++#define bPSDReport 0xffff ++ ++/* 3. Page9(0x900) */ ++#define bOFDMTxSC 0x30000000 /* Useless */ ++#define bCCKTxOn 0x1 ++#define bOFDMTxOn 0x2 ++#define bDebugPage 0xfff /* reset debug page and also HWord, LWord */ ++#define bDebugItem 0xff /* reset debug page and LWord */ ++#define bAntL 0x10 ++#define bAntNonHT 0x100 ++#define bAntHT1 0x1000 ++#define bAntHT2 0x10000 ++#define bAntHT1S1 0x100000 ++#define bAntNonHTS1 0x1000000 ++ ++/* 4. PageA(0xA00) */ ++#define bCCKBBMode 0x3 /* Useless */ ++#define bCCKTxPowerSaving 0x80 ++#define bCCKRxPowerSaving 0x40 ++ ++#define bCCKSideBand 0x10 /* Reg 0xa00 rCCK0_System 20/40 switch */ ++ ++#define bCCKScramble 0x8 /* Useless */ ++#define bCCKAntDiversity 0x8000 ++#define bCCKCarrierRecovery 0x4000 ++#define bCCKTxRate 0x3000 ++#define bCCKDCCancel 0x0800 ++#define bCCKISICancel 0x0400 ++#define bCCKMatchFilter 0x0200 ++#define bCCKEqualizer 0x0100 ++#define bCCKPreambleDetect 0x800000 ++#define bCCKFastFalseCCA 0x400000 ++#define bCCKChEstStart 0x300000 ++#define bCCKCCACount 0x080000 ++#define bCCKcs_lim 0x070000 ++#define bCCKBistMode 0x80000000 ++#define bCCKCCAMask 0x40000000 ++#define bCCKTxDACPhase 0x4 ++#define bCCKRxADCPhase 0x20000000 /* r_rx_clk */ ++#define bCCKr_cp_mode0 0x0100 ++#define bCCKTxDCOffset 0xf0 ++#define bCCKRxDCOffset 0xf ++#define bCCKCCAMode 0xc000 ++#define bCCKFalseCS_lim 0x3f00 ++#define bCCKCS_ratio 0xc00000 ++#define bCCKCorgBit_sel 0x300000 ++#define bCCKPD_lim 0x0f0000 ++#define bCCKNewCCA 0x80000000 ++#define bCCKRxHPofIG 0x8000 ++#define bCCKRxIG 0x7f00 ++#define bCCKLNAPolarity 0x800000 ++#define bCCKRx1stGain 0x7f0000 ++#define bCCKRFExtend 0x20000000 /* CCK Rx Iinital gain polarity */ ++#define bCCKRxAGCSatLevel 0x1f000000 ++#define bCCKRxAGCSatCount 0xe0 ++#define bCCKRxRFSettle 0x1f /* AGCsamp_dly */ ++#define bCCKFixedRxAGC 0x8000 ++#define bCCKAntennaPolarity 0x2000 ++#define bCCKTxFilterType 0x0c00 ++#define bCCKRxAGCReportType 0x0300 ++#define bCCKRxDAGCEn 0x80000000 ++#define bCCKRxDAGCPeriod 0x20000000 ++#define bCCKRxDAGCSatLevel 0x1f000000 ++#define bCCKTimingRecovery 0x800000 ++#define bCCKTxC0 0x3f0000 ++#define bCCKTxC1 0x3f000000 ++#define bCCKTxC2 0x3f ++#define bCCKTxC3 0x3f00 ++#define bCCKTxC4 0x3f0000 ++#define bCCKTxC5 0x3f000000 ++#define bCCKTxC6 0x3f ++#define bCCKTxC7 0x3f00 ++#define bCCKDebugPort 0xff0000 ++#define bCCKDACDebug 0x0f000000 ++#define bCCKFalseAlarmEnable 0x8000 ++#define bCCKFalseAlarmRead 0x4000 ++#define bCCKTRSSI 0x7f ++#define bCCKRxAGCReport 0xfe ++#define bCCKRxReport_AntSel 0x80000000 ++#define bCCKRxReport_MFOff 0x40000000 ++#define bCCKRxRxReport_SQLoss 0x20000000 ++#define bCCKRxReport_Pktloss 0x10000000 ++#define bCCKRxReport_Lockedbit 0x08000000 ++#define bCCKRxReport_RateError 0x04000000 ++#define bCCKRxReport_RxRate 0x03000000 ++#define bCCKRxFACounterLower 0xff ++#define bCCKRxFACounterUpper 0xff000000 ++#define bCCKRxHPAGCStart 0xe000 ++#define bCCKRxHPAGCFinal 0x1c00 ++#define bCCKRxFalseAlarmEnable 0x8000 ++#define bCCKFACounterFreeze 0x4000 ++#define bCCKTxPathSel 0x10000000 ++#define bCCKDefaultRxPath 0xc000000 ++#define bCCKOptionRxPath 0x3000000 ++ ++/* 5. PageC(0xC00) */ ++#define bNumOfSTF 0x3 /* Useless */ ++#define bShift_L 0xc0 ++#define bGI_TH 0xc ++#define bRxPathA 0x1 ++#define bRxPathB 0x2 ++#define bRxPathC 0x4 ++#define bRxPathD 0x8 ++#define bTxPathA 0x1 ++#define bTxPathB 0x2 ++#define bTxPathC 0x4 ++#define bTxPathD 0x8 ++#define bTRSSIFreq 0x200 ++#define bADCBackoff 0x3000 ++#define bDFIRBackoff 0xc000 ++#define bTRSSILatchPhase 0x10000 ++#define bRxIDCOffset 0xff ++#define bRxQDCOffset 0xff00 ++#define bRxDFIRMode 0x1800000 ++#define bRxDCNFType 0xe000000 ++#define bRXIQImb_A 0x3ff ++#define bRXIQImb_B 0xfc00 ++#define bRXIQImb_C 0x3f0000 ++#define bRXIQImb_D 0xffc00000 ++#define bDC_dc_Notch 0x60000 ++#define bRxNBINotch 0x1f000000 ++#define bPD_TH 0xf ++#define bPD_TH_Opt2 0xc000 ++#define bPWED_TH 0x700 ++#define bIfMF_Win_L 0x800 ++#define bPD_Option 0x1000 ++#define bMF_Win_L 0xe000 ++#define bBW_Search_L 0x30000 ++#define bwin_enh_L 0xc0000 ++#define bBW_TH 0x700000 ++#define bED_TH2 0x3800000 ++#define bBW_option 0x4000000 ++#define bRatio_TH 0x18000000 ++#define bWindow_L 0xe0000000 ++#define bSBD_Option 0x1 ++#define bFrame_TH 0x1c ++#define bFS_Option 0x60 ++#define bDC_Slope_check 0x80 ++#define bFGuard_Counter_DC_L 0xe00 ++#define bFrame_Weight_Short 0x7000 ++#define bSub_Tune 0xe00000 ++#define bFrame_DC_Length 0xe000000 ++#define bSBD_start_offset 0x30000000 ++#define bFrame_TH_2 0x7 ++#define bFrame_GI2_TH 0x38 ++#define bGI2_Sync_en 0x40 ++#define bSarch_Short_Early 0x300 ++#define bSarch_Short_Late 0xc00 ++#define bSarch_GI2_Late 0x70000 ++#define bCFOAntSum 0x1 ++#define bCFOAcc 0x2 ++#define bCFOStartOffset 0xc ++#define bCFOLookBack 0x70 ++#define bCFOSumWeight 0x80 ++#define bDAGCEnable 0x10000 ++#define bTXIQImb_A 0x3ff ++#define bTXIQImb_B 0xfc00 ++#define bTXIQImb_C 0x3f0000 ++#define bTXIQImb_D 0xffc00000 ++#define bTxIDCOffset 0xff ++#define bTxQDCOffset 0xff00 ++#define bTxDFIRMode 0x10000 ++#define bTxPesudoNoiseOn 0x4000000 ++#define bTxPesudoNoise_A 0xff ++#define bTxPesudoNoise_B 0xff00 ++#define bTxPesudoNoise_C 0xff0000 ++#define bTxPesudoNoise_D 0xff000000 ++#define bCCADropOption 0x20000 ++#define bCCADropThres 0xfff00000 ++#define bEDCCA_H 0xf ++#define bEDCCA_L 0xf0 ++#define bLambda_ED 0x300 ++#define bRxInitialGain 0x7f ++#define bRxAntDivEn 0x80 ++#define bRxAGCAddressForLNA 0x7f00 ++#define bRxHighPowerFlow 0x8000 ++#define bRxAGCFreezeThres 0xc0000 ++#define bRxFreezeStep_AGC1 0x300000 ++#define bRxFreezeStep_AGC2 0xc00000 ++#define bRxFreezeStep_AGC3 0x3000000 ++#define bRxFreezeStep_AGC0 0xc000000 ++#define bRxRssi_Cmp_En 0x10000000 ++#define bRxQuickAGCEn 0x20000000 ++#define bRxAGCFreezeThresMode 0x40000000 ++#define bRxOverFlowCheckType 0x80000000 ++#define bRxAGCShift 0x7f ++#define bTRSW_Tri_Only 0x80 ++#define bPowerThres 0x300 ++#define bRxAGCEn 0x1 ++#define bRxAGCTogetherEn 0x2 ++#define bRxAGCMin 0x4 ++#define bRxHP_Ini 0x7 ++#define bRxHP_TRLNA 0x70 ++#define bRxHP_RSSI 0x700 ++#define bRxHP_BBP1 0x7000 ++#define bRxHP_BBP2 0x70000 ++#define bRxHP_BBP3 0x700000 ++#define bRSSI_H 0x7f0000 /* the threshold for high power */ ++#define bRSSI_Gen 0x7f000000 /* the threshold for ant diversity */ ++#define bRxSettle_TRSW 0x7 ++#define bRxSettle_LNA 0x38 ++#define bRxSettle_RSSI 0x1c0 ++#define bRxSettle_BBP 0xe00 ++#define bRxSettle_RxHP 0x7000 ++#define bRxSettle_AntSW_RSSI 0x38000 ++#define bRxSettle_AntSW 0xc0000 ++#define bRxProcessTime_DAGC 0x300000 ++#define bRxSettle_HSSI 0x400000 ++#define bRxProcessTime_BBPPW 0x800000 ++#define bRxAntennaPowerShift 0x3000000 ++#define bRSSITableSelect 0xc000000 ++#define bRxHP_Final 0x7000000 ++#define bRxHTSettle_BBP 0x7 ++#define bRxHTSettle_HSSI 0x8 ++#define bRxHTSettle_RxHP 0x70 ++#define bRxHTSettle_BBPPW 0x80 ++#define bRxHTSettle_Idle 0x300 ++#define bRxHTSettle_Reserved 0x1c00 ++#define bRxHTRxHPEn 0x8000 ++#define bRxHTAGCFreezeThres 0x30000 ++#define bRxHTAGCTogetherEn 0x40000 ++#define bRxHTAGCMin 0x80000 ++#define bRxHTAGCEn 0x100000 ++#define bRxHTDAGCEn 0x200000 ++#define bRxHTRxHP_BBP 0x1c00000 ++#define bRxHTRxHP_Final 0xe0000000 ++#define bRxPWRatioTH 0x3 ++#define bRxPWRatioEn 0x4 ++#define bRxMFHold 0x3800 ++#define bRxPD_Delay_TH1 0x38 ++#define bRxPD_Delay_TH2 0x1c0 ++#define bRxPD_DC_COUNT_MAX 0x600 ++/* define bRxMF_Hold 0x3800 */ ++#define bRxPD_Delay_TH 0x8000 ++#define bRxProcess_Delay 0xf0000 ++#define bRxSearchrange_GI2_Early 0x700000 ++#define bRxFrame_Guard_Counter_L 0x3800000 ++#define bRxSGI_Guard_L 0xc000000 ++#define bRxSGI_Search_L 0x30000000 ++#define bRxSGI_TH 0xc0000000 ++#define bDFSCnt0 0xff ++#define bDFSCnt1 0xff00 ++#define bDFSFlag 0xf0000 ++#define bMFWeightSum 0x300000 ++#define bMinIdxTH 0x7f000000 ++#define bDAFormat 0x40000 ++#define bTxChEmuEnable 0x01000000 ++#define bTRSWIsolation_A 0x7f ++#define bTRSWIsolation_B 0x7f00 ++#define bTRSWIsolation_C 0x7f0000 ++#define bTRSWIsolation_D 0x7f000000 ++#define bExtLNAGain 0x7c00 ++ ++/* 6. PageE(0xE00) */ ++#define bSTBCEn 0x4 /* Useless */ ++#define bAntennaMapping 0x10 ++#define bNss 0x20 ++#define bCFOAntSumD 0x200 ++#define bPHYCounterReset 0x8000000 ++#define bCFOReportGet 0x4000000 ++#define bOFDMContinueTx 0x10000000 ++#define bOFDMSingleCarrier 0x20000000 ++#define bOFDMSingleTone 0x40000000 ++/* define bRxPath1 0x01 */ ++/* define bRxPath2 0x02 */ ++/* define bRxPath3 0x04 */ ++/* define bRxPath4 0x08 */ ++/* define bTxPath1 0x10 */ ++/* define bTxPath2 0x20 */ ++#define bHTDetect 0x100 ++#define bCFOEn 0x10000 ++#define bCFOValue 0xfff00000 ++#define bSigTone_Re 0x3f ++#define bSigTone_Im 0x7f00 ++#define bCounter_CCA 0xffff ++#define bCounter_ParityFail 0xffff0000 ++#define bCounter_RateIllegal 0xffff ++#define bCounter_CRC8Fail 0xffff0000 ++#define bCounter_MCSNoSupport 0xffff ++#define bCounter_FastSync 0xffff ++#define bShortCFO 0xfff ++#define bShortCFOTLength 12 /* total */ ++#define bShortCFOFLength 11 /* fraction */ ++#define bLongCFO 0x7ff ++#define bLongCFOTLength 11 ++#define bLongCFOFLength 11 ++#define bTailCFO 0x1fff ++#define bTailCFOTLength 13 ++#define bTailCFOFLength 12 ++#define bmax_en_pwdB 0xffff ++#define bCC_power_dB 0xffff0000 ++#define bnoise_pwdB 0xffff ++#define bPowerMeasTLength 10 ++#define bPowerMeasFLength 3 ++#define bRx_HT_BW 0x1 ++#define bRxSC 0x6 ++#define bRx_HT 0x8 ++#define bNB_intf_det_on 0x1 ++#define bIntf_win_len_cfg 0x30 ++#define bNB_Intf_TH_cfg 0x1c0 ++#define bRFGain 0x3f ++#define bTableSel 0x40 ++#define bTRSW 0x80 ++#define bRxSNR_A 0xff ++#define bRxSNR_B 0xff00 ++#define bRxSNR_C 0xff0000 ++#define bRxSNR_D 0xff000000 ++#define bSNREVMTLength 8 ++#define bSNREVMFLength 1 ++#define bCSI1st 0xff ++#define bCSI2nd 0xff00 ++#define bRxEVM1st 0xff0000 ++#define bRxEVM2nd 0xff000000 ++#define bSIGEVM 0xff ++#define bPWDB 0xff00 ++#define bSGIEN 0x10000 ++ ++#define bSFactorQAM1 0xf /* Useless */ ++#define bSFactorQAM2 0xf0 ++#define bSFactorQAM3 0xf00 ++#define bSFactorQAM4 0xf000 ++#define bSFactorQAM5 0xf0000 ++#define bSFactorQAM6 0xf0000 ++#define bSFactorQAM7 0xf00000 ++#define bSFactorQAM8 0xf000000 ++#define bSFactorQAM9 0xf0000000 ++#define bCSIScheme 0x100000 ++ ++#define bNoiseLvlTopSet 0x3 /* Useless */ ++#define bChSmooth 0x4 ++#define bChSmoothCfg1 0x38 ++#define bChSmoothCfg2 0x1c0 ++#define bChSmoothCfg3 0xe00 ++#define bChSmoothCfg4 0x7000 ++#define bMRCMode 0x800000 ++#define bTHEVMCfg 0x7000000 ++ ++#define bLoopFitType 0x1 /* Useless */ ++#define bUpdCFO 0x40 ++#define bUpdCFOOffData 0x80 ++#define bAdvUpdCFO 0x100 ++#define bAdvTimeCtrl 0x800 ++#define bUpdClko 0x1000 ++#define bFC 0x6000 ++#define bTrackingMode 0x8000 ++#define bPhCmpEnable 0x10000 ++#define bUpdClkoLTF 0x20000 ++#define bComChCFO 0x40000 ++#define bCSIEstiMode 0x80000 ++#define bAdvUpdEqz 0x100000 ++#define bUChCfg 0x7000000 ++#define bUpdEqz 0x8000000 ++ ++/* Rx Pseduo noise */ ++#define bRxPesudoNoiseOn 0x20000000 /* Useless */ ++#define bRxPesudoNoise_A 0xff ++#define bRxPesudoNoise_B 0xff00 ++#define bRxPesudoNoise_C 0xff0000 ++#define bRxPesudoNoise_D 0xff000000 ++#define bPesudoNoiseState_A 0xffff ++#define bPesudoNoiseState_B 0xffff0000 ++#define bPesudoNoiseState_C 0xffff ++#define bPesudoNoiseState_D 0xffff0000 ++ ++/* 7. RF Register */ ++/* Zebra1 */ ++#define bZebra1_HSSIEnable 0x8 /* Useless */ ++#define bZebra1_TRxControl 0xc00 ++#define bZebra1_TRxGainSetting 0x07f ++#define bZebra1_RxCorner 0xc00 ++#define bZebra1_TxChargePump 0x38 ++#define bZebra1_RxChargePump 0x7 ++#define bZebra1_ChannelNum 0xf80 ++#define bZebra1_TxLPFBW 0x400 ++#define bZebra1_RxLPFBW 0x600 ++ ++/* Zebra4 */ ++#define bRTL8256RegModeCtrl1 0x100 /* Useless */ ++#define bRTL8256RegModeCtrl0 0x40 ++#define bRTL8256_TxLPFBW 0x18 ++#define bRTL8256_RxLPFBW 0x600 ++ ++/* RTL8258 */ ++#define bRTL8258_TxLPFBW 0xc /* Useless */ ++#define bRTL8258_RxLPFBW 0xc00 ++#define bRTL8258_RSSILPFBW 0xc0 ++ ++ ++/* */ ++/* Other Definition */ ++/* */ ++ ++/* byte endable for sb_write */ ++#define bByte0 0x1 /* Useless */ ++#define bByte1 0x2 ++#define bByte2 0x4 ++#define bByte3 0x8 ++#define bWord0 0x3 ++#define bWord1 0xc ++#define bDWord 0xf ++ ++/* for PutRegsetting & GetRegSetting BitMask */ ++#define bMaskByte0 0xff /* Reg 0xc50 rOFDM0_XAAGCCore~0xC6f */ ++#define bMaskByte1 0xff00 ++#define bMaskByte2 0xff0000 ++#define bMaskByte3 0xff000000 ++#define bMaskHWord 0xffff0000 ++#define bMaskLWord 0x0000ffff ++#define bMaskDWord 0xffffffff ++#define bMaskH3Bytes 0xffffff00 ++#define bMask12Bits 0xfff ++#define bMaskH4Bits 0xf0000000 ++#define bMaskOFDM_D 0xffc00000 ++#define bMaskCCK 0x3f3f3f3f ++ ++ ++#define bEnable 0x1 /* Useless */ ++#define bDisable 0x0 ++ ++#define LeftAntenna 0x0 /* Useless */ ++#define RightAntenna 0x1 ++ ++#define tCheckTxStatus 500 /* 500ms Useless */ ++#define tUpdateRxCounter 100 /* 100ms */ ++ ++#define rateCCK 0 /* Useless */ ++#define rateOFDM 1 ++#define rateHT 2 ++ ++/* define Register-End */ ++#define bPMAC_End 0x1ff /* Useless */ ++#define bFPGAPHY0_End 0x8ff ++#define bFPGAPHY1_End 0x9ff ++#define bCCKPHY0_End 0xaff ++#define bOFDMPHY0_End 0xcff ++#define bOFDMPHY1_End 0xdff ++ ++/* define max debug item in each debug page */ ++/* define bMaxItem_FPGA_PHY0 0x9 */ ++/* define bMaxItem_FPGA_PHY1 0x3 */ ++/* define bMaxItem_PHY_11B 0x16 */ ++/* define bMaxItem_OFDM_PHY0 0x29 */ ++/* define bMaxItem_OFDM_PHY1 0x0 */ ++ ++#define bPMACControl 0x0 /* Useless */ ++#define bWMACControl 0x1 ++#define bWNICControl 0x2 ++ ++#define PathA 0x0 /* Useless */ ++#define PathB 0x1 ++#define PathC 0x2 ++#define PathD 0x3 ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++ ++#endif /* __INC_HAL8192SPHYREG_H */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/Hal8723BPhyCfg.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/Hal8723BPhyCfg.h +--- linux-4.3/3rdparty/rtl8723bs/include/Hal8723BPhyCfg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/Hal8723BPhyCfg.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,128 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __INC_HAL8723BPHYCFG_H__ ++#define __INC_HAL8723BPHYCFG_H__ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++#define LOOP_LIMIT 5 ++#define MAX_STALL_TIME 50 /* us */ ++#define AntennaDiversityValue 0x80 /* Adapter->bSoftwareAntennaDiversity ? 0x00:0x80) */ ++#define MAX_TXPWR_IDX_NMODE_92S 63 ++#define Reset_Cnt_Limit 3 ++ ++#define MAX_AGGR_NUM 0x07 ++ ++ ++/*--------------------------Define Parameters End-------------------------------*/ ++ ++ ++/*------------------------------Define structure----------------------------*/ ++ ++/*------------------------------Define structure End----------------------------*/ ++ ++/*--------------------------Exported Function prototype---------------------*/ ++u32 ++PHY_QueryBBReg_8723B( ++struct adapter *Adapter, ++u32 RegAddr, ++u32 BitMask ++ ); ++ ++void ++PHY_SetBBReg_8723B( ++struct adapter *Adapter, ++u32 RegAddr, ++u32 BitMask, ++u32 Data ++ ); ++ ++u32 ++PHY_QueryRFReg_8723B( ++struct adapter * Adapter, ++u8 eRFPath, ++u32 RegAddr, ++u32 BitMask ++ ); ++ ++void ++PHY_SetRFReg_8723B( ++struct adapter * Adapter, ++u8 eRFPath, ++u32 RegAddr, ++u32 BitMask, ++u32 Data ++ ); ++ ++/* MAC/BB/RF HAL config */ ++int PHY_BBConfig8723B(struct adapter *Adapter ); ++ ++int PHY_RFConfig8723B(struct adapter *Adapter ); ++ ++s32 PHY_MACConfig8723B(struct adapter *padapter); ++ ++void ++PHY_SetTxPowerIndex_8723B( ++struct adapter * Adapter, ++u32 PowerIndex, ++u8 RFPath, ++u8 Rate ++ ); ++ ++u8 ++PHY_GetTxPowerIndex_8723B( ++struct adapter * padapter, ++u8 RFPath, ++u8 Rate, ++enum CHANNEL_WIDTH BandWidth, ++u8 Channel ++ ); ++ ++void ++PHY_GetTxPowerLevel8723B( ++struct adapter * Adapter, ++ s32* powerlevel ++ ); ++ ++void ++PHY_SetTxPowerLevel8723B( ++struct adapter * Adapter, ++u8 channel ++ ); ++ ++void ++PHY_SetBWMode8723B( ++struct adapter * Adapter, ++enum CHANNEL_WIDTH Bandwidth, /* 20M or 40M */ ++unsigned char Offset /* Upper, Lower, or Don't care */ ++); ++ ++void ++PHY_SwChnl8723B(/* Call after initialization */ ++struct adapter *Adapter, ++u8 channel ++ ); ++ ++void ++PHY_SetSwChnlBWMode8723B( ++struct adapter * Adapter, ++u8 channel, ++enum CHANNEL_WIDTH Bandwidth, ++u8 Offset40, ++u8 Offset80 ++); ++ ++/*--------------------------Exported Function prototype End---------------------*/ ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/Hal8723BPhyReg.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/Hal8723BPhyReg.h +--- linux-4.3/3rdparty/rtl8723bs/include/Hal8723BPhyReg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/Hal8723BPhyReg.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,77 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __INC_HAL8723BPHYREG_H__ ++#define __INC_HAL8723BPHYREG_H__ ++ ++#include ++ ++/* BB Register Definition */ ++/* */ ++/* 4. Page9(0x900) */ ++/* */ ++#define rDPDT_control 0x92c ++#define rfe_ctrl_anta_src 0x930 ++#define rS0S1_PathSwitch 0x948 ++#define AGC_table_select 0xb2c ++ ++/* */ ++/* PageB(0xB00) */ ++/* */ ++#define rPdp_AntA 0xb00 ++#define rPdp_AntA_4 0xb04 ++#define rPdp_AntA_8 0xb08 ++#define rPdp_AntA_C 0xb0c ++#define rPdp_AntA_10 0xb10 ++#define rPdp_AntA_14 0xb14 ++#define rPdp_AntA_18 0xb18 ++#define rPdp_AntA_1C 0xb1c ++#define rPdp_AntA_20 0xb20 ++#define rPdp_AntA_24 0xb24 ++ ++#define rConfig_Pmpd_AntA 0xb28 ++#define rConfig_ram64x16 0xb2c ++ ++#define rBndA 0xb30 ++#define rHssiPar 0xb34 ++ ++#define rConfig_AntA 0xb68 ++#define rConfig_AntB 0xb6c ++ ++#define rPdp_AntB 0xb70 ++#define rPdp_AntB_4 0xb74 ++#define rPdp_AntB_8 0xb78 ++#define rPdp_AntB_C 0xb7c ++#define rPdp_AntB_10 0xb80 ++#define rPdp_AntB_14 0xb84 ++#define rPdp_AntB_18 0xb88 ++#define rPdp_AntB_1C 0xb8c ++#define rPdp_AntB_20 0xb90 ++#define rPdp_AntB_24 0xb94 ++ ++#define rConfig_Pmpd_AntB 0xb98 ++ ++#define rBndB 0xba0 ++ ++#define rAPK 0xbd8 ++#define rPm_Rx0_AntA 0xbdc ++#define rPm_Rx1_AntA 0xbe0 ++#define rPm_Rx2_AntA 0xbe4 ++#define rPm_Rx3_AntA 0xbe8 ++#define rPm_Rx0_AntB 0xbec ++#define rPm_Rx1_AntB 0xbf0 ++#define rPm_Rx2_AntB 0xbf4 ++#define rPm_Rx3_AntB 0xbf8 ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/Hal8723BPwrSeq.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/Hal8723BPwrSeq.h +--- linux-4.3/3rdparty/rtl8723bs/include/Hal8723BPwrSeq.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/Hal8723BPwrSeq.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,232 @@ ++#ifndef REALTEK_POWER_SEQUENCE_8723B ++#define REALTEK_POWER_SEQUENCE_8723B ++ ++#include "HalPwrSeqCmd.h" ++ ++/* ++ Check document WM-20130815-JackieLau-RTL8723B_Power_Architecture v08.vsd ++ There are 6 HW Power States: ++ 0: POFF--Power Off ++ 1: PDN--Power Down ++ 2: CARDEMU--Card Emulation ++ 3: ACT--Active Mode ++ 4: LPS--Low Power State ++ 5: SUS--Suspend ++ ++ The transision from different states are defined below ++ TRANS_CARDEMU_TO_ACT ++ TRANS_ACT_TO_CARDEMU ++ TRANS_CARDEMU_TO_SUS ++ TRANS_SUS_TO_CARDEMU ++ TRANS_CARDEMU_TO_PDN ++ TRANS_ACT_TO_LPS ++ TRANS_LPS_TO_ACT ++ ++ TRANS_END ++*/ ++#define RTL8723B_TRANS_CARDEMU_TO_ACT_STEPS 26 ++#define RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS 15 ++#define RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS 15 ++#define RTL8723B_TRANS_SUS_TO_CARDEMU_STEPS 15 ++#define RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS 15 ++#define RTL8723B_TRANS_PDN_TO_CARDEMU_STEPS 15 ++#define RTL8723B_TRANS_ACT_TO_LPS_STEPS 15 ++#define RTL8723B_TRANS_LPS_TO_ACT_STEPS 15 ++#define RTL8723B_TRANS_ACT_TO_SWLPS_STEPS 22 ++#define RTL8723B_TRANS_SWLPS_TO_ACT_STEPS 15 ++#define RTL8723B_TRANS_END_STEPS 1 ++ ++ ++#define RTL8723B_TRANS_CARDEMU_TO_ACT \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \ ++ {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0}, /*0x20[0] = 1b'1 enable LDOA12 MACRO block for all interface*/ \ ++ {0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*0x67[0] = 0 to disable BT_GPS_SEL pins*/ \ ++ {0x0001, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 1, PWRSEQ_DELAY_MS},/*Delay 1ms*/ \ ++ {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, 0}, /*0x00[5] = 1b'0 release analog Ips to digital , 1:isolation*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT4|BIT3|BIT2), 0},/* disable SW LPS 0x04[10]= 0 and WLSUS_EN 0x04[11]= 0*/ \ ++ {0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0 , BIT0},/* Disable USB suspend */ \ ++ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, BIT1},/* wait till 0x04[17] = 1 power ready*/ \ ++ {0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0 , 0},/* Enable USB suspend */ \ ++ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* release WLON reset 0x04[16]= 1*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* disable HWPDN 0x04[15]= 0*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT4|BIT3), 0},/* disable WL suspend*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* polling until return 0*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT0, 0},/**/ \ ++ {0x0010, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, BIT6},/* Enable WL control XTAL setting*/ \ ++ {0x0049, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1},/*Enable falling edge triggering interrupt*/\ ++ {0x0063, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1},/*Enable GPIO9 interrupt mode*/\ ++ {0x0062, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*Enable GPIO9 input mode*/\ ++ {0x0058, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/*Enable HSISR GPIO[C:0] interrupt*/\ ++ {0x005A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1},/*Enable HSISR GPIO9 interrupt*/\ ++ {0x0068, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, BIT3},/*For GPIO9 internal pull high setting by test chip*/\ ++ {0x0069, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, BIT6},/*For GPIO9 internal pull high setting*/\ ++ ++ ++#define RTL8723B_TRANS_ACT_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \ ++ {0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*0x1F[7:0] = 0 turn off RF*/ \ ++ {0x0049, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*Enable rising edge triggering interrupt*/ \ ++ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* release WLON reset 0x04[16]= 1*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*0x04[9] = 1 turn off MAC by HW state machine*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/ \ ++ {0x0010, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, 0},/* Enable BT control XTAL setting*/\ ++ {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5}, /*0x00[5] = 1b'1 analog Ips to digital , 1:isolation*/ \ ++ {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, /*0x20[0] = 1b'0 disable LDOA12 MACRO block*/\ ++ ++ ++#define RTL8723B_TRANS_CARDEMU_TO_SUS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4|BIT3, (BIT4|BIT3)}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, BIT3}, /*0x04[12:11] = 2b'01 enable WL suspend*/ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SDIO SOP option to disable BG/MB/ACK/SWR*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, BIT3|BIT4}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/ ++ ++#define RTL8723B_TRANS_SUS_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT7, 0}, /*clear suspend enable and power down enable*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*0x23[4] = 1b'0 12H LDO enter normal mode*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/ ++ ++#define RTL8723B_TRANS_CARDEMU_TO_CARDDIS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, omments here*/ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07 = 0x20 , SOP option to disable BG/MB*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, BIT3}, /*0x04[12:11] = 2b'01 enable WL suspend*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, BIT2}, /*0x04[10] = 1, enable SW LPS*/ \ ++ {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 1}, /*0x48[16] = 1 to enable GPIO9 as EXT WAKEUP*/ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/ ++ ++#define RTL8723B_TRANS_CARDDIS_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT7, 0}, /*clear suspend enable and power down enable*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\ ++ {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, /*0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/\ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*0x23[4] = 1b'0 12H LDO enter normal mode*/ \ ++ {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*PCIe DMA start*/ ++ ++ ++#define RTL8723B_TRANS_CARDEMU_TO_PDN \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK|PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SOP option to disable BG/MB/ACK/SWR*/ \ ++ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/* 0x04[16] = 0*/\ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, BIT7},/* 0x04[15] = 1*/ ++ ++#define RTL8723B_TRANS_PDN_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* 0x04[15] = 0*/ ++ ++#define RTL8723B_TRANS_ACT_TO_LPS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \ ++ {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},/*PCIe DMA stop*/ \ ++ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},/*Tx Pause*/ \ ++ {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled, and clock are gated*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*Whole BB is reset*/ \ ++ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x03},/*Reset MAC TRX*/ \ ++ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*check if removed later*/ \ ++ {0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/*When driver enter Sus/ Disable, enable LOP for BT*/ \ ++ {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5},/*Respond TxOK to scheduler*/ \ ++ ++ ++#define RTL8723B_TRANS_LPS_TO_ACT \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \ ++ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/\ ++ {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/\ ++ {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/\ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/\ ++ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*. 0x08[4] = 0 switch TSF to 40M*/\ ++ {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT7, 0}, /*Polling 0x109[7]= 0 TSF in 40M*/\ ++ {0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6|BIT7, 0}, /*. 0x29[7:6] = 2b'00 enable BB clock*/\ ++ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*. 0x101[1] = 1*/\ ++ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, /*. 0x100[7:0] = 0xFF enable WMAC TRX*/\ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1|BIT0, BIT1|BIT0}, /*. 0x02[1:0] = 2b'11 enable BB macro*/\ ++ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /*. 0x522 = 0*/ ++ ++ ++ #define RTL8723B_TRANS_ACT_TO_SWLPS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \ ++ {0x0194, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/*enable 32 K source*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled, and clock are gated*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 1},/*CCK and OFDM are enable*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled, and clock are gated*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 1},/*CCK and OFDM are enable*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled, and clock are gated*/ \ ++ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x3F},/*Reset MAC TRX*/ \ ++ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*disable security engine*/ \ ++ {0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x40},/*When driver enter Sus/ Disable, enable LOP for BT*/ \ ++ {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5},/*reset dual TSF*/ \ ++ {0x0003, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0},/*Reset CPU*/ \ ++ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*Reset MCUFWDL register*/ \ ++ {0x001D, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*Reset CPU IO Wrapper*/ \ ++ {0x001D, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 1},/*Reset CPU IO Wrapper*/ \ ++ {0x0287, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*polling RXFF packet number = 0 */ \ ++ {0x0286, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, BIT1},/*polling RXDMA idle */ \ ++ {0x013D, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/*Clear FW RPWM interrupt */\ ++ {0x0139, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/*Set FW RPWM interrupt source*/\ ++ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4},/*switch TSF to 32K*/\ ++ {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, BIT7},/*polling TSF stable*/\ ++ {0x0090, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/*Set FW LPS*/ \ ++ {0x0090, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT0, 0},/*polling FW LPS ready */ ++ ++ ++#define RTL8723B_TRANS_SWLPS_TO_ACT \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \ ++ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0},/*switch TSF to 32K*/\ ++ {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/*polling TSF stable*/\ ++ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*. 0x101[1] = 1, enable security engine*/\ ++ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, /*. 0x100[7:0] = 0xFF enable WMAC TRX*/\ ++ {0x06B7, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x09}, /*. reset MAC rx state machine*/\ ++ {0x06B4, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x86}, /*. reset MAC rx state machine*/\ ++ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1},/* set CPU RAM code ready*/ \ ++ {0x001D, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*Reset CPU IO Wrapper*/ \ ++ {0x0003, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0},/* Enable CPU*/ \ ++ {0x001D, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/*enable CPU IO Wrapper*/ \ ++ {0x0003, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, BIT2},/* Enable CPU*/ \ ++ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT7, BIT7},/*polling FW init ready */ \ ++ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT6, BIT6},/*polling FW init ready */ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0}, /*. 0x02[1:0] = 2b'11 enable BB macro*/\ ++ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /*. 0x522 = 0*/ ++ ++#define RTL8723B_TRANS_END \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \ ++ {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, 0, PWR_CMD_END, 0, 0}, ++ ++ ++extern WLAN_PWR_CFG rtl8723B_power_on_flow[RTL8723B_TRANS_CARDEMU_TO_ACT_STEPS+RTL8723B_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8723B_radio_off_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8723B_card_disable_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723B_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8723B_card_enable_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723B_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8723B_suspend_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS+RTL8723B_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8723B_resume_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS+RTL8723B_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8723B_hwpdn_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723B_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8723B_enter_lps_flow[RTL8723B_TRANS_ACT_TO_LPS_STEPS+RTL8723B_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8723B_leave_lps_flow[RTL8723B_TRANS_LPS_TO_ACT_STEPS+RTL8723B_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8723B_enter_swlps_flow[RTL8723B_TRANS_ACT_TO_SWLPS_STEPS+RTL8723B_TRANS_END_STEPS]; ++extern WLAN_PWR_CFG rtl8723B_leave_swlps_flow[RTL8723B_TRANS_SWLPS_TO_ACT_STEPS+RTL8723B_TRANS_END_STEPS]; ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/hal_btcoex.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_btcoex.h +--- linux-4.3/3rdparty/rtl8723bs/include/hal_btcoex.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_btcoex.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,68 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2013 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __HAL_BTCOEX_H__ ++#define __HAL_BTCOEX_H__ ++ ++#include ++ ++/* Some variables can't get from outsrc BT-Coex, */ ++/* so we need to save here */ ++typedef struct _BT_COEXIST ++{ ++ u8 bBtExist; ++ u8 btTotalAntNum; ++ u8 btChipType; ++ u8 bInitlized; ++} BT_COEXIST, *PBT_COEXIST; ++ ++void DBG_BT_INFO(u8 *dbgmsg); ++ ++void hal_btcoex_SetBTCoexist(struct adapter *padapter, u8 bBtExist); ++u8 hal_btcoex_IsBtExist(struct adapter *padapter); ++u8 hal_btcoex_IsBtDisabled(struct adapter *); ++void hal_btcoex_SetChipType(struct adapter *padapter, u8 chipType); ++void hal_btcoex_SetPgAntNum(struct adapter *padapter, u8 antNum); ++void hal_btcoex_SetSingleAntPath(struct adapter *padapter, u8 singleAntPath); ++ ++u8 hal_btcoex_Initialize(struct adapter *padapter); ++void hal_btcoex_PowerOnSetting(struct adapter *padapter); ++void hal_btcoex_InitHwConfig(struct adapter *padapter, u8 bWifiOnly); ++ ++void hal_btcoex_IpsNotify(struct adapter *padapter, u8 type); ++void hal_btcoex_LpsNotify(struct adapter *padapter, u8 type); ++void hal_btcoex_ScanNotify(struct adapter *padapter, u8 type); ++void hal_btcoex_ConnectNotify(struct adapter *padapter, u8 action); ++void hal_btcoex_MediaStatusNotify(struct adapter *padapter, u8 mediaStatus); ++void hal_btcoex_SpecialPacketNotify(struct adapter *padapter, u8 pktType); ++void hal_btcoex_IQKNotify(struct adapter *padapter, u8 state); ++void hal_btcoex_BtInfoNotify(struct adapter *padapter, u8 length, u8 *tmpBuf); ++void hal_btcoex_SuspendNotify(struct adapter *padapter, u8 state); ++void hal_btcoex_HaltNotify(struct adapter *padapter); ++ ++void hal_btcoex_Hanlder(struct adapter *padapter); ++ ++s32 hal_btcoex_IsBTCoexCtrlAMPDUSize(struct adapter *padapter); ++void hal_btcoex_SetManualControl(struct adapter *padapter, u8 bmanual); ++u8 hal_btcoex_IsBtControlLps(struct adapter *); ++u8 hal_btcoex_IsLpsOn(struct adapter *); ++u8 hal_btcoex_RpwmVal(struct adapter *); ++u8 hal_btcoex_LpsVal(struct adapter *); ++u32 hal_btcoex_GetRaMask(struct adapter *); ++void hal_btcoex_RecordPwrMode(struct adapter *padapter, u8 *pCmdBuf, u8 cmdLen); ++void hal_btcoex_DisplayBtCoexInfo(struct adapter *, u8 *pbuf, u32 bufsize); ++void hal_btcoex_SetDBG(struct adapter *, u32 *pDbgModule); ++u32 hal_btcoex_GetDBG(struct adapter *, u8 *pStrBuf, u32 bufSize); ++ ++#endif /* !__HAL_BTCOEX_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/hal_com.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_com.h +--- linux-4.3/3rdparty/rtl8723bs/include/hal_com.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_com.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,309 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __HAL_COMMON_H__ ++#define __HAL_COMMON_H__ ++ ++#include "HalVerDef.h" ++#include "hal_pg.h" ++#include "hal_phy.h" ++#include "hal_phy_reg.h" ++#include "hal_com_reg.h" ++#include "hal_com_phycfg.h" ++ ++/*------------------------------ Tx Desc definition Macro ------------------------*/ ++/* pragma mark -- Tx Desc related definition. -- */ ++/* */ ++/* */ ++/* Rate */ ++/* */ ++/* CCK Rates, TxHT = 0 */ ++#define DESC_RATE1M 0x00 ++#define DESC_RATE2M 0x01 ++#define DESC_RATE5_5M 0x02 ++#define DESC_RATE11M 0x03 ++ ++/* OFDM Rates, TxHT = 0 */ ++#define DESC_RATE6M 0x04 ++#define DESC_RATE9M 0x05 ++#define DESC_RATE12M 0x06 ++#define DESC_RATE18M 0x07 ++#define DESC_RATE24M 0x08 ++#define DESC_RATE36M 0x09 ++#define DESC_RATE48M 0x0a ++#define DESC_RATE54M 0x0b ++ ++/* MCS Rates, TxHT = 1 */ ++#define DESC_RATEMCS0 0x0c ++#define DESC_RATEMCS1 0x0d ++#define DESC_RATEMCS2 0x0e ++#define DESC_RATEMCS3 0x0f ++#define DESC_RATEMCS4 0x10 ++#define DESC_RATEMCS5 0x11 ++#define DESC_RATEMCS6 0x12 ++#define DESC_RATEMCS7 0x13 ++#define DESC_RATEMCS8 0x14 ++#define DESC_RATEMCS9 0x15 ++#define DESC_RATEMCS10 0x16 ++#define DESC_RATEMCS11 0x17 ++#define DESC_RATEMCS12 0x18 ++#define DESC_RATEMCS13 0x19 ++#define DESC_RATEMCS14 0x1a ++#define DESC_RATEMCS15 0x1b ++#define DESC_RATEMCS16 0x1C ++#define DESC_RATEMCS17 0x1D ++#define DESC_RATEMCS18 0x1E ++#define DESC_RATEMCS19 0x1F ++#define DESC_RATEMCS20 0x20 ++#define DESC_RATEMCS21 0x21 ++#define DESC_RATEMCS22 0x22 ++#define DESC_RATEMCS23 0x23 ++#define DESC_RATEMCS24 0x24 ++#define DESC_RATEMCS25 0x25 ++#define DESC_RATEMCS26 0x26 ++#define DESC_RATEMCS27 0x27 ++#define DESC_RATEMCS28 0x28 ++#define DESC_RATEMCS29 0x29 ++#define DESC_RATEMCS30 0x2A ++#define DESC_RATEMCS31 0x2B ++#define DESC_RATEVHTSS1MCS0 0x2C ++#define DESC_RATEVHTSS1MCS1 0x2D ++#define DESC_RATEVHTSS1MCS2 0x2E ++#define DESC_RATEVHTSS1MCS3 0x2F ++#define DESC_RATEVHTSS1MCS4 0x30 ++#define DESC_RATEVHTSS1MCS5 0x31 ++#define DESC_RATEVHTSS1MCS6 0x32 ++#define DESC_RATEVHTSS1MCS7 0x33 ++#define DESC_RATEVHTSS1MCS8 0x34 ++#define DESC_RATEVHTSS1MCS9 0x35 ++#define DESC_RATEVHTSS2MCS0 0x36 ++#define DESC_RATEVHTSS2MCS1 0x37 ++#define DESC_RATEVHTSS2MCS2 0x38 ++#define DESC_RATEVHTSS2MCS3 0x39 ++#define DESC_RATEVHTSS2MCS4 0x3A ++#define DESC_RATEVHTSS2MCS5 0x3B ++#define DESC_RATEVHTSS2MCS6 0x3C ++#define DESC_RATEVHTSS2MCS7 0x3D ++#define DESC_RATEVHTSS2MCS8 0x3E ++#define DESC_RATEVHTSS2MCS9 0x3F ++#define DESC_RATEVHTSS3MCS0 0x40 ++#define DESC_RATEVHTSS3MCS1 0x41 ++#define DESC_RATEVHTSS3MCS2 0x42 ++#define DESC_RATEVHTSS3MCS3 0x43 ++#define DESC_RATEVHTSS3MCS4 0x44 ++#define DESC_RATEVHTSS3MCS5 0x45 ++#define DESC_RATEVHTSS3MCS6 0x46 ++#define DESC_RATEVHTSS3MCS7 0x47 ++#define DESC_RATEVHTSS3MCS8 0x48 ++#define DESC_RATEVHTSS3MCS9 0x49 ++#define DESC_RATEVHTSS4MCS0 0x4A ++#define DESC_RATEVHTSS4MCS1 0x4B ++#define DESC_RATEVHTSS4MCS2 0x4C ++#define DESC_RATEVHTSS4MCS3 0x4D ++#define DESC_RATEVHTSS4MCS4 0x4E ++#define DESC_RATEVHTSS4MCS5 0x4F ++#define DESC_RATEVHTSS4MCS6 0x50 ++#define DESC_RATEVHTSS4MCS7 0x51 ++#define DESC_RATEVHTSS4MCS8 0x52 ++#define DESC_RATEVHTSS4MCS9 0x53 ++ ++#define HDATA_RATE(rate)\ ++(rate ==DESC_RATE1M)?"CCK_1M":\ ++(rate ==DESC_RATE2M)?"CCK_2M":\ ++(rate ==DESC_RATE5_5M)?"CCK5_5M":\ ++(rate ==DESC_RATE11M)?"CCK_11M":\ ++(rate ==DESC_RATE6M)?"OFDM_6M":\ ++(rate ==DESC_RATE9M)?"OFDM_9M":\ ++(rate ==DESC_RATE12M)?"OFDM_12M":\ ++(rate ==DESC_RATE18M)?"OFDM_18M":\ ++(rate ==DESC_RATE24M)?"OFDM_24M":\ ++(rate ==DESC_RATE36M)?"OFDM_36M":\ ++(rate ==DESC_RATE48M)?"OFDM_48M":\ ++(rate ==DESC_RATE54M)?"OFDM_54M":\ ++(rate ==DESC_RATEMCS0)?"MCS0":\ ++(rate ==DESC_RATEMCS1)?"MCS1":\ ++(rate ==DESC_RATEMCS2)?"MCS2":\ ++(rate ==DESC_RATEMCS3)?"MCS3":\ ++(rate ==DESC_RATEMCS4)?"MCS4":\ ++(rate ==DESC_RATEMCS5)?"MCS5":\ ++(rate ==DESC_RATEMCS6)?"MCS6":\ ++(rate ==DESC_RATEMCS7)?"MCS7":\ ++(rate ==DESC_RATEMCS8)?"MCS8":\ ++(rate ==DESC_RATEMCS9)?"MCS9":\ ++(rate ==DESC_RATEMCS10)?"MCS10":\ ++(rate ==DESC_RATEMCS11)?"MCS11":\ ++(rate ==DESC_RATEMCS12)?"MCS12":\ ++(rate ==DESC_RATEMCS13)?"MCS13":\ ++(rate ==DESC_RATEMCS14)?"MCS14":\ ++(rate ==DESC_RATEMCS15)?"MCS15":\ ++(rate ==DESC_RATEVHTSS1MCS0)?"VHTSS1MCS0":\ ++(rate ==DESC_RATEVHTSS1MCS1)?"VHTSS1MCS1":\ ++(rate ==DESC_RATEVHTSS1MCS2)?"VHTSS1MCS2":\ ++(rate ==DESC_RATEVHTSS1MCS3)?"VHTSS1MCS3":\ ++(rate ==DESC_RATEVHTSS1MCS4)?"VHTSS1MCS4":\ ++(rate ==DESC_RATEVHTSS1MCS5)?"VHTSS1MCS5":\ ++(rate ==DESC_RATEVHTSS1MCS6)?"VHTSS1MCS6":\ ++(rate ==DESC_RATEVHTSS1MCS7)?"VHTSS1MCS7":\ ++(rate ==DESC_RATEVHTSS1MCS8)?"VHTSS1MCS8":\ ++(rate ==DESC_RATEVHTSS1MCS9)?"VHTSS1MCS9":\ ++(rate ==DESC_RATEVHTSS2MCS0)?"VHTSS2MCS0":\ ++(rate ==DESC_RATEVHTSS2MCS1)?"VHTSS2MCS1":\ ++(rate ==DESC_RATEVHTSS2MCS2)?"VHTSS2MCS2":\ ++(rate ==DESC_RATEVHTSS2MCS3)?"VHTSS2MCS3":\ ++(rate ==DESC_RATEVHTSS2MCS4)?"VHTSS2MCS4":\ ++(rate ==DESC_RATEVHTSS2MCS5)?"VHTSS2MCS5":\ ++(rate ==DESC_RATEVHTSS2MCS6)?"VHTSS2MCS6":\ ++(rate ==DESC_RATEVHTSS2MCS7)?"VHTSS2MCS7":\ ++(rate ==DESC_RATEVHTSS2MCS8)?"VHTSS2MCS8":\ ++(rate ==DESC_RATEVHTSS2MCS9)?"VHTSS2MCS9":"UNKNOW" ++ ++ ++enum{ ++ UP_LINK, ++ DOWN_LINK, ++}; ++typedef enum _RT_MEDIA_STATUS { ++ RT_MEDIA_DISCONNECT = 0, ++ RT_MEDIA_CONNECT = 1 ++} RT_MEDIA_STATUS; ++ ++#define MAX_DLFW_PAGE_SIZE 4096 /* @ page : 4k bytes */ ++enum FIRMWARE_SOURCE { ++ FW_SOURCE_IMG_FILE = 0, ++ FW_SOURCE_HEADER_FILE = 1, /* from header file */ ++}; ++ ++/* BK, BE, VI, VO, HCCA, MANAGEMENT, COMMAND, HIGH, BEACON. */ ++/* define MAX_TX_QUEUE 9 */ ++ ++#define TX_SELE_HQ BIT(0) /* High Queue */ ++#define TX_SELE_LQ BIT(1) /* Low Queue */ ++#define TX_SELE_NQ BIT(2) /* Normal Queue */ ++#define TX_SELE_EQ BIT(3) /* Extern Queue */ ++ ++#define PageNum_128(_Len) (u32)(((_Len)>>7) + ((_Len)&0x7F ? 1:0)) ++#define PageNum_256(_Len) (u32)(((_Len)>>8) + ((_Len)&0xFF ? 1:0)) ++#define PageNum_512(_Len) (u32)(((_Len)>>9) + ((_Len)&0x1FF ? 1:0)) ++#define PageNum(_Len, _Size) (u32)(((_Len)/(_Size)) + ((_Len)&((_Size) - 1) ? 1:0)) ++ ++ ++u8 rtw_hal_data_init(struct adapter *padapter); ++void rtw_hal_data_deinit(struct adapter *padapter); ++ ++void dump_chip_info(HAL_VERSION ChipVersion); ++ ++u8 /* return the final channel plan decision */ ++hal_com_config_channel_plan( ++struct adapter *padapter, ++u8 hw_channel_plan, /* channel plan from HW (efuse/eeprom) */ ++u8 sw_channel_plan, /* channel plan from SW (registry/module param) */ ++u8 def_channel_plan, /* channel plan used when the former two is invalid */ ++bool AutoLoadFail ++ ); ++ ++bool ++HAL_IsLegalChannel( ++struct adapter *Adapter, ++u32 Channel ++ ); ++ ++u8 MRateToHwRate(u8 rate); ++ ++u8 HwRateToMRate(u8 rate); ++ ++void HalSetBrateCfg( ++ struct adapter * Adapter, ++ u8 *mBratesOS, ++ u16 *pBrateCfg); ++ ++bool ++Hal_MappingOutPipe( ++struct adapter *padapter, ++u8 NumOutPipe ++ ); ++ ++void hal_init_macaddr(struct adapter *adapter); ++ ++void rtw_init_hal_com_default_value(struct adapter * Adapter); ++ ++void c2h_evt_clear(struct adapter *adapter); ++s32 c2h_evt_read_88xx(struct adapter *adapter, u8 *buf); ++ ++u8 rtw_hal_networktype_to_raid(struct adapter *adapter, struct sta_info *psta); ++u8 rtw_get_mgntframe_raid(struct adapter *adapter, unsigned char network_type); ++void rtw_hal_update_sta_rate_mask(struct adapter *padapter, struct sta_info *psta); ++ ++void hw_var_port_switch (struct adapter *adapter); ++ ++void SetHwReg(struct adapter *padapter, u8 variable, u8 *val); ++void GetHwReg(struct adapter *padapter, u8 variable, u8 *val); ++void rtw_hal_check_rxfifo_full(struct adapter *adapter); ++ ++u8 SetHalDefVar(struct adapter *adapter, enum HAL_DEF_VARIABLE variable, ++ void *value); ++u8 GetHalDefVar(struct adapter *adapter, enum HAL_DEF_VARIABLE variable, ++ void *value); ++ ++bool eqNByte(u8 *str1, u8 *str2, u32 num); ++ ++bool IsHexDigit(char chTmp); ++ ++u32 MapCharToHexDigit(char chTmp); ++ ++bool GetHexValueFromString(char *szStr, u32 *pu4bVal, u32 *pu4bMove); ++ ++bool GetFractionValueFromString(char *szStr, u8 *pInteger, u8 *pFraction, ++ u32 *pu4bMove); ++ ++bool IsCommentString(char *szStr); ++ ++bool ParseQualifiedString(char *In, u32 *Start, char *Out, char LeftQualifier, ++ char RightQualifier); ++ ++bool GetU1ByteIntegerFromStringInDecimal(char *str, u8 *in); ++ ++bool isAllSpaceOrTab(u8 *data, u8 size); ++ ++void linked_info_dump(struct adapter *padapter, u8 benable); ++#ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA ++void rtw_get_raw_rssi_info(void *sel, struct adapter *padapter); ++void rtw_store_phy_info(struct adapter *padapter, union recv_frame *prframe); ++void rtw_dump_raw_rssi_info(struct adapter *padapter); ++#endif ++ ++#define HWSET_MAX_SIZE 512 ++ ++void rtw_bb_rf_gain_offset(struct adapter *padapter); ++ ++void GetHalODMVar(struct adapter *Adapter, ++ enum HAL_ODM_VARIABLE eVariable, ++ void * pValue1, ++ void * pValue2); ++void SetHalODMVar( ++ struct adapter * Adapter, ++ enum HAL_ODM_VARIABLE eVariable, ++ void * pValue1, ++ bool bSet); ++ ++#ifdef CONFIG_BACKGROUND_NOISE_MONITOR ++struct noise_info ++{ ++ u8 bPauseDIG; ++ u8 IGIValue; ++ u32 max_time;/* ms */ ++ u8 chan; ++}; ++#endif ++ ++#endif /* __HAL_COMMON_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/hal_com_h2c.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_com_h2c.h +--- linux-4.3/3rdparty/rtl8723bs/include/hal_com_h2c.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_com_h2c.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,293 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __COMMON_H2C_H__ ++#define __COMMON_H2C_H__ ++ ++/* */ ++/* H2C CMD DEFINITION ------------------------------------------------ */ ++/* */ ++/* 88e, 8723b, 8812, 8821, 92e use the same FW code base */ ++enum h2c_cmd{ ++ /* Common Class: 000 */ ++ H2C_RSVD_PAGE = 0x00, ++ H2C_MEDIA_STATUS_RPT = 0x01, ++ H2C_SCAN_ENABLE = 0x02, ++ H2C_KEEP_ALIVE = 0x03, ++ H2C_DISCON_DECISION = 0x04, ++ H2C_PSD_OFFLOAD = 0x05, ++ H2C_AP_OFFLOAD = 0x08, ++ H2C_BCN_RSVDPAGE = 0x09, ++ H2C_PROBERSP_RSVDPAGE = 0x0A, ++ H2C_FCS_RSVDPAGE = 0x10, ++ H2C_FCS_INFO = 0x11, ++ H2C_AP_WOW_GPIO_CTRL = 0x13, ++ ++ /* PoweSave Class: 001 */ ++ H2C_SET_PWR_MODE = 0x20, ++ H2C_PS_TUNING_PARA = 0x21, ++ H2C_PS_TUNING_PARA2 = 0x22, ++ H2C_P2P_LPS_PARAM = 0x23, ++ H2C_P2P_PS_OFFLOAD = 0x24, ++ H2C_PS_SCAN_ENABLE = 0x25, ++ H2C_SAP_PS_ = 0x26, ++ H2C_INACTIVE_PS_ = 0x27, /* Inactive_PS */ ++ H2C_FWLPS_IN_IPS_ = 0x28, ++ ++ /* Dynamic Mechanism Class: 010 */ ++ H2C_MACID_CFG = 0x40, ++ H2C_TXBF = 0x41, ++ H2C_RSSI_SETTING = 0x42, ++ H2C_AP_REQ_TXRPT = 0x43, ++ H2C_INIT_RATE_COLLECT = 0x44, ++ ++ /* BT Class: 011 */ ++ H2C_B_TYPE_TDMA = 0x60, ++ H2C_BT_INFO = 0x61, ++ H2C_FORCE_BT_TXPWR = 0x62, ++ H2C_BT_IGNORE_WLANACT = 0x63, ++ H2C_DAC_SWING_VALUE = 0x64, ++ H2C_ANT_SEL_RSV = 0x65, ++ H2C_WL_OPMODE = 0x66, ++ H2C_BT_MP_OPER = 0x67, ++ H2C_BT_CONTROL = 0x68, ++ H2C_BT_WIFI_CTRL = 0x69, ++ H2C_BT_FW_PATCH = 0x6A, ++ ++ /* WOWLAN Class: 100 */ ++ H2C_WOWLAN = 0x80, ++ H2C_REMOTE_WAKE_CTRL = 0x81, ++ H2C_AOAC_GLOBAL_INFO = 0x82, ++ H2C_AOAC_RSVD_PAGE = 0x83, ++ H2C_AOAC_RSVD_PAGE2 = 0x84, ++ H2C_D0_SCAN_OFFLOAD_CTRL = 0x85, ++ H2C_D0_SCAN_OFFLOAD_INFO = 0x86, ++ H2C_CHNL_SWITCH_OFFLOAD = 0x87, ++ H2C_AOAC_RSVDPAGE3 = 0x88, ++ ++ H2C_RESET_TSF = 0xC0, ++ H2C_MAXID, ++}; ++ ++#define H2C_RSVDPAGE_LOC_LEN 5 ++#define H2C_MEDIA_STATUS_RPT_LEN 3 ++#define H2C_KEEP_ALIVE_CTRL_LEN 2 ++#define H2C_DISCON_DECISION_LEN 3 ++#define H2C_AP_OFFLOAD_LEN 3 ++#define H2C_AP_WOW_GPIO_CTRL_LEN 4 ++#define H2C_AP_PS_LEN 2 ++#define H2C_PWRMODE_LEN 7 ++#define H2C_PSTUNEPARAM_LEN 4 ++#define H2C_MACID_CFG_LEN 7 ++#define H2C_BTMP_OPER_LEN 4 ++#define H2C_WOWLAN_LEN 4 ++#define H2C_REMOTE_WAKE_CTRL_LEN 3 ++#define H2C_AOAC_GLOBAL_INFO_LEN 2 ++#define H2C_AOAC_RSVDPAGE_LOC_LEN 7 ++#define H2C_SCAN_OFFLOAD_CTRL_LEN 4 ++#define H2C_BT_FW_PATCH_LEN 6 ++#define H2C_RSSI_SETTING_LEN 4 ++#define H2C_AP_REQ_TXRPT_LEN 2 ++#define H2C_FORCE_BT_TXPWR_LEN 3 ++#define H2C_BCN_RSVDPAGE_LEN 5 ++#define H2C_PROBERSP_RSVDPAGE_LEN 5 ++ ++#ifdef CONFIG_WOWLAN ++#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 cpIpAddr(des, src) ((des)[0]=(src)[0], (des)[1]=(src)[1], (des)[2]=(src)[2], (des)[3]=(src)[3]) ++ ++/* */ ++/* ARP packet */ ++/* */ ++/* LLC Header */ ++#define GET_ARP_PKT_LLC_TYPE(__pHeader) ReadEF2Byte(((u8 *)(__pHeader)) + 6) ++ ++/* ARP element */ ++#define GET_ARP_PKT_OPERATION(__pHeader) ReadEF2Byte(((u8 *)(__pHeader)) + 6) ++#define GET_ARP_PKT_SENDER_MAC_ADDR(__pHeader, _val) cpMacAddr((u8 *)(_val), ((u8 *)(__pHeader))+8) ++#define GET_ARP_PKT_SENDER_IP_ADDR(__pHeader, _val) cpIpAddr((u8 *)(_val), ((u8 *)(__pHeader))+14) ++#define GET_ARP_PKT_TARGET_MAC_ADDR(__pHeader, _val) cpMacAddr((u8 *)(_val), ((u8 *)(__pHeader))+18) ++#define GET_ARP_PKT_TARGET_IP_ADDR(__pHeader, _val) cpIpAddr((u8 *)(_val), ((u8 *)(__pHeader))+24) ++ ++#define SET_ARP_PKT_HW(__pHeader, __Value) WRITEEF2BYTE(((u8 *)(__pHeader)) + 0, __Value) ++#define SET_ARP_PKT_PROTOCOL(__pHeader, __Value) WRITEEF2BYTE(((u8 *)(__pHeader)) + 2, __Value) ++#define SET_ARP_PKT_HW_ADDR_LEN(__pHeader, __Value) WRITEEF1BYTE(((u8 *)(__pHeader)) + 4, __Value) ++#define SET_ARP_PKT_PROTOCOL_ADDR_LEN(__pHeader, __Value) WRITEEF1BYTE(((u8 *)(__pHeader)) + 5, __Value) ++#define SET_ARP_PKT_OPERATION(__pHeader, __Value) WRITEEF2BYTE(((u8 *)(__pHeader)) + 6, __Value) ++#define SET_ARP_PKT_SENDER_MAC_ADDR(__pHeader, _val) cpMacAddr(((u8 *)(__pHeader))+8, (u8 *)(_val)) ++#define SET_ARP_PKT_SENDER_IP_ADDR(__pHeader, _val) cpIpAddr(((u8 *)(__pHeader))+14, (u8 *)(_val)) ++#define SET_ARP_PKT_TARGET_MAC_ADDR(__pHeader, _val) cpMacAddr(((u8 *)(__pHeader))+18, (u8 *)(_val)) ++#define SET_ARP_PKT_TARGET_IP_ADDR(__pHeader, _val) cpIpAddr(((u8 *)(__pHeader))+24, (u8 *)(_val)) ++ ++#define FW_WOWLAN_FUN_EN BIT(0) ++#define FW_WOWLAN_PATTERN_MATCH BIT(1) ++#define FW_WOWLAN_MAGIC_PKT BIT(2) ++#define FW_WOWLAN_UNICAST BIT(3) ++#define FW_WOWLAN_ALL_PKT_DROP BIT(4) ++#define FW_WOWLAN_GPIO_ACTIVE BIT(5) ++#define FW_WOWLAN_REKEY_WAKEUP BIT(6) ++#define FW_WOWLAN_DEAUTH_WAKEUP BIT(7) ++ ++#define FW_WOWLAN_GPIO_WAKEUP_EN BIT(0) ++#define FW_FW_PARSE_MAGIC_PKT BIT(1) ++ ++#define FW_REMOTE_WAKE_CTRL_EN BIT(0) ++#define FW_REALWOWLAN_EN BIT(5) ++ ++#define FW_WOWLAN_KEEP_ALIVE_EN BIT(0) ++#define FW_ADOPT_USER BIT(1) ++#define FW_WOWLAN_KEEP_ALIVE_PKT_TYPE BIT(2) ++ ++#define FW_REMOTE_WAKE_CTRL_EN BIT(0) ++#define FW_ARP_EN BIT(1) ++#define FW_REALWOWLAN_EN BIT(5) ++#define FW_WOW_FW_UNICAST_EN BIT(7) ++ ++#endif /* CONFIG_WOWLAN */ ++ ++/* _RSVDPAGE_LOC_CMD_0x00 */ ++#define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd, 0, 8, __Value) ++#define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+1, 0, 8, __Value) ++#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+2, 0, 8, __Value) ++#define SET_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+3, 0, 8, __Value) ++#define SET_H2CCMD_RSVDPAGE_LOC_BT_QOS_NULL_DATA(__pH2CCmd, __Value)SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+4, 0, 8, __Value) ++ ++/* _MEDIA_STATUS_RPT_PARM_CMD_0x01 */ ++#define SET_H2CCMD_MSRRPT_PARM_OPMODE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 1, __Value) ++#define SET_H2CCMD_MSRRPT_PARM_MACID_IND(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 1, 1, __Value) ++#define SET_H2CCMD_MSRRPT_PARM_MACID(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd+1, 0, 8, __Value) ++#define SET_H2CCMD_MSRRPT_PARM_MACID_END(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd+2, 0, 8, __Value) ++ ++/* _KEEP_ALIVE_CMD_0x03 */ ++#define SET_H2CCMD_KEEPALIVE_PARM_ENABLE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 1, __Value) ++#define SET_H2CCMD_KEEPALIVE_PARM_ADOPT(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 1, 1, __Value) ++#define SET_H2CCMD_KEEPALIVE_PARM_PKT_TYPE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 2, 1, __Value) ++#define SET_H2CCMD_KEEPALIVE_PARM_CHECK_PERIOD(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd+1, 0, 8, __Value) ++ ++/* _DISCONNECT_DECISION_CMD_0x04 */ ++#define SET_H2CCMD_DISCONDECISION_PARM_ENABLE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 1, __Value) ++#define SET_H2CCMD_DISCONDECISION_PARM_ADOPT(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 1, 1, __Value) ++#define SET_H2CCMD_DISCONDECISION_PARM_CHECK_PERIOD(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd+1, 0, 8, __Value) ++#define SET_H2CCMD_DISCONDECISION_PARM_TRY_PKT_NUM(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd+2, 0, 8, __Value) ++ ++#ifdef CONFIG_AP_WOWLAN ++/* _AP_Offload 0x08 */ ++#define SET_H2CCMD_AP_WOWLAN_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd, 0, 8, __Value) ++/* _BCN_RsvdPage 0x09 */ ++#define SET_H2CCMD_AP_WOWLAN_RSVDPAGE_LOC_BCN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd, 0, 8, __Value) ++/* _Probersp_RsvdPage 0x0a */ ++#define SET_H2CCMD_AP_WOWLAN_RSVDPAGE_LOC_ProbeRsp(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd, 0, 8, __Value) ++/* _Probersp_RsvdPage 0x13 */ ++#define SET_H2CCMD_AP_WOW_GPIO_CTRL_INDEX(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 4, __Value) ++#define SET_H2CCMD_AP_WOW_GPIO_CTRL_C2H_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 4, 1, __Value) ++#define SET_H2CCMD_AP_WOW_GPIO_CTRL_PLUS(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 5, 1, __Value) ++#define SET_H2CCMD_AP_WOW_GPIO_CTRL_HIGH_ACTIVE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 6, 1, __Value) ++#define SET_H2CCMD_AP_WOW_GPIO_CTRL_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 7, 1, __Value) ++#define SET_H2CCMD_AP_WOW_GPIO_CTRL_DURATION(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+1, 0, 8, __Value) ++#define SET_H2CCMD_AP_WOW_GPIO_CTRL_C2H_DURATION(__pH2CCmd, __Value)SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+2, 0, 8, __Value) ++/* _AP_PS 0x26 */ ++#define SET_H2CCMD_AP_WOW_PS_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 1, __Value) ++#define SET_H2CCMD_AP_WOW_PS_32K_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 1, 1, __Value) ++#define SET_H2CCMD_AP_WOW_PS_RF(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 2, 1, __Value) ++#define SET_H2CCMD_AP_WOW_PS_DURATION(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+1, 0, 8, __Value) ++#endif ++ ++/* _WoWLAN PARAM_CMD_0x80 */ ++#define SET_H2CCMD_WOWLAN_FUNC_ENABLE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 1, __Value) ++#define SET_H2CCMD_WOWLAN_PATTERN_MATCH_ENABLE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 1, 1, __Value) ++#define SET_H2CCMD_WOWLAN_MAGIC_PKT_ENABLE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 2, 1, __Value) ++#define SET_H2CCMD_WOWLAN_UNICAST_PKT_ENABLE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 3, 1, __Value) ++#define SET_H2CCMD_WOWLAN_ALL_PKT_DROP(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 4, 1, __Value) ++#define SET_H2CCMD_WOWLAN_GPIO_ACTIVE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 5, 1, __Value) ++#define SET_H2CCMD_WOWLAN_REKEY_WAKE_UP(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 6, 1, __Value) ++#define SET_H2CCMD_WOWLAN_DISCONNECT_WAKE_UP(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 7, 1, __Value) ++#define SET_H2CCMD_WOWLAN_GPIONUM(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd)+1, 0, 7, __Value) ++#define SET_H2CCMD_WOWLAN_DATAPIN_WAKE_UP(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd)+1, 7, 1, __Value) ++#define SET_H2CCMD_WOWLAN_GPIO_DURATION(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+2, 0, 8, __Value) ++/* define SET_H2CCMD_WOWLAN_GPIO_PULSE_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd)+3, 0, 1, __Value) */ ++#define SET_H2CCMD_WOWLAN_GPIO_PULSE_COUNT(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+3, 0, 8, __Value) ++ ++/* _REMOTE_WAKEUP_CMD_0x81 */ ++#define SET_H2CCMD_REMOTE_WAKECTRL_ENABLE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 1, __Value) ++#define SET_H2CCMD_REMOTE_WAKE_CTRL_ARP_OFFLOAD_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 1, 1, __Value) ++#define SET_H2CCMD_REMOTE_WAKE_CTRL_NDP_OFFLOAD_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 2, 1, __Value) ++#define SET_H2CCMD_REMOTE_WAKE_CTRL_GTK_OFFLOAD_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 3, 1, __Value) ++#define SET_H2CCMD_REMOTE_WAKE_CTRL_NLO_OFFLOAD_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 4, 1, __Value) ++#define SET_H2CCMD_REMOTE_WAKE_CTRL_FW_UNICAST_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 7, 1, __Value) ++#define SET_H2CCMD_REMOTE_WAKE_CTRL_ARP_ACTION(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd)+2, 0, 1, __Value) ++ ++/* AOAC_GLOBAL_INFO_0x82 */ ++#define SET_H2CCMD_AOAC_GLOBAL_INFO_PAIRWISE_ENC_ALG(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd, 0, 8, __Value) ++#define SET_H2CCMD_AOAC_GLOBAL_INFO_GROUP_ENC_ALG(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+1, 0, 8, __Value) ++ ++/* AOAC_RSVDPAGE_LOC_0x83 */ ++#define SET_H2CCMD_AOAC_RSVDPAGE_LOC_REMOTE_WAKE_CTRL_INFO(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd), 0, 8, __Value) ++#define SET_H2CCMD_AOAC_RSVDPAGE_LOC_ARP_RSP(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+1, 0, 8, __Value) ++#define SET_H2CCMD_AOAC_RSVDPAGE_LOC_NEIGHBOR_ADV(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+2, 0, 8, __Value) ++#define SET_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_RSP(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+3, 0, 8, __Value) ++#define SET_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_INFO(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+4, 0, 8, __Value) ++#ifdef CONFIG_GTK_OL ++#define SET_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_EXT_MEM(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+5, 0, 8, __Value) ++#endif /* CONFIG_GTK_OL */ ++#ifdef CONFIG_PNO_SUPPORT ++#define SET_H2CCMD_AOAC_RSVDPAGE_LOC_NLO_INFO(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd), 0, 8, __Value) ++#endif ++ ++#ifdef CONFIG_PNO_SUPPORT ++/* D0_Scan_Offload_Info_0x86 */ ++#define SET_H2CCMD_AOAC_NLO_FUN_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd), 3, 1, __Value) ++#define SET_H2CCMD_AOAC_RSVDPAGE_LOC_PROBE_PACKET(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+1, 0, 8, __Value) ++#define SET_H2CCMD_AOAC_RSVDPAGE_LOC_SCAN_INFO(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+2, 0, 8, __Value) ++#define SET_H2CCMD_AOAC_RSVDPAGE_LOC_SSID_INFO(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+3, 0, 8, __Value) ++#endif /* CONFIG_PNO_SUPPORT */ ++ ++/* */ ++/* Structure -------------------------------------------------- */ ++/* */ ++typedef struct _RSVDPAGE_LOC { ++ u8 LocProbeRsp; ++ u8 LocPsPoll; ++ u8 LocNullData; ++ u8 LocQosNull; ++ u8 LocBTQosNull; ++#ifdef CONFIG_WOWLAN ++ u8 LocRemoteCtrlInfo; ++ u8 LocArpRsp; ++ u8 LocNbrAdv; ++ u8 LocGTKRsp; ++ u8 LocGTKInfo; ++ u8 LocProbeReq; ++ u8 LocNetList; ++#ifdef CONFIG_GTK_OL ++ u8 LocGTKEXTMEM; ++#endif /* CONFIG_GTK_OL */ ++#ifdef CONFIG_PNO_SUPPORT ++ u8 LocPNOInfo; ++ u8 LocScanInfo; ++ u8 LocSSIDInfo; ++ u8 LocProbePacket; ++#endif /* CONFIG_PNO_SUPPORT */ ++#endif /* CONFIG_WOWLAN */ ++#ifdef CONFIG_AP_WOWLAN ++ u8 LocApOffloadBCN; ++#endif /* CONFIG_AP_WOWLAN */ ++} RSVDPAGE_LOC, *PRSVDPAGE_LOC; ++ ++#endif ++#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) ++void rtw_get_current_ip_address(struct adapter *padapter, u8 *pcurrentip); ++void rtw_get_sec_iv(struct adapter *padapter, u8*pcur_dot11txpn, u8 *StaAddr); ++void rtw_set_sec_pn(struct adapter *padapter); ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/hal_com_phycfg.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_com_phycfg.h +--- linux-4.3/3rdparty/rtl8723bs/include/hal_com_phycfg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_com_phycfg.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,275 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __HAL_COM_PHYCFG_H__ ++#define __HAL_COM_PHYCFG_H__ ++ ++#define PathA 0x0 /* Useless */ ++#define PathB 0x1 ++#define PathC 0x2 ++#define PathD 0x3 ++ ++enum RATE_SECTION { ++ CCK = 0, ++ OFDM, ++ HT_MCS0_MCS7, ++ HT_MCS8_MCS15, ++ HT_MCS16_MCS23, ++ HT_MCS24_MCS31, ++ VHT_1SSMCS0_1SSMCS9, ++ VHT_2SSMCS0_2SSMCS9, ++ VHT_3SSMCS0_3SSMCS9, ++ VHT_4SSMCS0_4SSMCS9, ++}; ++ ++enum RF_TX_NUM { ++ RF_1TX = 0, ++ RF_2TX, ++ RF_3TX, ++ RF_4TX, ++ RF_MAX_TX_NUM, ++ RF_TX_NUM_NONIMPLEMENT, ++}; ++ ++#define MAX_POWER_INDEX 0x3F ++ ++enum _REGULATION_TXPWR_LMT { ++ TXPWR_LMT_FCC = 0, ++ TXPWR_LMT_MKK, ++ TXPWR_LMT_ETSI, ++ TXPWR_LMT_WW, ++ TXPWR_LMT_MAX_REGULATION_NUM, ++}; ++ ++/*------------------------------Define structure----------------------------*/ ++struct bb_register_def { ++ u32 rfintfs; /* set software control: */ ++ /* 0x870~0x877[8 bytes] */ ++ ++ u32 rfintfo; /* output data: */ ++ /* 0x860~0x86f [16 bytes] */ ++ ++ u32 rfintfe; /* output enable: */ ++ /* 0x860~0x86f [16 bytes] */ ++ ++ u32 rf3wireOffset; /* LSSI data: */ ++ /* 0x840~0x84f [16 bytes] */ ++ ++ u32 rfHSSIPara2; /* wire parameter control2 : */ ++ /* 0x824~0x827, 0x82c~0x82f, ++ * 0x834~0x837, 0x83c~0x83f ++ */ ++ u32 rfLSSIReadBack; /* LSSI RF readback data SI mode */ ++ /* 0x8a0~0x8af [16 bytes] */ ++ ++ u32 rfLSSIReadBackPi; /* LSSI RF readback data PI mode ++ * 0x8b8-8bc for Path A and B */ ++ ++}; ++ ++u8 ++PHY_GetTxPowerByRateBase( ++struct adapter * Adapter, ++u8 Band, ++u8 RfPath, ++u8 TxNum, ++enum RATE_SECTION RateSection ++ ); ++ ++u8 ++PHY_GetRateSectionIndexOfTxPowerByRate( ++struct adapter *padapter, ++u32 RegAddr, ++u32 BitMask ++ ); ++ ++void ++PHY_GetRateValuesOfTxPowerByRate( ++struct adapter *padapter, ++u32 RegAddr, ++u32 BitMask, ++u32 Value, ++ u8* RateIndex, ++ s8* PwrByRateVal, ++ u8* RateNum ++ ); ++ ++u8 ++PHY_GetRateIndexOfTxPowerByRate( ++u8 Rate ++ ); ++ ++void ++PHY_SetTxPowerIndexByRateSection( ++struct adapter * padapter, ++u8 RFPath, ++u8 Channel, ++u8 RateSection ++ ); ++ ++s8 ++PHY_GetTxPowerByRate( ++struct adapter *padapter, ++u8 Band, ++u8 RFPath, ++u8 TxNum, ++u8 RateIndex ++ ); ++ ++void ++PHY_SetTxPowerByRate( ++struct adapter *padapter, ++u8 Band, ++u8 RFPath, ++u8 TxNum, ++u8 Rate, ++s8 Value ++ ); ++ ++void ++PHY_SetTxPowerLevelByPath( ++struct adapter *Adapter, ++u8 channel, ++u8 path ++ ); ++ ++void ++PHY_SetTxPowerIndexByRateArray( ++struct adapter * padapter, ++u8 RFPath, ++enum CHANNEL_WIDTH BandWidth, ++u8 Channel, ++u8* Rates, ++u8 RateArraySize ++ ); ++ ++void ++PHY_InitTxPowerByRate( ++struct adapter *padapter ++ ); ++ ++void ++PHY_StoreTxPowerByRate( ++struct adapter *padapter, ++u32 Band, ++u32 RfPath, ++u32 TxNum, ++u32 RegAddr, ++u32 BitMask, ++u32 Data ++ ); ++ ++void ++PHY_TxPowerByRateConfiguration( ++ struct adapter * padapter ++ ); ++ ++u8 ++PHY_GetTxPowerIndexBase( ++struct adapter * padapter, ++u8 RFPath, ++u8 Rate, ++enum CHANNEL_WIDTH BandWidth, ++u8 Channel, ++ bool *bIn24G ++ ); ++ ++s8 PHY_GetTxPowerLimit (struct adapter *adapter, u32 RegPwrTblSel, ++ enum BAND_TYPE Band, enum CHANNEL_WIDTH Bandwidth, ++u8 RfPath, ++u8 DataRate, ++u8 Channel ++ ); ++ ++void ++PHY_SetTxPowerLimit( ++struct adapter * Adapter, ++u8 *Regulation, ++u8 *Band, ++u8 *Bandwidth, ++u8 *RateSection, ++u8 *RfPath, ++u8 *Channel, ++u8 *PowerLimit ++ ); ++ ++void ++PHY_ConvertTxPowerLimitToPowerIndex( ++struct adapter * Adapter ++ ); ++ ++void ++PHY_InitTxPowerLimit( ++struct adapter * Adapter ++ ); ++ ++s8 ++PHY_GetTxPowerTrackingOffset( ++ struct adapter *padapter, ++ u8 Rate, ++ u8 RFPath ++ ); ++ ++u8 ++PHY_GetTxPowerIndex( ++struct adapter * padapter, ++u8 RFPath, ++u8 Rate, ++enum CHANNEL_WIDTH BandWidth, ++u8 Channel ++ ); ++ ++void ++PHY_SetTxPowerIndex( ++struct adapter * padapter, ++u32 PowerIndex, ++u8 RFPath, ++u8 Rate ++ ); ++ ++void ++Hal_ChannelPlanToRegulation( ++struct adapter * Adapter, ++u16 ChannelPlan ++ ); ++ ++#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE ++#define MAX_PARA_FILE_BUF_LEN 25600 ++ ++#define LOAD_MAC_PARA_FILE BIT0 ++#define LOAD_BB_PARA_FILE BIT1 ++#define LOAD_BB_PG_PARA_FILE BIT2 ++#define LOAD_BB_MP_PARA_FILE BIT3 ++#define LOAD_RF_PARA_FILE BIT4 ++#define LOAD_RF_TXPWR_TRACK_PARA_FILE BIT5 ++#define LOAD_RF_TXPWR_LMT_PARA_FILE BIT6 ++ ++int phy_ConfigMACWithParaFile(struct adapter *Adapter, char*pFileName); ++ ++int phy_ConfigBBWithParaFile(struct adapter *Adapter, char*pFileName, u32 ConfigType); ++ ++int phy_ConfigBBWithPgParaFile(struct adapter *Adapter, char*pFileName); ++ ++int phy_ConfigBBWithMpParaFile(struct adapter *Adapter, char*pFileName); ++ ++int PHY_ConfigRFWithParaFile(struct adapter *Adapter, char*pFileName, u8 eRFPath); ++ ++int PHY_ConfigRFWithTxPwrTrackParaFile(struct adapter *Adapter, char*pFileName); ++ ++int PHY_ConfigRFWithPowerLimitTableParaFile(struct adapter *Adapter, char*pFileName); ++ ++void phy_free_filebuf(struct adapter *padapter); ++#endif /* CONFIG_LOAD_PHY_PARA_FROM_FILE */ ++ ++#endif /* __HAL_COMMON_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/hal_com_reg.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_com_reg.h +--- linux-4.3/3rdparty/rtl8723bs/include/hal_com_reg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_com_reg.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,1725 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __HAL_COMMON_REG_H__ ++#define __HAL_COMMON_REG_H__ ++ ++ ++#define MAC_ADDR_LEN 6 ++ ++#define HAL_NAV_UPPER_UNIT 128 /* micro-second */ ++ ++/* 8188E PKT_BUFF_ACCESS_CTRL value */ ++#define TXPKT_BUF_SELECT 0x69 ++#define RXPKT_BUF_SELECT 0xA5 ++#define DISABLE_TRXPKT_BUF_ACCESS 0x0 ++ ++/* */ ++/* */ ++/* */ ++ ++/* */ ++/* */ ++/* 0x0000h ~ 0x00FFh System Configuration */ ++/* */ ++/* */ ++#define REG_SYS_ISO_CTRL 0x0000 ++#define REG_SYS_FUNC_EN 0x0002 ++#define REG_APS_FSMCO 0x0004 ++#define REG_SYS_CLKR 0x0008 ++#define REG_9346CR 0x000A ++#define REG_SYS_EEPROM_CTRL 0x000A ++#define REG_EE_VPD 0x000C ++#define REG_AFE_MISC 0x0010 ++#define REG_SPS0_CTRL 0x0011 ++#define REG_SPS0_CTRL_6 0x0016 ++#define REG_POWER_OFF_IN_PROCESS 0x0017 ++#define REG_SPS_OCP_CFG 0x0018 ++#define REG_RSV_CTRL 0x001C ++#define REG_RF_CTRL 0x001F ++#define REG_LDOA15_CTRL 0x0020 ++#define REG_LDOV12D_CTRL 0x0021 ++#define REG_LDOHCI12_CTRL 0x0022 ++#define REG_LPLDO_CTRL 0x0023 ++#define REG_AFE_XTAL_CTRL 0x0024 ++#define REG_AFE_LDO_CTRL 0x0027 /* 1.5v for 8188EE test chip, 1.4v for MP chip */ ++#define REG_AFE_PLL_CTRL 0x0028 ++#define REG_MAC_PHY_CTRL 0x002c /* for 92d, DMDP, SMSP, DMSP contrl */ ++#define REG_APE_PLL_CTRL_EXT 0x002c ++#define REG_EFUSE_CTRL 0x0030 ++#define REG_EFUSE_TEST 0x0034 ++#define REG_PWR_DATA 0x0038 ++#define REG_CAL_TIMER 0x003C ++#define REG_ACLK_MON 0x003E ++#define REG_GPIO_MUXCFG 0x0040 ++#define REG_GPIO_IO_SEL 0x0042 ++#define REG_MAC_PINMUX_CFG 0x0043 ++#define REG_GPIO_PIN_CTRL 0x0044 ++#define REG_GPIO_INTM 0x0048 ++#define REG_LEDCFG0 0x004C ++#define REG_LEDCFG1 0x004D ++#define REG_LEDCFG2 0x004E ++#define REG_LEDCFG3 0x004F ++#define REG_FSIMR 0x0050 ++#define REG_FSISR 0x0054 ++#define REG_HSIMR 0x0058 ++#define REG_HSISR 0x005c ++#define REG_GPIO_PIN_CTRL_2 0x0060 /* RTL8723 WIFI/BT/GPS Multi-Function GPIO Pin Control. */ ++#define REG_GPIO_IO_SEL_2 0x0062 /* RTL8723 WIFI/BT/GPS Multi-Function GPIO Select. */ ++#define REG_MULTI_FUNC_CTRL 0x0068 /* RTL8723 WIFI/BT/GPS Multi-Function control source. */ ++#define REG_GSSR 0x006c ++#define REG_AFE_XTAL_CTRL_EXT 0x0078 /* RTL8188E */ ++#define REG_XCK_OUT_CTRL 0x007c /* RTL8188E */ ++#define REG_MCUFWDL 0x0080 ++#define REG_WOL_EVENT 0x0081 /* RTL8188E */ ++#define REG_MCUTSTCFG 0x0084 ++#define REG_FDHM0 0x0088 ++#define REG_HOST_SUSP_CNT 0x00BC /* RTL8192C Host suspend counter on FPGA platform */ ++#define REG_SYSTEM_ON_CTRL 0x00CC /* For 8723AE Reset after S3 */ ++#define REG_EFUSE_ACCESS 0x00CF /* Efuse access protection for RTL8723 */ ++#define REG_BIST_SCAN 0x00D0 ++#define REG_BIST_RPT 0x00D4 ++#define REG_BIST_ROM_RPT 0x00D8 ++#define REG_USB_SIE_INTF 0x00E0 ++#define REG_PCIE_MIO_INTF 0x00E4 ++#define REG_PCIE_MIO_INTD 0x00E8 ++#define REG_HPON_FSM 0x00EC ++#define REG_SYS_CFG 0x00F0 ++#define REG_GPIO_OUTSTS 0x00F4 /* For RTL8723 only. */ ++#define REG_TYPE_ID 0x00FC ++ ++/* */ ++/* 2010/12/29 MH Add for 92D */ ++/* */ ++#define REG_MAC_PHY_CTRL_NORMAL 0x00f8 ++ ++ ++/* */ ++/* */ ++/* 0x0100h ~ 0x01FFh MACTOP General Configuration */ ++/* */ ++/* */ ++#define REG_CR 0x0100 ++#define REG_PBP 0x0104 ++#define REG_PKT_BUFF_ACCESS_CTRL 0x0106 ++#define REG_TRXDMA_CTRL 0x010C ++#define REG_TRXFF_BNDY 0x0114 ++#define REG_TRXFF_STATUS 0x0118 ++#define REG_RXFF_PTR 0x011C ++#define REG_HIMR 0x0120 ++#define REG_HISR 0x0124 ++#define REG_HIMRE 0x0128 ++#define REG_HISRE 0x012C ++#define REG_CPWM 0x012F ++#define REG_FWIMR 0x0130 ++#define REG_FWISR 0x0134 ++#define REG_FTIMR 0x0138 ++#define REG_FTISR 0x013C /* RTL8192C */ ++#define REG_PKTBUF_DBG_CTRL 0x0140 ++#define REG_RXPKTBUF_CTRL (REG_PKTBUF_DBG_CTRL+2) ++#define REG_PKTBUF_DBG_DATA_L 0x0144 ++#define REG_PKTBUF_DBG_DATA_H 0x0148 ++ ++#define REG_TC0_CTRL 0x0150 ++#define REG_TC1_CTRL 0x0154 ++#define REG_TC2_CTRL 0x0158 ++#define REG_TC3_CTRL 0x015C ++#define REG_TC4_CTRL 0x0160 ++#define REG_TCUNIT_BASE 0x0164 ++#define REG_MBIST_START 0x0174 ++#define REG_MBIST_DONE 0x0178 ++#define REG_MBIST_FAIL 0x017C ++#define REG_32K_CTRL 0x0194 /* RTL8188E */ ++#define REG_C2HEVT_MSG_NORMAL 0x01A0 ++#define REG_C2HEVT_CLEAR 0x01AF ++#define REG_MCUTST_1 0x01c0 ++#define REG_MCUTST_WOWLAN 0x01C7 /* Defined after 8188E series. */ ++#define REG_FMETHR 0x01C8 ++#define REG_HMETFR 0x01CC ++#define REG_HMEBOX_0 0x01D0 ++#define REG_HMEBOX_1 0x01D4 ++#define REG_HMEBOX_2 0x01D8 ++#define REG_HMEBOX_3 0x01DC ++#define REG_LLT_INIT 0x01E0 ++ ++ ++/* */ ++/* */ ++/* 0x0200h ~ 0x027Fh TXDMA Configuration */ ++/* */ ++/* */ ++#define REG_RQPN 0x0200 ++#define REG_FIFOPAGE 0x0204 ++#define REG_TDECTRL 0x0208 ++#define REG_TXDMA_OFFSET_CHK 0x020C ++#define REG_TXDMA_STATUS 0x0210 ++#define REG_RQPN_NPQ 0x0214 ++#define REG_AUTO_LLT 0x0224 ++ ++ ++/* */ ++/* */ ++/* 0x0280h ~ 0x02FFh RXDMA Configuration */ ++/* */ ++/* */ ++#define REG_RXDMA_AGG_PG_TH 0x0280 ++#define REG_RXPKT_NUM 0x0284 ++#define REG_RXDMA_STATUS 0x0288 ++ ++/* */ ++/* */ ++/* 0x0300h ~ 0x03FFh PCIe */ ++/* */ ++/* */ ++#define REG_PCIE_CTRL_REG 0x0300 ++#define REG_INT_MIG 0x0304 /* Interrupt Migration */ ++#define REG_BCNQ_DESA 0x0308 /* TX Beacon Descriptor Address */ ++#define REG_HQ_DESA 0x0310 /* TX High Queue Descriptor Address */ ++#define REG_MGQ_DESA 0x0318 /* TX Manage Queue Descriptor Address */ ++#define REG_VOQ_DESA 0x0320 /* TX VO Queue Descriptor Address */ ++#define REG_VIQ_DESA 0x0328 /* TX VI Queue Descriptor Address */ ++#define REG_BEQ_DESA 0x0330 /* TX BE Queue Descriptor Address */ ++#define REG_BKQ_DESA 0x0338 /* TX BK Queue Descriptor Address */ ++#define REG_RX_DESA 0x0340 /* RX Queue Descriptor Address */ ++/* sherry added for DBI Read/Write 20091126 */ ++#define REG_DBI_WDATA 0x0348 /* Backdoor REG for Access Configuration */ ++#define REG_DBI_RDATA 0x034C /* Backdoor REG for Access Configuration */ ++#define REG_DBI_CTRL 0x0350 /* Backdoor REG for Access Configuration */ ++#define REG_DBI_FLAG 0x0352 /* Backdoor REG for Access Configuration */ ++#define REG_MDIO 0x0354 /* MDIO for Access PCIE PHY */ ++#define REG_DBG_SEL 0x0360 /* Debug Selection Register */ ++#define REG_PCIE_HRPWM 0x0361 /* PCIe RPWM */ ++#define REG_PCIE_HCPWM 0x0363 /* PCIe CPWM */ ++#define REG_WATCH_DOG 0x0368 ++ ++/* RTL8723 series ------------------------------- */ ++#define REG_PCIE_HISR_EN 0x0394 /* PCIE Local Interrupt Enable Register */ ++#define REG_PCIE_HISR 0x03A0 ++#define REG_PCIE_HISRE 0x03A4 ++#define REG_PCIE_HIMR 0x03A8 ++#define REG_PCIE_HIMRE 0x03AC ++ ++#define REG_USB_HIMR 0xFE38 ++#define REG_USB_HIMRE 0xFE3C ++#define REG_USB_HISR 0xFE78 ++#define REG_USB_HISRE 0xFE7C ++ ++ ++/* */ ++/* */ ++/* 0x0400h ~ 0x047Fh Protocol Configuration */ ++/* */ ++/* */ ++#define REG_VOQ_INFORMATION 0x0400 ++#define REG_VIQ_INFORMATION 0x0404 ++#define REG_BEQ_INFORMATION 0x0408 ++#define REG_BKQ_INFORMATION 0x040C ++#define REG_MGQ_INFORMATION 0x0410 ++#define REG_HGQ_INFORMATION 0x0414 ++#define REG_BCNQ_INFORMATION 0x0418 ++#define REG_TXPKT_EMPTY 0x041A ++#define REG_CPU_MGQ_INFORMATION 0x041C ++#define REG_FWHW_TXQ_CTRL 0x0420 ++#define REG_HWSEQ_CTRL 0x0423 ++#define REG_BCNQ_BDNY 0x0424 ++#define REG_MGQ_BDNY 0x0425 ++#define REG_LIFETIME_CTRL 0x0426 ++#define REG_MULTI_BCNQ_OFFSET 0x0427 ++#define REG_SPEC_SIFS 0x0428 ++#define REG_RL 0x042A ++#define REG_DARFRC 0x0430 ++#define REG_RARFRC 0x0438 ++#define REG_RRSR 0x0440 ++#define REG_ARFR0 0x0444 ++#define REG_ARFR1 0x0448 ++#define REG_ARFR2 0x044C ++#define REG_ARFR3 0x0450 ++#define REG_BCNQ1_BDNY 0x0457 ++ ++#define REG_AGGLEN_LMT 0x0458 ++#define REG_AMPDU_MIN_SPACE 0x045C ++#define REG_WMAC_LBK_BF_HD 0x045D ++#define REG_FAST_EDCA_CTRL 0x0460 ++#define REG_RD_RESP_PKT_TH 0x0463 ++ ++#define REG_INIRTS_RATE_SEL 0x0480 ++#define REG_INIDATA_RATE_SEL 0x0484 ++ ++#define REG_POWER_STAGE1 0x04B4 ++#define REG_POWER_STAGE2 0x04B8 ++#define REG_PKT_VO_VI_LIFE_TIME 0x04C0 ++#define REG_PKT_BE_BK_LIFE_TIME 0x04C2 ++#define REG_STBC_SETTING 0x04C4 ++#define REG_QUEUE_CTRL 0x04C6 ++#define REG_SINGLE_AMPDU_CTRL 0x04c7 ++#define REG_PROT_MODE_CTRL 0x04C8 ++#define REG_MAX_AGGR_NUM 0x04CA ++#define REG_RTS_MAX_AGGR_NUM 0x04CB ++#define REG_BAR_MODE_CTRL 0x04CC ++#define REG_RA_TRY_RATE_AGG_LMT 0x04CF ++#define REG_EARLY_MODE_CONTROL 0x04D0 ++#define REG_MACID_SLEEP 0x04D4 ++#define REG_NQOS_SEQ 0x04DC ++#define REG_QOS_SEQ 0x04DE ++#define REG_NEED_CPU_HANDLE 0x04E0 ++#define REG_PKT_LOSE_RPT 0x04E1 ++#define REG_PTCL_ERR_STATUS 0x04E2 ++#define REG_TX_RPT_CTRL 0x04EC ++#define REG_TX_RPT_TIME 0x04F0 /* 2 byte */ ++#define REG_DUMMY 0x04FC ++ ++/* */ ++/* */ ++/* 0x0500h ~ 0x05FFh EDCA Configuration */ ++/* */ ++/* */ ++#define REG_EDCA_VO_PARAM 0x0500 ++#define REG_EDCA_VI_PARAM 0x0504 ++#define REG_EDCA_BE_PARAM 0x0508 ++#define REG_EDCA_BK_PARAM 0x050C ++#define REG_BCNTCFG 0x0510 ++#define REG_PIFS 0x0512 ++#define REG_RDG_PIFS 0x0513 ++#define REG_SIFS_CTX 0x0514 ++#define REG_SIFS_TRX 0x0516 ++#define REG_TSFTR_SYN_OFFSET 0x0518 ++#define REG_AGGR_BREAK_TIME 0x051A ++#define REG_SLOT 0x051B ++#define REG_TX_PTCL_CTRL 0x0520 ++#define REG_TXPAUSE 0x0522 ++#define REG_DIS_TXREQ_CLR 0x0523 ++#define REG_RD_CTRL 0x0524 ++/* */ ++/* Format for offset 540h-542h: */ ++/* [3:0]: TBTT prohibit setup in unit of 32us. The time for HW getting beacon content before TBTT. */ ++/* [7:4]: Reserved. */ ++/* [19:8]: TBTT prohibit hold in unit of 32us. The time for HW holding to send the beacon packet. */ ++/* [23:20]: Reserved */ ++/* Description: */ ++/* | */ ++/* |<--Setup--|--Hold------------>| */ ++/* --------------|---------------------- */ ++/* | */ ++/* TBTT */ ++/* Note: We cannot update beacon content to HW or send any AC packets during the time between Setup and Hold. */ ++/* Described by Designer Tim and Bruce, 2011-01-14. */ ++/* */ ++#define REG_TBTT_PROHIBIT 0x0540 ++#define REG_RD_NAV_NXT 0x0544 ++#define REG_NAV_PROT_LEN 0x0546 ++#define REG_BCN_CTRL 0x0550 ++#define REG_BCN_CTRL_1 0x0551 ++#define REG_MBID_NUM 0x0552 ++#define REG_DUAL_TSF_RST 0x0553 ++#define REG_BCN_INTERVAL 0x0554 /* The same as REG_MBSSID_BCN_SPACE */ ++#define REG_DRVERLYINT 0x0558 ++#define REG_BCNDMATIM 0x0559 ++#define REG_ATIMWND 0x055A ++#define REG_USTIME_TSF 0x055C ++#define REG_BCN_MAX_ERR 0x055D ++#define REG_RXTSF_OFFSET_CCK 0x055E ++#define REG_RXTSF_OFFSET_OFDM 0x055F ++#define REG_TSFTR 0x0560 ++#define REG_TSFTR1 0x0568 /* HW Port 1 TSF Register */ ++#define REG_ATIMWND_1 0x0570 ++#define REG_P2P_CTWIN 0x0572 /* 1 Byte long (in unit of TU) */ ++#define REG_PSTIMER 0x0580 ++#define REG_TIMER0 0x0584 ++#define REG_TIMER1 0x0588 ++#define REG_ACMHWCTRL 0x05C0 ++#define REG_NOA_DESC_SEL 0x05CF ++#define REG_NOA_DESC_DURATION 0x05E0 ++#define REG_NOA_DESC_INTERVAL 0x05E4 ++#define REG_NOA_DESC_START 0x05E8 ++#define REG_NOA_DESC_COUNT 0x05EC ++ ++#define REG_DMC 0x05F0 /* Dual MAC Co-Existence Register */ ++#define REG_SCH_TX_CMD 0x05F8 ++ ++#define REG_FW_RESET_TSF_CNT_1 0x05FC ++#define REG_FW_RESET_TSF_CNT_0 0x05FD ++#define REG_FW_BCN_DIS_CNT 0x05FE ++ ++/* */ ++/* */ ++/* 0x0600h ~ 0x07FFh WMAC Configuration */ ++/* */ ++/* */ ++#define REG_APSD_CTRL 0x0600 ++#define REG_BWOPMODE 0x0603 ++#define REG_TCR 0x0604 ++#define REG_RCR 0x0608 ++#define REG_RX_PKT_LIMIT 0x060C ++#define REG_RX_DLK_TIME 0x060D ++#define REG_RX_DRVINFO_SZ 0x060F ++ ++#define REG_MACID 0x0610 ++#define REG_BSSID 0x0618 ++#define REG_MAR 0x0620 ++#define REG_MBIDCAMCFG 0x0628 ++ ++#define REG_PNO_STATUS 0x0631 ++#define REG_USTIME_EDCA 0x0638 ++#define REG_MAC_SPEC_SIFS 0x063A ++/* 20100719 Joseph: Hardware register definition change. (HW datasheet v54) */ ++#define REG_RESP_SIFS_CCK 0x063C /* [15:8]SIFS_R2T_OFDM, [7:0]SIFS_R2T_CCK */ ++#define REG_RESP_SIFS_OFDM 0x063E /* [15:8]SIFS_T2T_OFDM, [7:0]SIFS_T2T_CCK */ ++ ++#define REG_ACKTO 0x0640 ++#define REG_CTS2TO 0x0641 ++#define REG_EIFS 0x0642 ++ ++ ++/* RXERR_RPT */ ++#define RXERR_TYPE_OFDM_PPDU 0 ++#define RXERR_TYPE_OFDMfalse_ALARM 1 ++#define RXERR_TYPE_OFDM_MPDU_OK 2 ++#define RXERR_TYPE_OFDM_MPDU_FAIL 3 ++#define RXERR_TYPE_CCK_PPDU 4 ++#define RXERR_TYPE_CCKfalse_ALARM 5 ++#define RXERR_TYPE_CCK_MPDU_OK 6 ++#define RXERR_TYPE_CCK_MPDU_FAIL 7 ++#define RXERR_TYPE_HT_PPDU 8 ++#define RXERR_TYPE_HTfalse_ALARM 9 ++#define RXERR_TYPE_HT_MPDU_TOTAL 10 ++#define RXERR_TYPE_HT_MPDU_OK 11 ++#define RXERR_TYPE_HT_MPDU_FAIL 12 ++#define RXERR_TYPE_RX_FULL_DROP 15 ++ ++#define RXERR_COUNTER_MASK 0xFFFFF ++#define RXERR_RPT_RST BIT(27) ++#define _RXERR_RPT_SEL(type) ((type) << 28) ++ ++/* */ ++/* Note: */ ++/* The NAV upper value is very important to WiFi 11n 5.2.3 NAV test. The default value is */ ++/* always too small, but the WiFi TestPlan test by 25, 000 microseconds of NAV through sending */ ++/* CTS in the air. We must update this value greater than 25, 000 microseconds to pass the item. */ ++/* The offset of NAV_UPPER in 8192C Spec is incorrect, and the offset should be 0x0652. Commented */ ++/* by SD1 Scott. */ ++/* By Bruce, 2011-07-18. */ ++/* */ ++#define REG_NAV_UPPER 0x0652 /* unit of 128 */ ++ ++/* WMA, BA, CCX */ ++#define REG_NAV_CTRL 0x0650 ++#define REG_BACAMCMD 0x0654 ++#define REG_BACAMCONTENT 0x0658 ++#define REG_LBDLY 0x0660 ++#define REG_FWDLY 0x0661 ++#define REG_RXERR_RPT 0x0664 ++#define REG_WMAC_TRXPTCL_CTL 0x0668 ++ ++/* Security */ ++#define REG_CAMCMD 0x0670 ++#define REG_CAMWRITE 0x0674 ++#define REG_CAMREAD 0x0678 ++#define REG_CAMDBG 0x067C ++#define REG_SECCFG 0x0680 ++ ++/* Power */ ++#define REG_WOW_CTRL 0x0690 ++#define REG_PS_RX_INFO 0x0692 ++#define REG_UAPSD_TID 0x0693 ++#define REG_WKFMCAM_CMD 0x0698 ++#define REG_WKFMCAM_NUM REG_WKFMCAM_CMD ++#define REG_WKFMCAM_RWD 0x069C ++#define REG_RXFLTMAP0 0x06A0 ++#define REG_RXFLTMAP1 0x06A2 ++#define REG_RXFLTMAP2 0x06A4 ++#define REG_BCN_PSR_RPT 0x06A8 ++#define REG_BT_COEX_TABLE 0x06C0 ++ ++/* Hardware Port 2 */ ++#define REG_MACID1 0x0700 ++#define REG_BSSID1 0x0708 ++ ++ ++/* */ ++/* */ ++/* 0xFE00h ~ 0xFE55h USB Configuration */ ++/* */ ++/* */ ++#define REG_USB_INFO 0xFE17 ++#define REG_USB_SPECIAL_OPTION 0xFE55 ++#define REG_USB_DMA_AGG_TO 0xFE5B ++#define REG_USB_AGG_TO 0xFE5C ++#define REG_USB_AGG_TH 0xFE5D ++ ++#define REG_USB_HRPWM 0xFE58 ++#define REG_USB_HCPWM 0xFE57 ++ ++/* for 92DU high_Queue low_Queue Normal_Queue select */ ++#define REG_USB_High_NORMAL_Queue_Select_MAC0 0xFE44 ++/* define REG_USB_LOW_Queue_Select_MAC0 0xFE45 */ ++#define REG_USB_High_NORMAL_Queue_Select_MAC1 0xFE47 ++/* define REG_USB_LOW_Queue_Select_MAC1 0xFE48 */ ++ ++/* For test chip */ ++#define REG_TEST_USB_TXQS 0xFE48 ++#define REG_TEST_SIE_VID 0xFE60 /* 0xFE60~0xFE61 */ ++#define REG_TEST_SIE_PID 0xFE62 /* 0xFE62~0xFE63 */ ++#define REG_TEST_SIE_OPTIONAL 0xFE64 ++#define REG_TEST_SIE_CHIRP_K 0xFE65 ++#define REG_TEST_SIE_PHY 0xFE66 /* 0xFE66~0xFE6B */ ++#define REG_TEST_SIE_MAC_ADDR 0xFE70 /* 0xFE70~0xFE75 */ ++#define REG_TEST_SIE_STRING 0xFE80 /* 0xFE80~0xFEB9 */ ++ ++ ++/* For normal chip */ ++#define REG_NORMAL_SIE_VID 0xFE60 /* 0xFE60~0xFE61 */ ++#define REG_NORMAL_SIE_PID 0xFE62 /* 0xFE62~0xFE63 */ ++#define REG_NORMAL_SIE_OPTIONAL 0xFE64 ++#define REG_NORMAL_SIE_EP 0xFE65 /* 0xFE65~0xFE67 */ ++#define REG_NORMAL_SIE_PHY 0xFE68 /* 0xFE68~0xFE6B */ ++#define REG_NORMAL_SIE_OPTIONAL2 0xFE6C ++#define REG_NORMAL_SIE_GPS_EP 0xFE6D /* 0xFE6D, for RTL8723 only. */ ++#define REG_NORMAL_SIE_MAC_ADDR 0xFE70 /* 0xFE70~0xFE75 */ ++#define REG_NORMAL_SIE_STRING 0xFE80 /* 0xFE80~0xFEDF */ ++ ++ ++/* */ ++/* */ ++/* Redifine 8192C register definition for compatibility */ ++/* */ ++/* */ ++ ++/* TODO: use these definition when using REG_xxx naming rule. */ ++/* NOTE: DO NOT Remove these definition. Use later. */ ++ ++#define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */ ++#define EFUSE_TEST REG_EFUSE_TEST /* E-Fuse Test. */ ++#define MSR (REG_CR + 2) /* Media Status register */ ++/* define ISR REG_HISR */ ++ ++#define TSFR REG_TSFTR /* Timing Sync Function Timer Register. */ ++#define TSFR1 REG_TSFTR1 /* HW Port 1 TSF Register */ ++ ++#define PBP REG_PBP ++ ++/* Redifine MACID register, to compatible prior ICs. */ ++#define IDR0 REG_MACID /* MAC ID Register, Offset 0x0050-0x0053 */ ++#define IDR4 (REG_MACID + 4) /* MAC ID Register, Offset 0x0054-0x0055 */ ++ ++ ++/* */ ++/* 9. Security Control Registers (Offset:) */ ++/* */ ++#define RWCAM REG_CAMCMD /* IN 8190 Data Sheet is called CAMcmd */ ++#define WCAMI REG_CAMWRITE /* Software write CAM input content */ ++#define RCAMO REG_CAMREAD /* Software read/write CAM config */ ++#define CAMDBG REG_CAMDBG ++#define SECR REG_SECCFG /* Security Configuration Register */ ++ ++/* Unused register */ ++#define UnusedRegister 0x1BF ++#define DCAM UnusedRegister ++#define PSR UnusedRegister ++#define BBAddr UnusedRegister ++#define PhyDataR UnusedRegister ++ ++/* Min Spacing related settings. */ ++#define MAX_MSS_DENSITY_2T 0x13 ++#define MAX_MSS_DENSITY_1T 0x0A ++ ++/* */ ++/* 8192C Cmd9346CR bits (Offset 0xA, 16bit) */ ++/* */ ++#define CmdEEPROM_En BIT5 /* EEPROM enable when set 1 */ ++#define CmdEERPOMSEL BIT4 /* System EEPROM select, 0: boot from E-FUSE, 1: The EEPROM used is 9346 */ ++#define Cmd9346CR_9356SEL BIT4 ++ ++/* */ ++/* 8192C GPIO MUX Configuration Register (offset 0x40, 4 byte) */ ++/* */ ++#define GPIOSEL_GPIO 0 ++#define GPIOSEL_ENBT BIT5 ++ ++/* */ ++/* 8192C GPIO PIN Control Register (offset 0x44, 4 byte) */ ++/* */ ++#define GPIO_IN REG_GPIO_PIN_CTRL /* GPIO pins input value */ ++#define GPIO_OUT (REG_GPIO_PIN_CTRL+1) /* GPIO pins output value */ ++#define GPIO_IO_SEL (REG_GPIO_PIN_CTRL+2) /* GPIO pins output enable when a bit is set to "1"; otherwise, input is configured. */ ++#define GPIO_MOD (REG_GPIO_PIN_CTRL+3) ++ ++/* */ ++/* 8811A GPIO PIN Control Register (offset 0x60, 4 byte) */ ++/* */ ++#define GPIO_IN_8811A REG_GPIO_PIN_CTRL_2 /* GPIO pins input value */ ++#define GPIO_OUT_8811A (REG_GPIO_PIN_CTRL_2+1) /* GPIO pins output value */ ++#define GPIO_IO_SEL_8811A (REG_GPIO_PIN_CTRL_2+2) /* GPIO pins output enable when a bit is set to "1"; otherwise, input is configured. */ ++#define GPIO_MOD_8811A (REG_GPIO_PIN_CTRL_2+3) ++ ++/* */ ++/* 8723/8188E Host System Interrupt Mask Register (offset 0x58, 32 byte) */ ++/* */ ++#define HSIMR_GPIO12_0_INT_EN BIT0 ++#define HSIMR_SPS_OCP_INT_EN BIT5 ++#define HSIMR_RON_INT_EN BIT6 ++#define HSIMR_PDN_INT_EN BIT7 ++#define HSIMR_GPIO9_INT_EN BIT25 ++ ++/* */ ++/* 8723/8188E Host System Interrupt Status Register (offset 0x5C, 32 byte) */ ++/* */ ++#define HSISR_GPIO12_0_INT BIT0 ++#define HSISR_SPS_OCP_INT BIT5 ++#define HSISR_RON_INT BIT6 ++#define HSISR_PDNINT BIT7 ++#define HSISR_GPIO9_INT BIT25 ++ ++/* */ ++/* 8192C (MSR) Media Status Register (Offset 0x4C, 8 bits) */ ++/* */ ++/* ++Network Type ++00: No link ++01: Link in ad hoc network ++10: Link in infrastructure network ++11: AP mode ++Default: 00b. ++*/ ++#define MSR_NOLINK 0x00 ++#define MSR_ADHOC 0x01 ++#define MSR_INFRA 0x02 ++#define MSR_AP 0x03 ++ ++/* */ ++/* USB INTR CONTENT */ ++/* */ ++#define USB_C2H_CMDID_OFFSET 0 ++#define USB_C2H_SEQ_OFFSET 1 ++#define USB_C2H_EVENT_OFFSET 2 ++#define USB_INTR_CPWM_OFFSET 16 ++#define USB_INTR_CONTENT_C2H_OFFSET 0 ++#define USB_INTR_CONTENT_CPWM1_OFFSET 16 ++#define USB_INTR_CONTENT_CPWM2_OFFSET 20 ++#define USB_INTR_CONTENT_HISR_OFFSET 48 ++#define USB_INTR_CONTENT_HISRE_OFFSET 52 ++#define USB_INTR_CONTENT_LENGTH 56 ++ ++/* */ ++/* Response Rate Set Register (offset 0x440, 24bits) */ ++/* */ ++#define RRSR_1M BIT0 ++#define RRSR_2M BIT1 ++#define RRSR_5_5M BIT2 ++#define RRSR_11M BIT3 ++#define RRSR_6M BIT4 ++#define RRSR_9M BIT5 ++#define RRSR_12M BIT6 ++#define RRSR_18M BIT7 ++#define RRSR_24M BIT8 ++#define RRSR_36M BIT9 ++#define RRSR_48M BIT10 ++#define RRSR_54M BIT11 ++#define RRSR_MCS0 BIT12 ++#define RRSR_MCS1 BIT13 ++#define RRSR_MCS2 BIT14 ++#define RRSR_MCS3 BIT15 ++#define RRSR_MCS4 BIT16 ++#define RRSR_MCS5 BIT17 ++#define RRSR_MCS6 BIT18 ++#define RRSR_MCS7 BIT19 ++ ++#define RRSR_CCK_RATES (RRSR_11M|RRSR_5_5M|RRSR_2M|RRSR_1M) ++#define RRSR_OFDM_RATES (RRSR_54M|RRSR_48M|RRSR_36M|RRSR_24M|RRSR_18M|RRSR_12M|RRSR_9M|RRSR_6M) ++ ++/* WOL bit information */ ++#define HAL92C_WOL_PTK_UPDATE_EVENT BIT0 ++#define HAL92C_WOL_GTK_UPDATE_EVENT BIT1 ++#define HAL92C_WOL_DISASSOC_EVENT BIT2 ++#define HAL92C_WOL_DEAUTH_EVENT BIT3 ++#define HAL92C_WOL_FW_DISCONNECT_EVENT BIT4 ++ ++/* */ ++/* Rate Definition */ ++/* */ ++/* CCK */ ++#define RATR_1M 0x00000001 ++#define RATR_2M 0x00000002 ++#define RATR_55M 0x00000004 ++#define RATR_11M 0x00000008 ++/* OFDM */ ++#define RATR_6M 0x00000010 ++#define RATR_9M 0x00000020 ++#define RATR_12M 0x00000040 ++#define RATR_18M 0x00000080 ++#define RATR_24M 0x00000100 ++#define RATR_36M 0x00000200 ++#define RATR_48M 0x00000400 ++#define RATR_54M 0x00000800 ++/* MCS 1 Spatial Stream */ ++#define RATR_MCS0 0x00001000 ++#define RATR_MCS1 0x00002000 ++#define RATR_MCS2 0x00004000 ++#define RATR_MCS3 0x00008000 ++#define RATR_MCS4 0x00010000 ++#define RATR_MCS5 0x00020000 ++#define RATR_MCS6 0x00040000 ++#define RATR_MCS7 0x00080000 ++/* MCS 2 Spatial Stream */ ++#define RATR_MCS8 0x00100000 ++#define RATR_MCS9 0x00200000 ++#define RATR_MCS10 0x00400000 ++#define RATR_MCS11 0x00800000 ++#define RATR_MCS12 0x01000000 ++#define RATR_MCS13 0x02000000 ++#define RATR_MCS14 0x04000000 ++#define RATR_MCS15 0x08000000 ++ ++/* CCK */ ++#define RATE_1M BIT(0) ++#define RATE_2M BIT(1) ++#define RATE_5_5M BIT(2) ++#define RATE_11M BIT(3) ++/* OFDM */ ++#define RATE_6M BIT(4) ++#define RATE_9M BIT(5) ++#define RATE_12M BIT(6) ++#define RATE_18M BIT(7) ++#define RATE_24M BIT(8) ++#define RATE_36M BIT(9) ++#define RATE_48M BIT(10) ++#define RATE_54M BIT(11) ++/* MCS 1 Spatial Stream */ ++#define RATE_MCS0 BIT(12) ++#define RATE_MCS1 BIT(13) ++#define RATE_MCS2 BIT(14) ++#define RATE_MCS3 BIT(15) ++#define RATE_MCS4 BIT(16) ++#define RATE_MCS5 BIT(17) ++#define RATE_MCS6 BIT(18) ++#define RATE_MCS7 BIT(19) ++/* MCS 2 Spatial Stream */ ++#define RATE_MCS8 BIT(20) ++#define RATE_MCS9 BIT(21) ++#define RATE_MCS10 BIT(22) ++#define RATE_MCS11 BIT(23) ++#define RATE_MCS12 BIT(24) ++#define RATE_MCS13 BIT(25) ++#define RATE_MCS14 BIT(26) ++#define RATE_MCS15 BIT(27) ++ ++ ++/* ALL CCK Rate */ ++#define RATE_ALL_CCK RATR_1M|RATR_2M|RATR_55M|RATR_11M ++#define RATE_ALL_OFDM_AG RATR_6M|RATR_9M|RATR_12M|RATR_18M|RATR_24M|\ ++ RATR_36M|RATR_48M|RATR_54M ++#define RATE_ALL_OFDM_1SS RATR_MCS0|RATR_MCS1|RATR_MCS2|RATR_MCS3 |\ ++ RATR_MCS4|RATR_MCS5|RATR_MCS6 |RATR_MCS7 ++#define RATE_ALL_OFDM_2SS RATR_MCS8|RATR_MCS9 |RATR_MCS10|RATR_MCS11|\ ++ RATR_MCS12|RATR_MCS13|RATR_MCS14|RATR_MCS15 ++ ++#define RATE_BITMAP_ALL 0xFFFFF ++ ++/* Only use CCK 1M rate for ACK */ ++#define RATE_RRSR_CCK_ONLY_1M 0xFFFF1 ++#define RATE_RRSR_WITHOUT_CCK 0xFFFF0 ++ ++/* */ ++/* BW_OPMODE bits (Offset 0x603, 8bit) */ ++/* */ ++#define BW_OPMODE_20MHZ BIT2 ++#define BW_OPMODE_5G BIT1 ++ ++/* */ ++/* CAM Config Setting (offset 0x680, 1 byte) */ ++/* */ ++#define CAM_VALID BIT15 ++#define CAM_NOTVALID 0x0000 ++#define CAM_USEDK BIT5 ++ ++#define CAM_CONTENT_COUNT 8 ++ ++#define CAM_NONE 0x0 ++#define CAM_WEP40 0x01 ++#define CAM_TKIP 0x02 ++#define CAM_AES 0x04 ++#define CAM_WEP104 0x05 ++#define CAM_SMS4 0x6 ++ ++#define TOTAL_CAM_ENTRY 32 ++#define HALF_CAM_ENTRY 16 ++ ++#define CAM_CONFIG_USEDK true ++#define CAM_CONFIG_NO_USEDK false ++ ++#define CAM_WRITE BIT16 ++#define CAM_READ 0x00000000 ++#define CAM_POLLINIG BIT31 ++ ++/* */ ++/* 10. Power Save Control Registers */ ++/* */ ++#define WOW_PMEN BIT0 /* Power management Enable. */ ++#define WOW_WOMEN BIT1 /* WoW function on or off. */ ++#define WOW_MAGIC BIT2 /* Magic packet */ ++#define WOW_UWF BIT3 /* Unicast Wakeup frame. */ ++ ++/* */ ++/* 12. Host Interrupt Status Registers */ ++/* */ ++/* */ ++/* 8190 IMR/ISR bits */ ++/* */ ++#define IMR8190_DISABLED 0x0 ++#define IMR_DISABLED 0x0 ++/* IMR DW0 Bit 0-31 */ ++#define IMR_BCNDMAINT6 BIT31 /* Beacon DMA Interrupt 6 */ ++#define IMR_BCNDMAINT5 BIT30 /* Beacon DMA Interrupt 5 */ ++#define IMR_BCNDMAINT4 BIT29 /* Beacon DMA Interrupt 4 */ ++#define IMR_BCNDMAINT3 BIT28 /* Beacon DMA Interrupt 3 */ ++#define IMR_BCNDMAINT2 BIT27 /* Beacon DMA Interrupt 2 */ ++#define IMR_BCNDMAINT1 BIT26 /* Beacon DMA Interrupt 1 */ ++#define IMR_BCNDOK8 BIT25 /* Beacon Queue DMA OK Interrup 8 */ ++#define IMR_BCNDOK7 BIT24 /* Beacon Queue DMA OK Interrup 7 */ ++#define IMR_BCNDOK6 BIT23 /* Beacon Queue DMA OK Interrup 6 */ ++#define IMR_BCNDOK5 BIT22 /* Beacon Queue DMA OK Interrup 5 */ ++#define IMR_BCNDOK4 BIT21 /* Beacon Queue DMA OK Interrup 4 */ ++#define IMR_BCNDOK3 BIT20 /* Beacon Queue DMA OK Interrup 3 */ ++#define IMR_BCNDOK2 BIT19 /* Beacon Queue DMA OK Interrup 2 */ ++#define IMR_BCNDOK1 BIT18 /* Beacon Queue DMA OK Interrup 1 */ ++#define IMR_TIMEOUT2 BIT17 /* Timeout interrupt 2 */ ++#define IMR_TIMEOUT1 BIT16 /* Timeout interrupt 1 */ ++#define IMR_TXFOVW BIT15 /* Transmit FIFO Overflow */ ++#define IMR_PSTIMEOUT BIT14 /* Power save time out interrupt */ ++#define IMR_BcnInt BIT13 /* Beacon DMA Interrupt 0 */ ++#define IMR_RXFOVW BIT12 /* Receive FIFO Overflow */ ++#define IMR_RDU BIT11 /* Receive Descriptor Unavailable */ ++#define IMR_ATIMEND BIT10 /* For 92C, ATIM Window End Interrupt. For 8723 and later ICs, it also means P2P CTWin End interrupt. */ ++#define IMR_BDOK BIT9 /* Beacon Queue DMA OK Interrup */ ++#define IMR_HIGHDOK BIT8 /* High Queue DMA OK Interrupt */ ++#define IMR_TBDOK BIT7 /* Transmit Beacon OK interrup */ ++#define IMR_MGNTDOK BIT6 /* Management Queue DMA OK Interrupt */ ++#define IMR_TBDER BIT5 /* For 92C, Transmit Beacon Error Interrupt */ ++#define IMR_BKDOK BIT4 /* AC_BK DMA OK Interrupt */ ++#define IMR_BEDOK BIT3 /* AC_BE DMA OK Interrupt */ ++#define IMR_VIDOK BIT2 /* AC_VI DMA OK Interrupt */ ++#define IMR_VODOK BIT1 /* AC_VO DMA Interrupt */ ++#define IMR_ROK BIT0 /* Receive DMA OK Interrupt */ ++ ++/* 13. Host Interrupt Status Extension Register (Offset: 0x012C-012Eh) */ ++#define IMR_TSF_BIT32_TOGGLE BIT15 ++#define IMR_BcnInt_E BIT12 ++#define IMR_TXERR BIT11 ++#define IMR_RXERR BIT10 ++#define IMR_C2HCMD BIT9 ++#define IMR_CPWM BIT8 ++/* RSVD [2-7] */ ++#define IMR_OCPINT BIT1 ++#define IMR_WLANOFF BIT0 ++ ++/* */ ++/* 8723E series PCIE Host IMR/ISR bit */ ++/* */ ++/* IMR DW0 Bit 0-31 */ ++#define PHIMR_TIMEOUT2 BIT31 ++#define PHIMR_TIMEOUT1 BIT30 ++#define PHIMR_PSTIMEOUT BIT29 ++#define PHIMR_GTINT4 BIT28 ++#define PHIMR_GTINT3 BIT27 ++#define PHIMR_TXBCNERR BIT26 ++#define PHIMR_TXBCNOK BIT25 ++#define PHIMR_TSF_BIT32_TOGGLE BIT24 ++#define PHIMR_BCNDMAINT3 BIT23 ++#define PHIMR_BCNDMAINT2 BIT22 ++#define PHIMR_BCNDMAINT1 BIT21 ++#define PHIMR_BCNDMAINT0 BIT20 ++#define PHIMR_BCNDOK3 BIT19 ++#define PHIMR_BCNDOK2 BIT18 ++#define PHIMR_BCNDOK1 BIT17 ++#define PHIMR_BCNDOK0 BIT16 ++#define PHIMR_HSISR_IND_ON BIT15 ++#define PHIMR_BCNDMAINT_E BIT14 ++#define PHIMR_ATIMEND_E BIT13 ++#define PHIMR_ATIM_CTW_END BIT12 ++#define PHIMR_HISRE_IND BIT11 /* RO. HISRE Indicator (HISRE & HIMRE is true, this bit is set to 1) */ ++#define PHIMR_C2HCMD BIT10 ++#define PHIMR_CPWM2 BIT9 ++#define PHIMR_CPWM BIT8 ++#define PHIMR_HIGHDOK BIT7 /* High Queue DMA OK Interrupt */ ++#define PHIMR_MGNTDOK BIT6 /* Management Queue DMA OK Interrupt */ ++#define PHIMR_BKDOK BIT5 /* AC_BK DMA OK Interrupt */ ++#define PHIMR_BEDOK BIT4 /* AC_BE DMA OK Interrupt */ ++#define PHIMR_VIDOK BIT3 /* AC_VI DMA OK Interrupt */ ++#define PHIMR_VODOK BIT2 /* AC_VO DMA Interrupt */ ++#define PHIMR_RDU BIT1 /* Receive Descriptor Unavailable */ ++#define PHIMR_ROK BIT0 /* Receive DMA OK Interrupt */ ++ ++/* PCIE Host Interrupt Status Extension bit */ ++#define PHIMR_BCNDMAINT7 BIT23 ++#define PHIMR_BCNDMAINT6 BIT22 ++#define PHIMR_BCNDMAINT5 BIT21 ++#define PHIMR_BCNDMAINT4 BIT20 ++#define PHIMR_BCNDOK7 BIT19 ++#define PHIMR_BCNDOK6 BIT18 ++#define PHIMR_BCNDOK5 BIT17 ++#define PHIMR_BCNDOK4 BIT16 ++/* bit12 15: RSVD */ ++#define PHIMR_TXERR BIT11 ++#define PHIMR_RXERR BIT10 ++#define PHIMR_TXFOVW BIT9 ++#define PHIMR_RXFOVW BIT8 ++/* bit2-7: RSVD */ ++#define PHIMR_OCPINT BIT1 ++/* bit0: RSVD */ ++ ++#define UHIMR_TIMEOUT2 BIT31 ++#define UHIMR_TIMEOUT1 BIT30 ++#define UHIMR_PSTIMEOUT BIT29 ++#define UHIMR_GTINT4 BIT28 ++#define UHIMR_GTINT3 BIT27 ++#define UHIMR_TXBCNERR BIT26 ++#define UHIMR_TXBCNOK BIT25 ++#define UHIMR_TSF_BIT32_TOGGLE BIT24 ++#define UHIMR_BCNDMAINT3 BIT23 ++#define UHIMR_BCNDMAINT2 BIT22 ++#define UHIMR_BCNDMAINT1 BIT21 ++#define UHIMR_BCNDMAINT0 BIT20 ++#define UHIMR_BCNDOK3 BIT19 ++#define UHIMR_BCNDOK2 BIT18 ++#define UHIMR_BCNDOK1 BIT17 ++#define UHIMR_BCNDOK0 BIT16 ++#define UHIMR_HSISR_IND BIT15 ++#define UHIMR_BCNDMAINT_E BIT14 ++/* RSVD BIT13 */ ++#define UHIMR_CTW_END BIT12 ++/* RSVD BIT11 */ ++#define UHIMR_C2HCMD BIT10 ++#define UHIMR_CPWM2 BIT9 ++#define UHIMR_CPWM BIT8 ++#define UHIMR_HIGHDOK BIT7 /* High Queue DMA OK Interrupt */ ++#define UHIMR_MGNTDOK BIT6 /* Management Queue DMA OK Interrupt */ ++#define UHIMR_BKDOK BIT5 /* AC_BK DMA OK Interrupt */ ++#define UHIMR_BEDOK BIT4 /* AC_BE DMA OK Interrupt */ ++#define UHIMR_VIDOK BIT3 /* AC_VI DMA OK Interrupt */ ++#define UHIMR_VODOK BIT2 /* AC_VO DMA Interrupt */ ++#define UHIMR_RDU BIT1 /* Receive Descriptor Unavailable */ ++#define UHIMR_ROK BIT0 /* Receive DMA OK Interrupt */ ++ ++/* USB Host Interrupt Status Extension bit */ ++#define UHIMR_BCNDMAINT7 BIT23 ++#define UHIMR_BCNDMAINT6 BIT22 ++#define UHIMR_BCNDMAINT5 BIT21 ++#define UHIMR_BCNDMAINT4 BIT20 ++#define UHIMR_BCNDOK7 BIT19 ++#define UHIMR_BCNDOK6 BIT18 ++#define UHIMR_BCNDOK5 BIT17 ++#define UHIMR_BCNDOK4 BIT16 ++/* bit14-15: RSVD */ ++#define UHIMR_ATIMEND_E BIT13 ++#define UHIMR_ATIMEND BIT12 ++#define UHIMR_TXERR BIT11 ++#define UHIMR_RXERR BIT10 ++#define UHIMR_TXFOVW BIT9 ++#define UHIMR_RXFOVW BIT8 ++/* bit2-7: RSVD */ ++#define UHIMR_OCPINT BIT1 ++/* bit0: RSVD */ ++ ++ ++#define HAL_NIC_UNPLUG_ISR 0xFFFFFFFF /* The value when the NIC is unplugged for PCI. */ ++#define HAL_NIC_UNPLUG_PCI_ISR 0xEAEAEAEA /* The value when the NIC is unplugged for PCI in PCI interrupt (page 3). */ ++ ++/* */ ++/* 8188 IMR/ISR bits */ ++/* */ ++#define IMR_DISABLED_88E 0x0 ++/* IMR DW0(0x0060-0063) Bit 0-31 */ ++#define IMR_TXCCK_88E BIT30 /* TXRPT interrupt when CCX bit of the packet is set */ ++#define IMR_PSTIMEOUT_88E BIT29 /* Power Save Time Out Interrupt */ ++#define IMR_GTINT4_88E BIT28 /* When GTIMER4 expires, this bit is set to 1 */ ++#define IMR_GTINT3_88E BIT27 /* When GTIMER3 expires, this bit is set to 1 */ ++#define IMR_TBDER_88E BIT26 /* Transmit Beacon0 Error */ ++#define IMR_TBDOK_88E BIT25 /* Transmit Beacon0 OK */ ++#define IMR_TSF_BIT32_TOGGLE_88E BIT24 /* TSF Timer BIT32 toggle indication interrupt */ ++#define IMR_BCNDMAINT0_88E BIT20 /* Beacon DMA Interrupt 0 */ ++#define IMR_BCNDERR0_88E BIT16 /* Beacon Queue DMA Error 0 */ ++#define IMR_HSISR_IND_ON_INT_88E BIT15 /* HSISR Indicator (HSIMR & HSISR is true, this bit is set to 1) */ ++#define IMR_BCNDMAINT_E_88E BIT14 /* Beacon DMA Interrupt Extension for Win7 */ ++#define IMR_ATIMEND_88E BIT12 /* CTWidnow End or ATIM Window End */ ++#define IMR_HISR1_IND_INT_88E BIT11 /* HISR1 Indicator (HISR1 & HIMR1 is true, this bit is set to 1) */ ++#define IMR_C2HCMD_88E BIT10 /* CPU to Host Command INT Status, Write 1 clear */ ++#define IMR_CPWM2_88E BIT9 /* CPU power Mode exchange INT Status, Write 1 clear */ ++#define IMR_CPWM_88E BIT8 /* CPU power Mode exchange INT Status, Write 1 clear */ ++#define IMR_HIGHDOK_88E BIT7 /* High Queue DMA OK */ ++#define IMR_MGNTDOK_88E BIT6 /* Management Queue DMA OK */ ++#define IMR_BKDOK_88E BIT5 /* AC_BK DMA OK */ ++#define IMR_BEDOK_88E BIT4 /* AC_BE DMA OK */ ++#define IMR_VIDOK_88E BIT3 /* AC_VI DMA OK */ ++#define IMR_VODOK_88E BIT2 /* AC_VO DMA OK */ ++#define IMR_RDU_88E BIT1 /* Rx Descriptor Unavailable */ ++#define IMR_ROK_88E BIT0 /* Receive DMA OK */ ++ ++/* IMR DW1(0x00B4-00B7) Bit 0-31 */ ++#define IMR_BCNDMAINT7_88E BIT27 /* Beacon DMA Interrupt 7 */ ++#define IMR_BCNDMAINT6_88E BIT26 /* Beacon DMA Interrupt 6 */ ++#define IMR_BCNDMAINT5_88E BIT25 /* Beacon DMA Interrupt 5 */ ++#define IMR_BCNDMAINT4_88E BIT24 /* Beacon DMA Interrupt 4 */ ++#define IMR_BCNDMAINT3_88E BIT23 /* Beacon DMA Interrupt 3 */ ++#define IMR_BCNDMAINT2_88E BIT22 /* Beacon DMA Interrupt 2 */ ++#define IMR_BCNDMAINT1_88E BIT21 /* Beacon DMA Interrupt 1 */ ++#define IMR_BCNDOK7_88E BIT20 /* Beacon Queue DMA OK Interrup 7 */ ++#define IMR_BCNDOK6_88E BIT19 /* Beacon Queue DMA OK Interrup 6 */ ++#define IMR_BCNDOK5_88E BIT18 /* Beacon Queue DMA OK Interrup 5 */ ++#define IMR_BCNDOK4_88E BIT17 /* Beacon Queue DMA OK Interrup 4 */ ++#define IMR_BCNDOK3_88E BIT16 /* Beacon Queue DMA OK Interrup 3 */ ++#define IMR_BCNDOK2_88E BIT15 /* Beacon Queue DMA OK Interrup 2 */ ++#define IMR_BCNDOK1_88E BIT14 /* Beacon Queue DMA OK Interrup 1 */ ++#define IMR_ATIMEND_E_88E BIT13 /* ATIM Window End Extension for Win7 */ ++#define IMR_TXERR_88E BIT11 /* Tx Error Flag Interrupt Status, write 1 clear. */ ++#define IMR_RXERR_88E BIT10 /* Rx Error Flag INT Status, Write 1 clear */ ++#define IMR_TXFOVW_88E BIT9 /* Transmit FIFO Overflow */ ++#define IMR_RXFOVW_88E BIT8 /* Receive FIFO Overflow */ ++ ++/*=================================================================== ++===================================================================== ++Here the register defines are for 92C. When the define is as same with 92C, ++we will use the 92C's define for the consistency ++So the following defines for 92C is not entire!!!!!! ++===================================================================== ++=====================================================================*/ ++/* ++Based on Datasheet V33---090401 ++Register Summary ++Current IOREG MAP ++0x0000h ~ 0x00FFh System Configuration (256 Bytes) ++0x0100h ~ 0x01FFh MACTOP General Configuration (256 Bytes) ++0x0200h ~ 0x027Fh TXDMA Configuration (128 Bytes) ++0x0280h ~ 0x02FFh RXDMA Configuration (128 Bytes) ++0x0300h ~ 0x03FFh PCIE EMAC Reserved Region (256 Bytes) ++0x0400h ~ 0x04FFh Protocol Configuration (256 Bytes) ++0x0500h ~ 0x05FFh EDCA Configuration (256 Bytes) ++0x0600h ~ 0x07FFh WMAC Configuration (512 Bytes) ++0x2000h ~ 0x3FFFh 8051 FW Download Region (8196 Bytes) ++*/ ++ /* */ ++ /* 8192C (TXPAUSE) transmission pause (Offset 0x522, 8 bits) */ ++ /* */ ++/* Note: */ ++/* The the bits of stoping AC(VO/VI/BE/BK) queue in datasheet RTL8192S/RTL8192C are wrong, */ ++/* the correct arragement is VO - Bit0, VI - Bit1, BE - Bit2, and BK - Bit3. */ ++/* 8723 and 88E may be not correct either in the eralier version. Confirmed with DD Tim. */ ++/* By Bruce, 2011-09-22. */ ++#define StopBecon BIT6 ++#define StopHigh BIT5 ++#define StopMgt BIT4 ++#define StopBK BIT3 ++#define StopBE BIT2 ++#define StopVI BIT1 ++#define StopVO BIT0 ++ ++/* */ ++/* 8192C (RCR) Receive Configuration Register (Offset 0x608, 32 bits) */ ++/* */ ++#define RCR_APPFCS BIT31 /* WMAC append FCS after pauload */ ++#define RCR_APP_MIC BIT30 /* MACRX will retain the MIC at the bottom of the packet. */ ++#define RCR_APP_ICV BIT29 /* MACRX will retain the ICV at the bottom of the packet. */ ++#define RCR_APP_PHYST_RXFF BIT28 /* PHY Status is appended before RX packet in RXFF */ ++#define RCR_APP_BA_SSN BIT27 /* SSN of previous TXBA is appended as after original RXDESC as the 4-th DW of RXDESC. */ ++#define RCR_NONQOS_VHT BIT26 /* Reserved */ ++#define RCR_RSVD_BIT25 BIT25 /* Reserved */ ++#define RCR_ENMBID BIT24 /* Enable Multiple BssId. Only response ACK to the packets whose DID(A1) matching to the addresses in the MBSSID CAM Entries. */ ++#define RCR_LSIGEN BIT23 /* Enable LSIG TXOP Protection function. Search KEYCAM for each rx packet to check if LSIGEN bit is set. */ ++#define RCR_MFBEN BIT22 /* Enable immediate MCS Feedback function. When Rx packet with MRQ = 1'b1, then search KEYCAM to find sender's MCS Feedback function and send response. */ ++#define RCR_RSVD_BIT21 BIT21 /* Reserved */ ++#define RCR_RSVD_BIT20 BIT20 /* Reserved */ ++#define RCR_RSVD_BIT19 BIT19 /* Reserved */ ++#define RCR_TIM_PARSER_EN BIT18 /* RX Beacon TIM Parser. */ ++#define RCR_BM_DATA_EN BIT17 /* Broadcast data packet interrupt enable. */ ++#define RCR_UC_DATA_EN BIT16 /* Unicast data packet interrupt enable. */ ++#define RCR_RSVD_BIT15 BIT15 /* Reserved */ ++#define RCR_HTC_LOC_CTRL BIT14 /* MFC<--HTC = 1 MFC-->HTC = 0 */ ++#define RCR_AMF BIT13 /* Accept management type frame */ ++#define RCR_ACF BIT12 /* Accept control type frame. Control frames BA, BAR, and PS-Poll (when in AP mode) are not controlled by this bit. They are controlled by ADF. */ ++#define RCR_ADF BIT11 /* Accept data type frame. This bit also regulates BA, BAR, and PS-Poll (AP mode only). */ ++#define RCR_RSVD_BIT10 BIT10 /* Reserved */ ++#define RCR_AICV BIT9 /* Accept ICV error packet */ ++#define RCR_ACRC32 BIT8 /* Accept CRC32 error packet */ ++#define RCR_CBSSID_BCN BIT7 /* Accept BSSID match packet (Rx beacon, probe rsp) */ ++#define RCR_CBSSID_DATA BIT6 /* Accept BSSID match packet (Data) */ ++#define RCR_CBSSID RCR_CBSSID_DATA /* Accept BSSID match packet */ ++#define RCR_APWRMGT BIT5 /* Accept power management packet */ ++#define RCR_ADD3 BIT4 /* Accept address 3 match packet */ ++#define RCR_AB BIT3 /* Accept broadcast packet */ ++#define RCR_AM BIT2 /* Accept multicast packet */ ++#define RCR_APM BIT1 /* Accept physical match packet */ ++#define RCR_AAP BIT0 /* Accept all unicast packet */ ++ ++ ++/* */ ++/* */ ++/* 0x0000h ~ 0x00FFh System Configuration */ ++/* */ ++/* */ ++ ++/* 2 SYS_ISO_CTRL */ ++#define ISO_MD2PP BIT(0) ++#define ISO_UA2USB BIT(1) ++#define ISO_UD2CORE BIT(2) ++#define ISO_PA2PCIE BIT(3) ++#define ISO_PD2CORE BIT(4) ++#define ISO_IP2MAC BIT(5) ++#define ISO_DIOP BIT(6) ++#define ISO_DIOE BIT(7) ++#define ISO_EB2CORE BIT(8) ++#define ISO_DIOR BIT(9) ++#define PWC_EV12V BIT(15) ++ ++ ++/* 2 SYS_FUNC_EN */ ++#define FEN_BBRSTB BIT(0) ++#define FEN_BB_GLB_RSTn BIT(1) ++#define FEN_USBA BIT(2) ++#define FEN_UPLL BIT(3) ++#define FEN_USBD BIT(4) ++#define FEN_DIO_PCIE BIT(5) ++#define FEN_PCIEA BIT(6) ++#define FEN_PPLL BIT(7) ++#define FEN_PCIED BIT(8) ++#define FEN_DIOE BIT(9) ++#define FEN_CPUEN BIT(10) ++#define FEN_DCORE BIT(11) ++#define FEN_ELDR BIT(12) ++#define FEN_EN_25_1 BIT(13) ++#define FEN_HWPDN BIT(14) ++#define FEN_MREGEN BIT(15) ++ ++/* 2 APS_FSMCO */ ++#define PFM_LDALL BIT(0) ++#define PFM_ALDN BIT(1) ++#define PFM_LDKP BIT(2) ++#define PFM_WOWL BIT(3) ++#define EnPDN BIT(4) ++#define PDN_PL BIT(5) ++#define APFM_ONMAC BIT(8) ++#define APFM_OFF BIT(9) ++#define APFM_RSM BIT(10) ++#define AFSM_HSUS BIT(11) ++#define AFSM_PCIE BIT(12) ++#define APDM_MAC BIT(13) ++#define APDM_HOST BIT(14) ++#define APDM_HPDN BIT(15) ++#define RDY_MACON BIT(16) ++#define SUS_HOST BIT(17) ++#define ROP_ALD BIT(20) ++#define ROP_PWR BIT(21) ++#define ROP_SPS BIT(22) ++#define SOP_MRST BIT(25) ++#define SOP_FUSE BIT(26) ++#define SOP_ABG BIT(27) ++#define SOP_AMB BIT(28) ++#define SOP_RCK BIT(29) ++#define SOP_A8M BIT(30) ++#define XOP_BTCK BIT(31) ++ ++/* 2 SYS_CLKR */ ++#define ANAD16V_EN BIT(0) ++#define ANA8M BIT(1) ++#define MACSLP BIT(4) ++#define LOADER_CLK_EN BIT(5) ++ ++ ++/* 2 9346CR /REG_SYS_EEPROM_CTRL */ ++#define BOOT_FROM_EEPROM BIT(4) ++#define EEPROMSEL BIT(4) ++#define EEPROM_EN BIT(5) ++ ++ ++/* 2 RF_CTRL */ ++#define RF_EN BIT(0) ++#define RF_RSTB BIT(1) ++#define RF_SDMRSTB BIT(2) ++ ++ ++/* 2 LDOV12D_CTRL */ ++#define LDV12_EN BIT(0) ++#define LDV12_SDBY BIT(1) ++#define LPLDO_HSM BIT(2) ++#define LPLDO_LSM_DIS BIT(3) ++#define _LDV12_VADJ(x) (((x) & 0xF) << 4) ++ ++ ++ ++/* 2 EFUSE_TEST (For RTL8723 partially) */ ++#define EF_TRPT BIT(7) ++#define EF_CELL_SEL (BIT(8)|BIT(9)) /* 00: Wifi Efuse, 01: BT Efuse0, 10: BT Efuse1, 11: BT Efuse2 */ ++#define LDOE25_EN BIT(31) ++#define EFUSE_SEL(x) (((x) & 0x3) << 8) ++#define EFUSE_SEL_MASK 0x300 ++#define EFUSE_WIFI_SEL_0 0x0 ++#define EFUSE_BT_SEL_0 0x1 ++#define EFUSE_BT_SEL_1 0x2 ++#define EFUSE_BT_SEL_2 0x3 ++ ++ ++/* 2 8051FWDL */ ++/* 2 MCUFWDL */ ++#define MCUFWDL_EN BIT(0) ++#define MCUFWDL_RDY BIT(1) ++#define FWDL_ChkSum_rpt BIT(2) ++#define MACINI_RDY BIT(3) ++#define BBINI_RDY BIT(4) ++#define RFINI_RDY BIT(5) ++#define WINTINI_RDY BIT(6) ++#define RAM_DL_SEL BIT(7) ++#define ROM_DLEN BIT(19) ++#define CPRST BIT(23) ++ ++ ++/* 2 REG_SYS_CFG */ ++#define XCLK_VLD BIT(0) ++#define ACLK_VLD BIT(1) ++#define UCLK_VLD BIT(2) ++#define PCLK_VLD BIT(3) ++#define PCIRSTB BIT(4) ++#define V15_VLD BIT(5) ++#define SW_OFFLOAD_EN BIT(7) ++#define SIC_IDLE BIT(8) ++#define BD_MAC2 BIT(9) ++#define BD_MAC1 BIT(10) ++#define IC_MACPHY_MODE BIT(11) ++#define CHIP_VER (BIT(12)|BIT(13)|BIT(14)|BIT(15)) ++#define BT_FUNC BIT(16) ++#define VENDOR_ID BIT(19) ++#define EXT_VENDOR_ID (BIT(18)|BIT(19)) /* Currently only for RTL8723B */ ++#define PAD_HWPD_IDN BIT(22) ++#define TRP_VAUX_EN BIT(23) /* RTL ID */ ++#define TRP_BT_EN BIT(24) ++#define BD_PKG_SEL BIT(25) ++#define BD_HCI_SEL BIT(26) ++#define TYPE_ID BIT(27) ++#define RF_TYPE_ID BIT(27) ++ ++#define RTL_ID BIT(23) /* TestChip ID, 1:Test(RLE); 0:MP(RL) */ ++#define SPS_SEL BIT(24) /* 1:LDO regulator mode; 0:Switching regulator mode */ ++ ++ ++#define CHIP_VER_RTL_MASK 0xF000 /* Bit 12 ~ 15 */ ++#define CHIP_VER_RTL_SHIFT 12 ++#define EXT_VENDOR_ID_SHIFT 18 ++ ++/* 2 REG_GPIO_OUTSTS (For RTL8723 only) */ ++#define EFS_HCI_SEL (BIT(0)|BIT(1)) ++#define PAD_HCI_SEL (BIT(2)|BIT(3)) ++#define HCI_SEL (BIT(4)|BIT(5)) ++#define PKG_SEL_HCI BIT(6) ++#define FEN_GPS BIT(7) ++#define FEN_BT BIT(8) ++#define FEN_WL BIT(9) ++#define FEN_PCI BIT(10) ++#define FEN_USB BIT(11) ++#define BTRF_HWPDN_N BIT(12) ++#define WLRF_HWPDN_N BIT(13) ++#define PDN_BT_N BIT(14) ++#define PDN_GPS_N BIT(15) ++#define BT_CTL_HWPDN BIT(16) ++#define GPS_CTL_HWPDN BIT(17) ++#define PPHY_SUSB BIT(20) ++#define UPHY_SUSB BIT(21) ++#define PCI_SUSEN BIT(22) ++#define USB_SUSEN BIT(23) ++#define RF_RL_ID (BIT(31)|BIT(30)|BIT(29)|BIT(28)) ++ ++ ++/* */ ++/* */ ++/* 0x0100h ~ 0x01FFh MACTOP General Configuration */ ++/* */ ++/* */ ++ ++/* 2 Function Enable Registers */ ++/* 2 CR */ ++#define HCI_TXDMA_EN BIT(0) ++#define HCI_RXDMA_EN BIT(1) ++#define TXDMA_EN BIT(2) ++#define RXDMA_EN BIT(3) ++#define PROTOCOL_EN BIT(4) ++#define SCHEDULE_EN BIT(5) ++#define MACTXEN BIT(6) ++#define MACRXEN BIT(7) ++#define ENSWBCN BIT(8) ++#define ENSEC BIT(9) ++#define CALTMR_EN BIT(10) /* 32k CAL TMR enable */ ++ ++/* Network type */ ++#define _NETTYPE(x) (((x) & 0x3) << 16) ++#define MASK_NETTYPE 0x30000 ++#define NT_NO_LINK 0x0 ++#define NT_LINK_AD_HOC 0x1 ++#define NT_LINK_AP 0x2 ++#define NT_AS_AP 0x3 ++ ++/* 2 PBP - Page Size Register */ ++#define GET_RX_PAGE_SIZE(value) ((value) & 0xF) ++#define GET_TX_PAGE_SIZE(value) (((value) & 0xF0) >> 4) ++#define _PSRX_MASK 0xF ++#define _PSTX_MASK 0xF0 ++#define _PSRX(x) (x) ++#define _PSTX(x) ((x) << 4) ++ ++#define PBP_64 0x0 ++#define PBP_128 0x1 ++#define PBP_256 0x2 ++#define PBP_512 0x3 ++#define PBP_1024 0x4 ++ ++ ++/* 2 TX/RXDMA */ ++#define RXDMA_ARBBW_EN BIT(0) ++#define RXSHFT_EN BIT(1) ++#define RXDMA_AGG_EN BIT(2) ++#define QS_VO_QUEUE BIT(8) ++#define QS_VI_QUEUE BIT(9) ++#define QS_BE_QUEUE BIT(10) ++#define QS_BK_QUEUE BIT(11) ++#define QS_MANAGER_QUEUE BIT(12) ++#define QS_HIGH_QUEUE BIT(13) ++ ++#define HQSEL_VOQ BIT(0) ++#define HQSEL_VIQ BIT(1) ++#define HQSEL_BEQ BIT(2) ++#define HQSEL_BKQ BIT(3) ++#define HQSEL_MGTQ BIT(4) ++#define HQSEL_HIQ BIT(5) ++ ++/* For normal driver, 0x10C */ ++#define _TXDMA_CMQ_MAP(x) (((x)&0x3) << 16) ++#define _TXDMA_HIQ_MAP(x) (((x)&0x3) << 14) ++#define _TXDMA_MGQ_MAP(x) (((x)&0x3) << 12) ++#define _TXDMA_BKQ_MAP(x) (((x)&0x3) << 10) ++#define _TXDMA_BEQ_MAP(x) (((x)&0x3) << 8) ++#define _TXDMA_VIQ_MAP(x) (((x)&0x3) << 6) ++#define _TXDMA_VOQ_MAP(x) (((x)&0x3) << 4) ++ ++#define QUEUE_EXTRA 0 ++#define QUEUE_LOW 1 ++#define QUEUE_NORMAL 2 ++#define QUEUE_HIGH 3 ++ ++ ++/* 2 TRXFF_BNDY */ ++ ++ ++/* 2 LLT_INIT */ ++#define _LLT_NO_ACTIVE 0x0 ++#define _LLT_WRITE_ACCESS 0x1 ++#define _LLT_READ_ACCESS 0x2 ++ ++#define _LLT_INIT_DATA(x) ((x) & 0xFF) ++#define _LLT_INIT_ADDR(x) (((x) & 0xFF) << 8) ++#define _LLT_OP(x) (((x) & 0x3) << 30) ++#define _LLT_OP_VALUE(x) (((x) >> 30) & 0x3) ++ ++ ++/* */ ++/* */ ++/* 0x0200h ~ 0x027Fh TXDMA Configuration */ ++/* */ ++/* */ ++/* 2 RQPN */ ++#define _HPQ(x) ((x) & 0xFF) ++#define _LPQ(x) (((x) & 0xFF) << 8) ++#define _PUBQ(x) (((x) & 0xFF) << 16) ++#define _NPQ(x) ((x) & 0xFF) /* NOTE: in RQPN_NPQ register */ ++#define _EPQ(x) (((x) & 0xFF) << 16) /* NOTE: in RQPN_EPQ register */ ++ ++ ++#define HPQ_PUBLIC_DIS BIT(24) ++#define LPQ_PUBLIC_DIS BIT(25) ++#define LD_RQPN BIT(31) ++ ++ ++/* 2 TDECTL */ ++#define BLK_DESC_NUM_SHIFT 4 ++#define BLK_DESC_NUM_MASK 0xF ++ ++ ++/* 2 TXDMA_OFFSET_CHK */ ++#define DROP_DATA_EN BIT(9) ++ ++/* 2 AUTO_LLT */ ++#define BIT_SHIFT_TXPKTNUM 24 ++#define BIT_MASK_TXPKTNUM 0xff ++#define BIT_TXPKTNUM(x) (((x) & BIT_MASK_TXPKTNUM) << BIT_SHIFT_TXPKTNUM) ++ ++#define BIT_TDE_DBG_SEL BIT(23) ++#define BIT_AUTO_INIT_LLT BIT(16) ++ ++#define BIT_SHIFT_Tx_OQT_free_space 8 ++#define BIT_MASK_Tx_OQT_free_space 0xff ++#define BIT_Tx_OQT_free_space(x) (((x) & BIT_MASK_Tx_OQT_free_space) << BIT_SHIFT_Tx_OQT_free_space) ++ ++ ++/* */ ++/* */ ++/* 0x0280h ~ 0x028Bh RX DMA Configuration */ ++/* */ ++/* */ ++ ++/* 2 REG_RXDMA_CONTROL, 0x0286h */ ++/* Write only. When this bit is set, RXDMA will decrease RX PKT counter by one. Before */ ++/* this bit is polled, FW shall update RXFF_RD_PTR first. This register is write pulse and auto clear. */ ++/* define RXPKT_RELEASE_POLL BIT(0) */ ++/* Read only. When RXMA finishes on-going DMA operation, RXMDA will report idle state in */ ++/* this bit. FW can start releasing packets after RXDMA entering idle mode. */ ++/* define RXDMA_IDLE BIT(1) */ ++/* When this bit is set, RXDMA will enter this mode after on-going RXDMA packet to host */ ++/* completed, and stop DMA packet to host. RXDMA will then report Default: 0; */ ++/* define RW_RELEASE_EN BIT(2) */ ++ ++/* 2 REG_RXPKT_NUM, 0x0284 */ ++#define RXPKT_RELEASE_POLL BIT(16) ++#define RXDMA_IDLE BIT(17) ++#define RW_RELEASE_EN BIT(18) ++ ++/* */ ++/* */ ++/* 0x0400h ~ 0x047Fh Protocol Configuration */ ++/* */ ++/* */ ++/* 2 FWHW_TXQ_CTRL */ ++#define EN_AMPDU_RTY_NEW BIT(7) ++ ++ ++/* 2 SPEC SIFS */ ++#define _SPEC_SIFS_CCK(x) ((x) & 0xFF) ++#define _SPEC_SIFS_OFDM(x) (((x) & 0xFF) << 8) ++ ++/* 2 RL */ ++#define RETRY_LIMIT_SHORT_SHIFT 8 ++#define RETRY_LIMIT_LONG_SHIFT 0 ++ ++/* */ ++/* */ ++/* 0x0500h ~ 0x05FFh EDCA Configuration */ ++/* */ ++/* */ ++ ++/* 2 EDCA setting */ ++#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 ++ ++ ++#define _LRL(x) ((x) & 0x3F) ++#define _SRL(x) (((x) & 0x3F) << 8) ++ ++ ++/* 2 BCN_CTRL */ ++#define EN_TXBCN_RPT BIT(2) ++#define EN_BCN_FUNCTION BIT(3) ++#define STOP_BCNQ BIT(6) ++#define DIS_RX_BSSID_FIT BIT(6) ++ ++#define DIS_ATIM BIT(0) ++#define DIS_BCNQ_SUB BIT(1) ++#define DIS_TSF_UDT BIT(4) ++ ++/* The same function but different bit field. */ ++#define DIS_TSF_UDT0_NORMAL_CHIP BIT(4) ++#define DIS_TSF_UDT0_TEST_CHIP BIT(5) ++ ++ ++/* 2 ACMHWCTRL */ ++#define AcmHw_HwEn BIT(0) ++#define AcmHw_BeqEn BIT(1) ++#define AcmHw_ViqEn BIT(2) ++#define AcmHw_VoqEn BIT(3) ++#define AcmHw_BeqStatus BIT(4) ++#define AcmHw_ViqStatus BIT(5) ++#define AcmHw_VoqStatus BIT(6) ++ ++/* 2 REG_DUAL_TSF_RST (0x553) */ ++#define DUAL_TSF_RST_P2P BIT(4) ++ ++/* 2 REG_NOA_DESC_SEL (0x5CF) */ ++#define NOA_DESC_SEL_0 0 ++#define NOA_DESC_SEL_1 BIT(4) ++ ++/* */ ++/* */ ++/* 0x0600h ~ 0x07FFh WMAC Configuration */ ++/* */ ++/* */ ++ ++/* 2 APSD_CTRL */ ++#define APSDOFF BIT(6) ++ ++/* 2 TCR */ ++#define TSFRST BIT(0) ++#define DIS_GCLK BIT(1) ++#define PAD_SEL BIT(2) ++#define PWR_ST BIT(6) ++#define PWRBIT_OW_EN BIT(7) ++#define ACRC BIT(8) ++#define CFENDFORM BIT(9) ++#define ICV BIT(10) ++ ++ ++/* 2 RCR */ ++#define AAP BIT(0) ++#define APM BIT(1) ++#define AM BIT(2) ++#define AB BIT(3) ++#define ADD3 BIT(4) ++#define APWRMGT BIT(5) ++#define CBSSID BIT(6) ++#define CBSSID_DATA BIT(6) ++#define CBSSID_BCN BIT(7) ++#define ACRC32 BIT(8) ++#define AICV BIT(9) ++#define ADF BIT(11) ++#define ACF BIT(12) ++#define AMF BIT(13) ++#define HTC_LOC_CTRL BIT(14) ++#define UC_DATA_EN BIT(16) ++#define BM_DATA_EN BIT(17) ++#define MFBEN BIT(22) ++#define LSIGEN BIT(23) ++#define EnMBID BIT(24) ++#define FORCEACK BIT(26) ++#define APP_BASSN BIT(27) ++#define APP_PHYSTS BIT(28) ++#define APP_ICV BIT(29) ++#define APP_MIC BIT(30) ++#define APP_FCS BIT(31) ++ ++ ++/* 2 SECCFG */ ++#define SCR_TxUseDK BIT(0) /* Force Tx Use Default Key */ ++#define SCR_RxUseDK BIT(1) /* Force Rx Use Default Key */ ++#define SCR_TxEncEnable BIT(2) /* Enable Tx Encryption */ ++#define SCR_RxDecEnable BIT(3) /* Enable Rx Decryption */ ++#define SCR_SKByA2 BIT(4) /* Search kEY BY A2 */ ++#define SCR_NoSKMC BIT(5) /* No Key Search Multicast */ ++#define SCR_TXBCUSEDK BIT(6) /* Force Tx Broadcast packets Use Default Key */ ++#define SCR_RXBCUSEDK BIT(7) /* Force Rx Broadcast packets Use Default Key */ ++#define SCR_CHK_KEYID BIT(8) ++ ++/* */ ++/* */ ++/* SDIO Bus Specification */ ++/* */ ++/* */ ++ ++/* I/O bus domain address mapping */ ++#define SDIO_LOCAL_BASE 0x10250000 ++#define WLAN_IOREG_BASE 0x10260000 ++#define FIRMWARE_FIFO_BASE 0x10270000 ++#define TX_HIQ_BASE 0x10310000 ++#define TX_MIQ_BASE 0x10320000 ++#define TX_LOQ_BASE 0x10330000 ++#define TX_EPQ_BASE 0x10350000 ++#define RX_RX0FF_BASE 0x10340000 ++ ++/* SDIO host local register space mapping. */ ++#define SDIO_LOCAL_MSK 0x0FFF ++#define WLAN_IOREG_MSK 0x7FFF ++#define WLAN_FIFO_MSK 0x1FFF /* Aggregation Length[12:0] */ ++#define WLAN_RX0FF_MSK 0x0003 ++ ++#define SDIO_WITHOUT_REF_DEVICE_ID 0 /* Without reference to the SDIO Device ID */ ++#define SDIO_LOCAL_DEVICE_ID 0 /* 0b[16], 000b[15:13] */ ++#define WLAN_TX_HIQ_DEVICE_ID 4 /* 0b[16], 100b[15:13] */ ++#define WLAN_TX_MIQ_DEVICE_ID 5 /* 0b[16], 101b[15:13] */ ++#define WLAN_TX_LOQ_DEVICE_ID 6 /* 0b[16], 110b[15:13] */ ++#define WLAN_TX_EXQ_DEVICE_ID 3 /* 0b[16], 011b[15:13] */ ++#define WLAN_RX0FF_DEVICE_ID 7 /* 0b[16], 111b[15:13] */ ++#define WLAN_IOREG_DEVICE_ID 8 /* 1b[16] */ ++ ++/* SDIO Tx Free Page Index */ ++#define HI_QUEUE_IDX 0 ++#define MID_QUEUE_IDX 1 ++#define LOW_QUEUE_IDX 2 ++#define PUBLIC_QUEUE_IDX 3 ++ ++#define SDIO_MAX_TX_QUEUE 3 /* HIQ, MIQ and LOQ */ ++#define SDIO_MAX_RX_QUEUE 1 ++ ++#define SDIO_REG_TX_CTRL 0x0000 /* SDIO Tx Control */ ++#define SDIO_REG_HIMR 0x0014 /* SDIO Host Interrupt Mask */ ++#define SDIO_REG_HISR 0x0018 /* SDIO Host Interrupt Service Routine */ ++#define SDIO_REG_HCPWM 0x0019 /* HCI Current Power Mode */ ++#define SDIO_REG_RX0_REQ_LEN 0x001C /* RXDMA Request Length */ ++#define SDIO_REG_OQT_FREE_PG 0x001E /* OQT Free Page */ ++#define SDIO_REG_FREE_TXPG 0x0020 /* Free Tx Buffer Page */ ++#define SDIO_REG_HCPWM1 0x0024 /* HCI Current Power Mode 1 */ ++#define SDIO_REG_HCPWM2 0x0026 /* HCI Current Power Mode 2 */ ++#define SDIO_REG_FREE_TXPG_SEQ 0x0028 /* Free Tx Page Sequence */ ++#define SDIO_REG_HTSFR_INFO 0x0030 /* HTSF Informaion */ ++#define SDIO_REG_HRPWM1 0x0080 /* HCI Request Power Mode 1 */ ++#define SDIO_REG_HRPWM2 0x0082 /* HCI Request Power Mode 2 */ ++#define SDIO_REG_HPS_CLKR 0x0084 /* HCI Power Save Clock */ ++#define SDIO_REG_HSUS_CTRL 0x0086 /* SDIO HCI Suspend Control */ ++#define SDIO_REG_HIMR_ON 0x0090 /* SDIO Host Extension Interrupt Mask Always */ ++#define SDIO_REG_HISR_ON 0x0091 /* SDIO Host Extension Interrupt Status Always */ ++ ++#define SDIO_HIMR_DISABLED 0 ++ ++/* RTL8723/RTL8188E SDIO Host Interrupt Mask Register */ ++#define SDIO_HIMR_RX_REQUEST_MSK BIT0 ++#define SDIO_HIMR_AVAL_MSK BIT1 ++#define SDIO_HIMR_TXERR_MSK BIT2 ++#define SDIO_HIMR_RXERR_MSK BIT3 ++#define SDIO_HIMR_TXFOVW_MSK BIT4 ++#define SDIO_HIMR_RXFOVW_MSK BIT5 ++#define SDIO_HIMR_TXBCNOK_MSK BIT6 ++#define SDIO_HIMR_TXBCNERR_MSK BIT7 ++#define SDIO_HIMR_BCNERLY_INT_MSK BIT16 ++#define SDIO_HIMR_C2HCMD_MSK BIT17 ++#define SDIO_HIMR_CPWM1_MSK BIT18 ++#define SDIO_HIMR_CPWM2_MSK BIT19 ++#define SDIO_HIMR_HSISR_IND_MSK BIT20 ++#define SDIO_HIMR_GTINT3_IND_MSK BIT21 ++#define SDIO_HIMR_GTINT4_IND_MSK BIT22 ++#define SDIO_HIMR_PSTIMEOUT_MSK BIT23 ++#define SDIO_HIMR_OCPINT_MSK BIT24 ++#define SDIO_HIMR_ATIMEND_MSK BIT25 ++#define SDIO_HIMR_ATIMEND_E_MSK BIT26 ++#define SDIO_HIMR_CTWEND_MSK BIT27 ++ ++/* RTL8188E SDIO Specific */ ++#define SDIO_HIMR_MCU_ERR_MSK BIT28 ++#define SDIO_HIMR_TSF_BIT32_TOGGLE_MSK BIT29 ++ ++/* SDIO Host Interrupt Service Routine */ ++#define SDIO_HISR_RX_REQUEST BIT0 ++#define SDIO_HISR_AVAL BIT1 ++#define SDIO_HISR_TXERR BIT2 ++#define SDIO_HISR_RXERR BIT3 ++#define SDIO_HISR_TXFOVW BIT4 ++#define SDIO_HISR_RXFOVW BIT5 ++#define SDIO_HISR_TXBCNOK BIT6 ++#define SDIO_HISR_TXBCNERR BIT7 ++#define SDIO_HISR_BCNERLY_INT BIT16 ++#define SDIO_HISR_C2HCMD BIT17 ++#define SDIO_HISR_CPWM1 BIT18 ++#define SDIO_HISR_CPWM2 BIT19 ++#define SDIO_HISR_HSISR_IND BIT20 ++#define SDIO_HISR_GTINT3_IND BIT21 ++#define SDIO_HISR_GTINT4_IND BIT22 ++#define SDIO_HISR_PSTIMEOUT BIT23 ++#define SDIO_HISR_OCPINT BIT24 ++#define SDIO_HISR_ATIMEND BIT25 ++#define SDIO_HISR_ATIMEND_E BIT26 ++#define SDIO_HISR_CTWEND BIT27 ++ ++/* RTL8188E SDIO Specific */ ++#define SDIO_HISR_MCU_ERR BIT28 ++#define SDIO_HISR_TSF_BIT32_TOGGLE BIT29 ++ ++#define MASK_SDIO_HISR_CLEAR (SDIO_HISR_TXERR |\ ++ SDIO_HISR_RXERR |\ ++ SDIO_HISR_TXFOVW |\ ++ SDIO_HISR_RXFOVW |\ ++ SDIO_HISR_TXBCNOK |\ ++ SDIO_HISR_TXBCNERR |\ ++ SDIO_HISR_C2HCMD |\ ++ SDIO_HISR_CPWM1 |\ ++ SDIO_HISR_CPWM2 |\ ++ SDIO_HISR_HSISR_IND |\ ++ SDIO_HISR_GTINT3_IND |\ ++ SDIO_HISR_GTINT4_IND |\ ++ SDIO_HISR_PSTIMEOUT |\ ++ SDIO_HISR_OCPINT) ++ ++/* SDIO HCI Suspend Control Register */ ++#define HCI_RESUME_PWR_RDY BIT1 ++#define HCI_SUS_CTRL BIT0 ++ ++/* SDIO Tx FIFO related */ ++#define SDIO_TX_FREE_PG_QUEUE 4 /* The number of Tx FIFO free page */ ++#define SDIO_TX_FIFO_PAGE_SZ 128 ++ ++#define MAX_TX_AGG_PACKET_NUMBER 0x8 ++ ++/* */ ++/* */ ++/* 0xFE00h ~ 0xFE55h USB Configuration */ ++/* */ ++/* */ ++ ++/* 2 USB Information (0xFE17) */ ++#define USB_IS_HIGH_SPEED 0 ++#define USB_IS_FULL_SPEED 1 ++#define USB_SPEED_MASK BIT(5) ++ ++#define USB_NORMAL_SIE_EP_MASK 0xF ++#define USB_NORMAL_SIE_EP_SHIFT 4 ++ ++/* 2 Special Option */ ++#define USB_AGG_EN BIT(3) ++ ++/* 0; Use interrupt endpoint to upload interrupt pkt */ ++/* 1; Use bulk endpoint to upload interrupt pkt, */ ++#define INT_BULK_SEL BIT(4) ++ ++/* 2REG_C2HEVT_CLEAR */ ++#define C2H_EVT_HOST_CLOSE 0x00 /* Set by driver and notify FW that the driver has read the C2H command message */ ++#define C2H_EVT_FW_CLOSE 0xFF /* Set by FW indicating that FW had set the C2H command message and it's not yet read by driver. */ ++ ++ ++/* 2REG_MULTI_FUNC_CTRL(For RTL8723 Only) */ ++#define WL_HWPDN_EN BIT0 /* Enable GPIO[9] as WiFi HW PDn source */ ++#define WL_HWPDN_SL BIT1 /* WiFi HW PDn polarity control */ ++#define WL_FUNC_EN BIT2 /* WiFi function enable */ ++#define WL_HWROF_EN BIT3 /* Enable GPIO[9] as WiFi RF HW PDn source */ ++#define BT_HWPDN_EN BIT16 /* Enable GPIO[11] as BT HW PDn source */ ++#define BT_HWPDN_SL BIT17 /* BT HW PDn polarity control */ ++#define BT_FUNC_EN BIT18 /* BT function enable */ ++#define BT_HWROF_EN BIT19 /* Enable GPIO[11] as BT/GPS RF HW PDn source */ ++#define GPS_HWPDN_EN BIT20 /* Enable GPIO[10] as GPS HW PDn source */ ++#define GPS_HWPDN_SL BIT21 /* GPS HW PDn polarity control */ ++#define GPS_FUNC_EN BIT22 /* GPS function enable */ ++ ++/* 3 REG_LIFECTRL_CTRL */ ++#define HAL92C_EN_PKT_LIFE_TIME_BK BIT3 ++#define HAL92C_EN_PKT_LIFE_TIME_BE BIT2 ++#define HAL92C_EN_PKT_LIFE_TIME_VI BIT1 ++#define HAL92C_EN_PKT_LIFE_TIME_VO BIT0 ++ ++#define HAL92C_MSDU_LIFE_TIME_UNIT 128 /* in us, said by Tim. */ ++ ++/* 2 8192D PartNo. */ ++#define PARTNO_92D_NIC (BIT7|BIT6) ++#define PARTNO_92D_NIC_REMARK (BIT5|BIT4) ++#define PARTNO_SINGLE_BAND_VS BIT3 ++#define PARTNO_SINGLE_BAND_VS_REMARK BIT1 ++#define PARTNO_CONCURRENT_BAND_VC (BIT3|BIT2) ++#define PARTNO_CONCURRENT_BAND_VC_REMARK (BIT1|BIT0) ++ ++/* */ ++/* General definitions */ ++/* */ ++ ++#define LAST_ENTRY_OF_TX_PKT_BUFFER_8188E 176 ++#define LAST_ENTRY_OF_TX_PKT_BUFFER_8812 255 ++#define LAST_ENTRY_OF_TX_PKT_BUFFER_8723B 255 ++#define LAST_ENTRY_OF_TX_PKT_BUFFER_8192C 255 ++#define LAST_ENTRY_OF_TX_PKT_BUFFER_DUAL_MAC 127 ++ ++#define POLLING_LLT_THRESHOLD 20 ++#define POLLING_READY_TIMEOUT_COUNT 1000 ++ ++ ++/* GPIO BIT */ ++#define HAL_8192C_HW_GPIO_WPS_BIT BIT2 ++#define HAL_8192EU_HW_GPIO_WPS_BIT BIT7 ++#define HAL_8188E_HW_GPIO_WPS_BIT BIT7 ++ ++#endif /* __HAL_COMMON_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/hal_data.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_data.h +--- linux-4.3/3rdparty/rtl8723bs/include/hal_data.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_data.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,485 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __HAL_DATA_H__ ++#define __HAL_DATA_H__ ++ ++#include "odm_precomp.h" ++#include ++ ++#include ++ ++/* */ ++/* For RTL8723 WiFi/BT/GPS multi-function configuration. 2010.10.06. */ ++/* */ ++enum RT_MULTI_FUNC { ++ RT_MULTI_FUNC_NONE = 0x00, ++ RT_MULTI_FUNC_WIFI = 0x01, ++ RT_MULTI_FUNC_BT = 0x02, ++ RT_MULTI_FUNC_GPS = 0x04, ++}; ++/* */ ++/* For RTL8723 WiFi PDn/GPIO polarity control configuration. 2010.10.08. */ ++/* */ ++enum RT_POLARITY_CTL { ++ RT_POLARITY_LOW_ACT = 0, ++ RT_POLARITY_HIGH_ACT = 1, ++}; ++ ++/* For RTL8723 regulator mode. by tynli. 2011.01.14. */ ++enum RT_REGULATOR_MODE { ++ RT_SWITCHING_REGULATOR = 0, ++ RT_LDO_REGULATOR = 1, ++}; ++ ++enum RT_AMPDU_BURST { ++ RT_AMPDU_BURST_NONE = 0, ++ RT_AMPDU_BURST_92D = 1, ++ RT_AMPDU_BURST_88E = 2, ++ RT_AMPDU_BURST_8812_4 = 3, ++ RT_AMPDU_BURST_8812_8 = 4, ++ RT_AMPDU_BURST_8812_12 = 5, ++ RT_AMPDU_BURST_8812_15 = 6, ++ RT_AMPDU_BURST_8723B = 7, ++}; ++ ++#define CHANNEL_MAX_NUMBER 14+24+21 /* 14 is the max channel number */ ++#define CHANNEL_MAX_NUMBER_2G 14 ++#define CHANNEL_MAX_NUMBER_5G 54 /* Please refer to "phy_GetChnlGroup8812A" and "Hal_ReadTxPowerInfo8812A" */ ++#define CHANNEL_MAX_NUMBER_5G_80M 7 ++#define CHANNEL_GROUP_MAX 3+9 /* ch1~3, ch4~9, ch10~14 total three groups */ ++#define MAX_PG_GROUP 13 ++ ++/* Tx Power Limit Table Size */ ++#define MAX_REGULATION_NUM 4 ++#define MAX_RF_PATH_NUM_IN_POWER_LIMIT_TABLE 4 ++#define MAX_2_4G_BANDWITH_NUM 4 ++#define MAX_RATE_SECTION_NUM 10 ++#define MAX_5G_BANDWITH_NUM 4 ++ ++#define MAX_BASE_NUM_IN_PHY_REG_PG_2_4G 10 /* CCK:1, OFDM:1, HT:4, VHT:4 */ ++#define MAX_BASE_NUM_IN_PHY_REG_PG_5G 9 /* OFDM:1, HT:4, VHT:4 */ ++ ++ ++/* duplicate code, will move to ODM ######### */ ++/* define IQK_MAC_REG_NUM 4 */ ++/* define IQK_ADDA_REG_NUM 16 */ ++ ++/* define IQK_BB_REG_NUM 10 */ ++#define IQK_BB_REG_NUM_92C 9 ++#define IQK_BB_REG_NUM_92D 10 ++#define IQK_BB_REG_NUM_test 6 ++ ++#define IQK_Matrix_Settings_NUM_92D 1+24+21 ++ ++/* define HP_THERMAL_NUM 8 */ ++/* duplicate code, will move to ODM ######### */ ++ ++enum { ++ SINGLEMAC_SINGLEPHY, /* SMSP */ ++ DUALMAC_DUALPHY, /* DMDP */ ++ DUALMAC_SINGLEPHY, /* DMSP */ ++}; ++ ++#define PAGE_SIZE_128 128 ++#define PAGE_SIZE_256 256 ++#define PAGE_SIZE_512 512 ++ ++struct dm_priv { ++ u8 DM_Type; ++ ++#define DYNAMIC_FUNC_BT BIT0 ++ ++ u8 DMFlag; ++ u8 InitDMFlag; ++ /* u8 RSVD_1; */ ++ ++ u32 InitODMFlag; ++ /* Upper and Lower Signal threshold for Rate Adaptive */ ++ int UndecoratedSmoothedPWDB; ++ int UndecoratedSmoothedCCK; ++ int EntryMinUndecoratedSmoothedPWDB; ++ int EntryMaxUndecoratedSmoothedPWDB; ++ int MinUndecoratedPWDBForDM; ++ int LastMinUndecoratedPWDBForDM; ++ ++ s32 UndecoratedSmoothedBeacon; ++ ++/* duplicate code, will move to ODM ######### */ ++ /* for High Power */ ++ u8 bDynamicTxPowerEnable; ++ u8 LastDTPLvl; ++ u8 DynamicTxHighPowerLvl;/* Add by Jacken Tx Power Control for Near/Far Range 2008/03/06 */ ++ ++ /* for tx power tracking */ ++ u8 bTXPowerTracking; ++ u8 TXPowercount; ++ u8 bTXPowerTrackingInit; ++ u8 TxPowerTrackControl; /* for mp mode, turn off txpwrtracking as default */ ++ u8 TM_Trigger; ++ ++ u8 ThermalMeter[2]; /* ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 */ ++ u8 ThermalValue; ++ u8 ThermalValue_LCK; ++ u8 ThermalValue_IQK; ++ u8 ThermalValue_DPK; ++ u8 bRfPiEnable; ++ /* u8 RSVD_2; */ ++ ++ /* for APK */ ++ u32 APKoutput[2][2]; /* path A/B; output1_1a/output1_2a */ ++ u8 bAPKdone; ++ u8 bAPKThermalMeterIgnore; ++ u8 bDPdone; ++ u8 bDPPathAOK; ++ u8 bDPPathBOK; ++ /* u8 RSVD_3; */ ++ /* u8 RSVD_4; */ ++ /* u8 RSVD_5; */ ++ ++ /* for IQK */ ++ u32 ADDA_backup[IQK_ADDA_REG_NUM]; ++ u32 IQK_MAC_backup[IQK_MAC_REG_NUM]; ++ u32 IQK_BB_backup_recover[9]; ++ u32 IQK_BB_backup[IQK_BB_REG_NUM]; ++ ++ u8 PowerIndex_backup[6]; ++ u8 OFDM_index[2]; ++ ++ u8 bCCKinCH14; ++ u8 CCK_index; ++ u8 bDoneTxpower; ++ u8 CCK_index_HP; ++ ++ u8 OFDM_index_HP[2]; ++ u8 ThermalValue_HP[HP_THERMAL_NUM]; ++ u8 ThermalValue_HP_index; ++ /* u8 RSVD_6; */ ++ ++ /* for TxPwrTracking2 */ ++ s32 RegE94; ++ s32 RegE9C; ++ s32 RegEB4; ++ s32 RegEBC; ++ ++ u32 TXPowerTrackingCallbackCnt; /* cosa add for debug */ ++ ++ u32 prv_traffic_idx; /* edca turbo */ ++/* duplicate code, will move to ODM ######### */ ++ ++ /* Add for Reading Initial Data Rate SEL Register 0x484 during watchdog. Using for fill tx desc. 2011.3.21 by Thomas */ ++ u8 INIDATA_RATE[32]; ++}; ++ ++ ++struct hal_com_data { ++ HAL_VERSION VersionID; ++ enum RT_MULTI_FUNC MultiFunc; /* For multi-function consideration. */ ++ enum RT_POLARITY_CTL PolarityCtl; /* For Wifi PDn Polarity control. */ ++ enum RT_REGULATOR_MODE RegulatorMode; /* switching regulator or LDO */ ++ ++ u16 FirmwareVersion; ++ u16 FirmwareVersionRev; ++ u16 FirmwareSubVersion; ++ u16 FirmwareSignature; ++ ++ /* current WIFI_PHY values */ ++ enum WIRELESS_MODE CurrentWirelessMode; ++ enum CHANNEL_WIDTH CurrentChannelBW; ++ enum BAND_TYPE CurrentBandType; /* 0:2.4G, 1:5G */ ++ enum BAND_TYPE BandSet; ++ u8 CurrentChannel; ++ u8 CurrentCenterFrequencyIndex1; ++ u8 nCur40MhzPrimeSC;/* Control channel sub-carrier */ ++ u8 nCur80MhzPrimeSC; /* used for primary 40MHz of 80MHz mode */ ++ ++ u16 CustomerID; ++ u16 BasicRateSet; ++ u16 ForcedDataRate;/* Force Data Rate. 0: Auto, 0x02: 1M ~ 0x6C: 54M. */ ++ u32 ReceiveConfig; ++ ++ /* rf_ctrl */ ++ u8 rf_chip; ++ u8 rf_type; ++ u8 PackageType; ++ u8 NumTotalRFPath; ++ ++ u8 InterfaceSel; ++ u8 framesync; ++ u32 framesyncC34; ++ u8 framesyncMonitor; ++ u8 DefaultInitialGain[4]; ++ /* EEPROM setting. */ ++ u16 EEPROMVID; ++ u16 EEPROMSVID; ++ ++ u8 EEPROMCustomerID; ++ u8 EEPROMSubCustomerID; ++ u8 EEPROMVersion; ++ u8 EEPROMRegulatory; ++ u8 EEPROMThermalMeter; ++ u8 EEPROMBluetoothCoexist; ++ u8 EEPROMBluetoothType; ++ u8 EEPROMBluetoothAntNum; ++ u8 EEPROMBluetoothAntIsolation; ++ u8 EEPROMBluetoothRadioShared; ++ u8 bTXPowerDataReadFromEEPORM; ++ u8 bAPKThermalMeterIgnore; ++ u8 bDisableSWChannelPlan; /* flag of disable software change channel plan */ ++ ++ bool EepromOrEfuse; ++ u8 EfuseUsedPercentage; ++ u16 EfuseUsedBytes; ++ EFUSE_HAL EfuseHal; ++ ++ /* 3 [2.4G] */ ++ u8 Index24G_CCK_Base[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; ++ u8 Index24G_BW40_Base[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; ++ /* If only one tx, only BW20 and OFDM are used. */ ++ s8 CCK_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 OFDM_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 BW20_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 BW40_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ /* 3 [5G] */ ++ u8 Index5G_BW40_Base[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; ++ u8 Index5G_BW80_Base[MAX_RF_PATH][CHANNEL_MAX_NUMBER_5G_80M]; ++ s8 OFDM_5G_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 BW20_5G_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 BW40_5G_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 BW80_5G_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ ++ u8 Regulation2_4G; ++ u8 Regulation5G; ++ ++ u8 TxPwrInPercentage; ++ ++ u8 TxPwrCalibrateRate; ++ /* TX power by rate table at most 4RF path. */ ++ /* The register is */ ++ /* VHT TX power by rate off setArray = */ ++ /* Band:-2G&5G = 0 / 1 */ ++ /* RF: at most 4*4 = ABCD = 0/1/2/3 */ ++ /* CCK = 0 OFDM = 1/2 HT-MCS 0-15 =3/4/56 VHT =7/8/9/10/11 */ ++ u8 TxPwrByRateTable; ++ u8 TxPwrByRateBand; ++ s8 TxPwrByRateOffset[TX_PWR_BY_RATE_NUM_BAND] ++ [TX_PWR_BY_RATE_NUM_RF] ++ [TX_PWR_BY_RATE_NUM_RF] ++ [TX_PWR_BY_RATE_NUM_RATE]; ++ /* */ ++ ++ /* 2 Power Limit Table */ ++ u8 TxPwrLevelCck[RF_PATH_MAX_92C_88E][CHANNEL_MAX_NUMBER]; ++ u8 TxPwrLevelHT40_1S[RF_PATH_MAX_92C_88E][CHANNEL_MAX_NUMBER]; /* For HT 40MHZ pwr */ ++ u8 TxPwrLevelHT40_2S[RF_PATH_MAX_92C_88E][CHANNEL_MAX_NUMBER]; /* For HT 40MHZ pwr */ ++ s8 TxPwrHt20Diff[RF_PATH_MAX_92C_88E][CHANNEL_MAX_NUMBER];/* HT 20<->40 Pwr diff */ ++ u8 TxPwrLegacyHtDiff[RF_PATH_MAX_92C_88E][CHANNEL_MAX_NUMBER];/* For HT<->legacy pwr diff */ ++ ++ /* Power Limit Table for 2.4G */ ++ s8 TxPwrLimit_2_4G[MAX_REGULATION_NUM] ++ [MAX_2_4G_BANDWITH_NUM] ++ [MAX_RATE_SECTION_NUM] ++ [CHANNEL_MAX_NUMBER_2G] ++ [MAX_RF_PATH_NUM]; ++ ++ /* Power Limit Table for 5G */ ++ s8 TxPwrLimit_5G[MAX_REGULATION_NUM] ++ [MAX_5G_BANDWITH_NUM] ++ [MAX_RATE_SECTION_NUM] ++ [CHANNEL_MAX_NUMBER_5G] ++ [MAX_RF_PATH_NUM]; ++ ++ ++ /* Store the original power by rate value of the base of each rate section of rf path A & B */ ++ u8 TxPwrByRateBase2_4G[TX_PWR_BY_RATE_NUM_RF] ++ [TX_PWR_BY_RATE_NUM_RF] ++ [MAX_BASE_NUM_IN_PHY_REG_PG_2_4G]; ++ u8 TxPwrByRateBase5G[TX_PWR_BY_RATE_NUM_RF] ++ [TX_PWR_BY_RATE_NUM_RF] ++ [MAX_BASE_NUM_IN_PHY_REG_PG_5G]; ++ ++ /* For power group */ ++ u8 PwrGroupHT20[RF_PATH_MAX_92C_88E][CHANNEL_MAX_NUMBER]; ++ u8 PwrGroupHT40[RF_PATH_MAX_92C_88E][CHANNEL_MAX_NUMBER]; ++ ++ ++ ++ ++ u8 PGMaxGroup; ++ u8 LegacyHTTxPowerDiff;/* Legacy to HT rate power diff */ ++ /* The current Tx Power Level */ ++ u8 CurrentCckTxPwrIdx; ++ u8 CurrentOfdm24GTxPwrIdx; ++ u8 CurrentBW2024GTxPwrIdx; ++ u8 CurrentBW4024GTxPwrIdx; ++ ++ /* Read/write are allow for following hardware information variables */ ++ u8 pwrGroupCnt; ++ u32 MCSTxPowerLevelOriginalOffset[MAX_PG_GROUP][16]; ++ u32 CCKTxPowerLevelOriginalOffset; ++ ++ u8 CrystalCap; ++ u32 AntennaTxPath; /* Antenna path Tx */ ++ u32 AntennaRxPath; /* Antenna path Rx */ ++ ++ u8 PAType_2G; ++ u8 PAType_5G; ++ u8 LNAType_2G; ++ u8 LNAType_5G; ++ u8 ExternalPA_2G; ++ u8 ExternalLNA_2G; ++ u8 ExternalPA_5G; ++ u8 ExternalLNA_5G; ++ u8 TypeGLNA; ++ u8 TypeGPA; ++ u8 TypeALNA; ++ u8 TypeAPA; ++ u8 RFEType; ++ u8 BoardType; ++ u8 ExternalPA; ++ u8 bIQKInitialized; ++ bool bLCKInProgress; ++ ++ bool bSwChnl; ++ bool bSetChnlBW; ++ bool bChnlBWInitialized; ++ bool bNeedIQK; ++ ++ u8 bLedOpenDrain; /* Support Open-drain arrangement for controlling the LED. Added by Roger, 2009.10.16. */ ++ u8 TxPowerTrackControl; /* for mp mode, turn off txpwrtracking as default */ ++ u8 b1x1RecvCombine; /* for 1T1R receive combining */ ++ ++ u32 AcParam_BE; /* Original parameter for BE, use for EDCA turbo. */ ++ ++ struct bb_register_def PHYRegDef[4]; /* Radio A/B/C/D */ ++ ++ u32 RfRegChnlVal[2]; ++ ++ /* RDG enable */ ++ bool bRDGEnable; ++ ++ /* for host message to fw */ ++ u8 LastHMEBoxNum; ++ ++ u8 fw_ractrl; ++ u8 RegTxPause; ++ /* Beacon function related global variable. */ ++ u8 RegBcnCtrlVal; ++ u8 RegFwHwTxQCtrl; ++ u8 RegReg542; ++ u8 RegCR_1; ++ u8 Reg837; ++ u8 RegRFPathS1; ++ u16 RegRRSR; ++ ++ u8 CurAntenna; ++ u8 AntDivCfg; ++ u8 AntDetection; ++ u8 TRxAntDivType; ++ u8 ant_path; /* for 8723B s0/s1 selection */ ++ ++ u8 u1ForcedIgiLb; /* forced IGI lower bound */ ++ ++ u8 bDumpRxPkt;/* for debug */ ++ u8 bDumpTxPkt;/* for debug */ ++ u8 FwRsvdPageStartOffset; /* 2010.06.23. Added by tynli. Reserve page start offset except beacon in TxQ. */ ++ ++ /* 2010/08/09 MH Add CU power down mode. */ ++ bool pwrdown; ++ ++ /* Add for dual MAC 0--Mac0 1--Mac1 */ ++ u32 interfaceIndex; ++ ++ u8 OutEpQueueSel; ++ u8 OutEpNumber; ++ ++ /* 2010/12/10 MH Add for USB aggreation mode dynamic shceme. */ ++ bool UsbRxHighSpeedMode; ++ ++ /* 2010/11/22 MH Add for slim combo debug mode selective. */ ++ /* This is used for fix the drawback of CU TSMC-A/UMC-A cut. HW auto suspend ability. Close BT clock. */ ++ bool SlimComboDbg; ++ ++ /* u8 AMPDUDensity; */ ++ ++ /* Auto FSM to Turn On, include clock, isolation, power control for MAC only */ ++ u8 bMacPwrCtrlOn; ++ ++ u8 RegIQKFWOffload; ++ struct submit_ctx iqk_sctx; ++ ++ enum RT_AMPDU_BURST AMPDUBurstMode; /* 92C maybe not use, but for compile successfully */ ++ ++ u32 sdio_himr; ++ u32 sdio_hisr; ++ ++ /* SDIO Tx FIFO related. */ ++ /* HIQ, MID, LOW, PUB free pages; padapter->xmitpriv.free_txpg */ ++ u8 SdioTxFIFOFreePage[SDIO_TX_FREE_PG_QUEUE]; ++ _lock SdioTxFIFOFreePageLock; ++ u8 SdioTxOQTMaxFreeSpace; ++ u8 SdioTxOQTFreeSpace; ++ ++ ++ /* SDIO Rx FIFO related. */ ++ u8 SdioRxFIFOCnt; ++ u16 SdioRxFIFOSize; ++ ++ u32 sdio_tx_max_len[SDIO_MAX_TX_QUEUE];/* H, N, L, used for sdio tx aggregation max length per queue */ ++ ++ struct dm_priv dmpriv; ++ DM_ODM_T odmpriv; ++ ++ /* For bluetooth co-existance */ ++ BT_COEXIST bt_coexist; ++ ++ /* Interrupt related register information. */ ++ u32 SysIntrStatus; ++ u32 SysIntrMask; ++ ++ ++#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE ++ char para_file_buf[MAX_PARA_FILE_BUF_LEN]; ++ char *mac_reg; ++ u32 mac_reg_len; ++ char *bb_phy_reg; ++ u32 bb_phy_reg_len; ++ char *bb_agc_tab; ++ u32 bb_agc_tab_len; ++ char *bb_phy_reg_pg; ++ u32 bb_phy_reg_pg_len; ++ char *bb_phy_reg_mp; ++ u32 bb_phy_reg_mp_len; ++ char *rf_radio_a; ++ u32 rf_radio_a_len; ++ char *rf_radio_b; ++ u32 rf_radio_b_len; ++ char *rf_tx_pwr_track; ++ u32 rf_tx_pwr_track_len; ++ char *rf_tx_pwr_lmt; ++ u32 rf_tx_pwr_lmt_len; ++#endif ++ ++#ifdef CONFIG_BACKGROUND_NOISE_MONITOR ++ s16 noise[ODM_MAX_CHANNEL_NUM]; ++#endif ++ ++}; ++ ++#define GET_HAL_DATA(__padapter) ((struct hal_com_data *)((__padapter)->HalData)) ++#define GET_HAL_RFPATH_NUM(__padapter) (((struct hal_com_data *)((__padapter)->HalData))->NumTotalRFPath) ++#define RT_GetInterfaceSelection(_Adapter) (GET_HAL_DATA(_Adapter)->InterfaceSel) ++#define GET_RF_TYPE(__padapter) (GET_HAL_DATA(__padapter)->rf_type) ++ ++#endif /* __HAL_DATA_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/hal_intf.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_intf.h +--- linux-4.3/3rdparty/rtl8723bs/include/hal_intf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_intf.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,410 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __HAL_INTF_H__ ++#define __HAL_INTF_H__ ++ ++ ++enum RTL871X_HCI_TYPE { ++ RTW_PCIE = BIT0, ++ RTW_USB = BIT1, ++ RTW_SDIO = BIT2, ++ RTW_GSPI = BIT3, ++}; ++ ++enum HW_VARIABLES { ++ HW_VAR_MEDIA_STATUS, ++ HW_VAR_MEDIA_STATUS1, ++ HW_VAR_SET_OPMODE, ++ HW_VAR_MAC_ADDR, ++ HW_VAR_BSSID, ++ HW_VAR_INIT_RTS_RATE, ++ HW_VAR_BASIC_RATE, ++ HW_VAR_TXPAUSE, ++ HW_VAR_BCN_FUNC, ++ HW_VAR_CORRECT_TSF, ++ HW_VAR_CHECK_BSSID, ++ HW_VAR_MLME_DISCONNECT, ++ HW_VAR_MLME_SITESURVEY, ++ HW_VAR_MLME_JOIN, ++ HW_VAR_ON_RCR_AM, ++ HW_VAR_OFF_RCR_AM, ++ HW_VAR_BEACON_INTERVAL, ++ HW_VAR_SLOT_TIME, ++ HW_VAR_RESP_SIFS, ++ HW_VAR_ACK_PREAMBLE, ++ HW_VAR_SEC_CFG, ++ HW_VAR_SEC_DK_CFG, ++ HW_VAR_BCN_VALID, ++ HW_VAR_RF_TYPE, ++ HW_VAR_DM_FLAG, ++ HW_VAR_DM_FUNC_OP, ++ HW_VAR_DM_FUNC_SET, ++ HW_VAR_DM_FUNC_CLR, ++ HW_VAR_CAM_EMPTY_ENTRY, ++ HW_VAR_CAM_INVALID_ALL, ++ HW_VAR_CAM_WRITE, ++ HW_VAR_CAM_READ, ++ HW_VAR_AC_PARAM_VO, ++ HW_VAR_AC_PARAM_VI, ++ HW_VAR_AC_PARAM_BE, ++ HW_VAR_AC_PARAM_BK, ++ HW_VAR_ACM_CTRL, ++ HW_VAR_AMPDU_MIN_SPACE, ++ HW_VAR_AMPDU_FACTOR, ++ HW_VAR_RXDMA_AGG_PG_TH, ++ HW_VAR_SET_RPWM, ++ HW_VAR_CPWM, ++ HW_VAR_H2C_FW_PWRMODE, ++ HW_VAR_H2C_PS_TUNE_PARAM, ++ HW_VAR_H2C_FW_JOINBSSRPT, ++ HW_VAR_FWLPS_RF_ON, ++ HW_VAR_H2C_FW_P2P_PS_OFFLOAD, ++ HW_VAR_TDLS_WRCR, ++ HW_VAR_TDLS_INIT_CH_SEN, ++ HW_VAR_TDLS_RS_RCR, ++ HW_VAR_TDLS_DONE_CH_SEN, ++ HW_VAR_INITIAL_GAIN, ++ HW_VAR_TRIGGER_GPIO_0, ++ HW_VAR_BT_SET_COEXIST, ++ HW_VAR_BT_ISSUE_DELBA, ++ HW_VAR_CURRENT_ANTENNA, ++ HW_VAR_ANTENNA_DIVERSITY_LINK, ++ HW_VAR_ANTENNA_DIVERSITY_SELECT, ++ HW_VAR_SWITCH_EPHY_WoWLAN, ++ HW_VAR_EFUSE_USAGE, ++ HW_VAR_EFUSE_BYTES, ++ HW_VAR_EFUSE_BT_USAGE, ++ HW_VAR_EFUSE_BT_BYTES, ++ HW_VAR_FIFO_CLEARN_UP, ++ HW_VAR_CHECK_TXBUF, ++ HW_VAR_PCIE_STOP_TX_DMA, ++ HW_VAR_APFM_ON_MAC, /* Auto FSM to Turn On, include clock, isolation, power control for MAC only */ ++ /* The valid upper nav range for the HW updating, if the true value is larger than the upper range, the HW won't update it. */ ++ /* Unit in microsecond. 0 means disable this function. */ ++#ifdef CONFIG_WOWLAN ++ HW_VAR_WOWLAN, ++ HW_VAR_WAKEUP_REASON, ++ HW_VAR_RPWM_TOG, ++#endif ++#ifdef CONFIG_AP_WOWLAN ++ HW_VAR_AP_WOWLAN, ++#endif ++ HW_VAR_SYS_CLKR, ++ HW_VAR_NAV_UPPER, ++ HW_VAR_C2H_HANDLE, ++ HW_VAR_RPT_TIMER_SETTING, ++ HW_VAR_TX_RPT_MAX_MACID, ++ HW_VAR_H2C_MEDIA_STATUS_RPT, ++ HW_VAR_CHK_HI_QUEUE_EMPTY, ++ HW_VAR_DL_BCN_SEL, ++ HW_VAR_AMPDU_MAX_TIME, ++ HW_VAR_WIRELESS_MODE, ++ HW_VAR_USB_MODE, ++ HW_VAR_PORT_SWITCH, ++ HW_VAR_DO_IQK, ++ HW_VAR_DM_IN_LPS, ++ HW_VAR_SET_REQ_FW_PS, ++ HW_VAR_FW_PS_STATE, ++ HW_VAR_SOUNDING_ENTER, ++ HW_VAR_SOUNDING_LEAVE, ++ HW_VAR_SOUNDING_RATE, ++ HW_VAR_SOUNDING_STATUS, ++ HW_VAR_SOUNDING_FW_NDPA, ++ HW_VAR_SOUNDING_CLK, ++ HW_VAR_DL_RSVD_PAGE, ++ HW_VAR_MACID_SLEEP, ++ HW_VAR_MACID_WAKEUP, ++}; ++ ++enum HAL_DEF_VARIABLE { ++ HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, ++ HAL_DEF_IS_SUPPORT_ANT_DIV, ++ HAL_DEF_CURRENT_ANTENNA, ++ HAL_DEF_DRVINFO_SZ, ++ HAL_DEF_MAX_RECVBUF_SZ, ++ HAL_DEF_RX_PACKET_OFFSET, ++ HAL_DEF_DBG_DUMP_RXPKT,/* for dbg */ ++ HAL_DEF_DBG_DM_FUNC,/* for dbg */ ++ HAL_DEF_RA_DECISION_RATE, ++ HAL_DEF_RA_SGI, ++ HAL_DEF_PT_PWR_STATUS, ++ HAL_DEF_TX_LDPC, /* LDPC support */ ++ HAL_DEF_RX_LDPC, /* LDPC support */ ++ HAL_DEF_TX_STBC, /* TX STBC support */ ++ HAL_DEF_RX_STBC, /* RX STBC support */ ++ HAL_DEF_EXPLICIT_BEAMFORMER,/* Explicit Compressed Steering Capable */ ++ HAL_DEF_EXPLICIT_BEAMFORMEE,/* Explicit Compressed Beamforming Feedback Capable */ ++ HW_VAR_MAX_RX_AMPDU_FACTOR, ++ HW_DEF_RA_INFO_DUMP, ++ HAL_DEF_DBG_DUMP_TXPKT, ++ HW_DEF_FA_CNT_DUMP, ++ HW_DEF_ODM_DBG_FLAG, ++ HW_DEF_ODM_DBG_LEVEL, ++ HAL_DEF_TX_PAGE_SIZE, ++ HAL_DEF_TX_PAGE_BOUNDARY, ++ HAL_DEF_TX_PAGE_BOUNDARY_WOWLAN, ++ HAL_DEF_ANT_DETECT,/* to do for 8723a */ ++ HAL_DEF_PCI_SUUPORT_L1_BACKDOOR, /* Determine if the L1 Backdoor setting is turned on. */ ++ HAL_DEF_PCI_AMD_L1_SUPPORT, ++ HAL_DEF_PCI_ASPM_OSC, /* Support for ASPM OSC, added by Roger, 2013.03.27. */ ++ HAL_DEF_MACID_SLEEP, /* Support for MACID sleep */ ++ HAL_DEF_DBG_RX_INFO_DUMP, ++}; ++ ++enum HAL_ODM_VARIABLE { ++ HAL_ODM_STA_INFO, ++ HAL_ODM_P2P_STATE, ++ HAL_ODM_WIFI_DISPLAY_STATE, ++ HAL_ODM_NOISE_MONITOR, ++}; ++ ++enum HAL_INTF_PS_FUNC { ++ HAL_USB_SELECT_SUSPEND, ++ HAL_MAX_ID, ++}; ++ ++typedef s32 (*c2h_id_filter)(u8 *c2h_evt); ++ ++struct hal_ops { ++ u32 (*hal_power_on)(struct adapter *padapter); ++ void (*hal_power_off)(struct adapter *padapter); ++ u32 (*hal_init)(struct adapter *padapter); ++ u32 (*hal_deinit)(struct adapter *padapter); ++ ++ void (*free_hal_data)(struct adapter *padapter); ++ ++ u32 (*inirp_init)(struct adapter *padapter); ++ u32 (*inirp_deinit)(struct adapter *padapter); ++ void (*irp_reset)(struct adapter *padapter); ++ ++ s32 (*init_xmit_priv)(struct adapter *padapter); ++ void (*free_xmit_priv)(struct adapter *padapter); ++ ++ s32 (*init_recv_priv)(struct adapter *padapter); ++ void (*free_recv_priv)(struct adapter *padapter); ++ ++ void (*dm_init)(struct adapter *padapter); ++ void (*dm_deinit)(struct adapter *padapter); ++ void (*read_chip_version)(struct adapter *padapter); ++ ++ void (*init_default_value)(struct adapter *padapter); ++ ++ void (*intf_chip_configure)(struct adapter *padapter); ++ ++ void (*read_adapter_info)(struct adapter *padapter); ++ ++ void (*enable_interrupt)(struct adapter *padapter); ++ void (*disable_interrupt)(struct adapter *padapter); ++ u8 (*check_ips_status)(struct adapter *padapter); ++ s32 (*interrupt_handler)(struct adapter *padapter); ++ void (*clear_interrupt)(struct adapter *padapter); ++ void (*set_bwmode_handler)(struct adapter *padapter, enum CHANNEL_WIDTH Bandwidth, u8 Offset); ++ void (*set_channel_handler)(struct adapter *padapter, u8 channel); ++ void (*set_chnl_bw_handler)(struct adapter *padapter, u8 channel, enum CHANNEL_WIDTH Bandwidth, u8 Offset40, u8 Offset80); ++ ++ void (*set_tx_power_level_handler)(struct adapter *padapter, u8 channel); ++ void (*get_tx_power_level_handler)(struct adapter *padapter, s32 *powerlevel); ++ ++ void (*hal_dm_watchdog)(struct adapter *padapter); ++ void (*hal_dm_watchdog_in_lps)(struct adapter *padapter); ++ ++ ++ void (*SetHwRegHandler)(struct adapter *padapter, u8 variable, u8 *val); ++ void (*GetHwRegHandler)(struct adapter *padapter, u8 variable, u8 *val); ++ ++ void (*SetHwRegHandlerWithBuf)(struct adapter *padapter, u8 variable, u8 *pbuf, int len); ++ ++ u8 (*GetHalDefVarHandler)(struct adapter *padapter, enum HAL_DEF_VARIABLE eVariable, void *pValue); ++ u8 (*SetHalDefVarHandler)(struct adapter *padapter, enum HAL_DEF_VARIABLE eVariable, void *pValue); ++ ++ void (*GetHalODMVarHandler)(struct adapter *padapter, enum HAL_ODM_VARIABLE eVariable, void *pValue1, void *pValue2); ++ void (*SetHalODMVarHandler)(struct adapter *padapter, enum HAL_ODM_VARIABLE eVariable, void *pValue1, bool bSet); ++ ++ void (*UpdateRAMaskHandler)(struct adapter *padapter, u32 mac_id, u8 rssi_level); ++ void (*SetBeaconRelatedRegistersHandler)(struct adapter *padapter); ++ ++ void (*Add_RateATid)(struct adapter *padapter, u32 bitmap, u8 *arg, u8 rssi_level); ++ ++ void (*run_thread)(struct adapter *padapter); ++ void (*cancel_thread)(struct adapter *padapter); ++ ++ u8 (*interface_ps_func)(struct adapter *padapter, enum HAL_INTF_PS_FUNC efunc_id, u8 *val); ++ ++ s32 (*hal_xmit)(struct adapter *padapter, struct xmit_frame *pxmitframe); ++ /* ++ * mgnt_xmit should be implemented to run in interrupt context ++ */ ++ s32 (*mgnt_xmit)(struct adapter *padapter, struct xmit_frame *pmgntframe); ++ s32 (*hal_xmitframe_enqueue)(struct adapter *padapter, struct xmit_frame *pxmitframe); ++ ++ u32 (*read_bbreg)(struct adapter *padapter, u32 RegAddr, u32 BitMask); ++ void (*write_bbreg)(struct adapter *padapter, u32 RegAddr, u32 BitMask, u32 Data); ++ u32 (*read_rfreg)(struct adapter *padapter, u8 eRFPath, u32 RegAddr, u32 BitMask); ++ void (*write_rfreg)(struct adapter *padapter, u8 eRFPath, u32 RegAddr, u32 BitMask, u32 Data); ++ ++ void (*EfusePowerSwitch)(struct adapter *padapter, u8 bWrite, u8 PwrState); ++ void (*BTEfusePowerSwitch)(struct adapter *padapter, u8 bWrite, u8 PwrState); ++ void (*ReadEFuse)(struct adapter *padapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool bPseudoTest); ++ void (*EFUSEGetEfuseDefinition)(struct adapter *padapter, u8 efuseType, u8 type, void *pOut, bool bPseudoTest); ++ u16 (*EfuseGetCurrentSize)(struct adapter *padapter, u8 efuseType, bool bPseudoTest); ++ int (*Efuse_PgPacketRead)(struct adapter *padapter, u8 offset, u8 *data, bool bPseudoTest); ++ int (*Efuse_PgPacketWrite)(struct adapter *padapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest); ++ u8 (*Efuse_WordEnableDataWrite)(struct adapter *padapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest); ++ bool (*Efuse_PgPacketWrite_BT)(struct adapter *padapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest); ++ ++ s32 (*xmit_thread_handler)(struct adapter *padapter); ++ void (*hal_notch_filter)(struct adapter * adapter, bool enable); ++ void (*hal_reset_security_engine)(struct adapter * adapter); ++ s32 (*c2h_handler)(struct adapter *padapter, u8 *c2h_evt); ++ c2h_id_filter c2h_id_filter_ccx; ++ ++ s32 (*fill_h2c_cmd)(struct adapter *, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer); ++}; ++ ++enum RT_EEPROM_TYPE { ++ EEPROM_93C46, ++ EEPROM_93C56, ++ EEPROM_BOOT_EFUSE, ++}; ++ ++#define RF_CHANGE_BY_INIT 0 ++#define RF_CHANGE_BY_IPS BIT28 ++#define RF_CHANGE_BY_PS BIT29 ++#define RF_CHANGE_BY_HW BIT30 ++#define RF_CHANGE_BY_SW BIT31 ++ ++#define GET_EEPROM_EFUSE_PRIV(adapter) (&adapter->eeprompriv) ++#define is_boot_from_eeprom(adapter) (adapter->eeprompriv.EepromOrEfuse) ++ ++enum wowlan_subcode { ++ WOWLAN_PATTERN_MATCH = 1, ++ WOWLAN_MAGIC_PACKET = 2, ++ WOWLAN_UNICAST = 3, ++ WOWLAN_SET_PATTERN = 4, ++ WOWLAN_DUMP_REG = 5, ++ WOWLAN_ENABLE = 6, ++ WOWLAN_DISABLE = 7, ++ WOWLAN_STATUS = 8, ++ WOWLAN_DEBUG_RELOAD_FW = 9, ++ WOWLAN_DEBUG_1 = 10, ++ WOWLAN_DEBUG_2 = 11, ++ WOWLAN_AP_ENABLE = 12, ++ WOWLAN_AP_DISABLE = 13 ++}; ++ ++struct wowlan_ioctl_param{ ++ unsigned int subcode; ++ unsigned int subcode_value; ++ unsigned int wakeup_reason; ++ unsigned int len; ++ unsigned char pattern[0]; ++}; ++ ++#define Rx_Pairwisekey 0x01 ++#define Rx_GTK 0x02 ++#define Rx_DisAssoc 0x04 ++#define Rx_DeAuth 0x08 ++#define Rx_ARPReq 0x09 ++#define FWDecisionDisconnect 0x10 ++#define Rx_MagicPkt 0x21 ++#define Rx_UnicastPkt 0x22 ++#define Rx_PatternPkt 0x23 ++#define RX_PNOWakeUp 0x55 ++#define AP_WakeUp 0x66 ++ ++void rtw_hal_def_value_init(struct adapter *padapter); ++ ++void rtw_hal_free_data(struct adapter *padapter); ++ ++void rtw_hal_dm_init(struct adapter *padapter); ++void rtw_hal_dm_deinit(struct adapter *padapter); ++ ++uint rtw_hal_init(struct adapter *padapter); ++uint rtw_hal_deinit(struct adapter *padapter); ++void rtw_hal_stop(struct adapter *padapter); ++void rtw_hal_set_hwreg(struct adapter *padapter, u8 variable, u8 *val); ++void rtw_hal_get_hwreg(struct adapter *padapter, u8 variable, u8 *val); ++ ++void rtw_hal_set_hwreg_with_buf(struct adapter *padapter, u8 variable, u8 *pbuf, int len); ++ ++void rtw_hal_chip_configure(struct adapter *padapter); ++void rtw_hal_read_chip_info(struct adapter *padapter); ++void rtw_hal_read_chip_version(struct adapter *padapter); ++ ++u8 rtw_hal_set_def_var(struct adapter *padapter, enum HAL_DEF_VARIABLE eVariable, void *pValue); ++u8 rtw_hal_get_def_var(struct adapter *padapter, enum HAL_DEF_VARIABLE eVariable, void *pValue); ++ ++void rtw_hal_set_odm_var(struct adapter *padapter, enum HAL_ODM_VARIABLE eVariable, void *pValue1, bool bSet); ++void rtw_hal_get_odm_var(struct adapter *padapter, enum HAL_ODM_VARIABLE eVariable, void *pValue1, void *pValue2); ++ ++void rtw_hal_enable_interrupt(struct adapter *padapter); ++void rtw_hal_disable_interrupt(struct adapter *padapter); ++ ++u8 rtw_hal_check_ips_status(struct adapter *padapter); ++ ++s32 rtw_hal_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe); ++s32 rtw_hal_xmit(struct adapter *padapter, struct xmit_frame *pxmitframe); ++s32 rtw_hal_mgnt_xmit(struct adapter *padapter, struct xmit_frame *pmgntframe); ++ ++s32 rtw_hal_init_xmit_priv(struct adapter *padapter); ++void rtw_hal_free_xmit_priv(struct adapter *padapter); ++ ++s32 rtw_hal_init_recv_priv(struct adapter *padapter); ++void rtw_hal_free_recv_priv(struct adapter *padapter); ++ ++void rtw_hal_update_ra_mask(struct sta_info *psta, u8 rssi_level); ++void rtw_hal_add_ra_tid(struct adapter *padapter, u32 bitmap, u8 *arg, u8 rssi_level); ++ ++void rtw_hal_start_thread(struct adapter *padapter); ++void rtw_hal_stop_thread(struct adapter *padapter); ++ ++void rtw_hal_bcn_related_reg_setting(struct adapter *padapter); ++ ++u32 rtw_hal_read_bbreg(struct adapter *padapter, u32 RegAddr, u32 BitMask); ++void rtw_hal_write_bbreg(struct adapter *padapter, u32 RegAddr, u32 BitMask, u32 Data); ++u32 rtw_hal_read_rfreg(struct adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask); ++void rtw_hal_write_rfreg(struct adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask, u32 Data); ++ ++#define PHY_QueryBBReg(Adapter, RegAddr, BitMask) rtw_hal_read_bbreg((Adapter), (RegAddr), (BitMask)) ++#define PHY_SetBBReg(Adapter, RegAddr, BitMask, Data) rtw_hal_write_bbreg((Adapter), (RegAddr), (BitMask), (Data)) ++#define PHY_QueryRFReg(Adapter, eRFPath, RegAddr, BitMask) rtw_hal_read_rfreg((Adapter), (eRFPath), (RegAddr), (BitMask)) ++#define PHY_SetRFReg(Adapter, eRFPath, RegAddr, BitMask, Data) rtw_hal_write_rfreg((Adapter), (eRFPath), (RegAddr), (BitMask), (Data)) ++ ++#define PHY_SetMacReg PHY_SetBBReg ++#define PHY_QueryMacReg PHY_QueryBBReg ++ ++void rtw_hal_set_chan(struct adapter *padapter, u8 channel); ++void rtw_hal_set_chnl_bw(struct adapter *padapter, u8 channel, enum CHANNEL_WIDTH Bandwidth, u8 Offset40, u8 Offset80); ++void rtw_hal_dm_watchdog(struct adapter *padapter); ++void rtw_hal_dm_watchdog_in_lps(struct adapter *padapter); ++ ++s32 rtw_hal_xmit_thread_handler(struct adapter *padapter); ++ ++void rtw_hal_notch_filter(struct adapter * adapter, bool enable); ++void rtw_hal_reset_security_engine(struct adapter * adapter); ++ ++bool rtw_hal_c2h_valid(struct adapter *adapter, u8 *buf); ++s32 rtw_hal_c2h_evt_read(struct adapter *adapter, u8 *buf); ++s32 rtw_hal_c2h_handler(struct adapter *adapter, u8 *c2h_evt); ++c2h_id_filter rtw_hal_c2h_id_filter_ccx(struct adapter *adapter); ++ ++s32 rtw_hal_is_disable_sw_channel_plan(struct adapter *padapter); ++ ++s32 rtw_hal_macid_sleep(struct adapter *padapter, u32 macid); ++s32 rtw_hal_macid_wakeup(struct adapter *padapter, u32 macid); ++ ++s32 rtw_hal_fill_h2c_cmd(struct adapter *, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer); ++ ++#endif /* __HAL_INTF_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/hal_pg.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_pg.h +--- linux-4.3/3rdparty/rtl8723bs/include/hal_pg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_pg.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,81 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#ifndef __HAL_PG_H__ ++#define __HAL_PG_H__ ++ ++#define MAX_RF_PATH 4 ++/* MAX_TX_COUNT must always be set to 4, otherwise the read efuse table ++ * sequence will be wrong. ++ */ ++#define MAX_TX_COUNT 4 ++ ++/* For VHT series TX power by rate table. */ ++/* VHT TX power by rate off setArray = */ ++/* Band:-2G&5G = 0 / 1 */ ++/* RF: at most 4*4 = ABCD = 0/1/2/3 */ ++/* CCK = 0 OFDM = 1/2 HT-MCS 0-15 =3/4/56 VHT =7/8/9/10/11 */ ++#define TX_PWR_BY_RATE_NUM_BAND 2 ++#define TX_PWR_BY_RATE_NUM_RF 4 ++#define TX_PWR_BY_RATE_NUM_RATE 84 ++#define MAX_RF_PATH_NUM 2 ++#define MAX_CHNL_GROUP_24G 6 ++#define EEPROM_DEFAULT_BOARD_OPTION 0x00 ++ ++/* EEPROM/Efuse PG Offset for 8723BE/8723BU/8723BS */ ++/* 0x10 ~ 0x63 = TX power area. */ ++#define EEPROM_TX_PWR_INX_8723B 0x10 ++/* New EFUSE default value */ ++#define EEPROM_DEFAULT_24G_INDEX 0x2D ++#define EEPROM_DEFAULT_24G_HT20_DIFF 0X02 ++#define EEPROM_DEFAULT_24G_OFDM_DIFF 0X04 ++#define EEPROM_Default_ThermalMeter_8723B 0x18 ++#define EEPROM_Default_CrystalCap_8723B 0x20 ++ ++#define EEPROM_ChannelPlan_8723B 0xB8 ++#define EEPROM_XTAL_8723B 0xB9 ++#define EEPROM_THERMAL_METER_8723B 0xBA ++ ++#define EEPROM_RF_BOARD_OPTION_8723B 0xC1 ++#define EEPROM_RF_BT_SETTING_8723B 0xC3 ++#define EEPROM_VERSION_8723B 0xC4 ++#define EEPROM_CustomID_8723B 0xC5 ++#define EEPROM_DEFAULT_DIFF 0XFE ++ ++/* RTL8723BS */ ++#define EEPROM_MAC_ADDR_8723BS 0x11A ++#define EEPROM_Voltage_ADDR_8723B 0x8 ++#define RTL_EEPROM_ID 0x8129 ++ ++struct TxPowerInfo24G { ++ u8 IndexCCK_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G]; ++ u8 IndexBW40_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G]; ++ /* If only one tx, only BW20 and OFDM are used. */ ++ s8 CCK_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 OFDM_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 BW20_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++ s8 BW40_Diff[MAX_RF_PATH][MAX_TX_COUNT]; ++}; ++ ++enum { ++ Ant_x2 = 0, ++ Ant_x1 = 1 ++}; ++ ++enum { ++ BT_RTL8723B = 8, ++}; ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/hal_phy.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_phy.h +--- linux-4.3/3rdparty/rtl8723bs/include/hal_phy.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_phy.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,183 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __HAL_PHY_H__ ++#define __HAL_PHY_H__ ++ ++ ++#if DISABLE_BB_RF ++#define HAL_FW_ENABLE 0 ++#define HAL_MAC_ENABLE 0 ++#define HAL_BB_ENABLE 0 ++#define HAL_RF_ENABLE 0 ++#else /* FPGA_PHY and ASIC */ ++#define HAL_FW_ENABLE 1 ++#define HAL_MAC_ENABLE 1 ++#define HAL_BB_ENABLE 1 ++#define HAL_RF_ENABLE 1 ++#endif ++ ++#define RF6052_MAX_TX_PWR 0x3F ++#define RF6052_MAX_REG_88E 0xFF ++#define RF6052_MAX_REG_92C 0x7F ++ ++#define RF6052_MAX_REG \ ++ (RF6052_MAX_REG_88E > RF6052_MAX_REG_92C) ? RF6052_MAX_REG_88E: RF6052_MAX_REG_92C ++ ++#define GET_RF6052_REAL_MAX_REG(_Adapter) RF6052_MAX_REG_92C ++ ++#define RF6052_MAX_PATH 2 ++ ++/* */ ++/* Antenna detection method, i.e., using single tone detection or RSSI reported from each antenna detected. */ ++/* Added by Roger, 2013.05.22. */ ++/* */ ++#define ANT_DETECT_BY_SINGLE_TONE BIT0 ++#define ANT_DETECT_BY_RSSI BIT1 ++#define IS_ANT_DETECT_SUPPORT_SINGLE_TONE(__Adapter) ((GET_HAL_DATA(__Adapter)->AntDetection) & ANT_DETECT_BY_SINGLE_TONE) ++#define IS_ANT_DETECT_SUPPORT_RSSI(__Adapter) ((GET_HAL_DATA(__Adapter)->AntDetection) & ANT_DETECT_BY_RSSI) ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++enum BAND_TYPE { ++ BAND_ON_2_4G = 0, ++ BAND_ON_5G, ++ BAND_ON_BOTH, ++ BANDMAX ++}; ++ ++enum RF_TYPE { ++ RF_TYPE_MIN = 0, /* 0 */ ++ RF_8225 = 1, /* 1 11b/g RF for verification only */ ++ RF_8256 = 2, /* 2 11b/g/n */ ++ RF_8258 = 3, /* 3 11a/b/g/n RF */ ++ RF_6052 = 4, /* 4 11b/g/n RF */ ++ RF_PSEUDO_11N = 5, /* 5, It is a temporality RF. */ ++ RF_TYPE_MAX ++}; ++ ++enum RF_PATH { ++ RF_PATH_A = 0, ++ RF_PATH_B, ++ RF_PATH_C, ++ RF_PATH_D ++}; ++ ++#define TX_1S 0 ++#define TX_2S 1 ++#define TX_3S 2 ++#define TX_4S 3 ++ ++#define RF_PATH_MAX_92C_88E 2 ++#define RF_PATH_MAX_90_8812 4 /* Max RF number 90 support */ ++ ++enum ANTENNA_PATH { ++ ANTENNA_NONE = 0, ++ ANTENNA_D = 1, ++ ANTENNA_C = 2, ++ ANTENNA_CD = 3, ++ ANTENNA_B = 4, ++ ANTENNA_BD = 5, ++ ANTENNA_BC = 6, ++ ANTENNA_BCD = 7, ++ ANTENNA_A = 8, ++ ANTENNA_AD = 9, ++ ANTENNA_AC = 10, ++ ANTENNA_ACD = 11, ++ ANTENNA_AB = 12, ++ ANTENNA_ABD = 13, ++ ANTENNA_ABC = 14, ++ ANTENNA_ABCD = 15 ++}; ++ ++enum RF_CONTENT { ++ radioa_txt = 0x1000, ++ radiob_txt = 0x1001, ++ radioc_txt = 0x1002, ++ radiod_txt = 0x1003 ++}; ++ ++enum BaseBand_Config_Type { ++ BaseBand_Config_PHY_REG = 0, /* Radio Path A */ ++ BaseBand_Config_AGC_TAB = 1, /* Radio Path B */ ++ BaseBand_Config_AGC_TAB_2G = 2, ++ BaseBand_Config_AGC_TAB_5G = 3, ++ BaseBand_Config_PHY_REG_PG ++}; ++ ++enum HW_BLOCK { ++ HW_BLOCK_MAC = 0, ++ HW_BLOCK_PHY0 = 1, ++ HW_BLOCK_PHY1 = 2, ++ HW_BLOCK_RF = 3, ++ HW_BLOCK_MAXIMUM = 4, /* Never use this */ ++}; ++ ++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_N_24G = 0x10, ++ WIRELESS_MODE_N_5G = 0x20, ++ WIRELESS_MODE_AC_5G = 0x40, ++ WIRELESS_MODE_AC_24G = 0x80, ++ WIRELESS_MODE_AC_ONLY = 0x100, ++}; ++ ++enum SwChnlCmdID { ++ CmdID_End, ++ CmdID_SetTxPowerLevel, ++ CmdID_BBRegWrite10, ++ CmdID_WritePortUlong, ++ CmdID_WritePortUshort, ++ CmdID_WritePortUchar, ++ CmdID_RF_WriteReg, ++}; ++ ++struct SwChnlCmd { ++ enum SwChnlCmdID CmdID; ++ u32 Para1; ++ u32 Para2; ++ u32 msDelay; ++}; ++ ++struct R_ANTENNA_SELECT_OFDM { ++#ifdef __LITTLE_ENDIAN ++ u32 r_tx_antenna:4; ++ u32 r_ant_l:4; ++ u32 r_ant_non_ht:4; ++ u32 r_ant_ht1:4; ++ u32 r_ant_ht2:4; ++ u32 r_ant_ht_s1:4; ++ u32 r_ant_non_ht_s1:4; ++ u32 OFDM_TXSC:2; ++ u32 Reserved:2; ++#else ++ u32 Reserved:2; ++ u32 OFDM_TXSC:2; ++ u32 r_ant_non_ht_s1:4; ++ u32 r_ant_ht_s1:4; ++ u32 r_ant_ht2:4; ++ u32 r_ant_ht1:4; ++ u32 r_ant_non_ht:4; ++ u32 r_ant_l:4; ++ u32 r_tx_antenna:4; ++#endif ++}; ++ ++/*--------------------------Exported Function prototype---------------------*/ ++ ++#endif /* __HAL_COMMON_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/hal_phy_reg.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_phy_reg.h +--- linux-4.3/3rdparty/rtl8723bs/include/hal_phy_reg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_phy_reg.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,25 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __HAL_PHY_REG_H__ ++#define __HAL_PHY_REG_H__ ++ ++/* for PutRFRegsetting & GetRFRegSetting BitMask */ ++/* if (RTL92SE_FPGA_VERIFY == 1) */ ++/* define bRFRegOffsetMask 0xfff */ ++/* else */ ++#define bRFRegOffsetMask 0xfffff ++/* endif */ ++ ++#endif /* __HAL_PHY_REG_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/HalPwrSeqCmd.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/HalPwrSeqCmd.h +--- linux-4.3/3rdparty/rtl8723bs/include/HalPwrSeqCmd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/HalPwrSeqCmd.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,132 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __HALPWRSEQCMD_H__ ++#define __HALPWRSEQCMD_H__ ++ ++#include ++ ++/*---------------------------------------------*/ ++/* 3 The value of cmd: 4 bits */ ++/*---------------------------------------------*/ ++#define PWR_CMD_READ 0x00 ++ /* offset: the read register offset */ ++ /* msk: the mask of the read value */ ++ /* value: N/A, left by 0 */ ++ /* note: dirver shall implement this function by read & msk */ ++ ++#define PWR_CMD_WRITE 0x01 ++ /* offset: the read register offset */ ++ /* msk: the mask of the write bits */ ++ /* value: write value */ ++ /* note: driver shall implement this cmd by read & msk after write */ ++ ++#define PWR_CMD_POLLING 0x02 ++ /* offset: the read register offset */ ++ /* msk: the mask of the polled value */ ++ /* value: the value to be polled, masked by the msd field. */ ++ /* note: driver shall implement this cmd by */ ++ /* do{ */ ++ /* if ((Read(offset) & msk) == (value & msk)) */ ++ /* break; */ ++ /* } while (not timeout); */ ++ ++#define PWR_CMD_DELAY 0x03 ++ /* offset: the value to delay */ ++ /* msk: N/A */ ++ /* value: the unit of delay, 0: us, 1: ms */ ++ ++#define PWR_CMD_END 0x04 ++ /* offset: N/A */ ++ /* msk: N/A */ ++ /* value: N/A */ ++ ++/*---------------------------------------------*/ ++/* 3 The value of base: 4 bits */ ++/*---------------------------------------------*/ ++ /* define the base address of each block */ ++#define PWR_BASEADDR_MAC 0x00 ++#define PWR_BASEADDR_USB 0x01 ++#define PWR_BASEADDR_PCIE 0x02 ++#define PWR_BASEADDR_SDIO 0x03 ++ ++/*---------------------------------------------*/ ++/* 3 The value of interface_msk: 4 bits */ ++/*---------------------------------------------*/ ++#define PWR_INTF_SDIO_MSK BIT(0) ++#define PWR_INTF_USB_MSK BIT(1) ++#define PWR_INTF_PCI_MSK BIT(2) ++#define PWR_INTF_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3)) ++ ++/*---------------------------------------------*/ ++/* 3 The value of fab_msk: 4 bits */ ++/*---------------------------------------------*/ ++#define PWR_FAB_TSMC_MSK BIT(0) ++#define PWR_FAB_UMC_MSK BIT(1) ++#define PWR_FAB_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3)) ++ ++/*---------------------------------------------*/ ++/* 3 The value of cut_msk: 8 bits */ ++/*---------------------------------------------*/ ++#define PWR_CUT_TESTCHIP_MSK BIT(0) ++#define PWR_CUT_A_MSK BIT(1) ++#define PWR_CUT_B_MSK BIT(2) ++#define PWR_CUT_C_MSK BIT(3) ++#define PWR_CUT_D_MSK BIT(4) ++#define PWR_CUT_E_MSK BIT(5) ++#define PWR_CUT_F_MSK BIT(6) ++#define PWR_CUT_G_MSK BIT(7) ++#define PWR_CUT_ALL_MSK 0xFF ++ ++ ++typedef enum _PWRSEQ_CMD_DELAY_UNIT_ ++{ ++ PWRSEQ_DELAY_US, ++ PWRSEQ_DELAY_MS, ++} PWRSEQ_DELAY_UNIT; ++ ++typedef struct _WL_PWR_CFG_ ++{ ++ u16 offset; ++ u8 cut_msk; ++ u8 fab_msk:4; ++ u8 interface_msk:4; ++ u8 base:4; ++ u8 cmd:4; ++ u8 msk; ++ u8 value; ++} WLAN_PWR_CFG, *PWLAN_PWR_CFG; ++ ++ ++#define GET_PWR_CFG_OFFSET(__PWR_CMD) __PWR_CMD.offset ++#define GET_PWR_CFG_CUT_MASK(__PWR_CMD) __PWR_CMD.cut_msk ++#define GET_PWR_CFG_FAB_MASK(__PWR_CMD) __PWR_CMD.fab_msk ++#define GET_PWR_CFG_INTF_MASK(__PWR_CMD) __PWR_CMD.interface_msk ++#define GET_PWR_CFG_BASE(__PWR_CMD) __PWR_CMD.base ++#define GET_PWR_CFG_CMD(__PWR_CMD) __PWR_CMD.cmd ++#define GET_PWR_CFG_MASK(__PWR_CMD) __PWR_CMD.msk ++#define GET_PWR_CFG_VALUE(__PWR_CMD) __PWR_CMD.value ++ ++ ++/* */ ++/* Prototype of protected function. */ ++/* */ ++u8 HalPwrSeqCmdParsing( ++ struct adapter * padapter, ++ u8 CutVersion, ++ u8 FabVersion, ++ u8 InterfaceType, ++ WLAN_PWR_CFG PwrCfgCmd[]); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/hal_sdio.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_sdio.h +--- linux-4.3/3rdparty/rtl8723bs/include/hal_sdio.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/hal_sdio.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,26 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __HAL_SDIO_H_ ++#define __HAL_SDIO_H_ ++ ++#define ffaddr2deviceId(pdvobj, addr) (pdvobj->Queue2Pipe[addr]) ++ ++u8 rtw_hal_sdio_max_txoqt_free_space(struct adapter *padapter); ++u8 rtw_hal_sdio_query_tx_freepage(struct adapter *padapter, u8 PageIdx, u8 RequiredPageNum); ++void rtw_hal_sdio_update_tx_freepage(struct adapter *padapter, u8 PageIdx, u8 RequiredPageNum); ++void rtw_hal_set_sdio_tx_max_length(struct adapter *padapter, u8 numHQ, u8 numNQ, u8 numLQ, u8 numPubQ); ++u32 rtw_hal_get_sdio_tx_max_length(struct adapter *padapter, u8 queue_idx); ++ ++#endif /* __RTW_LED_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/HalVerDef.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/HalVerDef.h +--- linux-4.3/3rdparty/rtl8723bs/include/HalVerDef.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/HalVerDef.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,127 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __HAL_VERSION_DEF_H__ ++#define __HAL_VERSION_DEF_H__ ++ ++/* HAL_IC_TYPE_E */ ++typedef enum tag_HAL_IC_Type_Definition ++{ ++ CHIP_8192S = 0, ++ CHIP_8188C = 1, ++ CHIP_8192C = 2, ++ CHIP_8192D = 3, ++ CHIP_8723A = 4, ++ CHIP_8188E = 5, ++ CHIP_8812 = 6, ++ CHIP_8821 = 7, ++ CHIP_8723B = 8, ++ CHIP_8192E = 9, ++}HAL_IC_TYPE_E; ++ ++/* HAL_CHIP_TYPE_E */ ++typedef enum tag_HAL_CHIP_Type_Definition ++{ ++ TEST_CHIP = 0, ++ NORMAL_CHIP = 1, ++ FPGA = 2, ++}HAL_CHIP_TYPE_E; ++ ++/* HAL_CUT_VERSION_E */ ++typedef enum tag_HAL_Cut_Version_Definition ++{ ++ A_CUT_VERSION = 0, ++ B_CUT_VERSION = 1, ++ C_CUT_VERSION = 2, ++ D_CUT_VERSION = 3, ++ E_CUT_VERSION = 4, ++ F_CUT_VERSION = 5, ++ G_CUT_VERSION = 6, ++ H_CUT_VERSION = 7, ++ I_CUT_VERSION = 8, ++ J_CUT_VERSION = 9, ++ K_CUT_VERSION = 10, ++}HAL_CUT_VERSION_E; ++ ++/* HAL_Manufacturer */ ++typedef enum tag_HAL_Manufacturer_Version_Definition ++{ ++ CHIP_VENDOR_TSMC = 0, ++ CHIP_VENDOR_UMC = 1, ++ CHIP_VENDOR_SMIC = 2, ++}HAL_VENDOR_E; ++ ++typedef enum tag_HAL_RF_Type_Definition ++{ ++ RF_TYPE_1T1R = 0, ++ RF_TYPE_1T2R = 1, ++ RF_TYPE_2T2R = 2, ++ RF_TYPE_2T3R = 3, ++ RF_TYPE_2T4R = 4, ++ RF_TYPE_3T3R = 5, ++ RF_TYPE_3T4R = 6, ++ RF_TYPE_4T4R = 7, ++}HAL_RF_TYPE_E; ++ ++typedef struct tag_HAL_VERSION ++{ ++ HAL_IC_TYPE_E ICType; ++ HAL_CHIP_TYPE_E ChipType; ++ HAL_CUT_VERSION_E CUTVersion; ++ HAL_VENDOR_E VendorType; ++ HAL_RF_TYPE_E RFType; ++ u8 ROMVer; ++}HAL_VERSION,*PHAL_VERSION; ++ ++/* VERSION_8192C VersionID; */ ++/* HAL_VERSION VersionID; */ ++ ++/* Get element */ ++#define GET_CVID_IC_TYPE(version) ((HAL_IC_TYPE_E)((version).ICType) ) ++#define GET_CVID_CHIP_TYPE(version) ((HAL_CHIP_TYPE_E)((version).ChipType) ) ++#define GET_CVID_RF_TYPE(version) ((HAL_RF_TYPE_E)((version).RFType)) ++#define GET_CVID_MANUFACTUER(version) ((HAL_VENDOR_E)((version).VendorType)) ++#define GET_CVID_CUT_VERSION(version) ((HAL_CUT_VERSION_E)((version).CUTVersion)) ++#define GET_CVID_ROM_VERSION(version) (((version).ROMVer) & ROM_VERSION_MASK) ++ ++/* */ ++/* Common Macro. -- */ ++/* */ ++/* HAL_VERSION VersionID */ ++ ++/* HAL_CHIP_TYPE_E */ ++#define IS_TEST_CHIP(version) ((GET_CVID_CHIP_TYPE(version) ==TEST_CHIP)? true: false) ++#define IS_NORMAL_CHIP(version) ((GET_CVID_CHIP_TYPE(version) ==NORMAL_CHIP)? true: false) ++ ++/* HAL_CUT_VERSION_E */ ++#define IS_A_CUT(version) ((GET_CVID_CUT_VERSION(version) == A_CUT_VERSION) ? true : false) ++#define IS_B_CUT(version) ((GET_CVID_CUT_VERSION(version) == B_CUT_VERSION) ? true : false) ++#define IS_C_CUT(version) ((GET_CVID_CUT_VERSION(version) == C_CUT_VERSION) ? true : false) ++#define IS_D_CUT(version) ((GET_CVID_CUT_VERSION(version) == D_CUT_VERSION) ? true : false) ++#define IS_E_CUT(version) ((GET_CVID_CUT_VERSION(version) == E_CUT_VERSION) ? true : false) ++#define IS_I_CUT(version) ((GET_CVID_CUT_VERSION(version) == I_CUT_VERSION) ? true : false) ++#define IS_J_CUT(version) ((GET_CVID_CUT_VERSION(version) == J_CUT_VERSION) ? true : false) ++#define IS_K_CUT(version) ((GET_CVID_CUT_VERSION(version) == K_CUT_VERSION) ? true : false) ++ ++/* HAL_VENDOR_E */ ++#define IS_CHIP_VENDOR_TSMC(version) ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_TSMC)? true: false) ++#define IS_CHIP_VENDOR_UMC(version) ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_UMC)? true: false) ++#define IS_CHIP_VENDOR_SMIC(version) ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_SMIC)? true: false) ++ ++/* HAL_RF_TYPE_E */ ++#define IS_1T1R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T1R)? true : false) ++#define IS_1T2R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R)? true : false) ++#define IS_2T2R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R)? true : false) ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/ieee80211.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/ieee80211.h +--- linux-4.3/3rdparty/rtl8723bs/include/ieee80211.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/ieee80211.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,1345 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __IEEE80211_H ++#define __IEEE80211_H ++ ++#include ++ ++#define MGMT_QUEUE_NUM 5 ++ ++#define ETH_ALEN 6 ++#define ETH_TYPE_LEN 2 ++#define PAYLOAD_TYPE_LEN 1 ++ ++#define RTL_IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 28) ++ ++/* RTL871X_IOCTL_HOSTAPD ioctl() cmd: */ ++enum { ++ RTL871X_HOSTAPD_FLUSH = 1, ++ RTL871X_HOSTAPD_ADD_STA = 2, ++ RTL871X_HOSTAPD_REMOVE_STA = 3, ++ RTL871X_HOSTAPD_GET_INFO_STA = 4, ++ /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */ ++ RTL871X_HOSTAPD_GET_WPAIE_STA = 5, ++ RTL871X_SET_ENCRYPTION = 6, ++ RTL871X_GET_ENCRYPTION = 7, ++ RTL871X_HOSTAPD_SET_FLAGS_STA = 8, ++ RTL871X_HOSTAPD_GET_RID = 9, ++ RTL871X_HOSTAPD_SET_RID = 10, ++ RTL871X_HOSTAPD_SET_ASSOC_AP_ADDR = 11, ++ RTL871X_HOSTAPD_SET_GENERIC_ELEMENT = 12, ++ RTL871X_HOSTAPD_MLME = 13, ++ RTL871X_HOSTAPD_SCAN_REQ = 14, ++ RTL871X_HOSTAPD_STA_CLEAR_STATS = 15, ++ RTL871X_HOSTAPD_SET_BEACON = 16, ++ RTL871X_HOSTAPD_SET_WPS_BEACON = 17, ++ RTL871X_HOSTAPD_SET_WPS_PROBE_RESP = 18, ++ RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP = 19, ++ RTL871X_HOSTAPD_SET_HIDDEN_SSID = 20, ++ RTL871X_HOSTAPD_SET_MACADDR_ACL = 21, ++ RTL871X_HOSTAPD_ACL_ADD_STA = 22, ++ RTL871X_HOSTAPD_ACL_REMOVE_STA = 23, ++}; ++ ++/* STA flags */ ++#define WLAN_STA_AUTH BIT(0) ++#define WLAN_STA_ASSOC BIT(1) ++#define WLAN_STA_PS BIT(2) ++#define WLAN_STA_TIM BIT(3) ++#define WLAN_STA_PERM BIT(4) ++#define WLAN_STA_AUTHORIZED BIT(5) ++#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ ++#define WLAN_STA_SHORT_PREAMBLE BIT(7) ++#define WLAN_STA_PREAUTH BIT(8) ++#define WLAN_STA_WME BIT(9) ++#define WLAN_STA_MFP BIT(10) ++#define WLAN_STA_HT BIT(11) ++#define WLAN_STA_WPS BIT(12) ++#define WLAN_STA_MAYBE_WPS BIT(13) ++#define WLAN_STA_VHT BIT(14) ++#define WLAN_STA_NONERP BIT(31) ++ ++#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 ++#define IEEE_PARAM_WPAX_SELECT 7 ++ ++#define AUTH_ALG_OPEN_SYSTEM 0x1 ++#define AUTH_ALG_SHARED_KEY 0x2 ++#define AUTH_ALG_LEAP 0x00000004 ++ ++#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 ++ ++#define WPA_CIPHER_NONE BIT(0) ++#define WPA_CIPHER_WEP40 BIT(1) ++#define WPA_CIPHER_WEP104 BIT(2) ++#define WPA_CIPHER_TKIP BIT(3) ++#define WPA_CIPHER_CCMP BIT(4) ++ ++ ++ ++#define WPA_SELECTOR_LEN 4 ++extern u8 RTW_WPA_OUI_TYPE[] ; ++extern u16 RTW_WPA_VERSION ; ++extern u8 WPA_AUTH_KEY_MGMT_NONE[]; ++extern u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[]; ++extern u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[]; ++extern u8 WPA_CIPHER_SUITE_NONE[]; ++extern u8 WPA_CIPHER_SUITE_WEP40[]; ++extern u8 WPA_CIPHER_SUITE_TKIP[]; ++extern u8 WPA_CIPHER_SUITE_WRAP[]; ++extern u8 WPA_CIPHER_SUITE_CCMP[]; ++extern u8 WPA_CIPHER_SUITE_WEP104[]; ++ ++ ++#define RSN_HEADER_LEN 4 ++#define RSN_SELECTOR_LEN 4 ++ ++extern u16 RSN_VERSION_BSD; ++extern u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[]; ++extern u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[]; ++extern u8 RSN_CIPHER_SUITE_NONE[]; ++extern u8 RSN_CIPHER_SUITE_WEP40[]; ++extern u8 RSN_CIPHER_SUITE_TKIP[]; ++extern u8 RSN_CIPHER_SUITE_WRAP[]; ++extern u8 RSN_CIPHER_SUITE_CCMP[]; ++extern u8 RSN_CIPHER_SUITE_WEP104[]; ++ ++ ++typedef enum _RATEID_IDX_ { ++ RATEID_IDX_BGN_40M_2SS = 0, ++ RATEID_IDX_BGN_40M_1SS = 1, ++ RATEID_IDX_BGN_20M_2SS_BN = 2, ++ RATEID_IDX_BGN_20M_1SS_BN = 3, ++ RATEID_IDX_GN_N2SS = 4, ++ RATEID_IDX_GN_N1SS = 5, ++ RATEID_IDX_BG = 6, ++ RATEID_IDX_G = 7, ++ RATEID_IDX_B = 8, ++ RATEID_IDX_VHT_2SS = 9, ++ RATEID_IDX_VHT_1SS = 10, ++} RATEID_IDX, *PRATEID_IDX; ++ ++typedef enum _RATR_TABLE_MODE{ ++ RATR_INX_WIRELESS_NGB = 0, /* BGN 40 Mhz 2SS 1SS */ ++ RATR_INX_WIRELESS_NG = 1, /* GN or N */ ++ RATR_INX_WIRELESS_NB = 2, /* BGN 20 Mhz 2SS 1SS or BN */ ++ RATR_INX_WIRELESS_N = 3, ++ RATR_INX_WIRELESS_GB = 4, ++ RATR_INX_WIRELESS_G = 5, ++ RATR_INX_WIRELESS_B = 6, ++ RATR_INX_WIRELESS_MC = 7, ++ RATR_INX_WIRELESS_AC_N = 8, ++}RATR_TABLE_MODE, *PRATR_TABLE_MODE; ++ ++ ++enum NETWORK_TYPE ++{ ++ WIRELESS_INVALID = 0, ++ /* Sub-Element */ ++ WIRELESS_11B = BIT(0), /* tx: cck only , rx: cck only, hw: cck */ ++ WIRELESS_11G = BIT(1), /* tx: ofdm only, rx: ofdm & cck, hw: cck & ofdm */ ++ WIRELESS_11A = BIT(2), /* tx: ofdm only, rx: ofdm only, hw: ofdm only */ ++ WIRELESS_11_24N = BIT(3), /* tx: MCS only, rx: MCS & cck, hw: MCS & cck */ ++ WIRELESS_11_5N = BIT(4), /* tx: MCS only, rx: MCS & ofdm, hw: ofdm only */ ++ WIRELESS_AUTO = BIT(5), ++ WIRELESS_11AC = BIT(6), ++ ++ /* Combination */ ++ /* Type for current wireless mode */ ++ WIRELESS_11BG = (WIRELESS_11B|WIRELESS_11G), /* tx: cck & ofdm, rx: cck & ofdm & MCS, hw: cck & ofdm */ ++ WIRELESS_11G_24N = (WIRELESS_11G|WIRELESS_11_24N), /* tx: ofdm & MCS, rx: ofdm & cck & MCS, hw: cck & ofdm */ ++ WIRELESS_11A_5N = (WIRELESS_11A|WIRELESS_11_5N), /* tx: ofdm & MCS, rx: ofdm & MCS, hw: ofdm only */ ++ WIRELESS_11B_24N = (WIRELESS_11B|WIRELESS_11_24N), /* tx: ofdm & cck & MCS, rx: ofdm & cck & MCS, hw: ofdm & cck */ ++ WIRELESS_11BG_24N = (WIRELESS_11B|WIRELESS_11G|WIRELESS_11_24N), /* tx: ofdm & cck & MCS, rx: ofdm & cck & MCS, hw: ofdm & cck */ ++ WIRELESS_11_24AC = (WIRELESS_11G|WIRELESS_11AC), ++ WIRELESS_11_5AC = (WIRELESS_11A|WIRELESS_11AC), ++ ++ ++ /* Type for registry default wireless mode */ ++ WIRELESS_11AGN = (WIRELESS_11A|WIRELESS_11G|WIRELESS_11_24N|WIRELESS_11_5N), /* tx: ofdm & MCS, rx: ofdm & MCS, hw: ofdm only */ ++ WIRELESS_11ABGN = (WIRELESS_11A|WIRELESS_11B|WIRELESS_11G|WIRELESS_11_24N|WIRELESS_11_5N), ++ WIRELESS_MODE_24G = (WIRELESS_11B|WIRELESS_11G|WIRELESS_11_24N|WIRELESS_11AC), ++ WIRELESS_MODE_MAX = (WIRELESS_11A|WIRELESS_11B|WIRELESS_11G|WIRELESS_11_24N|WIRELESS_11_5N|WIRELESS_11AC), ++}; ++ ++#define SUPPORTED_24G_NETTYPE_MSK (WIRELESS_11B | WIRELESS_11G | WIRELESS_11_24N) ++ ++#define IsLegacyOnly(NetType) ((NetType) == ((NetType) & (WIRELESS_11BG|WIRELESS_11A))) ++ ++#define IsSupported24G(NetType) ((NetType) & SUPPORTED_24G_NETTYPE_MSK ? true : false) ++ ++#define IsEnableHWCCK(NetType) IsSupported24G(NetType) ++#define IsEnableHWOFDM(NetType) (((NetType) & (WIRELESS_11G|WIRELESS_11_24N)) ? true : false) ++ ++#define IsSupportedRxCCK(NetType) IsEnableHWCCK(NetType) ++#define IsSupportedRxOFDM(NetType) IsEnableHWOFDM(NetType) ++#define IsSupportedRxHT(NetType) IsEnableHWOFDM(NetType) ++ ++#define IsSupportedTxCCK(NetType) (((NetType) & (WIRELESS_11B)) ? true : false) ++#define IsSupportedTxOFDM(NetType) (((NetType) & (WIRELESS_11G|WIRELESS_11A)) ? true : false) ++#define IsSupportedHT(NetType) (((NetType) & (WIRELESS_11_24N|WIRELESS_11_5N)) ? true : false) ++ ++#define IsSupportedVHT(NetType) (((NetType) & (WIRELESS_11AC)) ? true : false) ++ ++ ++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; ++ struct { ++ u16 aid; ++ u16 capability; ++ int flags; ++ u8 tx_supp_rates[16]; ++ struct rtw_ieee80211_ht_cap ht_cap; ++ } add_sta; ++ struct { ++ u8 reserved[2];/* for set max_num_sta */ ++ u8 buf[0]; ++ } bcn_ie; ++ } u; ++}ieee_param; ++ ++typedef struct ieee_param_ex { ++ u32 cmd; ++ u8 sta_addr[ETH_ALEN]; ++ u8 data[0]; ++}ieee_param_ex; ++ ++struct sta_data{ ++ u16 aid; ++ u16 capability; ++ int flags; ++ u32 sta_set; ++ u8 tx_supp_rates[16]; ++ u32 tx_supp_rates_len; ++ struct rtw_ieee80211_ht_cap ht_cap; ++ u64 rx_pkts; ++ u64 rx_bytes; ++ u64 rx_drops; ++ u64 tx_pkts; ++ u64 tx_bytes; ++ u64 tx_drops; ++}; ++ ++#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 from ipw2200 driver */ ++#define IEEE_IBSS_MAC_HASH_SIZE 31 ++ ++struct ieee_ibss_seq { ++ u8 mac[ETH_ALEN]; ++ u16 seq_num; ++ u16 frag_num; ++ unsigned long packet_time; ++ struct list_head list; ++}; ++ ++struct eapol { ++ u8 snap[6]; ++ u16 ethertype; ++ u8 version; ++ u8 type; ++ u16 length; ++} __attribute__ ((packed)); ++ ++enum eap_type { ++ EAP_PACKET = 0, ++ EAPOL_START, ++ EAPOL_LOGOFF, ++ EAPOL_KEY, ++ EAPOL_ENCAP_ASF_ALERT ++}; ++ ++#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 RTW_IEEE80211_FCTL_VERS 0x0003 ++#define RTW_IEEE80211_FCTL_FTYPE 0x000c ++#define RTW_IEEE80211_FCTL_STYPE 0x00f0 ++#define RTW_IEEE80211_FCTL_TODS 0x0100 ++#define RTW_IEEE80211_FCTL_FROMDS 0x0200 ++#define RTW_IEEE80211_FCTL_MOREFRAGS 0x0400 ++#define RTW_IEEE80211_FCTL_RETRY 0x0800 ++#define RTW_IEEE80211_FCTL_PM 0x1000 ++#define RTW_IEEE80211_FCTL_MOREDATA 0x2000 ++#define RTW_IEEE80211_FCTL_PROTECTED 0x4000 ++#define RTW_IEEE80211_FCTL_ORDER 0x8000 ++#define RTW_IEEE80211_FCTL_CTL_EXT 0x0f00 ++ ++#define RTW_IEEE80211_FTYPE_MGMT 0x0000 ++#define RTW_IEEE80211_FTYPE_CTL 0x0004 ++#define RTW_IEEE80211_FTYPE_DATA 0x0008 ++#define RTW_IEEE80211_FTYPE_EXT 0x000c ++ ++/* management */ ++#define RTW_IEEE80211_STYPE_ASSOC_REQ 0x0000 ++#define RTW_IEEE80211_STYPE_ASSOC_RESP 0x0010 ++#define RTW_IEEE80211_STYPE_REASSOC_REQ 0x0020 ++#define RTW_IEEE80211_STYPE_REASSOC_RESP 0x0030 ++#define RTW_IEEE80211_STYPE_PROBE_REQ 0x0040 ++#define RTW_IEEE80211_STYPE_PROBE_RESP 0x0050 ++#define RTW_IEEE80211_STYPE_BEACON 0x0080 ++#define RTW_IEEE80211_STYPE_ATIM 0x0090 ++#define RTW_IEEE80211_STYPE_DISASSOC 0x00A0 ++#define RTW_IEEE80211_STYPE_AUTH 0x00B0 ++#define RTW_IEEE80211_STYPE_DEAUTH 0x00C0 ++#define RTW_IEEE80211_STYPE_ACTION 0x00D0 ++ ++/* control */ ++#define RTW_IEEE80211_STYPE_CTL_EXT 0x0060 ++#define RTW_IEEE80211_STYPE_BACK_REQ 0x0080 ++#define RTW_IEEE80211_STYPE_BACK 0x0090 ++#define RTW_IEEE80211_STYPE_PSPOLL 0x00A0 ++#define RTW_IEEE80211_STYPE_RTS 0x00B0 ++#define RTW_IEEE80211_STYPE_CTS 0x00C0 ++#define RTW_IEEE80211_STYPE_ACK 0x00D0 ++#define RTW_IEEE80211_STYPE_CFEND 0x00E0 ++#define RTW_IEEE80211_STYPE_CFENDACK 0x00F0 ++ ++/* data */ ++#define RTW_IEEE80211_STYPE_DATA 0x0000 ++#define RTW_IEEE80211_STYPE_DATA_CFACK 0x0010 ++#define RTW_IEEE80211_STYPE_DATA_CFPOLL 0x0020 ++#define RTW_IEEE80211_STYPE_DATA_CFACKPOLL 0x0030 ++#define RTW_IEEE80211_STYPE_NULLFUNC 0x0040 ++#define RTW_IEEE80211_STYPE_CFACK 0x0050 ++#define RTW_IEEE80211_STYPE_CFPOLL 0x0060 ++#define RTW_IEEE80211_STYPE_CFACKPOLL 0x0070 ++#define RTW_IEEE80211_STYPE_QOS_DATA 0x0080 ++#define RTW_IEEE80211_STYPE_QOS_DATA_CFACK 0x0090 ++#define RTW_IEEE80211_STYPE_QOS_DATA_CFPOLL 0x00A0 ++#define RTW_IEEE80211_STYPE_QOS_DATA_CFACKPOLL 0x00B0 ++#define RTW_IEEE80211_STYPE_QOS_NULLFUNC 0x00C0 ++#define RTW_IEEE80211_STYPE_QOS_CFACK 0x00D0 ++#define RTW_IEEE80211_STYPE_QOS_CFPOLL 0x00E0 ++#define RTW_IEEE80211_STYPE_QOS_CFACKPOLL 0x00F0 ++ ++/* sequence control field */ ++#define RTW_IEEE80211_SCTL_FRAG 0x000F ++#define RTW_IEEE80211_SCTL_SEQ 0xFFF0 ++ ++ ++#define RTW_ERP_INFO_NON_ERP_PRESENT BIT(0) ++#define RTW_ERP_INFO_USE_PROTECTION BIT(1) ++#define RTW_ERP_INFO_BARKER_PREAMBLE_MODE BIT(2) ++ ++/* QoS, QOS */ ++#define NORMAL_ACK 0 ++#define NO_ACK 1 ++#define NON_EXPLICIT_ACK 2 ++#define BLOCK_ACK 3 ++ ++#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 */ ++ ++#define ETH_P_ECONET 0x0018 ++ ++#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) & RTW_IEEE80211_FCTL_FTYPE) ++#define WLAN_FC_GET_STYPE(fc) ((fc) & RTW_IEEE80211_FCTL_STYPE) ++ ++#define WLAN_QC_GET_TID(qc) ((qc) & 0x0f) ++ ++#define WLAN_GET_SEQ_FRAG(seq) ((seq) & RTW_IEEE80211_SCTL_FRAG) ++#define WLAN_GET_SEQ_SEQ(seq) ((seq) & RTW_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 ++#define WLAN_REASON_ACTIVE_ROAM 65533 ++#define WLAN_REASON_JOIN_WRONG_CHANNEL 65534 ++#define WLAN_REASON_EXPIRATION_CHK 65535 ++ ++/* 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 ++/* EIDs defined by IEEE 802.11h - START */ ++#define WLAN_EID_PWR_CONSTRAINT 32 ++#define WLAN_EID_PWR_CAPABILITY 33 ++#define WLAN_EID_TPC_REQUEST 34 ++#define WLAN_EID_TPC_REPORT 35 ++#define WLAN_EID_SUPPORTED_CHANNELS 36 ++#define WLAN_EID_CHANNEL_SWITCH 37 ++#define WLAN_EID_MEASURE_REQUEST 38 ++#define WLAN_EID_MEASURE_REPORT 39 ++#define WLAN_EID_QUITE 40 ++#define WLAN_EID_IBSS_DFS 41 ++/* EIDs defined by IEEE 802.11h - END */ ++#define WLAN_EID_ERP_INFO 42 ++#define WLAN_EID_HT_CAP 45 ++#define WLAN_EID_RSN 48 ++#define WLAN_EID_EXT_SUPP_RATES 50 ++#define WLAN_EID_MOBILITY_DOMAIN 54 ++#define WLAN_EID_FAST_BSS_TRANSITION 55 ++#define WLAN_EID_TIMEOUT_INTERVAL 56 ++#define WLAN_EID_RIC_DATA 57 ++#define WLAN_EID_HT_OPERATION 61 ++#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62 ++#define WLAN_EID_20_40_BSS_COEXISTENCE 72 ++#define WLAN_EID_20_40_BSS_INTOLERANT 73 ++#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74 ++#define WLAN_EID_MMIE 76 ++#define WLAN_EID_VENDOR_SPECIFIC 221 ++#define WLAN_EID_GENERIC (WLAN_EID_VENDOR_SPECIFIC) ++#define WLAN_EID_VHT_CAPABILITY 191 ++#define WLAN_EID_VHT_OPERATION 192 ++#define WLAN_EID_VHT_OP_MODE_NOTIFY 199 ++ ++#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_NUM_OFDM_RATESLEN 8 ++ ++ ++#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 ++ ++ ++enum MGN_RATE{ ++ MGN_1M = 0x02, ++ MGN_2M = 0x04, ++ MGN_5_5M = 0x0B, ++ MGN_6M = 0x0C, ++ MGN_9M = 0x12, ++ MGN_11M = 0x16, ++ MGN_12M = 0x18, ++ MGN_18M = 0x24, ++ MGN_24M = 0x30, ++ MGN_36M = 0x48, ++ MGN_48M = 0x60, ++ MGN_54M = 0x6C, ++ MGN_MCS32 = 0x7F, ++ MGN_MCS0, ++ MGN_MCS1, ++ MGN_MCS2, ++ MGN_MCS3, ++ MGN_MCS4, ++ MGN_MCS5, ++ MGN_MCS6, ++ MGN_MCS7, ++ MGN_MCS8, ++ MGN_MCS9, ++ MGN_MCS10, ++ MGN_MCS11, ++ MGN_MCS12, ++ MGN_MCS13, ++ MGN_MCS14, ++ MGN_MCS15, ++ MGN_MCS16, ++ MGN_MCS17, ++ MGN_MCS18, ++ MGN_MCS19, ++ MGN_MCS20, ++ MGN_MCS21, ++ MGN_MCS22, ++ MGN_MCS23, ++ MGN_MCS24, ++ MGN_MCS25, ++ MGN_MCS26, ++ MGN_MCS27, ++ MGN_MCS28, ++ MGN_MCS29, ++ MGN_MCS30, ++ MGN_MCS31, ++ MGN_VHT1SS_MCS0, ++ MGN_VHT1SS_MCS1, ++ MGN_VHT1SS_MCS2, ++ MGN_VHT1SS_MCS3, ++ MGN_VHT1SS_MCS4, ++ MGN_VHT1SS_MCS5, ++ MGN_VHT1SS_MCS6, ++ MGN_VHT1SS_MCS7, ++ MGN_VHT1SS_MCS8, ++ MGN_VHT1SS_MCS9, ++ MGN_VHT2SS_MCS0, ++ MGN_VHT2SS_MCS1, ++ MGN_VHT2SS_MCS2, ++ MGN_VHT2SS_MCS3, ++ MGN_VHT2SS_MCS4, ++ MGN_VHT2SS_MCS5, ++ MGN_VHT2SS_MCS6, ++ MGN_VHT2SS_MCS7, ++ MGN_VHT2SS_MCS8, ++ MGN_VHT2SS_MCS9, ++ MGN_VHT3SS_MCS0, ++ MGN_VHT3SS_MCS1, ++ MGN_VHT3SS_MCS2, ++ MGN_VHT3SS_MCS3, ++ MGN_VHT3SS_MCS4, ++ MGN_VHT3SS_MCS5, ++ MGN_VHT3SS_MCS6, ++ MGN_VHT3SS_MCS7, ++ MGN_VHT3SS_MCS8, ++ MGN_VHT3SS_MCS9, ++ MGN_VHT4SS_MCS0, ++ MGN_VHT4SS_MCS1, ++ MGN_VHT4SS_MCS2, ++ MGN_VHT4SS_MCS3, ++ MGN_VHT4SS_MCS4, ++ MGN_VHT4SS_MCS5, ++ MGN_VHT4SS_MCS6, ++ MGN_VHT4SS_MCS7, ++ MGN_VHT4SS_MCS8, ++ MGN_VHT4SS_MCS9, ++ MGN_UNKNOWN ++}; ++ ++#define IS_HT_RATE(_rate) (_rate >= MGN_MCS0 && _rate <= MGN_MCS31) ++#define IS_VHT_RATE(_rate) (_rate >= MGN_VHT1SS_MCS0 && _rate <= MGN_VHT4SS_MCS9) ++#define IS_CCK_RATE(_rate) (MGN_1M == _rate || _rate == MGN_2M || _rate == MGN_5_5M || _rate == MGN_11M) ++#define IS_OFDM_RATE(_rate) (MGN_6M <= _rate && _rate <= MGN_54M && _rate != MGN_11M) ++ ++ ++/* 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 { ++ s8 rssi; ++ u8 signal; ++ u8 noise; ++ u8 received_channel; ++ u16 rate; /* in 100 kbps */ ++ u8 mask; ++ u8 freq; ++ u16 len; ++}; ++ ++/* 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 { ++ u32 first_frag_time; ++ uint seq; ++ uint last_frag; ++ uint qos; /* jackson */ ++ uint tid; /* jackson */ ++ struct sk_buff *skb; ++ u8 src_addr[ETH_ALEN]; ++ u8 dst_addr[ETH_ALEN]; ++}; ++ ++struct ieee80211_stats { ++ uint tx_unicast_frames; ++ uint tx_multicast_frames; ++ uint tx_fragments; ++ uint tx_unicast_octets; ++ uint tx_multicast_octets; ++ uint tx_deferred_transmissions; ++ uint tx_single_retry_frames; ++ uint tx_multiple_retry_frames; ++ uint tx_retry_limit_exceeded; ++ uint tx_discards; ++ uint rx_unicast_frames; ++ uint rx_multicast_frames; ++ uint rx_fragments; ++ uint rx_unicast_octets; ++ uint rx_multicast_octets; ++ uint rx_fcs_errors; ++ uint rx_discards_no_buffer; ++ uint tx_discards_wrong_sa; ++ uint rx_discards_undecryptable; ++ uint rx_message_in_msg_fragments; ++ uint rx_message_in_bad_msg_fragments; ++}; ++ ++struct ieee80211_softmac_stats { ++ uint rx_ass_ok; ++ uint rx_ass_err; ++ uint rx_probe_rq; ++ uint tx_probe_rs; ++ uint tx_beacons; ++ uint rx_auth_rq; ++ uint rx_auth_rs_ok; ++ uint rx_auth_rs_err; ++ uint tx_auth_rq; ++ uint no_auth_rs; ++ uint no_ass_rs; ++ uint tx_ass_rq; ++ uint rx_ass_rq; ++ uint tx_probe_rq; ++ uint reassoc; ++ uint swtxstop; ++ uint swtxawake; ++}; ++ ++#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 BIP_MAX_KEYID 5 ++#define BIP_AAD_SIZE 20 ++ ++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][WEP_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_CHALLENGE 16 ++#define MFIE_TYPE_ERP 42 ++#define MFIE_TYPE_RSN 48 ++#define MFIE_TYPE_RATES_EX 50 ++#define MFIE_TYPE_GENERIC 221 ++ ++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 ++ ++ ++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; ++} __attribute__ ((packed)); ++ ++struct ieee80211_txb { ++ u8 nr_frags; ++ u8 encrypted; ++ u16 reserved; ++ u16 frag_size; ++ u16 payload_size; ++ struct sk_buff *fragments[0]; ++}; ++ ++ ++/* 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 ++#define MAX_CHANNEL_NUMBER 161 ++#define IEEE80211_SOFTMAC_SCAN_TIME 400 ++/* HZ / 2) */ ++#define IEEE80211_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2) ++ ++#define CRC_LENGTH 4U ++ ++#define MAX_WPA_IE_LEN (256) ++#define MAX_WPS_IE_LEN (512) ++#define MAX_P2P_IE_LEN (256) ++#define MAX_WFD_IE_LEN (128) ++ ++#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 ++#define IW_ESSID_MAX_SIZE 32 ++/* ++join_res: ++-1: authentication fail ++-2: association fail ++> 0: TID ++*/ ++ ++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, ++ ++}; ++ ++#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] ++#define IP_FMT "%d.%d.%d.%d" ++#define IP_ARG(x) ((u8 *)(x))[0], ((u8 *)(x))[1], ((u8 *)(x))[2], ((u8 *)(x))[3] ++ ++extern __inline int is_multicast_mac_addr(const u8 *addr) ++{ ++ return ((addr[0] != 0xff) && (0x01 & addr[0])); ++} ++ ++extern __inline int is_broadcast_mac_addr(const u8 *addr) ++{ ++ return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \ ++ (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff)); ++} ++ ++extern __inline int is_zero_mac_addr(const u8 *addr) ++{ ++ return ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && \ ++ (addr[3] == 0x00) && (addr[4] == 0x00) && (addr[5] == 0x00)); ++} ++ ++#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; ++ ++ ++ ++#define MAXTID 16 ++ ++#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) ++ ++/* Action category code */ ++enum rtw_ieee80211_category { ++ RTW_WLAN_CATEGORY_SPECTRUM_MGMT = 0, ++ RTW_WLAN_CATEGORY_QOS = 1, ++ RTW_WLAN_CATEGORY_DLS = 2, ++ RTW_WLAN_CATEGORY_BACK = 3, ++ RTW_WLAN_CATEGORY_PUBLIC = 4, /* IEEE 802.11 public action frames */ ++ RTW_WLAN_CATEGORY_RADIO_MEASUREMENT = 5, ++ RTW_WLAN_CATEGORY_FT = 6, ++ RTW_WLAN_CATEGORY_HT = 7, ++ RTW_WLAN_CATEGORY_SA_QUERY = 8, ++ RTW_WLAN_CATEGORY_UNPROTECTED_WNM = 11, /* add for CONFIG_IEEE80211W, none 11w also can use */ ++ RTW_WLAN_CATEGORY_TDLS = 12, ++ RTW_WLAN_CATEGORY_SELF_PROTECTED = 15, /* add for CONFIG_IEEE80211W, none 11w also can use */ ++ RTW_WLAN_CATEGORY_WMM = 17, ++ RTW_WLAN_CATEGORY_VHT = 21, ++ RTW_WLAN_CATEGORY_P2P = 0x7f,/* P2P action frames */ ++}; ++ ++/* SPECTRUM_MGMT action code */ ++enum rtw_ieee80211_spectrum_mgmt_actioncode { ++ RTW_WLAN_ACTION_SPCT_MSR_REQ = 0, ++ RTW_WLAN_ACTION_SPCT_MSR_RPRT = 1, ++ RTW_WLAN_ACTION_SPCT_TPC_REQ = 2, ++ RTW_WLAN_ACTION_SPCT_TPC_RPRT = 3, ++ RTW_WLAN_ACTION_SPCT_CHL_SWITCH = 4, ++ RTW_WLAN_ACTION_SPCT_EXT_CHL_SWITCH = 5, ++}; ++ ++enum _PUBLIC_ACTION{ ++ ACT_PUBLIC_BSSCOEXIST = 0, /* 20/40 BSS Coexistence */ ++ ACT_PUBLIC_DSE_ENABLE = 1, ++ ACT_PUBLIC_DSE_DEENABLE = 2, ++ ACT_PUBLIC_DSE_REG_LOCATION = 3, ++ ACT_PUBLIC_EXT_CHL_SWITCH = 4, ++ ACT_PUBLIC_DSE_MSR_REQ = 5, ++ ACT_PUBLIC_DSE_MSR_RPRT = 6, ++ ACT_PUBLIC_MP = 7, /* Measurement Pilot */ ++ ACT_PUBLIC_DSE_PWR_CONSTRAINT = 8, ++ ACT_PUBLIC_VENDOR = 9, /* for WIFI_DIRECT */ ++ ACT_PUBLIC_GAS_INITIAL_REQ = 10, ++ ACT_PUBLIC_GAS_INITIAL_RSP = 11, ++ ACT_PUBLIC_GAS_COMEBACK_REQ = 12, ++ ACT_PUBLIC_GAS_COMEBACK_RSP = 13, ++ ACT_PUBLIC_TDLS_DISCOVERY_RSP = 14, ++ ACT_PUBLIC_LOCATION_TRACK = 15, ++ ACT_PUBLIC_MAX ++}; ++ ++/* BACK action code */ ++enum rtw_ieee80211_back_actioncode { ++ RTW_WLAN_ACTION_ADDBA_REQ = 0, ++ RTW_WLAN_ACTION_ADDBA_RESP = 1, ++ RTW_WLAN_ACTION_DELBA = 2, ++}; ++ ++/* HT features action code */ ++enum rtw_ieee80211_ht_actioncode { ++ RTW_WLAN_ACTION_HT_NOTI_CHNL_WIDTH = 0, ++ RTW_WLAN_ACTION_HT_SM_PS = 1, ++ RTW_WLAN_ACTION_HT_PSMP = 2, ++ RTW_WLAN_ACTION_HT_SET_PCO_PHASE = 3, ++ RTW_WLAN_ACTION_HT_CSI = 4, ++ RTW_WLAN_ACTION_HT_NON_COMPRESS_BEAMFORMING = 5, ++ RTW_WLAN_ACTION_HT_COMPRESS_BEAMFORMING = 6, ++ RTW_WLAN_ACTION_HT_ASEL_FEEDBACK = 7, ++}; ++ ++/* BACK (block-ack) parties */ ++enum rtw_ieee80211_back_parties { ++ RTW_WLAN_BACK_RECIPIENT = 0, ++ RTW_WLAN_BACK_INITIATOR = 1, ++ RTW_WLAN_BACK_TIMER = 2, ++}; ++ ++/* VHT features action code */ ++enum rtw_ieee80211_vht_actioncode{ ++ RTW_WLAN_ACTION_VHT_COMPRESSED_BEAMFORMING = 0, ++ RTW_WLAN_ACTION_VHT_GROUPID_MANAGEMENT = 1, ++ RTW_WLAN_ACTION_VHT_OPMODE_NOTIFICATION = 2, ++}; ++ ++ ++#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs) ++ * 00:50:F2 */ ++#define WME_OUI_TYPE 2 ++#define WME_OUI_SUBTYPE_INFORMATION_ELEMENT 0 ++#define WME_OUI_SUBTYPE_PARAMETER_ELEMENT 1 ++#define WME_OUI_SUBTYPE_TSPEC_ELEMENT 2 ++#define WME_VERSION 1 ++ ++#define WME_ACTION_CODE_SETUP_REQUEST 0 ++#define WME_ACTION_CODE_SETUP_RESPONSE 1 ++#define WME_ACTION_CODE_TEARDOWN 2 ++ ++#define WME_SETUP_RESPONSE_STATUS_ADMISSION_ACCEPTED 0 ++#define WME_SETUP_RESPONSE_STATUS_INVALID_PARAMETERS 1 ++#define WME_SETUP_RESPONSE_STATUS_REFUSED 3 ++ ++#define WME_TSPEC_DIRECTION_UPLINK 0 ++#define WME_TSPEC_DIRECTION_DOWNLINK 1 ++#define WME_TSPEC_DIRECTION_BI_DIRECTIONAL 3 ++ ++ ++#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */ ++ ++#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */ ++ ++/** ++ * enum rtw_ieee80211_channel_flags - channel flags ++ * ++ * Channel flags set by the regulatory control code. ++ * ++ * @RTW_IEEE80211_CHAN_DISABLED: This channel is disabled. ++ * @RTW_IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted ++ * on this channel. ++ * @RTW_IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel. ++ * @RTW_IEEE80211_CHAN_RADAR: Radar detection is required on this channel. ++ * @RTW_IEEE80211_CHAN_NO_HT40PLUS: extension channel above this channel ++ * is not permitted. ++ * @RTW_IEEE80211_CHAN_NO_HT40MINUS: extension channel below this channel ++ * is not permitted. ++ */ ++ enum rtw_ieee80211_channel_flags { ++ RTW_IEEE80211_CHAN_DISABLED = 1<<0, ++ RTW_IEEE80211_CHAN_PASSIVE_SCAN = 1<<1, ++ RTW_IEEE80211_CHAN_NO_IBSS = 1<<2, ++ RTW_IEEE80211_CHAN_RADAR = 1<<3, ++ RTW_IEEE80211_CHAN_NO_HT40PLUS = 1<<4, ++ RTW_IEEE80211_CHAN_NO_HT40MINUS = 1<<5, ++ }; ++ ++ #define RTW_IEEE80211_CHAN_NO_HT40 \ ++ (RTW_IEEE80211_CHAN_NO_HT40PLUS | RTW_IEEE80211_CHAN_NO_HT40MINUS) ++ ++/* Represent channel details, subset of ieee80211_channel */ ++struct rtw_ieee80211_channel { ++ /* enum ieee80211_band band; */ ++ /* u16 center_freq; */ ++ u16 hw_value; ++ u32 flags; ++ /* int max_antenna_gain; */ ++ /* int max_power; */ ++ /* int max_reg_power; */ ++ /* bool beacon_found; */ ++ /* u32 orig_flags; */ ++ /* int orig_mag; */ ++ /* int orig_mpwr; */ ++}; ++ ++#define CHAN_FMT \ ++ /*"band:%d, "*/ \ ++ /*"center_freq:%u, "*/ \ ++ "hw_value:%u, " \ ++ "flags:0x%08x" \ ++ /*"max_antenna_gain:%d\n"*/ \ ++ /*"max_power:%d\n"*/ \ ++ /*"max_reg_power:%d\n"*/ \ ++ /*"beacon_found:%u\n"*/ \ ++ /*"orig_flags:0x%08x\n"*/ \ ++ /*"orig_mag:%d\n"*/ \ ++ /*"orig_mpwr:%d\n"*/ ++ ++#define CHAN_ARG(channel) \ ++ /*(channel)->band*/ \ ++ /*, (channel)->center_freq*/ \ ++ (channel)->hw_value \ ++ , (channel)->flags \ ++ /*, (channel)->max_antenna_gain*/ \ ++ /*, (channel)->max_power*/ \ ++ /*, (channel)->max_reg_power*/ \ ++ /*, (channel)->beacon_found*/ \ ++ /*, (channel)->orig_flags*/ \ ++ /*, (channel)->orig_mag*/ \ ++ /*, (channel)->orig_mpwr*/ \ ++ ++/* Parsed Information Elements */ ++struct rtw_ieee802_11_elems { ++ u8 *ssid; ++ u8 ssid_len; ++ u8 *supp_rates; ++ u8 supp_rates_len; ++ u8 *fh_params; ++ u8 fh_params_len; ++ u8 *ds_params; ++ u8 ds_params_len; ++ u8 *cf_params; ++ u8 cf_params_len; ++ u8 *tim; ++ u8 tim_len; ++ u8 *ibss_params; ++ u8 ibss_params_len; ++ u8 *challenge; ++ u8 challenge_len; ++ u8 *erp_info; ++ u8 erp_info_len; ++ u8 *ext_supp_rates; ++ u8 ext_supp_rates_len; ++ u8 *wpa_ie; ++ u8 wpa_ie_len; ++ u8 *rsn_ie; ++ u8 rsn_ie_len; ++ u8 *wme; ++ u8 wme_len; ++ u8 *wme_tspec; ++ u8 wme_tspec_len; ++ u8 *wps_ie; ++ u8 wps_ie_len; ++ u8 *power_cap; ++ u8 power_cap_len; ++ u8 *supp_channels; ++ u8 supp_channels_len; ++ u8 *mdie; ++ u8 mdie_len; ++ u8 *ftie; ++ u8 ftie_len; ++ u8 *timeout_int; ++ u8 timeout_int_len; ++ u8 *ht_capabilities; ++ u8 ht_capabilities_len; ++ u8 *ht_operation; ++ u8 ht_operation_len; ++ u8 *vendor_ht_cap; ++ u8 vendor_ht_cap_len; ++ u8 *vht_capabilities; ++ u8 vht_capabilities_len; ++ u8 *vht_operation; ++ u8 vht_operation_len; ++ u8 *vht_op_mode_notify; ++ u8 vht_op_mode_notify_len; ++}; ++ ++typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes; ++ ++ParseRes rtw_ieee802_11_parse_elems(u8 *start, uint len, ++ struct rtw_ieee802_11_elems *elems, ++ int show_errors); ++ ++u8 *rtw_set_fixed_ie(unsigned char *pbuf, unsigned int len, unsigned char *source, unsigned int *frlen); ++u8 *rtw_set_ie(u8 *pbuf, sint index, uint len, u8 *source, uint *frlen); ++ ++enum secondary_ch_offset { ++ SCN = 0, /* no secondary channel */ ++ SCA = 1, /* secondary channel above */ ++ SCB = 3, /* secondary channel below */ ++}; ++ ++u8 *rtw_get_ie(u8*pbuf, sint index, sint *len, sint limit); ++u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, uint *ielen); ++int rtw_ies_remove_ie(u8 *ies, uint *ies_len, uint offset, u8 eid, u8 *oui, u8 oui_len); ++ ++void rtw_set_supported_rate(u8 *SupportedRates, uint mode) ; ++ ++unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit); ++unsigned char *rtw_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit); ++int rtw_get_wpa_cipher_suite(u8 *s); ++int rtw_get_wpa2_cipher_suite(u8 *s); ++int rtw_get_wapi_ie(u8 *in_ie, uint in_len, u8 *wapi_ie, u16 *wapi_len); ++int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x); ++int rtw_parse_wpa2_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x); ++ ++int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len); ++ ++u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen); ++u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen); ++u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id , u8 *buf_attr, u32 *len_attr); ++u8 *rtw_get_wps_attr_content(u8 *wps_ie, uint wps_ielen, u16 target_attr_id , u8 *buf_content, uint *len_content); ++ ++/** ++ * for_each_ie - iterate over continuous IEs ++ * @ie: ++ * @buf: ++ * @buf_len: ++ */ ++#define for_each_ie(ie, buf, buf_len) \ ++ for (ie = (void*)buf; (((u8 *)ie) - ((u8 *)buf) + 1) < buf_len; ie = (void*)(((u8 *)ie) + *(((u8 *)ie)+1) + 2)) ++ ++uint rtw_get_rateset_len(u8 *rateset); ++ ++struct registry_priv; ++int rtw_generate_ie(struct registry_priv *pregistrypriv); ++ ++ ++int rtw_get_bit_value_from_ieee_value(u8 val); ++ ++uint rtw_is_cckrates_included(u8 *rate); ++ ++uint rtw_is_cckratesonly_included(u8 *rate); ++ ++int rtw_check_network_type(unsigned char *rate, int ratelen, int channel); ++ ++void rtw_get_bcn_info(struct wlan_network *pnetwork); ++ ++void rtw_macaddr_cfg(u8 *mac_addr); ++ ++u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI, unsigned char * MCS_rate); ++ ++int rtw_action_frame_parse(const u8 *frame, u32 frame_len, u8 *category, u8 *action); ++const char *action_public_str(u8 action); ++ ++#endif /* IEEE80211_H */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/ioctl_cfg80211.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/ioctl_cfg80211.h +--- linux-4.3/3rdparty/rtl8723bs/include/ioctl_cfg80211.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/ioctl_cfg80211.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,132 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __IOCTL_CFG80211_H__ ++#define __IOCTL_CFG80211_H__ ++ ++#include ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)) ++#error This driver only works with kernel 3.19 and later ++#endif ++ ++struct rtw_wdev_invit_info { ++ u8 state; /* 0: req, 1:rep */ ++ u8 peer_mac[ETH_ALEN]; ++ u8 active; ++ u8 token; ++ u8 flags; ++ u8 status; ++ u8 req_op_ch; ++ u8 rsp_op_ch; ++}; ++ ++#define rtw_wdev_invit_info_init(invit_info) \ ++ do { \ ++ (invit_info)->state = 0xff; \ ++ memset((invit_info)->peer_mac, 0, ETH_ALEN); \ ++ (invit_info)->active = 0xff; \ ++ (invit_info)->token = 0; \ ++ (invit_info)->flags = 0x00; \ ++ (invit_info)->status = 0xff; \ ++ (invit_info)->req_op_ch = 0; \ ++ (invit_info)->rsp_op_ch = 0; \ ++ } while (0) ++ ++struct rtw_wdev_nego_info { ++ u8 state; /* 0: req, 1:rep, 2:conf */ ++ u8 peer_mac[ETH_ALEN]; ++ u8 active; ++ u8 token; ++ u8 status; ++ u8 req_intent; ++ u8 req_op_ch; ++ u8 req_listen_ch; ++ u8 rsp_intent; ++ u8 rsp_op_ch; ++ u8 conf_op_ch; ++}; ++ ++#define rtw_wdev_nego_info_init(nego_info) \ ++ do { \ ++ (nego_info)->state = 0xff; \ ++ memset((nego_info)->peer_mac, 0, ETH_ALEN); \ ++ (nego_info)->active = 0xff; \ ++ (nego_info)->token = 0; \ ++ (nego_info)->status = 0xff; \ ++ (nego_info)->req_intent = 0xff; \ ++ (nego_info)->req_op_ch = 0; \ ++ (nego_info)->req_listen_ch = 0; \ ++ (nego_info)->rsp_intent = 0xff; \ ++ (nego_info)->rsp_op_ch = 0; \ ++ (nego_info)->conf_op_ch = 0; \ ++ } while (0) ++ ++struct rtw_wdev_priv ++{ ++ struct wireless_dev *rtw_wdev; ++ ++ struct adapter *padapter; ++ ++ struct cfg80211_scan_request *scan_request; ++ _lock scan_req_lock; ++ ++ struct net_device *pmon_ndev;/* for monitor interface */ ++ char ifname_mon[IFNAMSIZ + 1]; /* interface name for monitor interface */ ++ ++ u8 p2p_enabled; ++ ++ u8 provdisc_req_issued; ++ ++ struct rtw_wdev_invit_info invit_info; ++ struct rtw_wdev_nego_info nego_info; ++ ++ u8 bandroid_scan; ++ bool block; ++ bool power_mgmt; ++}; ++ ++#define wiphy_to_adapter(x) (*((struct adapter **)wiphy_priv(x))) ++ ++#define wdev_to_ndev(w) ((w)->netdev) ++ ++int rtw_wdev_alloc(struct adapter *padapter, struct device *dev); ++void rtw_wdev_free(struct wireless_dev *wdev); ++void rtw_wdev_unregister(struct wireless_dev *wdev); ++ ++void rtw_cfg80211_init_wiphy(struct adapter *padapter); ++ ++void rtw_cfg80211_unlink_bss(struct adapter *padapter, struct wlan_network *pnetwork); ++void rtw_cfg80211_surveydone_event_callback(struct adapter *padapter); ++struct cfg80211_bss *rtw_cfg80211_inform_bss(struct adapter *padapter, struct wlan_network *pnetwork); ++int rtw_cfg80211_check_bss(struct adapter *padapter); ++void rtw_cfg80211_ibss_indicate_connect(struct adapter *padapter); ++void rtw_cfg80211_indicate_connect(struct adapter *padapter); ++void rtw_cfg80211_indicate_disconnect(struct adapter *padapter); ++void rtw_cfg80211_indicate_scan_done(struct adapter *adapter, bool aborted); ++ ++void rtw_cfg80211_indicate_sta_assoc(struct adapter *padapter, u8 *pmgmt_frame, uint frame_len); ++void rtw_cfg80211_indicate_sta_disassoc(struct adapter *padapter, unsigned char *da, unsigned short reason); ++ ++void rtw_cfg80211_rx_action(struct adapter *adapter, u8 *frame, uint frame_len, const char*msg); ++ ++bool rtw_cfg80211_pwr_mgmt(struct adapter *adapter); ++ ++#define rtw_cfg80211_rx_mgmt(adapter, freq, sig_dbm, buf, len, gfp) cfg80211_rx_mgmt((adapter)->rtw_wdev, freq, sig_dbm, buf, len, 0) ++#define rtw_cfg80211_send_rx_assoc(adapter, bss, buf, len) cfg80211_send_rx_assoc((adapter)->pnetdev, bss, buf, len) ++#define rtw_cfg80211_mgmt_tx_status(adapter, cookie, buf, len, ack, gfp) cfg80211_mgmt_tx_status((adapter)->rtw_wdev, cookie, buf, len, ack, gfp) ++#define rtw_cfg80211_ready_on_channel(adapter, cookie, chan, channel_type, duration, gfp) cfg80211_ready_on_channel((adapter)->rtw_wdev, cookie, chan, duration, gfp) ++#define rtw_cfg80211_remain_on_channel_expired(adapter, cookie, chan, chan_type, gfp) cfg80211_remain_on_channel_expired((adapter)->rtw_wdev, cookie, chan, gfp) ++ ++#endif /* __IOCTL_CFG80211_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/mlme_osdep.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/mlme_osdep.h +--- linux-4.3/3rdparty/rtl8723bs/include/mlme_osdep.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/mlme_osdep.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,27 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __MLME_OSDEP_H_ ++#define __MLME_OSDEP_H_ ++ ++ ++extern void rtw_init_mlme_timer(struct adapter *padapter); ++extern void rtw_os_indicate_disconnect(struct adapter *adapter); ++extern void rtw_os_indicate_connect(struct adapter *adapter); ++void rtw_os_indicate_scan_done(struct adapter *padapter, bool aborted); ++extern void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie); ++ ++void rtw_reset_securitypriv(struct adapter *adapter); ++ ++#endif /* _MLME_OSDEP_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/osdep_intf.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/osdep_intf.h +--- linux-4.3/3rdparty/rtl8723bs/include/osdep_intf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/osdep_intf.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,88 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#ifndef __OSDEP_INTF_H_ ++#define __OSDEP_INTF_H_ ++ ++ ++struct intf_priv { ++ ++ u8 *intf_dev; ++ u32 max_iosz; /* USB2.0: 128, USB1.1: 64, SDIO:64 */ ++ u32 max_xmitsz; /* USB2.0: unlimited, SDIO:512 */ ++ u32 max_recvsz; /* USB2.0: unlimited, SDIO:512 */ ++ ++ volatile u8 *io_rwmem; ++ volatile u8 *allocated_io_rwmem; ++ u32 io_wsz; /* unit: 4bytes */ ++ u32 io_rsz;/* unit: 4bytes */ ++ u8 intf_status; ++ ++ void (*_bus_io)(u8 *priv); ++ ++/* ++Under Sync. IRP (SDIO/USB) ++A protection mechanism is necessary for the io_rwmem(read/write protocol) ++ ++Under Async. IRP (SDIO/USB) ++The protection mechanism is through the pending queue. ++*/ ++ ++ _mutex ioctl_mutex; ++}; ++ ++ ++#ifdef CONFIG_R871X_TEST ++int rtw_start_pseudo_adhoc(struct adapter *padapter); ++int rtw_stop_pseudo_adhoc(struct adapter *padapter); ++#endif ++ ++struct dvobj_priv *devobj_init(void); ++void devobj_deinit(struct dvobj_priv *pdvobj); ++ ++u8 rtw_init_drv_sw(struct adapter *padapter); ++u8 rtw_free_drv_sw(struct adapter *padapter); ++u8 rtw_reset_drv_sw(struct adapter *padapter); ++void rtw_dev_unload(struct adapter *padapter); ++ ++u32 rtw_start_drv_threads(struct adapter *padapter); ++void rtw_stop_drv_threads (struct adapter *padapter); ++void rtw_cancel_all_timer(struct adapter *padapter); ++ ++int rtw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); ++ ++int rtw_init_netdev_name(struct net_device *pnetdev, const char *ifname); ++struct net_device *rtw_init_netdev(struct adapter *padapter); ++void rtw_unregister_netdevs(struct dvobj_priv *dvobj); ++ ++u16 rtw_recv_select_queue(struct sk_buff *skb); ++ ++int rtw_ndev_notifier_register(void); ++void rtw_ndev_notifier_unregister(void); ++ ++#include "../os_dep/rtw_proc.h" ++ ++void rtw_ips_dev_unload(struct adapter *padapter); ++ ++int rtw_ips_pwr_up(struct adapter *padapter); ++void rtw_ips_pwr_down(struct adapter *padapter); ++ ++int rtw_drv_register_netdev(struct adapter *padapter); ++void rtw_ndev_destructor(_nic_hdl ndev); ++ ++int rtw_suspend_common(struct adapter *padapter); ++int rtw_resume_common(struct adapter *padapter); ++ ++#endif /* _OSDEP_INTF_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/osdep_service.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/osdep_service.h +--- linux-4.3/3rdparty/rtl8723bs/include/osdep_service.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/osdep_service.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,281 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2013 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __OSDEP_SERVICE_H_ ++#define __OSDEP_SERVICE_H_ ++ ++ ++#define _FAIL 0 ++#define _SUCCESS 1 ++#define RTW_RX_HANDLED 2 ++ ++#include ++ ++#ifndef BIT ++ #define BIT(x) (1 << (x)) ++#endif ++ ++#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 ++#define BIT32 0x0100000000 ++#define BIT33 0x0200000000 ++#define BIT34 0x0400000000 ++#define BIT35 0x0800000000 ++#define BIT36 0x1000000000 ++ ++extern int RTW_STATUS_CODE(int error_code); ++ ++/* flags used for rtw_mstat_update() */ ++enum mstat_f { ++ /* type: 0x00ff */ ++ MSTAT_TYPE_VIR = 0x00, ++ MSTAT_TYPE_PHY = 0x01, ++ MSTAT_TYPE_SKB = 0x02, ++ MSTAT_TYPE_USB = 0x03, ++ MSTAT_TYPE_MAX = 0x04, ++ ++ /* func: 0xff00 */ ++ MSTAT_FUNC_UNSPECIFIED = 0x00<<8, ++ MSTAT_FUNC_IO = 0x01<<8, ++ MSTAT_FUNC_TX_IO = 0x02<<8, ++ MSTAT_FUNC_RX_IO = 0x03<<8, ++ MSTAT_FUNC_TX = 0x04<<8, ++ MSTAT_FUNC_RX = 0x05<<8, ++ MSTAT_FUNC_MAX = 0x06<<8, ++}; ++ ++#define mstat_tf_idx(flags) ((flags)&0xff) ++#define mstat_ff_idx(flags) (((flags)&0xff00) >> 8) ++ ++typedef enum mstat_status{ ++ MSTAT_ALLOC_SUCCESS = 0, ++ MSTAT_ALLOC_FAIL, ++ MSTAT_FREE ++} MSTAT_STATUS; ++ ++#define rtw_mstat_update(flag, status, sz) do {} while (0) ++#define rtw_mstat_dump(sel) do {} while (0) ++u8*_rtw_zmalloc(u32 sz); ++u8*_rtw_malloc(u32 sz); ++void _kfree(u8 *pbuf, u32 sz); ++ ++struct sk_buff *_rtw_skb_alloc(u32 sz); ++struct sk_buff *_rtw_skb_copy(const struct sk_buff *skb); ++struct sk_buff *_rtw_skb_clone(struct sk_buff *skb); ++int _rtw_netif_rx(_nic_hdl ndev, struct sk_buff *skb); ++ ++#define rtw_malloc(sz) _rtw_malloc((sz)) ++#define rtw_zmalloc(sz) _rtw_zmalloc((sz)) ++ ++#define rtw_skb_alloc(size) _rtw_skb_alloc((size)) ++#define rtw_skb_alloc_f(size, mstat_f) _rtw_skb_alloc((size)) ++#define rtw_skb_copy(skb) _rtw_skb_copy((skb)) ++#define rtw_skb_clone(skb) _rtw_skb_clone((skb)) ++#define rtw_skb_copy_f(skb, mstat_f) _rtw_skb_copy((skb)) ++#define rtw_skb_clone_f(skb, mstat_f) _rtw_skb_clone((skb)) ++#define rtw_netif_rx(ndev, skb) _rtw_netif_rx(ndev, skb) ++ ++extern void _rtw_init_queue(struct __queue *pqueue); ++ ++extern void rtw_init_timer(_timer *ptimer, void *padapter, void *pfunc); ++ ++static __inline void thread_enter(char *name) ++{ ++ allow_signal(SIGTERM); ++} ++ ++__inline static void flush_signals_thread(void) ++{ ++ if (signal_pending (current)) ++ { ++ flush_signals(current); ++ } ++} ++ ++#define rtw_warn_on(condition) WARN_ON(condition) ++ ++__inline static int rtw_bug_check(void *parg1, void *parg2, void *parg3, void *parg4) ++{ ++ int ret = true; ++ ++ return ret; ++ ++} ++ ++#define _RND(sz, r) ((((sz)+((r)-1))/(r))*(r)) ++#define RND4(x) (((x >> 2) + (((x & 3) == 0) ? 0: 1)) << 2) ++ ++__inline static u32 _RND4(u32 sz) ++{ ++ ++ u32 val; ++ ++ val = ((sz >> 2) + ((sz & 3) ? 1: 0)) << 2; ++ ++ return val; ++ ++} ++ ++__inline static u32 _RND8(u32 sz) ++{ ++ ++ u32 val; ++ ++ val = ((sz >> 3) + ((sz & 7) ? 1: 0)) << 3; ++ ++ return val; ++ ++} ++ ++#ifndef MAC_FMT ++#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" ++#endif ++#ifndef MAC_ARG ++#define MAC_ARG(x) ((u8 *)(x))[0], ((u8 *)(x))[1], ((u8 *)(x))[2], ((u8 *)(x))[3], ((u8 *)(x))[4], ((u8 *)(x))[5] ++#endif ++ ++ ++#ifdef CONFIG_AP_WOWLAN ++extern void rtw_softap_lock_suspend(void); ++extern void rtw_softap_unlock_suspend(void); ++#endif ++ ++/* File operation APIs, just for linux now */ ++extern int rtw_is_file_readable(char *path); ++extern int rtw_retrive_from_file(char *path, u8 *buf, u32 sz); ++ ++extern void rtw_free_netdev(struct net_device * netdev); ++ ++ ++extern u64 rtw_modular64(u64 x, u64 y); ++ ++/* Macros for handling unaligned memory accesses */ ++ ++#define RTW_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1])) ++#define RTW_PUT_BE16(a, val) \ ++ do { \ ++ (a)[0] = ((u16) (val)) >> 8; \ ++ (a)[1] = ((u16) (val)) & 0xff; \ ++ } while (0) ++ ++#define RTW_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) ++#define RTW_PUT_LE16(a, val) \ ++ do { \ ++ (a)[1] = ((u16) (val)) >> 8; \ ++ (a)[0] = ((u16) (val)) & 0xff; \ ++ } while (0) ++ ++#define RTW_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ ++ ((u32) (a)[2])) ++#define RTW_PUT_BE24(a, val) \ ++ do { \ ++ (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \ ++ (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ ++ (a)[2] = (u8) (((u32) (val)) & 0xff); \ ++ } while (0) ++ ++#define RTW_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ ++ (((u32) (a)[2]) << 8) | ((u32) (a)[3])) ++#define RTW_PUT_BE32(a, val) \ ++ do { \ ++ (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ ++ (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ ++ (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ ++ (a)[3] = (u8) (((u32) (val)) & 0xff); \ ++ } while (0) ++ ++#define RTW_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \ ++ (((u32) (a)[1]) << 8) | ((u32) (a)[0])) ++#define RTW_PUT_LE32(a, val) \ ++ do { \ ++ (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ ++ (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ ++ (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ ++ (a)[0] = (u8) (((u32) (val)) & 0xff); \ ++ } while (0) ++ ++#define RTW_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \ ++ (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \ ++ (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \ ++ (((u64) (a)[6]) << 8) | ((u64) (a)[7])) ++#define RTW_PUT_BE64(a, val) \ ++ do { \ ++ (a)[0] = (u8) (((u64) (val)) >> 56); \ ++ (a)[1] = (u8) (((u64) (val)) >> 48); \ ++ (a)[2] = (u8) (((u64) (val)) >> 40); \ ++ (a)[3] = (u8) (((u64) (val)) >> 32); \ ++ (a)[4] = (u8) (((u64) (val)) >> 24); \ ++ (a)[5] = (u8) (((u64) (val)) >> 16); \ ++ (a)[6] = (u8) (((u64) (val)) >> 8); \ ++ (a)[7] = (u8) (((u64) (val)) & 0xff); \ ++ } while (0) ++ ++#define RTW_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \ ++ (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \ ++ (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \ ++ (((u64) (a)[1]) << 8) | ((u64) (a)[0])) ++ ++void rtw_buf_free(u8 **buf, u32 *buf_len); ++void rtw_buf_update(u8 **buf, u32 *buf_len, u8 *src, u32 src_len); ++ ++struct rtw_cbuf { ++ u32 write; ++ u32 read; ++ u32 size; ++ void *bufs[0]; ++}; ++ ++bool rtw_cbuf_full(struct rtw_cbuf *cbuf); ++bool rtw_cbuf_empty(struct rtw_cbuf *cbuf); ++bool rtw_cbuf_push(struct rtw_cbuf *cbuf, void *buf); ++void *rtw_cbuf_pop(struct rtw_cbuf *cbuf); ++struct rtw_cbuf *rtw_cbuf_alloc(u32 size); ++ ++/* String handler */ ++/* ++ * Write formatted output to sized buffer ++ */ ++#define rtw_sprintf(buf, size, format, arg...) snprintf(buf, size, format, ##arg) ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/osdep_service_linux.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/osdep_service_linux.h +--- linux-4.3/3rdparty/rtl8723bs/include/osdep_service_linux.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/osdep_service_linux.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,178 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2013 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __OSDEP_LINUX_SERVICE_H_ ++#define __OSDEP_LINUX_SERVICE_H_ ++ ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ /* include */ ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include /* for struct tasklet_struct */ ++ #include ++ #include ++ #include ++ #include ++ ++/* #include */ ++ #include ++ #include ++ ++ typedef struct semaphore _sema; ++ typedef spinlock_t _lock; ++ typedef struct mutex _mutex; ++ typedef struct timer_list _timer; ++ ++ struct __queue { ++ struct list_head queue; ++ _lock lock; ++ }; ++ ++ typedef struct sk_buff _pkt; ++ typedef unsigned char _buffer; ++ ++ typedef int _OS_STATUS; ++ /* typedef u32 _irqL; */ ++ typedef unsigned long _irqL; ++ typedef struct net_device * _nic_hdl; ++ ++ #define thread_exit() complete_and_exit(NULL, 0) ++ ++ typedef void timer_hdl_return; ++ typedef void* timer_hdl_context; ++ ++ typedef struct work_struct _workitem; ++ ++__inline static struct list_head *get_next(struct list_head *list) ++{ ++ return list->next; ++} ++ ++__inline static struct list_head *get_list_head(struct __queue *queue) ++{ ++ return (&(queue->queue)); ++} ++ ++ ++#define LIST_CONTAINOR(ptr, type, member) \ ++ ((type *)((char *)(ptr)-(__kernel_size_t)(&((type *)0)->member))) ++ ++#define RTW_TIMER_HDL_ARGS void *FunctionContext ++ ++__inline static void _init_timer(_timer *ptimer, _nic_hdl nic_hdl, void *pfunc, void* cntx) ++{ ++ /* setup_timer(ptimer, pfunc, (u32)cntx); */ ++ ptimer->function = pfunc; ++ ptimer->data = (unsigned long)cntx; ++ init_timer(ptimer); ++} ++ ++__inline static void _set_timer(_timer *ptimer, u32 delay_time) ++{ ++ mod_timer(ptimer , (jiffies+(delay_time*HZ/1000))); ++} ++ ++__inline static void _cancel_timer(_timer *ptimer, u8 *bcancelled) ++{ ++ del_timer_sync(ptimer); ++ *bcancelled = true;/* true == 1; false == 0 */ ++} ++ ++ ++__inline static void _init_workitem(_workitem *pwork, void *pfunc, void *cntx) ++{ ++ INIT_WORK(pwork, pfunc); ++} ++ ++__inline static void _set_workitem(_workitem *pwork) ++{ ++ schedule_work(pwork); ++} ++ ++__inline static void _cancel_workitem_sync(_workitem *pwork) ++{ ++ cancel_work_sync(pwork); ++} ++ ++static inline int rtw_netif_queue_stopped(struct net_device *pnetdev) ++{ ++ return (netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 0)) && ++ netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 1)) && ++ netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 2)) && ++ netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 3))); ++} ++ ++static inline void rtw_netif_wake_queue(struct net_device *pnetdev) ++{ ++ netif_tx_wake_all_queues(pnetdev); ++} ++ ++static inline void rtw_netif_start_queue(struct net_device *pnetdev) ++{ ++ netif_tx_start_all_queues(pnetdev); ++} ++ ++static inline void rtw_netif_stop_queue(struct net_device *pnetdev) ++{ ++ netif_tx_stop_all_queues(pnetdev); ++} ++ ++static inline void rtw_merge_string(char *dst, int dst_len, char *src1, char *src2) ++{ ++ int len = 0; ++ len += snprintf(dst+len, dst_len - len, "%s", src1); ++ len += snprintf(dst+len, dst_len - len, "%s", src2); ++} ++ ++#define rtw_signal_process(pid, sig) kill_pid(find_vpid((pid)), (sig), 1) ++ ++#define rtw_netdev_priv(netdev) (((struct rtw_netdev_priv_indicator *)netdev_priv(netdev))->priv) ++ ++#define NDEV_FMT "%s" ++#define NDEV_ARG(ndev) ndev->name ++#define ADPT_FMT "%s" ++#define ADPT_ARG(adapter) adapter->pnetdev->name ++#define FUNC_NDEV_FMT "%s(%s)" ++#define FUNC_NDEV_ARG(ndev) __func__, ndev->name ++#define FUNC_ADPT_FMT "%s(%s)" ++#define FUNC_ADPT_ARG(adapter) __func__, adapter->pnetdev->name ++ ++struct rtw_netdev_priv_indicator { ++ void *priv; ++ u32 sizeof_priv; ++}; ++struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv, void *old_priv); ++extern struct net_device * rtw_alloc_etherdev(int sizeof_priv); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/recv_osdep.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/recv_osdep.h +--- linux-4.3/3rdparty/rtl8723bs/include/recv_osdep.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/recv_osdep.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,48 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RECV_OSDEP_H_ ++#define __RECV_OSDEP_H_ ++ ++ ++extern sint _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter); ++extern void _rtw_free_recv_priv (struct recv_priv *precvpriv); ++ ++ ++extern s32 rtw_recv_entry(union recv_frame *precv_frame); ++extern int rtw_recv_indicatepkt(struct adapter *adapter, union recv_frame *precv_frame); ++extern void rtw_recv_returnpacket(_nic_hdl cnxt, _pkt *preturnedpkt); ++ ++extern void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup); ++ ++int rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter); ++void rtw_free_recv_priv (struct recv_priv *precvpriv); ++ ++ ++int rtw_os_recv_resource_alloc(struct adapter *padapter, union recv_frame *precvframe); ++void rtw_os_recv_resource_free(struct recv_priv *precvpriv); ++ ++ ++void rtw_os_free_recvframe(union recv_frame *precvframe); ++ ++ ++int rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf); ++ ++_pkt *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata); ++void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt_attrib *pattrib); ++ ++void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl); ++ ++ ++#endif /* */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtl8192c_recv.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtl8192c_recv.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtl8192c_recv.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtl8192c_recv.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,50 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef _RTL8192C_RECV_H_ ++#define _RTL8192C_RECV_H_ ++ ++#define RECV_BLK_SZ 512 ++#define RECV_BLK_CNT 16 ++#define RECV_BLK_TH RECV_BLK_CNT ++ ++#define MAX_RECVBUF_SZ (10240) ++ ++struct phy_stat ++{ ++ unsigned int phydw0; ++ ++ unsigned int phydw1; ++ ++ unsigned int phydw2; ++ ++ unsigned int phydw3; ++ ++ unsigned int phydw4; ++ ++ unsigned int phydw5; ++ ++ unsigned int phydw6; ++ ++ unsigned int phydw7; ++}; ++ ++/* Rx smooth factor */ ++#define Rx_Smooth_Factor (20) ++ ++ ++void rtl8192c_translate_rx_signal_stuff(union recv_frame *precvframe, struct phy_stat *pphy_status); ++void rtl8192c_query_rx_desc_status(union recv_frame *precvframe, struct recv_stat *pdesc); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtl8192c_rf.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtl8192c_rf.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtl8192c_rf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtl8192c_rf.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,39 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef _RTL8192C_RF_H_ ++#define _RTL8192C_RF_H_ ++ ++ ++/* */ ++/* RF RL6052 Series API */ ++/* */ ++void rtl8192c_RF_ChangeTxPath(struct adapter *Adapter, ++ u16 DataRate); ++void rtl8192c_PHY_RF6052SetBandwidth( ++ struct adapter * Adapter, ++ enum CHANNEL_WIDTH Bandwidth); ++void rtl8192c_PHY_RF6052SetCckTxPower( ++ struct adapter *Adapter, ++ u8* pPowerlevel); ++void rtl8192c_PHY_RF6052SetOFDMTxPower( ++ struct adapter *Adapter, ++ u8* pPowerLevel, ++ u8 Channel); ++int PHY_RF6052_Config8192C(struct adapter * Adapter ); ++ ++/*--------------------------Exported Function prototype---------------------*/ ++ ++ ++#endif/* End of HalRf.h */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtl8723b_cmd.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtl8723b_cmd.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtl8723b_cmd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtl8723b_cmd.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,199 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTL8723B_CMD_H__ ++#define __RTL8723B_CMD_H__ ++ ++/* */ ++/* H2C CMD DEFINITION ------------------------------------------------ */ ++/* */ ++ ++enum h2c_cmd_8723B{ ++ /* Common Class: 000 */ ++ H2C_8723B_RSVD_PAGE = 0x00, ++ H2C_8723B_MEDIA_STATUS_RPT = 0x01, ++ H2C_8723B_SCAN_ENABLE = 0x02, ++ H2C_8723B_KEEP_ALIVE = 0x03, ++ H2C_8723B_DISCON_DECISION = 0x04, ++ H2C_8723B_PSD_OFFLOAD = 0x05, ++ H2C_8723B_AP_OFFLOAD = 0x08, ++ H2C_8723B_BCN_RSVDPAGE = 0x09, ++ H2C_8723B_PROBERSP_RSVDPAGE = 0x0A, ++ H2C_8723B_FCS_RSVDPAGE = 0x10, ++ H2C_8723B_FCS_INFO = 0x11, ++ H2C_8723B_AP_WOW_GPIO_CTRL = 0x13, ++ ++ /* PoweSave Class: 001 */ ++ H2C_8723B_SET_PWR_MODE = 0x20, ++ H2C_8723B_PS_TUNING_PARA = 0x21, ++ H2C_8723B_PS_TUNING_PARA2 = 0x22, ++ H2C_8723B_P2P_LPS_PARAM = 0x23, ++ H2C_8723B_P2P_PS_OFFLOAD = 0x24, ++ H2C_8723B_PS_SCAN_ENABLE = 0x25, ++ H2C_8723B_SAP_PS_ = 0x26, ++ H2C_8723B_INACTIVE_PS_ = 0x27, /* Inactive_PS */ ++ H2C_8723B_FWLPS_IN_IPS_ = 0x28, ++ ++ /* Dynamic Mechanism Class: 010 */ ++ H2C_8723B_MACID_CFG = 0x40, ++ H2C_8723B_TXBF = 0x41, ++ H2C_8723B_RSSI_SETTING = 0x42, ++ H2C_8723B_AP_REQ_TXRPT = 0x43, ++ H2C_8723B_INIT_RATE_COLLECT = 0x44, ++ ++ /* BT Class: 011 */ ++ H2C_8723B_B_TYPE_TDMA = 0x60, ++ H2C_8723B_BT_INFO = 0x61, ++ H2C_8723B_FORCE_BT_TXPWR = 0x62, ++ H2C_8723B_BT_IGNORE_WLANACT = 0x63, ++ H2C_8723B_DAC_SWING_VALUE = 0x64, ++ H2C_8723B_ANT_SEL_RSV = 0x65, ++ H2C_8723B_WL_OPMODE = 0x66, ++ H2C_8723B_BT_MP_OPER = 0x67, ++ H2C_8723B_BT_CONTROL = 0x68, ++ H2C_8723B_BT_WIFI_CTRL = 0x69, ++ H2C_8723B_BT_FW_PATCH = 0x6A, ++ H2C_8723B_BT_WLAN_CALIBRATION = 0x6D, ++ ++ /* WOWLAN Class: 100 */ ++ H2C_8723B_WOWLAN = 0x80, ++ H2C_8723B_REMOTE_WAKE_CTRL = 0x81, ++ H2C_8723B_AOAC_GLOBAL_INFO = 0x82, ++ H2C_8723B_AOAC_RSVD_PAGE = 0x83, ++ H2C_8723B_AOAC_RSVD_PAGE2 = 0x84, ++ H2C_8723B_D0_SCAN_OFFLOAD_CTRL = 0x85, ++ H2C_8723B_D0_SCAN_OFFLOAD_INFO = 0x86, ++ H2C_8723B_CHNL_SWITCH_OFFLOAD = 0x87, ++ ++ H2C_8723B_RESET_TSF = 0xC0, ++ H2C_8723B_MAXID, ++}; ++/* */ ++/* H2C CMD CONTENT -------------------------------------------------- */ ++/* */ ++/* _RSVDPAGE_LOC_CMD_0x00 */ ++#define SET_8723B_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd, 0, 8, __Value) ++#define SET_8723B_H2CCMD_RSVDPAGE_LOC_PSPOLL(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+1, 0, 8, __Value) ++#define SET_8723B_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+2, 0, 8, __Value) ++#define SET_8723B_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+3, 0, 8, __Value) ++#define SET_8723B_H2CCMD_RSVDPAGE_LOC_BT_QOS_NULL_DATA(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+4, 0, 8, __Value) ++ ++/* _MEDIA_STATUS_RPT_PARM_CMD_0x01 */ ++#define SET_8723B_H2CCMD_MSRRPT_PARM_OPMODE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 1, __Value) ++#define SET_8723B_H2CCMD_MSRRPT_PARM_MACID_IND(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 1, 1, __Value) ++#define SET_8723B_H2CCMD_MSRRPT_PARM_MACID(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd+1, 0, 8, __Value) ++#define SET_8723B_H2CCMD_MSRRPT_PARM_MACID_END(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd+2, 0, 8, __Value) ++ ++/* _KEEP_ALIVE_CMD_0x03 */ ++#define SET_8723B_H2CCMD_KEEPALIVE_PARM_ENABLE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 1, __Value) ++#define SET_8723B_H2CCMD_KEEPALIVE_PARM_ADOPT(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 1, 1, __Value) ++#define SET_8723B_H2CCMD_KEEPALIVE_PARM_PKT_TYPE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 2, 1, __Value) ++#define SET_8723B_H2CCMD_KEEPALIVE_PARM_CHECK_PERIOD(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd+1, 0, 8, __Value) ++ ++/* _DISCONNECT_DECISION_CMD_0x04 */ ++#define SET_8723B_H2CCMD_DISCONDECISION_PARM_ENABLE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 1, __Value) ++#define SET_8723B_H2CCMD_DISCONDECISION_PARM_ADOPT(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 1, 1, __Value) ++#define SET_8723B_H2CCMD_DISCONDECISION_PARM_CHECK_PERIOD(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd+1, 0, 8, __Value) ++#define SET_8723B_H2CCMD_DISCONDECISION_PARM_TRY_PKT_NUM(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd+2, 0, 8, __Value) ++ ++/* _PWR_MOD_CMD_0x20 */ ++#define SET_8723B_H2CCMD_PWRMODE_PARM_MODE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd, 0, 8, __Value) ++#define SET_8723B_H2CCMD_PWRMODE_PARM_RLBM(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd)+1, 0, 4, __Value) ++#define SET_8723B_H2CCMD_PWRMODE_PARM_SMART_PS(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd)+1, 4, 4, __Value) ++#define SET_8723B_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+2, 0, 8, __Value) ++#define SET_8723B_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+3, 0, 8, __Value) ++#define SET_8723B_H2CCMD_PWRMODE_PARM_PWR_STATE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+4, 0, 8, __Value) ++#define SET_8723B_H2CCMD_PWRMODE_PARM_BYTE5(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT((__pH2CCmd)+5, 0, 8, __Value) ++ ++#define GET_8723B_H2CCMD_PWRMODE_PARM_MODE(__pH2CCmd) LE_BITS_TO_1BYTE(__pH2CCmd, 0, 8) ++ ++/* _PS_TUNE_PARAM_CMD_0x21 */ ++#define SET_8723B_H2CCMD_PSTUNE_PARM_BCN_TO_LIMIT(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 8, __Value) ++#define SET_8723B_H2CCMD_PSTUNE_PARM_DTIM_TIMEOUT(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+1, 0, 8, __Value) ++#define SET_8723B_H2CCMD_PSTUNE_PARM_ADOPT(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+2, 0, 1, __Value) ++#define SET_8723B_H2CCMD_PSTUNE_PARM_PS_TIMEOUT(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+2, 1, 7, __Value) ++#define SET_8723B_H2CCMD_PSTUNE_PARM_DTIM_PERIOD(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+3, 0, 8, __Value) ++ ++/* _MACID_CFG_CMD_0x40 */ ++#define SET_8723B_H2CCMD_MACID_CFG_MACID(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 8, __Value) ++#define SET_8723B_H2CCMD_MACID_CFG_RAID(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+1, 0, 5, __Value) ++#define SET_8723B_H2CCMD_MACID_CFG_SGI_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+1, 7, 1, __Value) ++#define SET_8723B_H2CCMD_MACID_CFG_BW(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+2, 0, 2, __Value) ++#define SET_8723B_H2CCMD_MACID_CFG_NO_UPDATE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+2, 3, 1, __Value) ++#define SET_8723B_H2CCMD_MACID_CFG_VHT_EN(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+2, 4, 2, __Value) ++#define SET_8723B_H2CCMD_MACID_CFG_DISPT(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+2, 6, 1, __Value) ++#define SET_8723B_H2CCMD_MACID_CFG_DISRA(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+2, 7, 1, __Value) ++#define SET_8723B_H2CCMD_MACID_CFG_RATE_MASK0(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+3, 0, 8, __Value) ++#define SET_8723B_H2CCMD_MACID_CFG_RATE_MASK1(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+4, 0, 8, __Value) ++#define SET_8723B_H2CCMD_MACID_CFG_RATE_MASK2(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+5, 0, 8, __Value) ++#define SET_8723B_H2CCMD_MACID_CFG_RATE_MASK3(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+6, 0, 8, __Value) ++ ++/* _RSSI_SETTING_CMD_0x42 */ ++#define SET_8723B_H2CCMD_RSSI_SETTING_MACID(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 8, __Value) ++#define SET_8723B_H2CCMD_RSSI_SETTING_RSSI(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+2, 0, 7, __Value) ++#define SET_8723B_H2CCMD_RSSI_SETTING_ULDL_STATE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+3, 0, 8, __Value) ++ ++/* _AP_REQ_TXRPT_CMD_0x43 */ ++#define SET_8723B_H2CCMD_APREQRPT_PARM_MACID1(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 8, __Value) ++#define SET_8723B_H2CCMD_APREQRPT_PARM_MACID2(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+1, 0, 8, __Value) ++ ++/* _FORCE_BT_TXPWR_CMD_0x62 */ ++#define SET_8723B_H2CCMD_BT_PWR_IDX(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd, 0, 8, __Value) ++ ++/* _FORCE_BT_MP_OPER_CMD_0x67 */ ++#define SET_8723B_H2CCMD_BT_MPOPER_VER(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 4, __Value) ++#define SET_8723B_H2CCMD_BT_MPOPER_REQNUM(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 4, 4, __Value) ++#define SET_8723B_H2CCMD_BT_MPOPER_IDX(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+1, 0, 8, __Value) ++#define SET_8723B_H2CCMD_BT_MPOPER_PARAM1(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+2, 0, 8, __Value) ++#define SET_8723B_H2CCMD_BT_MPOPER_PARAM2(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+3, 0, 8, __Value) ++#define SET_8723B_H2CCMD_BT_MPOPER_PARAM3(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd+4, 0, 8, __Value) ++ ++/* _BT_FW_PATCH_0x6A */ ++#define SET_8723B_H2CCMD_BT_FW_PATCH_SIZE(__pH2CCmd, __Value) SET_BITS_TO_LE_2BYTE((u8 *)(__pH2CCmd), 0, 16, __Value) ++#define SET_8723B_H2CCMD_BT_FW_PATCH_ADDR0(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd)+2, 0, 8, __Value) ++#define SET_8723B_H2CCMD_BT_FW_PATCH_ADDR1(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd)+3, 0, 8, __Value) ++#define SET_8723B_H2CCMD_BT_FW_PATCH_ADDR2(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd)+4, 0, 8, __Value) ++#define SET_8723B_H2CCMD_BT_FW_PATCH_ADDR3(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE((__pH2CCmd)+5, 0, 8, __Value) ++ ++/* */ ++/* Function Statement -------------------------------------------------- */ ++/* */ ++ ++/* host message to firmware cmd */ ++void rtl8723b_set_FwPwrMode_cmd(struct adapter *padapter, u8 Mode); ++void rtl8723b_set_FwJoinBssRpt_cmd(struct adapter *padapter, u8 mstatus); ++void rtl8723b_set_rssi_cmd(struct adapter *padapter, u8 *param); ++void rtl8723b_Add_RateATid(struct adapter *padapter, u32 bitmap, u8 *arg, u8 rssi_level); ++void rtl8723b_fw_try_ap_cmd(struct adapter *padapter, u32 need_ack); ++/* s32 rtl8723b_set_lowpwr_lps_cmd(struct adapter *padapter, u8 enable); */ ++void rtl8723b_set_FwPsTuneParam_cmd(struct adapter *padapter); ++void rtl8723b_set_FwMacIdConfig_cmd(struct adapter *padapter, u8 mac_id, u8 raid, u8 bw, u8 sgi, u32 mask); ++void rtl8723b_set_FwMediaStatusRpt_cmd(struct adapter *padapter, u8 mstatus, u8 macid); ++void rtl8723b_download_rsvd_page(struct adapter *padapter, u8 mstatus); ++void rtl8723b_download_BTCoex_AP_mode_rsvd_page(struct adapter *padapter); ++ ++void CheckFwRsvdPageContent(struct adapter *padapter); ++ ++#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) ++void rtl8723b_set_wowlan_cmd(struct adapter *padapter, u8 enable); ++void rtl8723b_set_ap_wowlan_cmd(struct adapter *padapter, u8 enable); ++void SetFwRelatedForWoWLAN8723b(struct adapter *padapter, u8 bHostIsGoingtoSleep); ++#endif/* CONFIG_WOWLAN */ ++ ++void rtl8723b_set_FwPwrModeInIPS_cmd(struct adapter *padapter, u8 cmd_param); ++ ++s32 FillH2CCmd8723B(struct adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer); ++ ++#define FillH2CCmd FillH2CCmd8723B ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtl8723b_dm.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtl8723b_dm.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtl8723b_dm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtl8723b_dm.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,41 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTL8723B_DM_H__ ++#define __RTL8723B_DM_H__ ++/* */ ++/* Description: */ ++/* */ ++/* This file is for 8723B dynamic mechanism only */ ++/* */ ++/* */ ++/* */ ++ ++/* */ ++/* structure and define */ ++/* */ ++ ++/* */ ++/* function prototype */ ++/* */ ++ ++void rtl8723b_init_dm_priv(struct adapter *padapter); ++ ++void rtl8723b_InitHalDm(struct adapter *padapter); ++void rtl8723b_HalDmWatchDog(struct adapter *padapter); ++void rtl8723b_HalDmWatchDog_in_LPS(struct adapter *padapter); ++void rtl8723b_hal_dm_in_lps(struct adapter *padapter); ++ ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtl8723b_hal.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtl8723b_hal.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtl8723b_hal.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtl8723b_hal.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,279 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTL8723B_HAL_H__ ++#define __RTL8723B_HAL_H__ ++ ++#include "hal_data.h" ++ ++#include "rtl8723b_spec.h" ++#include "rtl8723b_rf.h" ++#include "rtl8723b_dm.h" ++#include "rtl8723b_recv.h" ++#include "rtl8723b_xmit.h" ++#include "rtl8723b_cmd.h" ++#include "rtw_mp.h" ++#include "Hal8723BPwrSeq.h" ++#include "Hal8723BPhyReg.h" ++#include "Hal8723BPhyCfg.h" ++ ++/* */ ++/* RTL8723B From file */ ++/* */ ++ #define RTL8723B_FW_IMG "rtl8723b/FW_NIC.bin" ++ #define RTL8723B_FW_WW_IMG "rtl8723b/FW_WoWLAN.bin" ++ #define RTL8723B_PHY_REG "rtl8723b/PHY_REG.txt" ++ #define RTL8723B_PHY_RADIO_A "rtl8723b/RadioA.txt" ++ #define RTL8723B_PHY_RADIO_B "rtl8723b/RadioB.txt" ++ #define RTL8723B_TXPWR_TRACK "rtl8723b/TxPowerTrack.txt" ++ #define RTL8723B_AGC_TAB "rtl8723b/AGC_TAB.txt" ++ #define RTL8723B_PHY_MACREG "rtl8723b/MAC_REG.txt" ++ #define RTL8723B_PHY_REG_PG "rtl8723b/PHY_REG_PG.txt" ++ #define RTL8723B_PHY_REG_MP "rtl8723b/PHY_REG_MP.txt" ++ #define RTL8723B_TXPWR_LMT "rtl8723b/TXPWR_LMT.txt" ++ ++/* */ ++/* RTL8723B From header */ ++/* */ ++ ++#define FW_8723B_SIZE 0x8000 ++#define FW_8723B_START_ADDRESS 0x1000 ++#define FW_8723B_END_ADDRESS 0x1FFF /* 0x5FFF */ ++ ++#define IS_FW_HEADER_EXIST_8723B(_pFwHdr) ((le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x5300) ++ ++struct rt_firmware { ++ u32 ulFwLength; ++ u8 *szFwBuffer; ++}; ++ ++/* This structure must be cared byte-ordering */ ++struct rt_firmware_hdr { ++ /* 8-byte alinment required */ ++ ++ /* LONG WORD 0 ---- */ ++ __le16 Signature; /* 92C0: test chip; 92C, 88C0: test chip; 88C1: MP A-cut; 92C1: MP A-cut */ ++ u8 Category; /* AP/NIC and USB/PCI */ ++ u8 Function; /* Reserved for different FW function indcation, for further use when driver needs to download different FW in different conditions */ ++ __le16 Version; /* FW Version */ ++ __le16 Subversion; /* FW Subversion, default 0x00 */ ++ ++ /* LONG WORD 1 ---- */ ++ u8 Month; /* Release time Month field */ ++ u8 Date; /* Release time Date field */ ++ u8 Hour; /* Release time Hour field */ ++ u8 Minute; /* Release time Minute field */ ++ __le16 RamCodeSize; /* The size of RAM code */ ++ __le16 Rsvd2; ++ ++ /* LONG WORD 2 ---- */ ++ __le32 SvnIdx; /* The SVN entry index */ ++ __le32 Rsvd3; ++ ++ /* LONG WORD 3 ---- */ ++ __le32 Rsvd4; ++ __le32 Rsvd5; ++}; ++ ++#define DRIVER_EARLY_INT_TIME_8723B 0x05 ++#define BCN_DMA_ATIME_INT_TIME_8723B 0x02 ++ ++/* for 8723B */ ++/* TX 32K, RX 16K, Page size 128B for TX, 8B for RX */ ++#define PAGE_SIZE_TX_8723B 128 ++#define PAGE_SIZE_RX_8723B 8 ++ ++#define RX_DMA_SIZE_8723B 0x4000 /* 16K */ ++#define RX_DMA_RESERVED_SIZE_8723B 0x80 /* 128B, reserved for tx report */ ++#define RX_DMA_BOUNDARY_8723B (RX_DMA_SIZE_8723B - RX_DMA_RESERVED_SIZE_8723B - 1) ++ ++ ++/* Note: We will divide number of page equally for each queue other than public queue! */ ++ ++/* For General Reserved Page Number(Beacon Queue is reserved page) */ ++/* Beacon:2, PS-Poll:1, Null Data:1, Qos Null Data:1, BT Qos Null Data:1 */ ++#define BCNQ_PAGE_NUM_8723B 0x08 ++#define BCNQ1_PAGE_NUM_8723B 0x00 ++ ++#ifdef CONFIG_PNO_SUPPORT ++#undef BCNQ1_PAGE_NUM_8723B ++#define BCNQ1_PAGE_NUM_8723B 0x00 /* 0x04 */ ++#endif ++#define MAX_RX_DMA_BUFFER_SIZE_8723B 0x2800 /* RX 10K */ ++ ++/* For WoWLan , more reserved page */ ++/* ARP Rsp:1, RWC:1, GTK Info:1, GTK RSP:2, GTK EXT MEM:2, PNO: 6 */ ++#ifdef CONFIG_WOWLAN ++#define WOWLAN_PAGE_NUM_8723B 0x07 ++#else ++#define WOWLAN_PAGE_NUM_8723B 0x00 ++#endif ++ ++#ifdef CONFIG_PNO_SUPPORT ++#undef WOWLAN_PAGE_NUM_8723B ++#define WOWLAN_PAGE_NUM_8723B 0x0d ++#endif ++ ++#ifdef CONFIG_AP_WOWLAN ++#define AP_WOWLAN_PAGE_NUM_8723B 0x02 ++#endif ++ ++#define TX_TOTAL_PAGE_NUMBER_8723B (0xFF - BCNQ_PAGE_NUM_8723B - BCNQ1_PAGE_NUM_8723B - WOWLAN_PAGE_NUM_8723B) ++#define TX_PAGE_BOUNDARY_8723B (TX_TOTAL_PAGE_NUMBER_8723B + 1) ++ ++#define WMM_NORMAL_TX_TOTAL_PAGE_NUMBER_8723B TX_TOTAL_PAGE_NUMBER_8723B ++#define WMM_NORMAL_TX_PAGE_BOUNDARY_8723B (WMM_NORMAL_TX_TOTAL_PAGE_NUMBER_8723B + 1) ++ ++/* For Normal Chip Setting */ ++/* (HPQ + LPQ + NPQ + PUBQ) shall be TX_TOTAL_PAGE_NUMBER_8723B */ ++#define NORMAL_PAGE_NUM_HPQ_8723B 0x0C ++#define NORMAL_PAGE_NUM_LPQ_8723B 0x02 ++#define NORMAL_PAGE_NUM_NPQ_8723B 0x02 ++ ++/* Note: For Normal Chip Setting, modify later */ ++#define WMM_NORMAL_PAGE_NUM_HPQ_8723B 0x30 ++#define WMM_NORMAL_PAGE_NUM_LPQ_8723B 0x20 ++#define WMM_NORMAL_PAGE_NUM_NPQ_8723B 0x20 ++ ++ ++#include "HalVerDef.h" ++#include "hal_com.h" ++ ++#define EFUSE_OOB_PROTECT_BYTES 15 ++ ++#define HAL_EFUSE_MEMORY ++ ++#define HWSET_MAX_SIZE_8723B 512 ++#define EFUSE_REAL_CONTENT_LEN_8723B 512 ++#define EFUSE_MAP_LEN_8723B 512 ++#define EFUSE_MAX_SECTION_8723B 64 ++ ++#define EFUSE_IC_ID_OFFSET 506 /* For some inferiority IC purpose. added by Roger, 2009.09.02. */ ++#define AVAILABLE_EFUSE_ADDR(addr) (addr < EFUSE_REAL_CONTENT_LEN_8723B) ++ ++#define EFUSE_ACCESS_ON 0x69 /* For RTL8723 only. */ ++#define EFUSE_ACCESS_OFF 0x00 /* For RTL8723 only. */ ++ ++/* */ ++/* EFUSE for BT definition */ ++/* */ ++#define EFUSE_BT_REAL_BANK_CONTENT_LEN 512 ++#define EFUSE_BT_REAL_CONTENT_LEN 1536 /* 512*3 */ ++#define EFUSE_BT_MAP_LEN 1024 /* 1k bytes */ ++#define EFUSE_BT_MAX_SECTION 128 /* 1024/8 */ ++ ++#define EFUSE_PROTECT_BYTES_BANK 16 ++ ++/* Description: Determine the types of C2H events that are the same in driver and Fw. */ ++/* Fisrt constructed by tynli. 2009.10.09. */ ++typedef enum _C2H_EVT ++{ ++ C2H_DBG = 0, ++ C2H_TSF = 1, ++ C2H_AP_RPT_RSP = 2, ++ C2H_CCX_TX_RPT = 3, /* The FW notify the report of the specific tx packet. */ ++ C2H_BT_RSSI = 4, ++ C2H_BT_OP_MODE = 5, ++ C2H_EXT_RA_RPT = 6, ++ C2H_8723B_BT_INFO = 9, ++ C2H_HW_INFO_EXCH = 10, ++ C2H_8723B_BT_MP_INFO = 11, ++ MAX_C2HEVENT ++} C2H_EVT; ++ ++typedef struct _C2H_EVT_HDR ++{ ++ u8 CmdID; ++ u8 CmdLen; ++ u8 CmdSeq; ++} __attribute__((__packed__)) C2H_EVT_HDR, *PC2H_EVT_HDR; ++ ++typedef enum tag_Package_Definition ++{ ++ PACKAGE_DEFAULT, ++ PACKAGE_QFN68, ++ PACKAGE_TFBGA90, ++ PACKAGE_TFBGA80, ++ PACKAGE_TFBGA79 ++}PACKAGE_TYPE_E; ++ ++#define INCLUDE_MULTI_FUNC_BT(_Adapter) (GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_BT) ++#define INCLUDE_MULTI_FUNC_GPS(_Adapter) (GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_GPS) ++ ++/* rtl8723a_hal_init.c */ ++s32 rtl8723b_FirmwareDownload(struct adapter *padapter, bool bUsedWoWLANFw); ++void rtl8723b_FirmwareSelfReset(struct adapter *padapter); ++void rtl8723b_InitializeFirmwareVars(struct adapter *padapter); ++ ++void rtl8723b_InitAntenna_Selection(struct adapter *padapter); ++void rtl8723b_init_default_value(struct adapter *padapter); ++ ++s32 rtl8723b_InitLLTTable(struct adapter *padapter); ++ ++/* EFuse */ ++u8 GetEEPROMSize8723B(struct adapter *padapter); ++void Hal_InitPGData(struct adapter *padapter, u8 *PROMContent); ++void Hal_EfuseParseIDCode(struct adapter *padapter, u8 *hwinfo); ++void Hal_EfuseParseTxPowerInfo_8723B(struct adapter *padapter, u8 *PROMContent, bool AutoLoadFail); ++void Hal_EfuseParseBTCoexistInfo_8723B(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail); ++void Hal_EfuseParseEEPROMVer_8723B(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail); ++void Hal_EfuseParseChnlPlan_8723B(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail); ++void Hal_EfuseParseCustomerID_8723B(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail); ++void Hal_EfuseParseAntennaDiversity_8723B(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail); ++void Hal_EfuseParseXtal_8723B(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail); ++void Hal_EfuseParseThermalMeter_8723B(struct adapter *padapter, u8 *hwinfo, u8 AutoLoadFail); ++void Hal_EfuseParsePackageType_8723B(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail); ++void Hal_EfuseParseVoltage_8723B(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail); ++ ++void C2HPacketHandler_8723B(struct adapter *padapter, u8 *pbuffer, u16 length); ++ ++void rtl8723b_set_hal_ops(struct hal_ops *pHalFunc); ++void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val); ++void GetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val); ++u8 SetHalDefVar8723B(struct adapter *padapter, enum HAL_DEF_VARIABLE variable, void *pval); ++u8 GetHalDefVar8723B(struct adapter *padapter, enum HAL_DEF_VARIABLE variable, void *pval); ++ ++/* register */ ++void rtl8723b_InitBeaconParameters(struct adapter *padapter); ++void _InitBurstPktLen_8723BS(struct adapter * Adapter); ++void _8051Reset8723(struct adapter *padapter); ++#ifdef CONFIG_WOWLAN ++void Hal_DetectWoWMode(struct adapter *padapter); ++#endif /* CONFIG_WOWLAN */ ++ ++void rtl8723b_start_thread(struct adapter *padapter); ++void rtl8723b_stop_thread(struct adapter *padapter); ++ ++#if defined(CONFIG_CHECK_BT_HANG) ++void rtl8723bs_init_checkbthang_workqueue(struct adapter * adapter); ++void rtl8723bs_free_checkbthang_workqueue(struct adapter * adapter); ++void rtl8723bs_cancle_checkbthang_workqueue(struct adapter * adapter); ++void rtl8723bs_hal_check_bt_hang(struct adapter * adapter); ++#endif ++ ++#ifdef CONFIG_GPIO_WAKEUP ++void HalSetOutPutGPIO(struct adapter *padapter, u8 index, u8 OutPutValue); ++#endif ++ ++int FirmwareDownloadBT(struct adapter * Adapter, struct rt_firmware *firmware); ++ ++void CCX_FwC2HTxRpt_8723b(struct adapter *padapter, u8 *pdata, u8 len); ++s32 c2h_id_filter_ccx_8723b(u8 *buf); ++s32 c2h_handler_8723b(struct adapter *padapter, u8 *pC2hEvent); ++u8 MRateToHwRate8723B(u8 rate); ++u8 HwRateToMRate8723B(u8 rate); ++ ++void Hal_ReadRFGainOffset(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtl8723b_recv.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtl8723b_recv.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtl8723b_recv.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtl8723b_recv.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,144 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTL8723B_RECV_H__ ++#define __RTL8723B_RECV_H__ ++ ++#include ++ ++typedef struct rxreport_8723b ++{ ++ /* DWORD 0 */ ++ u32 pktlen:14; ++ u32 crc32:1; ++ u32 icverr:1; ++ u32 drvinfosize:4; ++ u32 security:3; ++ u32 qos:1; ++ u32 shift:2; ++ u32 physt:1; ++ u32 swdec:1; ++ u32 rsvd0028:2; ++ u32 eor:1; ++ u32 rsvd0031:1; ++ ++ /* DWORD 1 */ ++ u32 macid:7; ++ u32 rsvd0407:1; ++ u32 tid:4; ++ u32 macid_vld:1; ++ u32 amsdu:1; ++ u32 rxid_match:1; ++ u32 paggr:1; ++ u32 a1fit:4; ++ u32 chkerr:1; /* 20 */ ++ u32 rx_ipv:1; ++ u32 rx_is_tcp_udp:1; ++ u32 chk_vld:1; /* 23 */ ++ u32 pam:1; ++ u32 pwr:1; ++ u32 md:1; ++ u32 mf:1; ++ u32 type:2; ++ u32 mc:1; ++ u32 bc:1; ++ ++ /* DWORD 2 */ ++ u32 seq:12; ++ u32 frag:4; ++ u32 rx_is_qos:1; ++ u32 rsvd0817:1; ++ u32 wlanhd_iv_len:6; ++ u32 hwrsvd0824:4; ++ u32 c2h_ind:1; ++ u32 rsvd0829:2; ++ u32 fcs_ok:1; ++ ++ /* DWORD 3 */ ++ u32 rx_rate:7; ++ u32 rsvd1207:3; ++ u32 htc:1; ++ u32 esop:1; ++ u32 bssid_fit:2; ++ u32 rsvd1214:2; ++ u32 dma_agg_num:8; ++ u32 rsvd1224:5; ++ u32 patternmatch:1; ++ u32 unicastwake:1; ++ u32 magicwake:1; ++ ++ /* DWORD 4 */ ++ u32 splcp:1; /* Ofdm sgi or cck_splcp */ ++ u32 ldpc:1; ++ u32 stbc:1; ++ u32 not_sounding:1; ++ u32 bw:2; ++ u32 rsvd1606:26; ++ ++ /* DWORD 5 */ ++ u32 tsfl; ++} RXREPORT, *PRXREPORT; ++ ++typedef struct phystatus_8723b ++{ ++ u32 rxgain_a:7; ++ u32 trsw_a:1; ++ u32 rxgain_b:7; ++ u32 trsw_b:1; ++ u32 chcorr_l:16; ++ ++ u32 sigqualcck:8; ++ u32 cfo_a:8; ++ u32 cfo_b:8; ++ u32 chcorr_h:8; ++ ++ u32 noisepwrdb_h:8; ++ u32 cfo_tail_a:8; ++ u32 cfo_tail_b:8; ++ u32 rsvd0824:8; ++ ++ u32 rsvd1200:8; ++ u32 rxevm_a:8; ++ u32 rxevm_b:8; ++ u32 rxsnr_a:8; ++ ++ u32 rxsnr_b:8; ++ u32 noisepwrdb_l:8; ++ u32 rsvd1616:8; ++ u32 postsnr_a:8; ++ ++ u32 postsnr_b:8; ++ u32 csi_a:8; ++ u32 csi_b:8; ++ u32 targetcsi_a:8; ++ ++ u32 targetcsi_b:8; ++ u32 sigevm:8; ++ u32 maxexpwr:8; ++ u32 exintflag:1; ++ u32 sgien:1; ++ u32 rxsc:2; ++ u32 idlelong:1; ++ u32 anttrainen:1; ++ u32 antselb:1; ++ u32 antsel:1; ++} PHYSTATUS, *PPHYSTATUS; ++ ++s32 rtl8723bs_init_recv_priv(struct adapter *padapter); ++void rtl8723bs_free_recv_priv(struct adapter *padapter); ++ ++void rtl8723b_query_rx_phy_status(union recv_frame *prframe, struct phy_stat *pphy_stat); ++void rtl8723b_process_phy_info(struct adapter *padapter, void *prframe); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtl8723b_rf.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtl8723b_rf.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtl8723b_rf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtl8723b_rf.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,26 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTL8723B_RF_H__ ++#define __RTL8723B_RF_H__ ++ ++#include "rtl8192c_rf.h" ++ ++int PHY_RF6052_Config8723B(struct adapter *Adapter ); ++ ++void ++PHY_RF6052SetBandwidth8723B(struct adapter *Adapter, ++ enum CHANNEL_WIDTH Bandwidth); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtl8723b_spec.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtl8723b_spec.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtl8723b_spec.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtl8723b_spec.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,262 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ *******************************************************************************/ ++#ifndef __RTL8723B_SPEC_H__ ++#define __RTL8723B_SPEC_H__ ++ ++#include ++ ++ ++#define HAL_NAV_UPPER_UNIT_8723B 128 /* micro-second */ ++ ++/* */ ++/* */ ++/* 0x0000h ~ 0x00FFh System Configuration */ ++/* */ ++/* */ ++#define REG_RSV_CTRL_8723B 0x001C /* 3 Byte */ ++#define REG_BT_WIFI_ANTENNA_SWITCH_8723B 0x0038 ++#define REG_HSISR_8723B 0x005c ++#define REG_PAD_CTRL1_8723B 0x0064 ++#define REG_AFE_CTRL_4_8723B 0x0078 ++#define REG_HMEBOX_DBG_0_8723B 0x0088 ++#define REG_HMEBOX_DBG_1_8723B 0x008A ++#define REG_HMEBOX_DBG_2_8723B 0x008C ++#define REG_HMEBOX_DBG_3_8723B 0x008E ++#define REG_HIMR0_8723B 0x00B0 ++#define REG_HISR0_8723B 0x00B4 ++#define REG_HIMR1_8723B 0x00B8 ++#define REG_HISR1_8723B 0x00BC ++#define REG_PMC_DBG_CTRL2_8723B 0x00CC ++ ++/* */ ++/* */ ++/* 0x0100h ~ 0x01FFh MACTOP General Configuration */ ++/* */ ++/* */ ++#define REG_C2HEVT_CMD_ID_8723B 0x01A0 ++#define REG_C2HEVT_CMD_LEN_8723B 0x01AE ++#define REG_WOWLAN_WAKE_REASON 0x01C7 ++#define REG_WOWLAN_GTK_DBG1 0x630 ++#define REG_WOWLAN_GTK_DBG2 0x634 ++ ++#define REG_HMEBOX_EXT0_8723B 0x01F0 ++#define REG_HMEBOX_EXT1_8723B 0x01F4 ++#define REG_HMEBOX_EXT2_8723B 0x01F8 ++#define REG_HMEBOX_EXT3_8723B 0x01FC ++ ++/* */ ++/* */ ++/* 0x0200h ~ 0x027Fh TXDMA Configuration */ ++/* */ ++/* */ ++ ++/* */ ++/* */ ++/* 0x0280h ~ 0x02FFh RXDMA Configuration */ ++/* */ ++/* */ ++#define REG_RXDMA_CONTROL_8723B 0x0286 /* Control the RX DMA. */ ++#define REG_RXDMA_MODE_CTRL_8723B 0x0290 ++ ++/* */ ++/* */ ++/* 0x0300h ~ 0x03FFh PCIe */ ++/* */ ++/* */ ++#define REG_PCIE_CTRL_REG_8723B 0x0300 ++#define REG_INT_MIG_8723B 0x0304 /* Interrupt Migration */ ++#define REG_BCNQ_DESA_8723B 0x0308 /* TX Beacon Descriptor Address */ ++#define REG_HQ_DESA_8723B 0x0310 /* TX High Queue Descriptor Address */ ++#define REG_MGQ_DESA_8723B 0x0318 /* TX Manage Queue Descriptor Address */ ++#define REG_VOQ_DESA_8723B 0x0320 /* TX VO Queue Descriptor Address */ ++#define REG_VIQ_DESA_8723B 0x0328 /* TX VI Queue Descriptor Address */ ++#define REG_BEQ_DESA_8723B 0x0330 /* TX BE Queue Descriptor Address */ ++#define REG_BKQ_DESA_8723B 0x0338 /* TX BK Queue Descriptor Address */ ++#define REG_RX_DESA_8723B 0x0340 /* RX Queue Descriptor Address */ ++#define REG_DBI_WDATA_8723B 0x0348 /* DBI Write Data */ ++#define REG_DBI_RDATA_8723B 0x034C /* DBI Read Data */ ++#define REG_DBI_ADDR_8723B 0x0350 /* DBI Address */ ++#define REG_DBI_FLAG_8723B 0x0352 /* DBI Read/Write Flag */ ++#define REG_MDIO_WDATA_8723B 0x0354 /* MDIO for Write PCIE PHY */ ++#define REG_MDIO_RDATA_8723B 0x0356 /* MDIO for Reads PCIE PHY */ ++#define REG_MDIO_CTL_8723B 0x0358 /* MDIO for Control */ ++#define REG_DBG_SEL_8723B 0x0360 /* Debug Selection Register */ ++#define REG_PCIE_HRPWM_8723B 0x0361 /* PCIe RPWM */ ++#define REG_PCIE_HCPWM_8723B 0x0363 /* PCIe CPWM */ ++#define REG_PCIE_MULTIFET_CTRL_8723B 0x036A /* PCIE Multi-Fethc Control */ ++ ++/* */ ++/* */ ++/* 0x0400h ~ 0x047Fh Protocol Configuration */ ++/* */ ++/* */ ++#define REG_TXPKTBUF_BCNQ_BDNY_8723B 0x0424 ++#define REG_TXPKTBUF_MGQ_BDNY_8723B 0x0425 ++#define REG_TXPKTBUF_WMAC_LBK_BF_HD_8723B 0x045D ++#ifdef CONFIG_WOWLAN ++#define REG_TXPKTBUF_IV_LOW 0x0484 ++#define REG_TXPKTBUF_IV_HIGH 0x0488 ++#endif ++#define REG_AMPDU_BURST_MODE_8723B 0x04BC ++ ++/* */ ++/* */ ++/* 0x0500h ~ 0x05FFh EDCA Configuration */ ++/* */ ++/* */ ++#define REG_SECONDARY_CCA_CTRL_8723B 0x0577 ++ ++/* */ ++/* */ ++/* 0x0600h ~ 0x07FFh WMAC Configuration */ ++/* */ ++/* */ ++ ++ ++/* */ ++/* SDIO Bus Specification */ ++/* */ ++ ++/* */ ++/* SDIO CMD Address Mapping */ ++/* */ ++ ++/* */ ++/* I/O bus domain (Host) */ ++/* */ ++ ++/* */ ++/* SDIO register */ ++/* */ ++#define SDIO_REG_HCPWM1_8723B 0x025 /* HCI Current Power Mode 1 */ ++ ++ ++/* */ ++/* 8723 Regsiter Bit and Content definition */ ++/* */ ++ ++/* 2 HSISR */ ++/* interrupt mask which needs to clear */ ++#define MASK_HSISR_CLEAR (HSISR_GPIO12_0_INT |\ ++ HSISR_SPS_OCP_INT |\ ++ HSISR_RON_INT |\ ++ HSISR_PDNINT |\ ++ HSISR_GPIO9_INT) ++ ++/* */ ++/* */ ++/* 0x0100h ~ 0x01FFh MACTOP General Configuration */ ++/* */ ++/* */ ++ ++ ++/* */ ++/* */ ++/* 0x0200h ~ 0x027Fh TXDMA Configuration */ ++/* */ ++/* */ ++ ++/* */ ++/* */ ++/* 0x0280h ~ 0x02FFh RXDMA Configuration */ ++/* */ ++/* */ ++#define BIT_USB_RXDMA_AGG_EN BIT(31) ++#define RXDMA_AGG_MODE_EN BIT(1) ++ ++#ifdef CONFIG_WOWLAN ++#define RXPKT_RELEASE_POLL BIT(16) ++#define RXDMA_IDLE BIT(17) ++#define RW_RELEASE_EN BIT(18) ++#endif ++ ++/* */ ++/* */ ++/* 0x0400h ~ 0x047Fh Protocol Configuration */ ++/* */ ++/* */ ++ ++/* */ ++/* 8723B REG_CCK_CHECK (offset 0x454) */ ++/* */ ++#define BIT_BCN_PORT_SEL BIT5 ++ ++/* */ ++/* */ ++/* 0x0500h ~ 0x05FFh EDCA Configuration */ ++/* */ ++/* */ ++ ++/* */ ++/* */ ++/* 0x0600h ~ 0x07FFh WMAC Configuration */ ++/* */ ++/* */ ++#define EEPROM_RF_GAIN_OFFSET 0xC1 ++#define EEPROM_RF_GAIN_VAL 0x1F6 ++ ++ ++/* */ ++/* 8195 IMR/ISR bits (offset 0xB0, 8bits) */ ++/* */ ++#define IMR_DISABLED_8723B 0 ++/* IMR DW0(0x00B0-00B3) Bit 0-31 */ ++#define IMR_TIMER2_8723B BIT31 /* Timeout interrupt 2 */ ++#define IMR_TIMER1_8723B BIT30 /* Timeout interrupt 1 */ ++#define IMR_PSTIMEOUT_8723B BIT29 /* Power Save Time Out Interrupt */ ++#define IMR_GTINT4_8723B BIT28 /* When GTIMER4 expires, this bit is set to 1 */ ++#define IMR_GTINT3_8723B BIT27 /* When GTIMER3 expires, this bit is set to 1 */ ++#define IMR_TXBCN0ERR_8723B BIT26 /* Transmit Beacon0 Error */ ++#define IMR_TXBCN0OK_8723B BIT25 /* Transmit Beacon0 OK */ ++#define IMR_TSF_BIT32_TOGGLE_8723B BIT24 /* TSF Timer BIT32 toggle indication interrupt */ ++#define IMR_BCNDMAINT0_8723B BIT20 /* Beacon DMA Interrupt 0 */ ++#define IMR_BCNDERR0_8723B BIT16 /* Beacon Queue DMA OK0 */ ++#define IMR_HSISR_IND_ON_INT_8723B BIT15 /* HSISR Indicator (HSIMR & HSISR is true, this bit is set to 1) */ ++#define IMR_BCNDMAINT_E_8723B BIT14 /* Beacon DMA Interrupt Extension for Win7 */ ++#define IMR_ATIMEND_8723B BIT12 /* CTWidnow End or ATIM Window End */ ++#define IMR_C2HCMD_8723B BIT10 /* CPU to Host Command INT Status, Write 1 clear */ ++#define IMR_CPWM2_8723B BIT9 /* CPU power Mode exchange INT Status, Write 1 clear */ ++#define IMR_CPWM_8723B BIT8 /* CPU power Mode exchange INT Status, Write 1 clear */ ++#define IMR_HIGHDOK_8723B BIT7 /* High Queue DMA OK */ ++#define IMR_MGNTDOK_8723B BIT6 /* Management Queue DMA OK */ ++#define IMR_BKDOK_8723B BIT5 /* AC_BK DMA OK */ ++#define IMR_BEDOK_8723B BIT4 /* AC_BE DMA OK */ ++#define IMR_VIDOK_8723B BIT3 /* AC_VI DMA OK */ ++#define IMR_VODOK_8723B BIT2 /* AC_VO DMA OK */ ++#define IMR_RDU_8723B BIT1 /* Rx Descriptor Unavailable */ ++#define IMR_ROK_8723B BIT0 /* Receive DMA OK */ ++ ++/* IMR DW1(0x00B4-00B7) Bit 0-31 */ ++#define IMR_BCNDMAINT7_8723B BIT27 /* Beacon DMA Interrupt 7 */ ++#define IMR_BCNDMAINT6_8723B BIT26 /* Beacon DMA Interrupt 6 */ ++#define IMR_BCNDMAINT5_8723B BIT25 /* Beacon DMA Interrupt 5 */ ++#define IMR_BCNDMAINT4_8723B BIT24 /* Beacon DMA Interrupt 4 */ ++#define IMR_BCNDMAINT3_8723B BIT23 /* Beacon DMA Interrupt 3 */ ++#define IMR_BCNDMAINT2_8723B BIT22 /* Beacon DMA Interrupt 2 */ ++#define IMR_BCNDMAINT1_8723B BIT21 /* Beacon DMA Interrupt 1 */ ++#define IMR_BCNDOK7_8723B BIT20 /* Beacon Queue DMA OK Interrup 7 */ ++#define IMR_BCNDOK6_8723B BIT19 /* Beacon Queue DMA OK Interrup 6 */ ++#define IMR_BCNDOK5_8723B BIT18 /* Beacon Queue DMA OK Interrup 5 */ ++#define IMR_BCNDOK4_8723B BIT17 /* Beacon Queue DMA OK Interrup 4 */ ++#define IMR_BCNDOK3_8723B BIT16 /* Beacon Queue DMA OK Interrup 3 */ ++#define IMR_BCNDOK2_8723B BIT15 /* Beacon Queue DMA OK Interrup 2 */ ++#define IMR_BCNDOK1_8723B BIT14 /* Beacon Queue DMA OK Interrup 1 */ ++#define IMR_ATIMEND_E_8723B BIT13 /* ATIM Window End Extension for Win7 */ ++#define IMR_TXERR_8723B BIT11 /* Tx Error Flag Interrupt Status, write 1 clear. */ ++#define IMR_RXERR_8723B BIT10 /* Rx Error Flag INT Status, Write 1 clear */ ++#define IMR_TXFOVW_8723B BIT9 /* Transmit FIFO Overflow */ ++#define IMR_RXFOVW_8723B BIT8 /* Receive FIFO Overflow */ ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtl8723b_xmit.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtl8723b_xmit.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtl8723b_xmit.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtl8723b_xmit.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,458 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTL8723B_XMIT_H__ ++#define __RTL8723B_XMIT_H__ ++ ++/* */ ++/* Queue Select Value in TxDesc */ ++/* */ ++#define QSLT_BK 0x2/* 0x01 */ ++#define QSLT_BE 0x0 ++#define QSLT_VI 0x5/* 0x4 */ ++#define QSLT_VO 0x7/* 0x6 */ ++#define QSLT_BEACON 0x10 ++#define QSLT_HIGH 0x11 ++#define QSLT_MGNT 0x12 ++#define QSLT_CMD 0x13 ++ ++#define MAX_TID (15) ++ ++/* OFFSET 0 */ ++#define OFFSET_SZ 0 ++#define OFFSET_SHT 16 ++#define BMC BIT(24) ++#define LSG BIT(26) ++#define FSG BIT(27) ++#define OWN BIT(31) ++ ++ ++/* OFFSET 4 */ ++#define PKT_OFFSET_SZ 0 ++#define BK BIT(6) ++#define QSEL_SHT 8 ++#define Rate_ID_SHT 16 ++#define NAVUSEHDR BIT(20) ++#define PKT_OFFSET_SHT 26 ++#define HWPC BIT(31) ++ ++/* OFFSET 8 */ ++#define AGG_EN BIT(29) ++ ++/* OFFSET 12 */ ++#define SEQ_SHT 16 ++ ++/* OFFSET 16 */ ++#define QoS BIT(6) ++#define HW_SEQ_EN BIT(7) ++#define USERATE BIT(8) ++#define DISDATAFB BIT(10) ++#define DATA_SHORT BIT(24) ++#define DATA_BW BIT(25) ++ ++/* OFFSET 20 */ ++#define SGI BIT(6) ++ ++/* */ ++/* defined for TX DESC Operation */ ++/* */ ++typedef struct txdesc_8723b ++{ ++ /* Offset 0 */ ++ u32 pktlen:16; ++ u32 offset:8; ++ u32 bmc:1; ++ u32 htc:1; ++ u32 rsvd0026:1; ++ u32 rsvd0027:1; ++ u32 linip:1; ++ u32 noacm:1; ++ u32 gf:1; ++ u32 rsvd0031:1; ++ ++ /* Offset 4 */ ++ u32 macid:7; ++ u32 rsvd0407:1; ++ u32 qsel:5; ++ u32 rdg_nav_ext:1; ++ u32 lsig_txop_en:1; ++ u32 pifs:1; ++ u32 rate_id:5; ++ u32 en_desc_id:1; ++ u32 sectype:2; ++ u32 pkt_offset:5; /* unit: 8 bytes */ ++ u32 moredata:1; ++ u32 txop_ps_cap:1; ++ u32 txop_ps_mode:1; ++ ++ /* Offset 8 */ ++ u32 p_aid:9; ++ u32 rsvd0809:1; ++ u32 cca_rts:2; ++ u32 agg_en:1; ++ u32 rdg_en:1; ++ u32 null_0:1; ++ u32 null_1:1; ++ u32 bk:1; ++ u32 morefrag:1; ++ u32 raw:1; ++ u32 spe_rpt:1; ++ u32 ampdu_density:3; ++ u32 bt_null:1; ++ u32 g_id:6; ++ u32 rsvd0830:2; ++ ++ /* Offset 12 */ ++ u32 wheader_len:4; ++ u32 chk_en:1; ++ u32 early_rate:1; ++ u32 hw_ssn_sel:2; ++ u32 userate:1; ++ u32 disrtsfb:1; ++ u32 disdatafb:1; ++ u32 cts2self:1; ++ u32 rtsen:1; ++ u32 hw_rts_en:1; ++ u32 port_id:1; ++ u32 navusehdr:1; ++ u32 use_max_len:1; ++ u32 max_agg_num:5; ++ u32 ndpa:2; ++ u32 ampdu_max_time:8; ++ ++ /* Offset 16 */ ++ u32 datarate:7; ++ u32 try_rate:1; ++ u32 data_ratefb_lmt:5; ++ u32 rts_ratefb_lmt:4; ++ u32 rty_lmt_en:1; ++ u32 data_rt_lmt:6; ++ u32 rtsrate:5; ++ u32 pcts_en:1; ++ u32 pcts_mask_idx:2; ++ ++ /* Offset 20 */ ++ u32 data_sc:4; ++ u32 data_short:1; ++ u32 data_bw:2; ++ u32 data_ldpc:1; ++ u32 data_stbc:2; ++ u32 vcs_stbc:2; ++ u32 rts_short:1; ++ u32 rts_sc:4; ++ u32 rsvd2016:7; ++ u32 tx_ant:4; ++ u32 txpwr_offset:3; ++ u32 rsvd2031:1; ++ ++ /* Offset 24 */ ++ u32 sw_define:12; ++ u32 mbssid:4; ++ u32 antsel_A:3; ++ u32 antsel_B:3; ++ u32 antsel_C:3; ++ u32 antsel_D:3; ++ u32 rsvd2428:4; ++ ++ /* Offset 28 */ ++ u32 checksum:16; ++ u32 rsvd2816:8; ++ u32 usb_txagg_num:8; ++ ++ /* Offset 32 */ ++ u32 rts_rc:6; ++ u32 bar_rty_th:2; ++ u32 data_rc:6; ++ u32 rsvd3214:1; ++ u32 en_hwseq:1; ++ u32 nextneadpage:8; ++ u32 tailpage:8; ++ ++ /* Offset 36 */ ++ u32 padding_len:11; ++ u32 txbf_path:1; ++ u32 seq:12; ++ u32 final_data_rate:8; ++}TXDESC_8723B, *PTXDESC_8723B; ++ ++#ifndef __INC_HAL8723BDESC_H ++#define __INC_HAL8723BDESC_H ++ ++#define RX_STATUS_DESC_SIZE_8723B 24 ++#define RX_DRV_INFO_SIZE_UNIT_8723B 8 ++ ++ ++/* DWORD 0 */ ++#define SET_RX_STATUS_DESC_PKT_LEN_8723B(__pRxStatusDesc, __Value) SET_BITS_TO_LE_4BYTE(__pRxStatusDesc, 0, 14, __Value) ++#define SET_RX_STATUS_DESC_EOR_8723B(__pRxStatusDesc, __Value) SET_BITS_TO_LE_4BYTE(__pRxStatusDesc, 30, 1, __Value) ++#define SET_RX_STATUS_DESC_OWN_8723B(__pRxStatusDesc, __Value) SET_BITS_TO_LE_4BYTE(__pRxStatusDesc, 31, 1, __Value) ++ ++#define GET_RX_STATUS_DESC_PKT_LEN_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc, 0, 14) ++#define GET_RX_STATUS_DESC_CRC32_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc, 14, 1) ++#define GET_RX_STATUS_DESC_ICV_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc, 15, 1) ++#define GET_RX_STATUS_DESC_DRVINFO_SIZE_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc, 16, 4) ++#define GET_RX_STATUS_DESC_SECURITY_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc, 20, 3) ++#define GET_RX_STATUS_DESC_QOS_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc, 23, 1) ++#define GET_RX_STATUS_DESC_SHIFT_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc, 24, 2) ++#define GET_RX_STATUS_DESC_PHY_STATUS_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc, 26, 1) ++#define GET_RX_STATUS_DESC_SWDEC_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc, 27, 1) ++#define GET_RX_STATUS_DESC_LAST_SEG_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc, 28, 1) ++#define GET_RX_STATUS_DESC_FIRST_SEG_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc, 29, 1) ++#define GET_RX_STATUS_DESC_EOR_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc, 30, 1) ++#define GET_RX_STATUS_DESC_OWN_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc, 31, 1) ++ ++/* DWORD 1 */ ++#define GET_RX_STATUS_DESC_MACID_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+4, 0, 7) ++#define GET_RX_STATUS_DESC_TID_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+4, 8, 4) ++#define GET_RX_STATUS_DESC_AMSDU_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+4, 13, 1) ++#define GET_RX_STATUS_DESC_RXID_MATCH_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+4, 14, 1) ++#define GET_RX_STATUS_DESC_PAGGR_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+4, 15, 1) ++#define GET_RX_STATUS_DESC_A1_FIT_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+4, 16, 4) ++#define GET_RX_STATUS_DESC_CHKERR_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+4, 20, 1) ++#define GET_RX_STATUS_DESC_IPVER_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+4, 21, 1) ++#define GET_RX_STATUS_DESC_IS_TCPUDP__8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+4, 22, 1) ++#define GET_RX_STATUS_DESC_CHK_VLD_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+4, 23, 1) ++#define GET_RX_STATUS_DESC_PAM_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+4, 24, 1) ++#define GET_RX_STATUS_DESC_PWR_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+4, 25, 1) ++#define GET_RX_STATUS_DESC_MORE_DATA_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+4, 26, 1) ++#define GET_RX_STATUS_DESC_MORE_FRAG_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+4, 27, 1) ++#define GET_RX_STATUS_DESC_TYPE_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+4, 28, 2) ++#define GET_RX_STATUS_DESC_MC_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+4, 30, 1) ++#define GET_RX_STATUS_DESC_BC_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+4, 31, 1) ++ ++/* DWORD 2 */ ++#define GET_RX_STATUS_DESC_SEQ_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc+8, 0, 12) ++#define GET_RX_STATUS_DESC_FRAG_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc+8, 12, 4) ++#define GET_RX_STATUS_DESC_RX_IS_QOS_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc+8, 16, 1) ++#define GET_RX_STATUS_DESC_WLANHD_IV_LEN_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc+8, 18, 6) ++#define GET_RX_STATUS_DESC_RPT_SEL_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc+8, 28, 1) ++ ++/* DWORD 3 */ ++#define GET_RX_STATUS_DESC_RX_RATE_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc+12, 0, 7) ++#define GET_RX_STATUS_DESC_HTC_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc+12, 10, 1) ++#define GET_RX_STATUS_DESC_EOSP_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc+12, 11, 1) ++#define GET_RX_STATUS_DESC_BSSID_FIT_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc+12, 12, 2) ++#define GET_RX_STATUS_DESC_PATTERN_MATCH_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+12, 29, 1) ++#define GET_RX_STATUS_DESC_UNICAST_MATCH_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+12, 30, 1) ++#define GET_RX_STATUS_DESC_MAGIC_MATCH_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+12, 31, 1) ++ ++/* DWORD 6 */ ++#define GET_RX_STATUS_DESC_SPLCP_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+16, 0, 1) ++#define GET_RX_STATUS_DESC_LDPC_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+16, 1, 1) ++#define GET_RX_STATUS_DESC_STBC_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+16, 2, 1) ++#define GET_RX_STATUS_DESC_BW_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+16, 4, 2) ++ ++/* DWORD 5 */ ++#define GET_RX_STATUS_DESC_TSFL_8723B(__pRxStatusDesc) LE_BITS_TO_4BYTE(__pRxStatusDesc+20, 0, 32) ++ ++#define GET_RX_STATUS_DESC_BUFF_ADDR_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+24, 0, 32) ++#define GET_RX_STATUS_DESC_BUFF_ADDR64_8723B(__pRxDesc) LE_BITS_TO_4BYTE(__pRxDesc+28, 0, 32) ++ ++#define SET_RX_STATUS_DESC_BUFF_ADDR_8723B(__pRxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pRxDesc+24, 0, 32, __Value) ++ ++ ++/* Dword 0 */ ++#define GET_TX_DESC_OWN_8723B(__pTxDesc) LE_BITS_TO_4BYTE(__pTxDesc, 31, 1) ++ ++#define SET_TX_DESC_PKT_SIZE_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc, 0, 16, __Value) ++#define SET_TX_DESC_OFFSET_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc, 16, 8, __Value) ++#define SET_TX_DESC_BMC_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc, 24, 1, __Value) ++#define SET_TX_DESC_HTC_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc, 25, 1, __Value) ++#define SET_TX_DESC_LAST_SEG_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc, 26, 1, __Value) ++#define SET_TX_DESC_FIRST_SEG_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc, 27, 1, __Value) ++#define SET_TX_DESC_LINIP_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc, 28, 1, __Value) ++#define SET_TX_DESC_NO_ACM_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc, 29, 1, __Value) ++#define SET_TX_DESC_GF_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc, 30, 1, __Value) ++#define SET_TX_DESC_OWN_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc, 31, 1, __Value) ++ ++/* Dword 1 */ ++#define SET_TX_DESC_MACID_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+4, 0, 7, __Value) ++#define SET_TX_DESC_QUEUE_SEL_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+4, 8, 5, __Value) ++#define SET_TX_DESC_RDG_NAV_EXT_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+4, 13, 1, __Value) ++#define SET_TX_DESC_LSIG_TXOP_EN_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+4, 14, 1, __Value) ++#define SET_TX_DESC_PIFS_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+4, 15, 1, __Value) ++#define SET_TX_DESC_RATE_ID_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+4, 16, 5, __Value) ++#define SET_TX_DESC_EN_DESC_ID_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+4, 21, 1, __Value) ++#define SET_TX_DESC_SEC_TYPE_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+4, 22, 2, __Value) ++#define SET_TX_DESC_PKT_OFFSET_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+4, 24, 5, __Value) ++ ++ ++/* Dword 2 */ ++#define SET_TX_DESC_PAID_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 0, 9, __Value) ++#define SET_TX_DESC_CCA_RTS_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 10, 2, __Value) ++#define SET_TX_DESC_AGG_ENABLE_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 12, 1, __Value) ++#define SET_TX_DESC_RDG_ENABLE_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 13, 1, __Value) ++#define SET_TX_DESC_AGG_BREAK_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 16, 1, __Value) ++#define SET_TX_DESC_MORE_FRAG_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 17, 1, __Value) ++#define SET_TX_DESC_RAW_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 18, 1, __Value) ++#define SET_TX_DESC_SPE_RPT_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 19, 1, __Value) ++#define SET_TX_DESC_AMPDU_DENSITY_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 20, 3, __Value) ++#define SET_TX_DESC_BT_INT_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 23, 1, __Value) ++#define SET_TX_DESC_GID_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 24, 6, __Value) ++ ++ ++/* Dword 3 */ ++#define SET_TX_DESC_WHEADER_LEN_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+12, 0, 4, __Value) ++#define SET_TX_DESC_CHK_EN_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+12, 4, 1, __Value) ++#define SET_TX_DESC_EARLY_MODE_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+12, 5, 1, __Value) ++#define SET_TX_DESC_HWSEQ_SEL_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+12, 6, 2, __Value) ++#define SET_TX_DESC_USE_RATE_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+12, 8, 1, __Value) ++#define SET_TX_DESC_DISABLE_RTS_FB_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+12, 9, 1, __Value) ++#define SET_TX_DESC_DISABLE_FB_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+12, 10, 1, __Value) ++#define SET_TX_DESC_CTS2SELF_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+12, 11, 1, __Value) ++#define SET_TX_DESC_RTS_ENABLE_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+12, 12, 1, __Value) ++#define SET_TX_DESC_HW_RTS_ENABLE_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+12, 13, 1, __Value) ++#define SET_TX_DESC_NAV_USE_HDR_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+12, 15, 1, __Value) ++#define SET_TX_DESC_USE_MAX_LEN_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+12, 16, 1, __Value) ++#define SET_TX_DESC_MAX_AGG_NUM_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+12, 17, 5, __Value) ++#define SET_TX_DESC_NDPA_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+12, 22, 2, __Value) ++#define SET_TX_DESC_AMPDU_MAX_TIME_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+12, 24, 8, __Value) ++ ++/* Dword 4 */ ++#define SET_TX_DESC_TX_RATE_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+16, 0, 7, __Value) ++#define SET_TX_DESC_DATA_RATE_FB_LIMIT_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+16, 8, 5, __Value) ++#define SET_TX_DESC_RTS_RATE_FB_LIMIT_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+16, 13, 4, __Value) ++#define SET_TX_DESC_RETRY_LIMIT_ENABLE_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+16, 17, 1, __Value) ++#define SET_TX_DESC_DATA_RETRY_LIMIT_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+16, 18, 6, __Value) ++#define SET_TX_DESC_RTS_RATE_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+16, 24, 5, __Value) ++ ++ ++/* Dword 5 */ ++#define SET_TX_DESC_DATA_SC_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+20, 0, 4, __Value) ++#define SET_TX_DESC_DATA_SHORT_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+20, 4, 1, __Value) ++#define SET_TX_DESC_DATA_BW_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+20, 5, 2, __Value) ++#define SET_TX_DESC_DATA_LDPC_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+20, 7, 1, __Value) ++#define SET_TX_DESC_DATA_STBC_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+20, 8, 2, __Value) ++#define SET_TX_DESC_CTROL_STBC_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+20, 10, 2, __Value) ++#define SET_TX_DESC_RTS_SHORT_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+20, 12, 1, __Value) ++#define SET_TX_DESC_RTS_SC_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+20, 13, 4, __Value) ++ ++ ++/* Dword 6 */ ++#define SET_TX_DESC_SW_DEFINE_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+24, 0, 12, __Value) ++#define SET_TX_DESC_ANTSEL_A_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+24, 16, 3, __Value) ++#define SET_TX_DESC_ANTSEL_B_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+24, 19, 3, __Value) ++#define SET_TX_DESC_ANTSEL_C_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+24, 22, 3, __Value) ++#define SET_TX_DESC_ANTSEL_D_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+24, 25, 3, __Value) ++ ++/* Dword 7 */ ++#define SET_TX_DESC_TX_DESC_CHECKSUM_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+28, 0, 16, __Value) ++#define SET_TX_DESC_USB_TXAGG_NUM_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+28, 24, 8, __Value) ++#define SET_TX_DESC_SDIO_TXSEQ_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+28, 16, 8, __Value) ++ ++/* Dword 8 */ ++#define SET_TX_DESC_HWSEQ_EN_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+32, 15, 1, __Value) ++ ++/* Dword 9 */ ++#define SET_TX_DESC_SEQ_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+36, 12, 12, __Value) ++ ++/* Dword 10 */ ++#define SET_TX_DESC_TX_BUFFER_ADDRESS_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+40, 0, 32, __Value) ++#define GET_TX_DESC_TX_BUFFER_ADDRESS_8723B(__pTxDesc) LE_BITS_TO_4BYTE(__pTxDesc+40, 0, 32) ++ ++/* Dword 11 */ ++#define SET_TX_DESC_NEXT_DESC_ADDRESS_8723B(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+48, 0, 32, __Value) ++ ++ ++#define SET_EARLYMODE_PKTNUM_8723B(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr, 0, 4, __Value) ++#define SET_EARLYMODE_LEN0_8723B(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr, 4, 15, __Value) ++#define SET_EARLYMODE_LEN1_1_8723B(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr, 19, 13, __Value) ++#define SET_EARLYMODE_LEN1_2_8723B(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr+4, 0, 2, __Value) ++#define SET_EARLYMODE_LEN2_8723B(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr+4, 2, 15, __Value) ++#define SET_EARLYMODE_LEN3_8723B(__pAddr, __Value) SET_BITS_TO_LE_4BYTE(__pAddr+4, 17, 15, __Value) ++ ++#endif ++/* */ ++/* */ ++/* Rate */ ++/* */ ++/* */ ++/* CCK Rates, TxHT = 0 */ ++#define DESC8723B_RATE1M 0x00 ++#define DESC8723B_RATE2M 0x01 ++#define DESC8723B_RATE5_5M 0x02 ++#define DESC8723B_RATE11M 0x03 ++ ++/* OFDM Rates, TxHT = 0 */ ++#define DESC8723B_RATE6M 0x04 ++#define DESC8723B_RATE9M 0x05 ++#define DESC8723B_RATE12M 0x06 ++#define DESC8723B_RATE18M 0x07 ++#define DESC8723B_RATE24M 0x08 ++#define DESC8723B_RATE36M 0x09 ++#define DESC8723B_RATE48M 0x0a ++#define DESC8723B_RATE54M 0x0b ++ ++/* MCS Rates, TxHT = 1 */ ++#define DESC8723B_RATEMCS0 0x0c ++#define DESC8723B_RATEMCS1 0x0d ++#define DESC8723B_RATEMCS2 0x0e ++#define DESC8723B_RATEMCS3 0x0f ++#define DESC8723B_RATEMCS4 0x10 ++#define DESC8723B_RATEMCS5 0x11 ++#define DESC8723B_RATEMCS6 0x12 ++#define DESC8723B_RATEMCS7 0x13 ++#define DESC8723B_RATEMCS8 0x14 ++#define DESC8723B_RATEMCS9 0x15 ++#define DESC8723B_RATEMCS10 0x16 ++#define DESC8723B_RATEMCS11 0x17 ++#define DESC8723B_RATEMCS12 0x18 ++#define DESC8723B_RATEMCS13 0x19 ++#define DESC8723B_RATEMCS14 0x1a ++#define DESC8723B_RATEMCS15 0x1b ++#define DESC8723B_RATEVHTSS1MCS0 0x2c ++#define DESC8723B_RATEVHTSS1MCS1 0x2d ++#define DESC8723B_RATEVHTSS1MCS2 0x2e ++#define DESC8723B_RATEVHTSS1MCS3 0x2f ++#define DESC8723B_RATEVHTSS1MCS4 0x30 ++#define DESC8723B_RATEVHTSS1MCS5 0x31 ++#define DESC8723B_RATEVHTSS1MCS6 0x32 ++#define DESC8723B_RATEVHTSS1MCS7 0x33 ++#define DESC8723B_RATEVHTSS1MCS8 0x34 ++#define DESC8723B_RATEVHTSS1MCS9 0x35 ++#define DESC8723B_RATEVHTSS2MCS0 0x36 ++#define DESC8723B_RATEVHTSS2MCS1 0x37 ++#define DESC8723B_RATEVHTSS2MCS2 0x38 ++#define DESC8723B_RATEVHTSS2MCS3 0x39 ++#define DESC8723B_RATEVHTSS2MCS4 0x3a ++#define DESC8723B_RATEVHTSS2MCS5 0x3b ++#define DESC8723B_RATEVHTSS2MCS6 0x3c ++#define DESC8723B_RATEVHTSS2MCS7 0x3d ++#define DESC8723B_RATEVHTSS2MCS8 0x3e ++#define DESC8723B_RATEVHTSS2MCS9 0x3f ++ ++ ++#define RX_HAL_IS_CCK_RATE_8723B(pDesc)\ ++ (GET_RX_STATUS_DESC_RX_RATE_8723B(pDesc) == DESC8723B_RATE1M ||\ ++ GET_RX_STATUS_DESC_RX_RATE_8723B(pDesc) == DESC8723B_RATE2M ||\ ++ GET_RX_STATUS_DESC_RX_RATE_8723B(pDesc) == DESC8723B_RATE5_5M ||\ ++ GET_RX_STATUS_DESC_RX_RATE_8723B(pDesc) == DESC8723B_RATE11M) ++ ++ ++void rtl8723b_update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem); ++void rtl8723b_fill_fake_txdesc(struct adapter *padapter, u8 *pDesc, u32 BufferLen, u8 IsPsPoll, u8 IsBTQosNull, u8 bDataFrame); ++ ++s32 rtl8723bs_init_xmit_priv(struct adapter *padapter); ++void rtl8723bs_free_xmit_priv(struct adapter *padapter); ++s32 rtl8723bs_hal_xmit(struct adapter *padapter, struct xmit_frame *pxmitframe); ++s32 rtl8723bs_mgnt_xmit(struct adapter *padapter, struct xmit_frame *pmgntframe); ++s32 rtl8723bs_hal_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe); ++s32 rtl8723bs_xmit_buf_handler(struct adapter *padapter); ++int rtl8723bs_xmit_thread(void *context); ++#define hal_xmit_handler rtl8723bs_xmit_buf_handler ++ ++u8 BWMapping_8723B(struct adapter * Adapter, struct pkt_attrib *pattrib); ++u8 SCMapping_8723B(struct adapter * Adapter, struct pkt_attrib *pattrib); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_ap.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_ap.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_ap.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_ap.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,47 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTW_AP_H_ ++#define __RTW_AP_H_ ++ ++void init_mlme_ap_info(struct adapter *padapter); ++void free_mlme_ap_info(struct adapter *padapter); ++/* void update_BCNTIM(struct adapter *padapter); */ ++void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx); ++void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level); ++void expire_timeout_chk(struct adapter *padapter); ++void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta); ++void start_bss_network(struct adapter *padapter, u8 *pbuf); ++int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len); ++void rtw_ap_restore_network(struct adapter *padapter); ++void rtw_set_macaddr_acl(struct adapter *padapter, int mode); ++int rtw_acl_add_sta(struct adapter *padapter, u8 *addr); ++int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr); ++ ++u8 rtw_ap_set_pairwise_key(struct adapter *padapter, struct sta_info *psta); ++int rtw_ap_set_group_key(struct adapter *padapter, u8 *key, u8 alg, int keyid); ++int rtw_ap_set_wep_key(struct adapter *padapter, u8 *key, u8 keylen, int keyid, u8 set_tx); ++ ++void associated_clients_update(struct adapter *padapter, u8 updated); ++void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta); ++u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta); ++void sta_info_update(struct adapter *padapter, struct sta_info *psta); ++void ap_sta_info_defer_update(struct adapter *padapter, struct sta_info *psta); ++u8 ap_free_sta(struct adapter *padapter, struct sta_info *psta, bool active, u16 reason); ++int rtw_sta_flush(struct adapter *padapter); ++void start_ap_mode(struct adapter *padapter); ++void stop_ap_mode(struct adapter *padapter); ++ ++#endif ++void update_bmc_sta(struct adapter *padapter); +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_beamforming.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_beamforming.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_beamforming.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_beamforming.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,135 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTW_BEAMFORMING_H_ ++#define __RTW_BEAMFORMING_H_ ++ ++#define BEAMFORMING_ENTRY_NUM 2 ++#define GET_BEAMFORM_INFO(_pmlmepriv) ((struct beamforming_info *)(&(_pmlmepriv)->beamforming_info)) ++ ++typedef enum _BEAMFORMING_ENTRY_STATE ++{ ++ BEAMFORMING_ENTRY_STATE_UNINITIALIZE, ++ BEAMFORMING_ENTRY_STATE_INITIALIZEING, ++ BEAMFORMING_ENTRY_STATE_INITIALIZED, ++ BEAMFORMING_ENTRY_STATE_PROGRESSING, ++ BEAMFORMING_ENTRY_STATE_PROGRESSED, ++}BEAMFORMING_ENTRY_STATE, *PBEAMFORMING_ENTRY_STATE; ++ ++ ++typedef enum _BEAMFORMING_STATE ++{ ++ BEAMFORMING_STATE_IDLE, ++ BEAMFORMING_STATE_START, ++ BEAMFORMING_STATE_END, ++}BEAMFORMING_STATE, *PBEAMFORMING_STATE; ++ ++ ++typedef enum _BEAMFORMING_CAP ++{ ++ BEAMFORMING_CAP_NONE = 0x0, ++ BEAMFORMER_CAP_HT_EXPLICIT = 0x1, ++ BEAMFORMEE_CAP_HT_EXPLICIT = 0x2, ++ BEAMFORMER_CAP_VHT_SU = 0x4, /* Self has er Cap, because Reg er & peer ee */ ++ BEAMFORMEE_CAP_VHT_SU = 0x8, /* Self has ee Cap, because Reg ee & peer er */ ++ BEAMFORMER_CAP = 0x10, ++ BEAMFORMEE_CAP = 0x20, ++}BEAMFORMING_CAP, *PBEAMFORMING_CAP; ++ ++ ++typedef enum _SOUNDING_MODE ++{ ++ SOUNDING_SW_VHT_TIMER = 0x0, ++ SOUNDING_SW_HT_TIMER = 0x1, ++ SOUNDING_STOP_All_TIMER = 0x2, ++ SOUNDING_HW_VHT_TIMER = 0x3, ++ SOUNDING_HW_HT_TIMER = 0x4, ++ SOUNDING_STOP_OID_TIMER = 0x5, ++ SOUNDING_AUTO_VHT_TIMER = 0x6, ++ SOUNDING_AUTO_HT_TIMER = 0x7, ++ SOUNDING_FW_VHT_TIMER = 0x8, ++ SOUNDING_FW_HT_TIMER = 0x9, ++}SOUNDING_MODE, *PSOUNDING_MODE; ++ ++ ++enum BEAMFORMING_CTRL_TYPE ++{ ++ BEAMFORMING_CTRL_ENTER = 0, ++ BEAMFORMING_CTRL_LEAVE = 1, ++ BEAMFORMING_CTRL_START_PERIOD = 2, ++ BEAMFORMING_CTRL_END_PERIOD = 3, ++ BEAMFORMING_CTRL_SOUNDING_FAIL =4, ++ BEAMFORMING_CTRL_SOUNDING_CLK =5, ++}; ++ ++struct beamforming_entry { ++ bool bUsed; ++ bool bSound; ++ u16 aid; /* Used to construct AID field of NDPA packet. */ ++ u16 mac_id; /* Used to Set Reg42C in IBSS mode. */ ++ u16 p_aid; /* Used to fill Reg42C & Reg714 to compare with P_AID of Tx DESC. */ ++ u8 mac_addr[6];/* Used to fill Reg6E4 to fill Mac address of CSI report frame. */ ++ enum CHANNEL_WIDTH sound_bw; /* Sounding BandWidth */ ++ u16 sound_period; ++ BEAMFORMING_CAP beamforming_entry_cap; ++ BEAMFORMING_ENTRY_STATE beamforming_entry_state; ++ u8 LogSeq; ++ u8 LogRetryCnt; ++ u8 LogSuccessCnt; ++ u8 LogStatusFailCnt; ++ u8 PreCsiReport[327]; ++ u8 DefaultCsiCnt; ++ bool bDefaultCSI; ++}; ++ ++struct sounding_info { ++ u8 sound_idx; ++ enum CHANNEL_WIDTH sound_bw; ++ SOUNDING_MODE sound_mode; ++ u16 sound_period; ++}; ++ ++struct beamforming_info { ++ BEAMFORMING_CAP beamforming_cap; ++ BEAMFORMING_STATE beamforming_state; ++ struct beamforming_entry beamforming_entry[BEAMFORMING_ENTRY_NUM]; ++ u8 beamforming_cur_idx; ++ u8 beamforming_in_progress; ++ u8 sounding_sequence; ++ struct sounding_info sounding_info; ++}; ++ ++struct rtw_ndpa_sta_info { ++ u16 aid:12; ++ u16 feedback_type:1; ++ u16 nc_index:3; ++}; ++ ++BEAMFORMING_CAP beamforming_get_entry_beam_cap_by_mac_id(void *pmlmepriv , u8 mac_id); ++void beamforming_notify(struct adapter * adapter); ++BEAMFORMING_CAP beamforming_get_beamform_cap(struct beamforming_info *pBeamInfo); ++ ++u32 beamforming_get_report_frame(struct adapter * Adapter, union recv_frame *precv_frame); ++ ++bool beamforming_send_ht_ndpa_packet(struct adapter * Adapter, u8 *ra, enum CHANNEL_WIDTH bw, u8 qidx); ++bool beamforming_send_vht_ndpa_packet(struct adapter * Adapter, u8 *ra, u16 aid, enum CHANNEL_WIDTH bw, u8 qidx); ++ ++void beamforming_check_sounding_success(struct adapter * Adapter, bool status); ++ ++void beamforming_watchdog(struct adapter * Adapter); ++ ++void beamforming_wk_hdl(struct adapter *padapter, u8 type, u8 *pbuf); ++u8 beamforming_wk_cmd(struct adapter *padapter, s32 type, u8 *pbuf, s32 size, u8 enqueue); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_br_ext.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_br_ext.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_br_ext.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_br_ext.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,63 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef _RTW_BR_EXT_H_ ++#define _RTW_BR_EXT_H_ ++ ++#define MACADDRLEN 6 ++#define _DEBUG_ERR DBG_8192C ++#define _DEBUG_INFO /* DBG_8192C */ ++#define DEBUG_WARN DBG_8192C ++#define DEBUG_INFO /* DBG_8192C */ ++#define DEBUG_ERR DBG_8192C ++/* define GET_MY_HWADDR ((GET_MIB(priv))->dot11OperationEntry.hwaddr) */ ++#define GET_MY_HWADDR(padapter) ((padapter)->eeprompriv.mac_addr) ++ ++#define NAT25_HASH_BITS 4 ++#define NAT25_HASH_SIZE (1 << NAT25_HASH_BITS) ++#define NAT25_AGEING_TIME 300 ++ ++#define MAX_NETWORK_ADDR_LEN 17 ++ ++struct nat25_network_db_entry ++{ ++ struct nat25_network_db_entry *next_hash; ++ struct nat25_network_db_entry **pprev_hash; ++ atomic_t use_count; ++ unsigned char macAddr[6]; ++ unsigned long ageing_timer; ++ unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; ++}; ++ ++enum NAT25_METHOD { ++ NAT25_MIN, ++ NAT25_CHECK, ++ NAT25_INSERT, ++ NAT25_LOOKUP, ++ NAT25_PARSE, ++ NAT25_MAX ++}; ++ ++struct br_ext_info { ++ unsigned int nat25_disable; ++ unsigned int macclone_enable; ++ unsigned int dhcp_bcst_disable; ++ int addPPPoETag; /* 1: Add PPPoE relay-SID, 0: disable */ ++ unsigned char nat25_dmzMac[MACADDRLEN]; ++ unsigned int nat25sc_disable; ++}; ++ ++void nat25_db_cleanup(struct adapter *priv); ++ ++#endif /* _RTW_BR_EXT_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_btcoex.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_btcoex.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_btcoex.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_btcoex.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,64 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2013 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTW_BTCOEX_H__ ++#define __RTW_BTCOEX_H__ ++ ++#include ++ ++ ++#define PACKET_NORMAL 0 ++#define PACKET_DHCP 1 ++#define PACKET_ARP 2 ++#define PACKET_EAPOL 3 ++ ++void rtw_btcoex_Initialize(struct adapter *); ++void rtw_btcoex_PowerOnSetting(struct adapter *padapter); ++void rtw_btcoex_HAL_Initialize(struct adapter *padapter, u8 bWifiOnly); ++void rtw_btcoex_IpsNotify(struct adapter *, u8 type); ++void rtw_btcoex_LpsNotify(struct adapter *, u8 type); ++void rtw_btcoex_ScanNotify(struct adapter *, u8 type); ++void rtw_btcoex_ConnectNotify(struct adapter *, u8 action); ++void rtw_btcoex_MediaStatusNotify(struct adapter *, u8 mediaStatus); ++void rtw_btcoex_SpecialPacketNotify(struct adapter *, u8 pktType); ++void rtw_btcoex_IQKNotify(struct adapter *padapter, u8 state); ++void rtw_btcoex_BtInfoNotify(struct adapter *, u8 length, u8 *tmpBuf); ++void rtw_btcoex_SuspendNotify(struct adapter *, u8 state); ++void rtw_btcoex_HaltNotify(struct adapter *); ++u8 rtw_btcoex_IsBtDisabled(struct adapter *); ++void rtw_btcoex_Handler(struct adapter *); ++s32 rtw_btcoex_IsBTCoexCtrlAMPDUSize(struct adapter *); ++void rtw_btcoex_SetManualControl(struct adapter *, u8 bmanual); ++u8 rtw_btcoex_IsBtControlLps(struct adapter *); ++u8 rtw_btcoex_IsLpsOn(struct adapter *); ++u8 rtw_btcoex_RpwmVal(struct adapter *); ++u8 rtw_btcoex_LpsVal(struct adapter *); ++void rtw_btcoex_SetBTCoexist(struct adapter *, u8 bBtExist); ++void rtw_btcoex_SetChipType(struct adapter *, u8 chipType); ++void rtw_btcoex_SetPGAntNum(struct adapter *, u8 antNum); ++void rtw_btcoex_SetSingleAntPath(struct adapter *padapter, u8 singleAntPath); ++u32 rtw_btcoex_GetRaMask(struct adapter *); ++void rtw_btcoex_RecordPwrMode(struct adapter *, u8 *pCmdBuf, u8 cmdLen); ++void rtw_btcoex_DisplayBtCoexInfo(struct adapter *, u8 *pbuf, u32 bufsize); ++void rtw_btcoex_SetDBG(struct adapter *, u32 *pDbgModule); ++u32 rtw_btcoex_GetDBG(struct adapter *, u8 *pStrBuf, u32 bufSize); ++ ++/* ================================================== */ ++/* Below Functions are called by BT-Coex */ ++/* ================================================== */ ++void rtw_btcoex_RejectApAggregatedPacket(struct adapter *, u8 enable); ++void rtw_btcoex_LPS_Enter(struct adapter *); ++void rtw_btcoex_LPS_Leave(struct adapter *); ++ ++#endif /* __RTW_BTCOEX_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_byteorder.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_byteorder.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_byteorder.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_byteorder.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,24 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef _RTL871X_BYTEORDER_H_ ++#define _RTL871X_BYTEORDER_H_ ++ ++#if defined (__LITTLE_ENDIAN) ++#include ++#else ++# include ++#endif ++ ++#endif /* _RTL871X_BYTEORDER_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_cmd.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_cmd.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_cmd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_cmd.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,980 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTW_CMD_H_ ++#define __RTW_CMD_H_ ++ ++ ++#define C2H_MEM_SZ (16*1024) ++ ++ #define FREE_CMDOBJ_SZ 128 ++ ++ #define MAX_CMDSZ 1024 ++ #define MAX_RSPSZ 512 ++ #define MAX_EVTSZ 1024 ++ ++ #define CMDBUFF_ALIGN_SZ 512 ++ ++ struct cmd_obj { ++ struct adapter *padapter; ++ u16 cmdcode; ++ u8 res; ++ u8 *parmbuf; ++ u32 cmdsz; ++ u8 *rsp; ++ u32 rspsz; ++ struct submit_ctx *sctx; ++ /* _sema cmd_sem; */ ++ struct list_head list; ++ }; ++ ++ /* cmd flags */ ++ enum { ++ RTW_CMDF_DIRECTLY = BIT0, ++ RTW_CMDF_WAIT_ACK = BIT1, ++ }; ++ ++ struct cmd_priv { ++ _sema cmd_queue_sema; ++ /* _sema cmd_done_sema; */ ++ _sema terminate_cmdthread_sema; ++ struct __queue cmd_queue; ++ u8 cmd_seq; ++ u8 *cmd_buf; /* shall be non-paged, and 4 bytes aligned */ ++ u8 *cmd_allocated_buf; ++ u8 *rsp_buf; /* shall be non-paged, and 4 bytes aligned */ ++ u8 *rsp_allocated_buf; ++ u32 cmd_issued_cnt; ++ u32 cmd_done_cnt; ++ u32 rsp_cnt; ++ atomic_t cmdthd_running; ++ /* u8 cmdthd_running; */ ++ u8 stop_req; ++ struct adapter *padapter; ++ _mutex sctx_mutex; ++ }; ++ ++ struct evt_priv { ++ _workitem c2h_wk; ++ bool c2h_wk_alive; ++ struct rtw_cbuf *c2h_queue; ++ #define C2H_QUEUE_MAX_LEN 10 ++ ++ atomic_t event_seq; ++ u8 *evt_buf; /* shall be non-paged, and 4 bytes aligned */ ++ u8 *evt_allocated_buf; ++ u32 evt_done_cnt; ++ u8 *c2h_mem; ++ u8 *allocated_c2h_mem; ++ }; ++ ++#define init_h2fwcmd_w_parm_no_rsp(pcmd, pparm, code) \ ++do {\ ++ INIT_LIST_HEAD(&pcmd->list);\ ++ pcmd->cmdcode = code;\ ++ pcmd->parmbuf = (u8 *)(pparm);\ ++ pcmd->cmdsz = sizeof (*pparm);\ ++ pcmd->rsp = NULL;\ ++ pcmd->rspsz = 0;\ ++} while (0) ++ ++#define init_h2fwcmd_w_parm_no_parm_rsp(pcmd, code) \ ++do {\ ++ INIT_LIST_HEAD(&pcmd->list);\ ++ pcmd->cmdcode = code;\ ++ pcmd->parmbuf = NULL;\ ++ pcmd->cmdsz = 0;\ ++ pcmd->rsp = NULL;\ ++ pcmd->rspsz = 0;\ ++} while (0) ++ ++struct c2h_evt_hdr { ++ u8 id:4; ++ u8 plen:4; ++ u8 seq; ++ u8 payload[0]; ++}; ++ ++struct c2h_evt_hdr_88xx { ++ u8 id; ++ u8 seq; ++ u8 payload[12]; ++ u8 plen; ++ u8 trigger; ++}; ++ ++#define c2h_evt_valid(c2h_evt) ((c2h_evt)->id || (c2h_evt)->plen) ++ ++struct P2P_PS_Offload_t { ++ u8 Offload_En:1; ++ u8 role:1; /* 1: Owner, 0: Client */ ++ u8 CTWindow_En:1; ++ u8 NoA0_En:1; ++ u8 NoA1_En:1; ++ u8 AllStaSleep:1; /* Only valid in Owner */ ++ u8 discovery:1; ++ u8 rsvd:1; ++}; ++ ++struct P2P_PS_CTWPeriod_t { ++ u8 CTWPeriod; /* TU */ ++}; ++ ++extern u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj); ++extern struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv); ++extern void rtw_free_cmd_obj(struct cmd_obj *pcmd); ++ ++void rtw_stop_cmd_thread(struct adapter *adapter); ++int rtw_cmd_thread(void *context); ++ ++extern u32 rtw_init_cmd_priv (struct cmd_priv *pcmdpriv); ++extern void rtw_free_cmd_priv (struct cmd_priv *pcmdpriv); ++ ++extern u32 rtw_init_evt_priv (struct evt_priv *pevtpriv); ++extern void rtw_free_evt_priv (struct evt_priv *pevtpriv); ++extern void rtw_evt_notify_isr(struct evt_priv *pevtpriv); ++ ++enum rtw_drvextra_cmd_id ++{ ++ NONE_WK_CID, ++ DYNAMIC_CHK_WK_CID, ++ DM_CTRL_WK_CID, ++ PBC_POLLING_WK_CID, ++ POWER_SAVING_CTRL_WK_CID,/* IPS, AUTOSuspend */ ++ LPS_CTRL_WK_CID, ++ ANT_SELECT_WK_CID, ++ P2P_PS_WK_CID, ++ P2P_PROTO_WK_CID, ++ CHECK_HIQ_WK_CID,/* for softap mode, check hi queue if empty */ ++ INTEl_WIDI_WK_CID, ++ C2H_WK_CID, ++ RTP_TIMER_CFG_WK_CID, ++ RESET_SECURITYPRIV, /* add for CONFIG_IEEE80211W, none 11w also can use */ ++ FREE_ASSOC_RESOURCES, /* add for CONFIG_IEEE80211W, none 11w also can use */ ++ DM_IN_LPS_WK_CID, ++ DM_RA_MSK_WK_CID, /* add for STA update RAMask when bandwith change. */ ++ BEAMFORMING_WK_CID, ++ LPS_CHANGE_DTIM_CID, ++ BTINFO_WK_CID, ++ MAX_WK_CID ++}; ++ ++enum LPS_CTRL_TYPE ++{ ++ LPS_CTRL_SCAN = 0, ++ LPS_CTRL_JOINBSS = 1, ++ LPS_CTRL_CONNECT =2, ++ LPS_CTRL_DISCONNECT =3, ++ LPS_CTRL_SPECIAL_PACKET =4, ++ LPS_CTRL_LEAVE =5, ++ LPS_CTRL_TRAFFIC_BUSY = 6, ++}; ++ ++enum RFINTFS { ++ SWSI, ++ HWSI, ++ HWPI, ++}; ++ ++/* ++Caller Mode: Infra, Ad-HoC(C) ++ ++Notes: To enter USB suspend mode ++ ++Command Mode ++ ++*/ ++struct usb_suspend_parm { ++ u32 action;/* 1: sleep, 0:resume */ ++}; ++ ++/* ++Caller Mode: Infra, Ad-HoC ++ ++Notes: To join a known BSS. ++ ++Command-Event Mode ++ ++*/ ++ ++/* ++Caller Mode: Infra, Ad-Hoc ++ ++Notes: To join the specified bss ++ ++Command Event Mode ++ ++*/ ++struct joinbss_parm { ++ struct wlan_bssid_ex network; ++}; ++ ++/* ++Caller Mode: Infra, Ad-HoC(C) ++ ++Notes: To disconnect the current associated BSS ++ ++Command Mode ++ ++*/ ++struct disconnect_parm { ++ u32 deauth_timeout_ms; ++}; ++ ++/* ++Caller Mode: AP, Ad-HoC(M) ++ ++Notes: To create a BSS ++ ++Command Mode ++*/ ++struct createbss_parm { ++ struct wlan_bssid_ex network; ++}; ++ ++/* ++Caller Mode: AP, Ad-HoC, Infra ++ ++Notes: To set the NIC mode of RTL8711 ++ ++Command Mode ++ ++The definition of mode: ++ ++#define IW_MODE_AUTO 0 Let the driver decides which AP to join ++#define IW_MODE_ADHOC 1 Single cell network (Ad-Hoc Clients) ++#define IW_MODE_INFRA 2 Multi cell network, roaming, .. ++#define IW_MODE_MASTER 3 Synchronisation master or Access Point ++#define IW_MODE_REPEAT 4 Wireless Repeater (forwarder) ++#define IW_MODE_SECOND 5 Secondary master/repeater (backup) ++#define IW_MODE_MONITOR 6 Passive monitor (listen only) ++ ++*/ ++struct setopmode_parm { ++ u8 mode; ++ u8 rsvd[3]; ++}; ++ ++/* ++Caller Mode: AP, Ad-HoC, Infra ++ ++Notes: To ask RTL8711 performing site-survey ++ ++Command-Event Mode ++ ++*/ ++ ++#define RTW_SSID_SCAN_AMOUNT 9 /* for WEXT_CSCAN_AMOUNT 9 */ ++#define RTW_CHANNEL_SCAN_AMOUNT (14+37) ++struct sitesurvey_parm { ++ sint scan_mode; /* active: 1, passive: 0 */ ++ u8 ssid_num; ++ u8 ch_num; ++ struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT]; ++ struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT]; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To set the auth type of RTL8711. open/shared/802.1x ++ ++Command Mode ++ ++*/ ++struct setauth_parm { ++ u8 mode; /* 0: legacy open, 1: legacy shared 2: 802.1x */ ++ u8 _1x; /* 0: PSK, 1: TLS */ ++ u8 rsvd[2]; ++}; ++ ++/* ++Caller Mode: Infra ++ ++a. algorithm: wep40, wep104, tkip & aes ++b. keytype: grp key/unicast key ++c. key contents ++ ++when shared key ==> keyid is the camid ++when 802.1x ==> keyid [0:1] ==> grp key ++when 802.1x ==> keyid > 2 ==> unicast key ++ ++*/ ++struct setkey_parm { ++ u8 algorithm; /* encryption algorithm, could be none, wep40, TKIP, CCMP, wep104 */ ++ u8 keyid; ++ u8 grpkey; /* 1: this is the grpkey for 802.1x. 0: this is the unicast key for 802.1x */ ++ u8 set_tx; /* 1: main tx key for wep. 0: other key. */ ++ u8 key[16]; /* this could be 40 or 104 */ ++}; ++ ++/* ++When in AP or Ad-Hoc mode, this is used to ++allocate an sw/hw entry for a newly associated sta. ++ ++Command ++ ++when shared key ==> algorithm/keyid ++ ++*/ ++struct set_stakey_parm { ++ u8 addr[ETH_ALEN]; ++ u8 algorithm; ++ u8 keyid; ++ u8 key[16]; ++}; ++ ++struct set_stakey_rsp { ++ u8 addr[ETH_ALEN]; ++ u8 keyid; ++ u8 rsvd; ++}; ++ ++/* ++Caller Ad-Hoc/AP ++ ++Command -Rsp(AID == CAMID) mode ++ ++This is to force fw to add an sta_data entry per driver's request. ++ ++FW will write an cam entry associated with it. ++ ++*/ ++struct set_assocsta_parm { ++ u8 addr[ETH_ALEN]; ++}; ++ ++struct set_assocsta_rsp { ++ u8 cam_id; ++ u8 rsvd[3]; ++}; ++ ++/* ++ Caller Ad-Hoc/AP ++ ++ Command mode ++ ++ This is to force fw to del an sta_data entry per driver's request ++ ++ FW will invalidate the cam entry associated with it. ++ ++*/ ++struct del_assocsta_parm { ++ u8 addr[ETH_ALEN]; ++}; ++ ++/* ++Caller Mode: AP/Ad-HoC(M) ++ ++Notes: To notify fw that given staid has changed its power state ++ ++Command Mode ++ ++*/ ++struct setstapwrstate_parm { ++ u8 staid; ++ u8 status; ++ u8 hwaddr[6]; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To setup the basic rate of RTL8711 ++ ++Command Mode ++ ++*/ ++struct setbasicrate_parm { ++ u8 basicrates[NumRates]; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To read the current basic rate ++ ++Command-Rsp Mode ++ ++*/ ++struct getbasicrate_parm { ++ u32 rsvd; ++}; ++ ++struct getbasicrate_rsp { ++ u8 basicrates[NumRates]; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To setup the data rate of RTL8711 ++ ++Command Mode ++ ++*/ ++struct setdatarate_parm { ++ u8 mac_id; ++ u8 datarates[NumRates]; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To read the current data rate ++ ++Command-Rsp Mode ++ ++*/ ++struct getdatarate_parm { ++ u32 rsvd; ++ ++}; ++struct getdatarate_rsp { ++ u8 datarates[NumRates]; ++}; ++ ++ ++/* ++Caller Mode: Any ++AP: AP can use the info for the contents of beacon frame ++Infra: STA can use the info when sitesurveying ++Ad-HoC(M): Like AP ++Ad-HoC(C): Like STA ++ ++ ++Notes: To set the phy capability of the NIC ++ ++Command Mode ++ ++*/ ++ ++struct setphyinfo_parm { ++ struct regulatory_class class_sets[NUM_REGULATORYS]; ++ u8 status; ++}; ++ ++struct getphyinfo_parm { ++ u32 rsvd; ++}; ++ ++struct getphyinfo_rsp { ++ struct regulatory_class class_sets[NUM_REGULATORYS]; ++ u8 status; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To set the channel/modem/band ++This command will be used when channel/modem/band is changed. ++ ++Command Mode ++ ++*/ ++struct setphy_parm { ++ u8 rfchannel; ++ u8 modem; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To get the current setting of channel/modem/band ++ ++Command-Rsp Mode ++ ++*/ ++struct getphy_parm { ++ u32 rsvd; ++ ++}; ++struct getphy_rsp { ++ u8 rfchannel; ++ u8 modem; ++}; ++ ++struct readBB_parm { ++ u8 offset; ++}; ++struct readBB_rsp { ++ u8 value; ++}; ++ ++struct readTSSI_parm { ++ u8 offset; ++}; ++struct readTSSI_rsp { ++ u8 value; ++}; ++ ++struct writeBB_parm { ++ u8 offset; ++ u8 value; ++}; ++ ++struct readRF_parm { ++ u8 offset; ++}; ++struct readRF_rsp { ++ u32 value; ++}; ++ ++struct writeRF_parm { ++ u32 offset; ++ u32 value; ++}; ++ ++struct getrfintfs_parm { ++ u8 rfintfs; ++}; ++ ++ ++struct Tx_Beacon_param ++{ ++ struct wlan_bssid_ex network; ++}; ++ ++/* ++ Notes: This command is used for H2C/C2H loopback testing ++ ++ mac[0] == 0 ++ ==> CMD mode, return H2C_SUCCESS. ++ The following condition must be ture under CMD mode ++ mac[1] == mac[4], mac[2] == mac[3], mac[0]=mac[5]= 0; ++ s0 == 0x1234, s1 == 0xabcd, w0 == 0x78563412, w1 == 0x5aa5def7; ++ s2 == (b1 << 8 | b0); ++ ++ mac[0] == 1 ++ ==> CMD_RSP mode, return H2C_SUCCESS_RSP ++ ++ The rsp layout shall be: ++ rsp: parm: ++ mac[0] = mac[5]; ++ mac[1] = mac[4]; ++ mac[2] = mac[3]; ++ mac[3] = mac[2]; ++ mac[4] = mac[1]; ++ mac[5] = mac[0]; ++ s0 = s1; ++ s1 = swap16(s0); ++ w0 = swap32(w1); ++ b0 = b1 ++ s2 = s0 + s1 ++ b1 = b0 ++ w1 = w0 ++ ++ mac[0] == 2 ++ ==> CMD_EVENT mode, return H2C_SUCCESS ++ The event layout shall be: ++ event: parm: ++ mac[0] = mac[5]; ++ mac[1] = mac[4]; ++ mac[2] = event's sequence number, starting from 1 to parm's marc[3] ++ mac[3] = mac[2]; ++ mac[4] = mac[1]; ++ mac[5] = mac[0]; ++ s0 = swap16(s0) - event.mac[2]; ++ s1 = s1 + event.mac[2]; ++ w0 = swap32(w0); ++ b0 = b1 ++ s2 = s0 + event.mac[2] ++ b1 = b0 ++ w1 = swap32(w1) - event.mac[2]; ++ ++ parm->mac[3] is the total event counts that host requested. ++ ++ ++ event will be the same with the cmd's param. ++ ++*/ ++ ++/* CMD param Formart for driver extra cmd handler */ ++struct drvextra_cmd_parm { ++ int ec_id; /* extra cmd id */ ++ int type; /* Can use this field as the type id or command size */ ++ int size; /* buffer size */ ++ unsigned char *pbuf; ++}; ++ ++/*------------------- Below are used for RF/BB tunning ---------------------*/ ++ ++struct setantenna_parm { ++ u8 tx_antset; ++ u8 rx_antset; ++ u8 tx_antenna; ++ u8 rx_antenna; ++}; ++ ++struct enrateadaptive_parm { ++ u32 en; ++}; ++ ++struct settxagctbl_parm { ++ u32 txagc[MAX_RATES_LENGTH]; ++}; ++ ++struct gettxagctbl_parm { ++ u32 rsvd; ++}; ++struct gettxagctbl_rsp { ++ u32 txagc[MAX_RATES_LENGTH]; ++}; ++ ++struct setagcctrl_parm { ++ u32 agcctrl; /* 0: pure hw, 1: fw */ ++}; ++ ++ ++struct setssup_parm { ++ u32 ss_ForceUp[MAX_RATES_LENGTH]; ++}; ++ ++struct getssup_parm { ++ u32 rsvd; ++}; ++struct getssup_rsp { ++ u8 ss_ForceUp[MAX_RATES_LENGTH]; ++}; ++ ++ ++struct setssdlevel_parm { ++ u8 ss_DLevel[MAX_RATES_LENGTH]; ++}; ++ ++struct getssdlevel_parm { ++ u32 rsvd; ++}; ++struct getssdlevel_rsp { ++ u8 ss_DLevel[MAX_RATES_LENGTH]; ++}; ++ ++struct setssulevel_parm { ++ u8 ss_ULevel[MAX_RATES_LENGTH]; ++}; ++ ++struct getssulevel_parm { ++ u32 rsvd; ++}; ++struct getssulevel_rsp { ++ u8 ss_ULevel[MAX_RATES_LENGTH]; ++}; ++ ++ ++struct setcountjudge_parm { ++ u8 count_judge[MAX_RATES_LENGTH]; ++}; ++ ++struct getcountjudge_parm { ++ u32 rsvd; ++}; ++struct getcountjudge_rsp { ++ u8 count_judge[MAX_RATES_LENGTH]; ++}; ++ ++ ++struct setratable_parm { ++ u8 ss_ForceUp[NumRates]; ++ u8 ss_ULevel[NumRates]; ++ u8 ss_DLevel[NumRates]; ++ u8 count_judge[NumRates]; ++}; ++ ++struct getratable_parm { ++ uint rsvd; ++}; ++struct getratable_rsp { ++ u8 ss_ForceUp[NumRates]; ++ u8 ss_ULevel[NumRates]; ++ u8 ss_DLevel[NumRates]; ++ u8 count_judge[NumRates]; ++}; ++ ++ ++/* to get TX, RX retry count */ ++struct gettxretrycnt_parm{ ++ unsigned int rsvd; ++}; ++struct gettxretrycnt_rsp{ ++ unsigned long tx_retrycnt; ++}; ++ ++struct getrxretrycnt_parm{ ++ unsigned int rsvd; ++}; ++struct getrxretrycnt_rsp{ ++ unsigned long rx_retrycnt; ++}; ++ ++/* to get BCNOK, BCNERR count */ ++struct getbcnokcnt_parm{ ++ unsigned int rsvd; ++}; ++struct getbcnokcnt_rsp{ ++ unsigned long bcnokcnt; ++}; ++ ++struct getbcnerrcnt_parm{ ++ unsigned int rsvd; ++}; ++struct getbcnerrcnt_rsp{ ++ unsigned long bcnerrcnt; ++}; ++ ++/* to get current TX power level */ ++struct getcurtxpwrlevel_parm{ ++ unsigned int rsvd; ++}; ++struct getcurtxpwrlevel_rsp{ ++ unsigned short tx_power; ++}; ++ ++struct setprobereqextraie_parm { ++ unsigned char e_id; ++ unsigned char ie_len; ++ unsigned char ie[0]; ++}; ++ ++struct setassocreqextraie_parm { ++ unsigned char e_id; ++ unsigned char ie_len; ++ unsigned char ie[0]; ++}; ++ ++struct setproberspextraie_parm { ++ unsigned char e_id; ++ unsigned char ie_len; ++ unsigned char ie[0]; ++}; ++ ++struct setassocrspextraie_parm { ++ unsigned char e_id; ++ unsigned char ie_len; ++ unsigned char ie[0]; ++}; ++ ++ ++struct addBaReq_parm ++{ ++ unsigned int tid; ++ u8 addr[ETH_ALEN]; ++}; ++ ++/*H2C Handler index: 46 */ ++struct set_ch_parm { ++ u8 ch; ++ u8 bw; ++ u8 ch_offset; ++}; ++ ++/*H2C Handler index: 59 */ ++struct SetChannelPlan_param ++{ ++ u8 channel_plan; ++}; ++ ++/*H2C Handler index: 60 */ ++struct LedBlink_param ++{ ++ void *pLed; ++}; ++ ++/*H2C Handler index: 61 */ ++struct SetChannelSwitch_param ++{ ++ u8 new_ch_no; ++}; ++ ++/*H2C Handler index: 62 */ ++struct TDLSoption_param ++{ ++ u8 addr[ETH_ALEN]; ++ u8 option; ++}; ++ ++/*H2C Handler index: 64 */ ++struct RunInThread_param ++{ ++ void (*func)(void*); ++ void *context; ++}; ++ ++ ++#define GEN_CMD_CODE(cmd) cmd ## _CMD_ ++ ++ ++/* ++ ++Result: ++0x00: success ++0x01: sucess, and check Response. ++0x02: cmd ignored due to duplicated sequcne number ++0x03: cmd dropped due to invalid cmd code ++0x04: reserved. ++ ++*/ ++ ++#define H2C_RSP_OFFSET 512 ++ ++#define H2C_SUCCESS 0x00 ++#define H2C_SUCCESS_RSP 0x01 ++#define H2C_DUPLICATED 0x02 ++#define H2C_DROPPED 0x03 ++#define H2C_PARAMETERS_ERROR 0x04 ++#define H2C_REJECTED 0x05 ++#define H2C_CMD_OVERFLOW 0x06 ++#define H2C_RESERVED 0x07 ++ ++u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid, int ssid_num, struct rtw_ieee80211_channel *ch, int ch_num); ++extern u8 rtw_createbss_cmd(struct adapter *padapter); ++u8 rtw_startbss_cmd(struct adapter *padapter, int flags); ++ ++struct sta_info; ++extern u8 rtw_setstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 unicast_key, bool enqueue); ++extern u8 rtw_clearstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 enqueue); ++ ++extern u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network* pnetwork); ++u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueue); ++extern u8 rtw_setopmode_cmd(struct adapter *padapter, enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype, bool enqueue); ++extern u8 rtw_setdatarate_cmd(struct adapter *padapter, u8 *rateset); ++extern u8 rtw_setrfintfs_cmd(struct adapter *padapter, u8 mode); ++ ++extern u8 rtw_gettssi_cmd(struct adapter *padapter, u8 offset, u8 *pval); ++extern u8 rtw_setfwdig_cmd(struct adapter *padapter, u8 type); ++extern u8 rtw_setfwra_cmd(struct adapter *padapter, u8 type); ++ ++extern u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr); ++/* add for CONFIG_IEEE80211W, none 11w also can use */ ++extern u8 rtw_reset_securitypriv_cmd(struct adapter *padapter); ++extern u8 rtw_free_assoc_resources_cmd(struct adapter *padapter); ++extern u8 rtw_dynamic_chk_wk_cmd(struct adapter *adapter); ++ ++u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue); ++u8 rtw_dm_in_lps_wk_cmd(struct adapter *padapter); ++ ++u8 rtw_dm_ra_mask_wk_cmd(struct adapter *padapter, u8 *psta); ++ ++extern u8 rtw_ps_cmd(struct adapter *padapter); ++ ++u8 rtw_chk_hi_queue_cmd(struct adapter *padapter); ++ ++extern u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan, u8 enqueue, u8 swconfig); ++ ++extern u8 rtw_c2h_packet_wk_cmd(struct adapter *padapter, u8 *pbuf, u16 length); ++extern u8 rtw_c2h_wk_cmd(struct adapter *padapter, u8 *c2h_evt); ++ ++u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf); ++ ++extern void rtw_survey_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd); ++extern void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd); ++extern void rtw_joinbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd); ++extern void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd); ++extern void rtw_getbbrfreg_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd); ++ ++extern void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd); ++extern void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd); ++extern void rtw_getrttbl_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd); ++ ++ ++struct _cmd_callback { ++ u32 cmd_code; ++ void (*callback)(struct adapter *padapter, struct cmd_obj *cmd); ++}; ++ ++enum rtw_h2c_cmd ++{ ++ GEN_CMD_CODE(_Read_MACREG) , /*0*/ ++ GEN_CMD_CODE(_Write_MACREG) , ++ GEN_CMD_CODE(_Read_BBREG) , ++ GEN_CMD_CODE(_Write_BBREG) , ++ GEN_CMD_CODE(_Read_RFREG) , ++ GEN_CMD_CODE(_Write_RFREG) , /*5*/ ++ GEN_CMD_CODE(_Read_EEPROM) , ++ GEN_CMD_CODE(_Write_EEPROM) , ++ GEN_CMD_CODE(_Read_EFUSE) , ++ GEN_CMD_CODE(_Write_EFUSE) , ++ ++ GEN_CMD_CODE(_Read_CAM) , /*10*/ ++ GEN_CMD_CODE(_Write_CAM) , ++ GEN_CMD_CODE(_setBCNITV), ++ GEN_CMD_CODE(_setMBIDCFG), ++ GEN_CMD_CODE(_JoinBss), /*14*/ ++ GEN_CMD_CODE(_DisConnect) , /*15*/ ++ GEN_CMD_CODE(_CreateBss) , ++ GEN_CMD_CODE(_SetOpMode) , ++ GEN_CMD_CODE(_SiteSurvey), /*18*/ ++ GEN_CMD_CODE(_SetAuth) , ++ ++ GEN_CMD_CODE(_SetKey) , /*20*/ ++ GEN_CMD_CODE(_SetStaKey) , ++ GEN_CMD_CODE(_SetAssocSta) , ++ GEN_CMD_CODE(_DelAssocSta) , ++ GEN_CMD_CODE(_SetStaPwrState) , ++ GEN_CMD_CODE(_SetBasicRate) , /*25*/ ++ GEN_CMD_CODE(_GetBasicRate) , ++ GEN_CMD_CODE(_SetDataRate) , ++ GEN_CMD_CODE(_GetDataRate) , ++ GEN_CMD_CODE(_SetPhyInfo) , ++ ++ GEN_CMD_CODE(_GetPhyInfo) , /*30*/ ++ GEN_CMD_CODE(_SetPhy) , ++ GEN_CMD_CODE(_GetPhy) , ++ GEN_CMD_CODE(_readRssi) , ++ GEN_CMD_CODE(_readGain) , ++ GEN_CMD_CODE(_SetAtim) , /*35*/ ++ GEN_CMD_CODE(_SetPwrMode) , ++ GEN_CMD_CODE(_JoinbssRpt), ++ GEN_CMD_CODE(_SetRaTable) , ++ GEN_CMD_CODE(_GetRaTable) , ++ ++ GEN_CMD_CODE(_GetCCXReport), /*40*/ ++ GEN_CMD_CODE(_GetDTMReport), ++ GEN_CMD_CODE(_GetTXRateStatistics), ++ GEN_CMD_CODE(_SetUsbSuspend), ++ GEN_CMD_CODE(_SetH2cLbk), ++ GEN_CMD_CODE(_AddBAReq) , /*45*/ ++ GEN_CMD_CODE(_SetChannel), /*46*/ ++ GEN_CMD_CODE(_SetTxPower), ++ GEN_CMD_CODE(_SwitchAntenna), ++ GEN_CMD_CODE(_SetCrystalCap), ++ GEN_CMD_CODE(_SetSingleCarrierTx), /*50*/ ++ ++ GEN_CMD_CODE(_SetSingleToneTx),/*51*/ ++ GEN_CMD_CODE(_SetCarrierSuppressionTx), ++ GEN_CMD_CODE(_SetContinuousTx), ++ GEN_CMD_CODE(_SwitchBandwidth), /*54*/ ++ GEN_CMD_CODE(_TX_Beacon), /*55*/ ++ ++ GEN_CMD_CODE(_Set_MLME_EVT), /*56*/ ++ GEN_CMD_CODE(_Set_Drv_Extra), /*57*/ ++ GEN_CMD_CODE(_Set_H2C_MSG), /*58*/ ++ ++ GEN_CMD_CODE(_SetChannelPlan), /*59*/ ++ GEN_CMD_CODE(_LedBlink), /*60*/ ++ ++ GEN_CMD_CODE(_SetChannelSwitch), /*61*/ ++ GEN_CMD_CODE(_TDLS), /*62*/ ++ GEN_CMD_CODE(_ChkBMCSleepq), /*63*/ ++ ++ GEN_CMD_CODE(_RunInThreadCMD), /*64*/ ++ ++ MAX_H2CCMD ++}; ++ ++#define _GetBBReg_CMD_ _Read_BBREG_CMD_ ++#define _SetBBReg_CMD_ _Write_BBREG_CMD_ ++#define _GetRFReg_CMD_ _Read_RFREG_CMD_ ++#define _SetRFReg_CMD_ _Write_RFREG_CMD_ ++ ++#endif /* _CMD_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_debug.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_debug.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_debug.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_debug.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,355 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTW_DEBUG_H__ ++#define __RTW_DEBUG_H__ ++ ++#include ++ ++#define _drv_always_ 1 ++#define _drv_emerg_ 2 ++#define _drv_alert_ 3 ++#define _drv_crit_ 4 ++#define _drv_err_ 5 ++#define _drv_warning_ 6 ++#define _drv_notice_ 7 ++#define _drv_info_ 8 ++#define _drv_dump_ 9 ++#define _drv_debug_ 10 ++ ++ ++#define _module_rtl871x_xmit_c_ BIT(0) ++#define _module_xmit_osdep_c_ BIT(1) ++#define _module_rtl871x_recv_c_ BIT(2) ++#define _module_recv_osdep_c_ BIT(3) ++#define _module_rtl871x_mlme_c_ BIT(4) ++#define _module_mlme_osdep_c_ BIT(5) ++#define _module_rtl871x_sta_mgt_c_ BIT(6) ++#define _module_rtl871x_cmd_c_ BIT(7) ++#define _module_cmd_osdep_c_ BIT(8) ++#define _module_rtl871x_io_c_ BIT(9) ++#define _module_io_osdep_c_ BIT(10) ++#define _module_os_intfs_c_ BIT(11) ++#define _module_rtl871x_security_c_ BIT(12) ++#define _module_rtl871x_eeprom_c_ BIT(13) ++#define _module_hal_init_c_ BIT(14) ++#define _module_hci_hal_init_c_ BIT(15) ++#define _module_rtl871x_ioctl_c_ BIT(16) ++#define _module_rtl871x_ioctl_set_c_ BIT(17) ++#define _module_rtl871x_ioctl_query_c_ BIT(18) ++#define _module_rtl871x_pwrctrl_c_ BIT(19) ++#define _module_hci_intfs_c_ BIT(20) ++#define _module_hci_ops_c_ BIT(21) ++#define _module_osdep_service_c_ BIT(22) ++#define _module_mp_ BIT(23) ++#define _module_hci_ops_os_c_ BIT(24) ++#define _module_rtl871x_ioctl_os_c BIT(25) ++#define _module_rtl8712_cmd_c_ BIT(26) ++/* define _module_efuse_ BIT(27) */ ++#define _module_rtl8192c_xmit_c_ BIT(28) ++#define _module_hal_xmit_c_ BIT(28) ++#define _module_efuse_ BIT(29) ++#define _module_rtl8712_recv_c_ BIT(30) ++#define _module_rtl8712_led_c_ BIT(31) ++ ++#undef _MODULE_DEFINE_ ++ ++#if defined _RTW_XMIT_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_xmit_c_ ++#elif defined _XMIT_OSDEP_C_ ++ #define _MODULE_DEFINE_ _module_xmit_osdep_c_ ++#elif defined _RTW_RECV_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_recv_c_ ++#elif defined _RECV_OSDEP_C_ ++ #define _MODULE_DEFINE_ _module_recv_osdep_c_ ++#elif defined _RTW_MLME_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_mlme_c_ ++#elif defined _MLME_OSDEP_C_ ++ #define _MODULE_DEFINE_ _module_mlme_osdep_c_ ++#elif defined _RTW_MLME_EXT_C_ ++ #define _MODULE_DEFINE_ 1 ++#elif defined _RTW_STA_MGT_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_sta_mgt_c_ ++#elif defined _RTW_CMD_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_cmd_c_ ++#elif defined _CMD_OSDEP_C_ ++ #define _MODULE_DEFINE_ _module_cmd_osdep_c_ ++#elif defined _RTW_IO_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_io_c_ ++#elif defined _IO_OSDEP_C_ ++ #define _MODULE_DEFINE_ _module_io_osdep_c_ ++#elif defined _OS_INTFS_C_ ++ #define _MODULE_DEFINE_ _module_os_intfs_c_ ++#elif defined _RTW_SECURITY_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_security_c_ ++#elif defined _RTW_EEPROM_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_eeprom_c_ ++#elif defined _HAL_INTF_C_ ++ #define _MODULE_DEFINE_ _module_hal_init_c_ ++#elif (defined _HCI_HAL_INIT_C_) || (defined _SDIO_HALINIT_C_) ++ #define _MODULE_DEFINE_ _module_hci_hal_init_c_ ++#elif defined _RTL871X_IOCTL_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_ioctl_c_ ++#elif defined _RTL871X_IOCTL_SET_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_ioctl_set_c_ ++#elif defined _RTL871X_IOCTL_QUERY_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_ioctl_query_c_ ++#elif defined _RTL871X_PWRCTRL_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_pwrctrl_c_ ++#elif defined _RTW_PWRCTRL_C_ ++ #define _MODULE_DEFINE_ 1 ++#elif defined _HCI_INTF_C_ ++ #define _MODULE_DEFINE_ _module_hci_intfs_c_ ++#elif defined _HCI_OPS_C_ ++ #define _MODULE_DEFINE_ _module_hci_ops_c_ ++#elif defined _SDIO_OPS_C_ ++ #define _MODULE_DEFINE_ 1 ++#elif defined _OSDEP_HCI_INTF_C_ ++ #define _MODULE_DEFINE_ _module_hci_intfs_c_ ++#elif defined _OSDEP_SERVICE_C_ ++ #define _MODULE_DEFINE_ _module_osdep_service_c_ ++#elif defined _HCI_OPS_OS_C_ ++ #define _MODULE_DEFINE_ _module_hci_ops_os_c_ ++#elif defined _RTL871X_IOCTL_LINUX_C_ ++ #define _MODULE_DEFINE_ _module_rtl871x_ioctl_os_c ++#elif defined _RTL8712_CMD_C_ ++ #define _MODULE_DEFINE_ _module_rtl8712_cmd_c_ ++#elif defined _RTL8192C_XMIT_C_ ++ #define _MODULE_DEFINE_ 1 ++#elif defined _RTL8723AS_XMIT_C_ ++ #define _MODULE_DEFINE_ 1 ++#elif defined _RTL8712_RECV_C_ ++ #define _MODULE_DEFINE_ _module_rtl8712_recv_c_ ++#elif defined _RTL8192CU_RECV_C_ ++ #define _MODULE_DEFINE_ _module_rtl8712_recv_c_ ++#elif defined _RTL871X_MLME_EXT_C_ ++ #define _MODULE_DEFINE_ _module_mlme_osdep_c_ ++#elif defined _RTW_EFUSE_C_ ++ #define _MODULE_DEFINE_ _module_efuse_ ++#endif ++ ++#define RT_TRACE(_Comp, _Level, Fmt) do{}while (0) ++#define RT_PRINT_DATA(_Comp, _Level, _TitleString, _HexData, _HexDataLen) do{}while (0) ++ ++#define DBG_871X(x, ...) do {} while (0) ++#define MSG_8192C(x, ...) do {} while (0) ++#define DBG_8192C(x,...) do {} while (0) ++#define DBG_871X_LEVEL(x,...) do {} while (0) ++ ++#undef _dbgdump ++ ++#ifndef _RTL871X_DEBUG_C_ ++ extern u32 GlobalDebugLevel; ++ extern u64 GlobalDebugComponents; ++#endif ++ ++#define _dbgdump printk ++ ++#define DRIVER_PREFIX "RTL8723BS: " ++ ++#if defined(_dbgdump) ++ ++/* with driver-defined prefix */ ++#undef DBG_871X_LEVEL ++#define DBG_871X_LEVEL(level, fmt, arg...) \ ++ do {\ ++ if (level <= GlobalDebugLevel) {\ ++ if (level <= _drv_err_ && level > _drv_always_) \ ++ _dbgdump(DRIVER_PREFIX"ERROR " fmt, ##arg);\ ++ else \ ++ _dbgdump(DRIVER_PREFIX fmt, ##arg);\ ++ }\ ++ }while (0) ++ ++/* without driver-defined prefix */ ++#undef _DBG_871X_LEVEL ++#define _DBG_871X_LEVEL(level, fmt, arg...) \ ++ do {\ ++ if (level <= GlobalDebugLevel) {\ ++ if (level <= _drv_err_ && level > _drv_always_) \ ++ _dbgdump("ERROR " fmt, ##arg);\ ++ else \ ++ _dbgdump(fmt, ##arg);\ ++ }\ ++ }while (0) ++ ++#define RTW_DBGDUMP NULL /* 'stream' for _dbgdump */ ++ ++/* dump message to selected 'stream' */ ++#define DBG_871X_SEL(sel, fmt, arg...) \ ++ do { \ ++ if (sel == RTW_DBGDUMP) \ ++ _DBG_871X_LEVEL(_drv_always_, fmt, ##arg); \ ++ else \ ++ seq_printf(sel, fmt, ##arg); \ ++ } while (0) ++ ++/* dump message to selected 'stream' with driver-defined prefix */ ++#define DBG_871X_SEL_NL(sel, fmt, arg...) \ ++ do { \ ++ if (sel == RTW_DBGDUMP) \ ++ DBG_871X_LEVEL(_drv_always_, fmt, ##arg); \ ++ else \ ++ seq_printf(sel, fmt, ##arg); \ ++ } while (0) ++ ++#endif /* defined(_dbgdump) */ ++ ++#ifdef CONFIG_DEBUG ++#if defined(_dbgdump) ++ #undef DBG_871X ++ #define DBG_871X(...) do {\ ++ _dbgdump(DRIVER_PREFIX __VA_ARGS__);\ ++ }while (0) ++ ++ #undef MSG_8192C ++ #define MSG_8192C(...) do {\ ++ _dbgdump(DRIVER_PREFIX __VA_ARGS__);\ ++ }while (0) ++ ++ #undef DBG_8192C ++ #define DBG_8192C(...) do {\ ++ _dbgdump(DRIVER_PREFIX __VA_ARGS__);\ ++ }while (0) ++#endif /* defined(_dbgdump) */ ++#endif /* CONFIG_DEBUG */ ++ ++#ifdef CONFIG_DEBUG_RTL871X ++ ++#if defined(_dbgdump) && defined(_MODULE_DEFINE_) ++ ++ #undef RT_TRACE ++ #define RT_TRACE(_Comp, _Level, Fmt)\ ++ do {\ ++ if ((_Comp & GlobalDebugComponents) && (_Level <= GlobalDebugLevel)) {\ ++ _dbgdump("%s [0x%08x,%d]", DRIVER_PREFIX, (unsigned int)_Comp, _Level);\ ++ _dbgdump Fmt;\ ++ }\ ++ }while (0) ++ ++#endif /* defined(_dbgdump) && defined(_MODULE_DEFINE_) */ ++ ++ ++#if defined(_dbgdump) ++ #undef RT_PRINT_DATA ++ #define RT_PRINT_DATA(_Comp, _Level, _TitleString, _HexData, _HexDataLen) \ ++ if (((_Comp) & GlobalDebugComponents) && (_Level <= GlobalDebugLevel)) \ ++ { \ ++ int __i; \ ++ u8 *ptr = (u8 *)_HexData; \ ++ _dbgdump("%s", DRIVER_PREFIX); \ ++ _dbgdump(_TitleString); \ ++ for (__i = 0; __i<(int)_HexDataLen; __i++) \ ++ { \ ++ _dbgdump("%02X%s", ptr[__i], (((__i + 1) % 4) == 0)?" ":" "); \ ++ if (((__i + 1) % 16) == 0) _dbgdump("\n"); \ ++ } \ ++ _dbgdump("\n"); \ ++ } ++#endif /* defined(_dbgdump) */ ++#endif /* CONFIG_DEBUG_RTL871X */ ++ ++#ifdef CONFIG_DBG_COUNTER ++#define DBG_COUNTER(counter) counter++ ++#else ++#define DBG_COUNTER(counter) ++#endif ++ ++void dump_drv_version(void *sel); ++void dump_log_level(void *sel); ++ ++void sd_f0_reg_dump(void *sel, struct adapter *adapter); ++ ++void mac_reg_dump(void *sel, struct adapter *adapter); ++void bb_reg_dump(void *sel, struct adapter *adapter); ++void rf_reg_dump(void *sel, struct adapter *adapter); ++ ++#ifdef CONFIG_PROC_DEBUG ++ssize_t proc_set_write_reg(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++int proc_get_read_reg(struct seq_file *m, void *v); ++ssize_t proc_set_read_reg(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++ ++int proc_get_fwstate(struct seq_file *m, void *v); ++int proc_get_sec_info(struct seq_file *m, void *v); ++int proc_get_mlmext_state(struct seq_file *m, void *v); ++ ++int proc_get_roam_flags(struct seq_file *m, void *v); ++ssize_t proc_set_roam_flags(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++int proc_get_roam_param(struct seq_file *m, void *v); ++ssize_t proc_set_roam_param(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++ssize_t proc_set_roam_tgt_addr(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++ ++int proc_get_qos_option(struct seq_file *m, void *v); ++int proc_get_ht_option(struct seq_file *m, void *v); ++int proc_get_rf_info(struct seq_file *m, void *v); ++int proc_get_survey_info(struct seq_file *m, void *v); ++int proc_get_ap_info(struct seq_file *m, void *v); ++int proc_get_adapter_state(struct seq_file *m, void *v); ++int proc_get_trx_info(struct seq_file *m, void *v); ++int proc_get_rate_ctl(struct seq_file *m, void *v); ++ssize_t proc_set_rate_ctl(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++int proc_get_suspend_resume_info(struct seq_file *m, void *v); ++ ++ssize_t proc_set_fwdl_test_case(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++ssize_t proc_set_wait_hiq_empty(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++ ++int proc_get_all_sta_info(struct seq_file *m, void *v); ++ ++int proc_get_rx_signal(struct seq_file *m, void *v); ++ssize_t proc_set_rx_signal(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++int proc_get_hw_status(struct seq_file *m, void *v); ++ ++int proc_get_ht_enable(struct seq_file *m, void *v); ++ssize_t proc_set_ht_enable(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++ ++int proc_get_bw_mode(struct seq_file *m, void *v); ++ssize_t proc_set_bw_mode(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++ ++int proc_get_ampdu_enable(struct seq_file *m, void *v); ++ssize_t proc_set_ampdu_enable(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++ ++int proc_get_rx_ampdu(struct seq_file *m, void *v); ++ssize_t proc_set_rx_ampdu(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++ ++int proc_get_rx_stbc(struct seq_file *m, void *v); ++ssize_t proc_set_rx_stbc(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++ ++int proc_get_en_fwps(struct seq_file *m, void *v); ++ssize_t proc_set_en_fwps(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++ ++/* int proc_get_two_path_rssi(struct seq_file *m, void *v); */ ++int proc_get_rssi_disp(struct seq_file *m, void *v); ++ssize_t proc_set_rssi_disp(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++ ++int proc_get_btcoex_dbg(struct seq_file *m, void *v); ++ssize_t proc_set_btcoex_dbg(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++int proc_get_btcoex_info(struct seq_file *m, void *v); ++ ++int proc_get_odm_dbg_comp(struct seq_file *m, void *v); ++ssize_t proc_set_odm_dbg_comp(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++int proc_get_odm_dbg_level(struct seq_file *m, void *v); ++ssize_t proc_set_odm_dbg_level(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++ ++int proc_get_odm_adaptivity(struct seq_file *m, void *v); ++ssize_t proc_set_odm_adaptivity(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++ ++#ifdef CONFIG_DBG_COUNTER ++int proc_get_rx_logs(struct seq_file *m, void *v); ++int proc_get_tx_logs(struct seq_file *m, void *v); ++int proc_get_int_logs(struct seq_file *m, void *v); ++#endif ++ ++#endif /* CONFIG_PROC_DEBUG */ ++ ++#endif /* __RTW_DEBUG_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_eeprom.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_eeprom.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_eeprom.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_eeprom.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,128 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTW_EEPROM_H__ ++#define __RTW_EEPROM_H__ ++ ++ ++#define RTL8712_EEPROM_ID 0x8712 ++/* define EEPROM_MAX_SIZE 256 */ ++ ++#define HWSET_MAX_SIZE_128 128 ++#define HWSET_MAX_SIZE_256 256 ++#define HWSET_MAX_SIZE_512 512 ++ ++#define EEPROM_MAX_SIZE HWSET_MAX_SIZE_512 ++ ++#define CLOCK_RATE 50 /* 100us */ ++ ++/* EEPROM opcodes */ ++#define EEPROM_READ_OPCODE 06 ++#define EEPROM_WRITE_OPCODE 05 ++#define EEPROM_ERASE_OPCODE 07 ++#define EEPROM_EWEN_OPCODE 19 /* Erase/write enable */ ++#define EEPROM_EWDS_OPCODE 16 /* Erase/write disable */ ++ ++/* Country codes */ ++#define USA 0x555320 ++#define EUROPE 0x1 /* temp, should be provided later */ ++#define JAPAN 0x2 /* temp, should be provided later */ ++ ++#define eeprom_cis0_sz 17 ++#define eeprom_cis1_sz 50 ++ ++/* */ ++/* Customer ID, note that: */ ++/* This variable is initiailzed through EEPROM or registry, */ ++/* however, its definition may be different with that in EEPROM for */ ++/* EEPROM size consideration. So, we have to perform proper translation between them. */ ++/* Besides, CustomerID of registry has precedence of that of EEPROM. */ ++/* defined below. 060703, by rcnjko. */ ++/* */ ++typedef enum _RT_CUSTOMER_ID ++{ ++ RT_CID_DEFAULT = 0, ++ RT_CID_8187_ALPHA0 = 1, ++ RT_CID_8187_SERCOMM_PS = 2, ++ RT_CID_8187_HW_LED = 3, ++ RT_CID_8187_NETGEAR = 4, ++ RT_CID_WHQL = 5, ++ RT_CID_819x_CAMEO = 6, ++ RT_CID_819x_RUNTOP = 7, ++ RT_CID_819x_Senao = 8, ++ RT_CID_TOSHIBA = 9, /* Merge by Jacken, 2008/01/31. */ ++ RT_CID_819x_Netcore = 10, ++ RT_CID_Nettronix = 11, ++ RT_CID_DLINK = 12, ++ RT_CID_PRONET = 13, ++ RT_CID_COREGA = 14, ++ RT_CID_CHINA_MOBILE = 15, ++ RT_CID_819x_ALPHA = 16, ++ RT_CID_819x_Sitecom = 17, ++ RT_CID_CCX = 18, /* It's set under CCX logo test and isn't demanded for CCX functions, but for test behavior like retry limit and tx report. By Bruce, 2009-02-17. */ ++ RT_CID_819x_Lenovo = 19, ++ RT_CID_819x_QMI = 20, ++ RT_CID_819x_Edimax_Belkin = 21, ++ RT_CID_819x_Sercomm_Belkin = 22, ++ RT_CID_819x_CAMEO1 = 23, ++ RT_CID_819x_MSI = 24, ++ RT_CID_819x_Acer = 25, ++ RT_CID_819x_AzWave_ASUS = 26, ++ RT_CID_819x_AzWave = 27, /* For AzWave in PCIe, The ID is AzWave use and not only Asus */ ++ RT_CID_819x_HP = 28, ++ RT_CID_819x_WNC_COREGA = 29, ++ RT_CID_819x_Arcadyan_Belkin = 30, ++ RT_CID_819x_SAMSUNG = 31, ++ RT_CID_819x_CLEVO = 32, ++ RT_CID_819x_DELL = 33, ++ RT_CID_819x_PRONETS = 34, ++ RT_CID_819x_Edimax_ASUS = 35, ++ RT_CID_NETGEAR = 36, ++ RT_CID_PLANEX = 37, ++ RT_CID_CC_C = 38, ++ RT_CID_819x_Xavi = 39, ++ RT_CID_LENOVO_CHINA = 40, ++ RT_CID_INTEL_CHINA = 41, ++ RT_CID_TPLINK_HPWR = 42, ++ RT_CID_819x_Sercomm_Netgear = 43, ++ RT_CID_819x_ALPHA_Dlink = 44,/* add by ylb 20121012 for customer led for alpha */ ++ RT_CID_WNC_NEC = 45,/* add by page for NEC */ ++ RT_CID_DNI_BUFFALO = 46,/* add by page for NEC */ ++}RT_CUSTOMER_ID, *PRT_CUSTOMER_ID; ++ ++struct eeprom_priv ++{ ++ u8 bautoload_fail_flag; ++ u8 bloadfile_fail_flag; ++ u8 bloadmac_fail_flag; ++ u8 EepromOrEfuse; ++ ++ u8 mac_addr[6]; /* PermanentAddress */ ++ ++ u16 channel_plan; ++ u16 CustomerID; ++ ++ u8 efuse_eeprom_data[EEPROM_MAX_SIZE]; /* 92C:256bytes, 88E:512bytes, we use union set (512bytes) */ ++ u8 adjuseVoltageVal; ++ ++ u8 EEPROMRFGainOffset; ++ u8 EEPROMRFGainVal; ++ ++ u8 sdio_setting; ++ u32 ocr; ++ u8 cis0[eeprom_cis0_sz]; ++ u8 cis1[eeprom_cis1_sz]; ++}; ++ ++#endif /* __RTL871X_EEPROM_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_efuse.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_efuse.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_efuse.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_efuse.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,132 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTW_EFUSE_H__ ++#define __RTW_EFUSE_H__ ++ ++ ++#define EFUSE_ERROE_HANDLE 1 ++ ++#define PG_STATE_HEADER 0x01 ++#define PG_STATE_WORD_0 0x02 ++#define PG_STATE_WORD_1 0x04 ++#define PG_STATE_WORD_2 0x08 ++#define PG_STATE_WORD_3 0x10 ++#define PG_STATE_DATA 0x20 ++ ++#define PG_SWBYTE_H 0x01 ++#define PG_SWBYTE_L 0x02 ++ ++#define PGPKT_DATA_SIZE 8 ++ ++#define EFUSE_WIFI 0 ++#define EFUSE_BT 1 ++ ++enum _EFUSE_DEF_TYPE { ++ TYPE_EFUSE_MAX_SECTION = 0, ++ TYPE_EFUSE_REAL_CONTENT_LEN = 1, ++ TYPE_AVAILABLE_EFUSE_BYTES_BANK = 2, ++ TYPE_AVAILABLE_EFUSE_BYTES_TOTAL = 3, ++ TYPE_EFUSE_MAP_LEN = 4, ++ TYPE_EFUSE_PROTECT_BYTES_BANK = 5, ++ TYPE_EFUSE_CONTENT_LEN_BANK = 6, ++}; ++ ++#define EFUSE_MAX_MAP_LEN 512 ++ ++#define EFUSE_MAX_HW_SIZE 512 ++#define EFUSE_MAX_SECTION_BASE 16 ++ ++#define EXT_HEADER(header) ((header & 0x1F) == 0x0F) ++#define ALL_WORDS_DISABLED(wde) ((wde & 0x0F) == 0x0F) ++#define GET_HDR_OFFSET_2_0(header) ((header & 0xE0) >> 5) ++ ++#define EFUSE_REPEAT_THRESHOLD_ 3 ++ ++/* */ ++/* The following is for BT Efuse definition */ ++/* */ ++#define EFUSE_BT_MAX_MAP_LEN 1024 ++#define EFUSE_MAX_BANK 4 ++#define EFUSE_MAX_BT_BANK (EFUSE_MAX_BANK-1) ++/* */ ++/*--------------------------Define Parameters-------------------------------*/ ++#define EFUSE_MAX_WORD_UNIT 4 ++ ++/*------------------------------Define structure----------------------------*/ ++typedef struct PG_PKT_STRUCT_A{ ++ u8 offset; ++ u8 word_en; ++ u8 data[8]; ++ u8 word_cnts; ++}PGPKT_STRUCT,*PPGPKT_STRUCT; ++ ++/*------------------------------Define structure----------------------------*/ ++typedef struct _EFUSE_HAL{ ++ u8 fakeEfuseBank; ++ u32 fakeEfuseUsedBytes; ++ u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE]; ++ u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN]; ++ u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN]; ++ ++ u16 BTEfuseUsedBytes; ++ u8 BTEfuseUsedPercentage; ++ u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; ++ u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN]; ++ u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN]; ++ ++ u16 fakeBTEfuseUsedBytes; ++ u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; ++ u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN]; ++ u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN]; ++}EFUSE_HAL, *PEFUSE_HAL; ++ ++ ++/*------------------------Export global variable----------------------------*/ ++extern u8 fakeEfuseBank; ++extern u32 fakeEfuseUsedBytes; ++extern u8 fakeEfuseContent[]; ++extern u8 fakeEfuseInitMap[]; ++extern u8 fakeEfuseModifiedMap[]; ++ ++extern u32 BTEfuseUsedBytes; ++extern u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; ++extern u8 BTEfuseInitMap[]; ++extern u8 BTEfuseModifiedMap[]; ++ ++extern u32 fakeBTEfuseUsedBytes; ++extern u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; ++extern u8 fakeBTEfuseInitMap[]; ++extern u8 fakeBTEfuseModifiedMap[]; ++/*------------------------Export global variable----------------------------*/ ++ ++u16 Efuse_GetCurrentSize(struct adapter *padapter, u8 efuseType, bool bPseudoTest); ++u8 Efuse_CalculateWordCnts(u8 word_en); ++void EFUSE_GetEfuseDefinition(struct adapter *padapter, u8 efuseType, u8 type, void *pOut, bool bPseudoTest); ++u8 efuse_OneByteRead(struct adapter *padapter, u16 addr, u8 *data, bool bPseudoTest); ++u8 efuse_OneByteWrite(struct adapter *padapter, u16 addr, u8 data, bool bPseudoTest); ++ ++void Efuse_PowerSwitch(struct adapter *padapter, u8 bWrite, u8 PwrState); ++int Efuse_PgPacketRead(struct adapter *padapter, u8 offset, u8 *data, bool bPseudoTest); ++int Efuse_PgPacketWrite(struct adapter *padapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest); ++void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata); ++u8 Efuse_WordEnableDataWrite(struct adapter *padapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest); ++ ++u8 EFUSE_Read1Byte(struct adapter *padapter, u16 Address); ++void EFUSE_ShadowMapUpdate(struct adapter *padapter, u8 efuseType, bool bPseudoTest); ++void EFUSE_ShadowRead(struct adapter *padapter, u8 Type, u16 Offset, u32 *Value); ++void Rtw_Hal_ReadMACAddrFromFile(struct adapter *padapter); ++u32 Rtw_Hal_readPGDataFromConfigFile(struct adapter *padapter); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_event.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_event.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_event.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_event.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,117 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef _RTW_EVENT_H_ ++#define _RTW_EVENT_H_ ++ ++/* ++Used to report a bss has been scanned ++ ++*/ ++struct survey_event { ++ struct wlan_bssid_ex bss; ++}; ++ ++/* ++Used to report that the requested site survey has been done. ++ ++bss_cnt indicates the number of bss that has been reported. ++ ++ ++*/ ++struct surveydone_event { ++ unsigned int bss_cnt; ++ ++}; ++ ++/* ++Used to report the link result of joinning the given bss ++ ++ ++join_res: ++-1: authentication fail ++-2: association fail ++> 0: TID ++ ++*/ ++struct joinbss_event { ++ struct wlan_network network; ++}; ++ ++/* ++Used to report a given STA has joinned the created BSS. ++It is used in AP/Ad-HoC(M) mode. ++ ++ ++*/ ++struct stassoc_event { ++ unsigned char macaddr[6]; ++ unsigned char rsvd[2]; ++ int cam_id; ++ ++}; ++ ++struct stadel_event { ++ unsigned char macaddr[6]; ++ unsigned char rsvd[2]; /* for reason */ ++ int mac_id; ++}; ++ ++struct addba_event ++{ ++ unsigned int tid; ++}; ++ ++struct wmm_event ++{ ++ unsigned char wmm; ++}; ++ ++#define GEN_EVT_CODE(event) event ## _EVT_ ++ ++ ++ ++struct fwevent { ++ u32 parmsize; ++ void (*event_callback)(struct adapter *dev, u8 *pbuf); ++}; ++ ++ ++#define C2HEVENT_SZ 32 ++ ++struct event_node{ ++ unsigned char *node; ++ unsigned char evt_code; ++ unsigned short evt_sz; ++ volatile int *caller_ff_tail; ++ int caller_ff_sz; ++}; ++ ++struct c2hevent_queue { ++ volatile int head; ++ volatile int tail; ++ struct event_node nodes[C2HEVENT_SZ]; ++ unsigned char seq; ++}; ++ ++#define NETWORK_QUEUE_SZ 4 ++ ++struct network_queue { ++ volatile int head; ++ volatile int tail; ++ struct wlan_bssid_ex networks[NETWORK_QUEUE_SZ]; ++}; ++ ++ ++#endif /* _WLANEVENT_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_ht.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_ht.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_ht.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_ht.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,118 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef _RTW_HT_H_ ++#define _RTW_HT_H_ ++ ++ ++struct ht_priv ++{ ++ u8 ht_option; ++ u8 ampdu_enable;/* for enable Tx A-MPDU */ ++ u8 tx_amsdu_enable;/* for enable Tx A-MSDU */ ++ u8 bss_coexist;/* for 20/40 Bss coexist */ ++ ++ /* u8 baddbareq_issued[16]; */ ++ u32 tx_amsdu_maxlen; /* 1: 8k, 0:4k ; default:8k, for tx */ ++ u32 rx_ampdu_maxlen; /* for rx reordering ctrl win_sz, updated when join_callback. */ ++ ++ u8 rx_ampdu_min_spacing; ++ ++ u8 ch_offset;/* PRIME_CHNL_OFFSET */ ++ u8 sgi_20m; ++ u8 sgi_40m; ++ ++ /* for processing Tx A-MPDU */ ++ u8 agg_enable_bitmap; ++ /* u8 ADDBA_retry_count; */ ++ u8 candidate_tid_bitmap; ++ ++ u8 ldpc_cap; ++ u8 stbc_cap; ++ u8 beamform_cap; ++ ++ struct rtw_ieee80211_ht_cap ht_cap; ++ ++}; ++ ++typedef enum AGGRE_SIZE{ ++ HT_AGG_SIZE_8K = 0, ++ HT_AGG_SIZE_16K = 1, ++ HT_AGG_SIZE_32K = 2, ++ HT_AGG_SIZE_64K = 3, ++ VHT_AGG_SIZE_128K = 4, ++ VHT_AGG_SIZE_256K = 5, ++ VHT_AGG_SIZE_512K = 6, ++ VHT_AGG_SIZE_1024K = 7, ++}AGGRE_SIZE_E, *PAGGRE_SIZE_E; ++ ++typedef enum _RT_HT_INF0_CAP{ ++ RT_HT_CAP_USE_TURBO_AGGR = 0x01, ++ RT_HT_CAP_USE_LONG_PREAMBLE = 0x02, ++ RT_HT_CAP_USE_AMPDU = 0x04, ++ RT_HT_CAP_USE_WOW = 0x8, ++ RT_HT_CAP_USE_SOFTAP = 0x10, ++ RT_HT_CAP_USE_92SE = 0x20, ++ RT_HT_CAP_USE_88C_92C = 0x40, ++ RT_HT_CAP_USE_AP_CLIENT_MODE = 0x80, /* AP team request to reserve this bit, by Emily */ ++}RT_HT_INF0_CAPBILITY, *PRT_HT_INF0_CAPBILITY; ++ ++typedef enum _RT_HT_INF1_CAP{ ++ RT_HT_CAP_USE_VIDEO_CLIENT = 0x01, ++ RT_HT_CAP_USE_JAGUAR_BCUT = 0x02, ++ RT_HT_CAP_USE_JAGUAR_CCUT = 0x04, ++}RT_HT_INF1_CAPBILITY, *PRT_HT_INF1_CAPBILITY; ++ ++#define LDPC_HT_ENABLE_RX BIT0 ++#define LDPC_HT_ENABLE_TX BIT1 ++#define LDPC_HT_TEST_TX_ENABLE BIT2 ++#define LDPC_HT_CAP_TX BIT3 ++ ++#define STBC_HT_ENABLE_RX BIT0 ++#define STBC_HT_ENABLE_TX BIT1 ++#define STBC_HT_TEST_TX_ENABLE BIT2 ++#define STBC_HT_CAP_TX BIT3 ++ ++#define BEAMFORMING_HT_BEAMFORMER_ENABLE BIT0 /* Declare our NIC supports beamformer */ ++#define BEAMFORMING_HT_BEAMFORMEE_ENABLE BIT1 /* Declare our NIC supports beamformee */ ++#define BEAMFORMING_HT_BEAMFORMER_TEST BIT2 /* Transmiting Beamforming no matter the target supports it or not */ ++ ++/* */ ++/* The HT Control field */ ++/* */ ++#define SET_HT_CTRL_CSI_STEERING(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+2, 6, 2, _val) ++#define SET_HT_CTRL_NDP_ANNOUNCEMENT(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart)+3, 0, 1, _val) ++#define GET_HT_CTRL_NDP_ANNOUNCEMENT(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+3, 0, 1) ++ ++/* 20/40 BSS Coexist */ ++#define SET_EXT_CAPABILITY_ELE_BSS_COEXIST(_pEleStart, _val) SET_BITS_TO_LE_1BYTE((_pEleStart), 0, 1, _val) ++#define GET_EXT_CAPABILITY_ELE_BSS_COEXIST(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart), 0, 1) ++ ++ ++#define GET_HT_CAPABILITY_ELE_LDPC_CAP(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 0, 1) ++#define GET_HT_CAPABILITY_ELE_TX_STBC(_pEleStart) LE_BITS_TO_1BYTE(_pEleStart, 7, 1) ++ ++#define GET_HT_CAPABILITY_ELE_RX_STBC(_pEleStart) LE_BITS_TO_1BYTE((_pEleStart)+1, 0, 2) ++ ++/* TXBF Capabilities */ ++#define SET_HT_CAP_TXBF_RECEIVE_NDP_CAP(_pEleStart, _val) SET_BITS_TO_LE_4BYTE(((u8 *)(_pEleStart))+21, 3, 1, ((u8)_val)) ++#define SET_HT_CAP_TXBF_TRANSMIT_NDP_CAP(_pEleStart, _val) SET_BITS_TO_LE_4BYTE(((u8 *)(_pEleStart))+21, 4, 1, ((u8)_val)) ++#define SET_HT_CAP_TXBF_EXPLICIT_COMP_STEERING_CAP(_pEleStart, _val) SET_BITS_TO_LE_4BYTE(((u8 *)(_pEleStart))+21, 10, 1, ((u8)_val)) ++#define SET_HT_CAP_TXBF_EXPLICIT_COMP_FEEDBACK_CAP(_pEleStart, _val) SET_BITS_TO_LE_4BYTE(((u8 *)(_pEleStart))+21, 15, 2, ((u8)_val)) ++#define SET_HT_CAP_TXBF_COMP_STEERING_NUM_ANTENNAS(_pEleStart, _val) SET_BITS_TO_LE_4BYTE(((u8 *)(_pEleStart))+21, 23, 2, ((u8)_val)) ++ ++#define GET_HT_CAP_TXBF_EXPLICIT_COMP_STEERING_CAP(_pEleStart) LE_BITS_TO_4BYTE((_pEleStart)+21, 10, 1) ++#define GET_HT_CAP_TXBF_EXPLICIT_COMP_FEEDBACK_CAP(_pEleStart) LE_BITS_TO_4BYTE((_pEleStart)+21, 15, 2) ++ ++#endif /* _RTL871X_HT_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_ioctl.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_ioctl.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_ioctl.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_ioctl.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,80 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef _RTW_IOCTL_H_ ++#define _RTW_IOCTL_H_ ++ ++/* 00 - Success */ ++/* 11 - Error */ ++#define STATUS_SUCCESS (0x00000000L) ++#define STATUS_PENDING (0x00000103L) ++ ++#define STATUS_UNSUCCESSFUL (0xC0000001L) ++#define STATUS_INSUFFICIENT_RESOURCES (0xC000009AL) ++#define STATUS_NOT_SUPPORTED (0xC00000BBL) ++ ++#define NDIS_STATUS_SUCCESS ((uint)STATUS_SUCCESS) ++#define NDIS_STATUS_PENDING ((uint)STATUS_PENDING) ++#define NDIS_STATUS_NOT_RECOGNIZED ((uint)0x00010001L) ++#define NDIS_STATUS_NOT_COPIED ((uint)0x00010002L) ++#define NDIS_STATUS_NOT_ACCEPTED ((uint)0x00010003L) ++#define NDIS_STATUS_CALL_ACTIVE ((uint)0x00010007L) ++ ++#define NDIS_STATUS_FAILURE ((uint)STATUS_UNSUCCESSFUL) ++#define NDIS_STATUS_RESOURCES ((uint)STATUS_INSUFFICIENT_RESOURCES) ++#define NDIS_STATUS_CLOSING ((uint)0xC0010002L) ++#define NDIS_STATUS_BAD_VERSION ((uint)0xC0010004L) ++#define NDIS_STATUS_BAD_CHARACTERISTICS ((uint)0xC0010005L) ++#define NDIS_STATUS_ADAPTER_NOT_FOUND ((uint)0xC0010006L) ++#define NDIS_STATUS_OPEN_FAILED ((uint)0xC0010007L) ++#define NDIS_STATUS_DEVICE_FAILED ((uint)0xC0010008L) ++#define NDIS_STATUS_MULTICAST_FULL ((uint)0xC0010009L) ++#define NDIS_STATUS_MULTICAST_EXISTS ((uint)0xC001000AL) ++#define NDIS_STATUS_MULTICAST_NOT_FOUND ((uint)0xC001000BL) ++#define NDIS_STATUS_REQUEST_ABORTED ((uint)0xC001000CL) ++#define NDIS_STATUS_RESET_IN_PROGRESS ((uint)0xC001000DL) ++#define NDIS_STATUS_CLOSING_INDICATING ((uint)0xC001000EL) ++#define NDIS_STATUS_NOT_SUPPORTED ((uint)STATUS_NOT_SUPPORTED) ++#define NDIS_STATUS_INVALID_PACKET ((uint)0xC001000FL) ++#define NDIS_STATUS_OPEN_LIST_FULL ((uint)0xC0010010L) ++#define NDIS_STATUS_ADAPTER_NOT_READY ((uint)0xC0010011L) ++#define NDIS_STATUS_ADAPTER_NOT_OPEN ((uint)0xC0010012L) ++#define NDIS_STATUS_NOT_INDICATING ((uint)0xC0010013L) ++#define NDIS_STATUS_INVALID_LENGTH ((uint)0xC0010014L) ++#define NDIS_STATUS_INVALID_DATA ((uint)0xC0010015L) ++#define NDIS_STATUS_BUFFER_TOO_SHORT ((uint)0xC0010016L) ++#define NDIS_STATUS_INVALID_OID ((uint)0xC0010017L) ++#define NDIS_STATUS_ADAPTER_REMOVED ((uint)0xC0010018L) ++#define NDIS_STATUS_UNSUPPORTED_MEDIA ((uint)0xC0010019L) ++#define NDIS_STATUS_GROUP_ADDRESS_IN_USE ((uint)0xC001001AL) ++#define NDIS_STATUS_FILE_NOT_FOUND ((uint)0xC001001BL) ++#define NDIS_STATUS_ERROR_READING_FILE ((uint)0xC001001CL) ++#define NDIS_STATUS_ALREADY_MAPPED ((uint)0xC001001DL) ++#define NDIS_STATUS_RESOURCE_CONFLICT ((uint)0xC001001EL) ++#define NDIS_STATUS_NO_CABLE ((uint)0xC001001FL) ++ ++#define NDIS_STATUS_INVALID_SAP ((uint)0xC0010020L) ++#define NDIS_STATUS_SAP_IN_USE ((uint)0xC0010021L) ++#define NDIS_STATUS_INVALID_ADDRESS ((uint)0xC0010022L) ++#define NDIS_STATUS_VC_NOT_ACTIVATED ((uint)0xC0010023L) ++#define NDIS_STATUS_DEST_OUT_OF_ORDER ((uint)0xC0010024L) /* cause 27 */ ++#define NDIS_STATUS_VC_NOT_AVAILABLE ((uint)0xC0010025L) /* cause 35, 45 */ ++#define NDIS_STATUS_CELLRATE_NOT_AVAILABLE ((uint)0xC0010026L) /* cause 37 */ ++#define NDIS_STATUS_INCOMPATABLE_QOS ((uint)0xC0010027L) /* cause 49 */ ++#define NDIS_STATUS_AAL_PARAMS_UNSUPPORTED ((uint)0xC0010028L) /* cause 93 */ ++#define NDIS_STATUS_NO_ROUTE_TO_DESTINATION ((uint)0xC0010029L) /* cause 3 */ ++ ++extern struct iw_handler_def rtw_handlers_def; ++ ++#endif /* #ifndef __INC_CEINFO_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_ioctl_set.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_ioctl_set.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_ioctl_set.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_ioctl_set.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,41 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTW_IOCTL_SET_H_ ++#define __RTW_IOCTL_SET_H_ ++ ++ ++typedef u8 NDIS_802_11_PMKID_VALUE[16]; ++ ++typedef struct _BSSIDInfo { ++ NDIS_802_11_MAC_ADDRESS BSSID; ++ NDIS_802_11_PMKID_VALUE PMKID; ++} BSSIDInfo, *PBSSIDInfo; ++ ++ ++u8 rtw_set_802_11_authentication_mode(struct adapter *pdapter, enum NDIS_802_11_AUTHENTICATION_MODE authmode); ++u8 rtw_set_802_11_bssid(struct adapter *padapter, u8 *bssid); ++u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep * wep); ++u8 rtw_set_802_11_disassociate(struct adapter *padapter); ++u8 rtw_set_802_11_bssid_list_scan(struct adapter *padapter, struct ndis_802_11_ssid *pssid, int ssid_max_num); ++u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter, enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype); ++u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid * ssid); ++u8 rtw_set_802_11_connect(struct adapter *padapter, u8 *bssid, struct ndis_802_11_ssid *ssid); ++ ++u8 rtw_validate_bssid(u8 *bssid); ++u8 rtw_validate_ssid(struct ndis_802_11_ssid *ssid); ++ ++u16 rtw_get_cur_max_rate(struct adapter *adapter); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_io.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_io.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_io.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_io.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,373 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#ifndef _RTW_IO_H_ ++#define _RTW_IO_H_ ++ ++#define NUM_IOREQ 8 ++ ++#define MAX_PROT_SZ (64-16) ++ ++#define _IOREADY 0 ++#define _IO_WAIT_COMPLETE 1 ++#define _IO_WAIT_RSP 2 ++ ++/* IO COMMAND TYPE */ ++#define _IOSZ_MASK_ (0x7F) ++#define _IO_WRITE_ BIT(7) ++#define _IO_FIXED_ BIT(8) ++#define _IO_BURST_ BIT(9) ++#define _IO_BYTE_ BIT(10) ++#define _IO_HW_ BIT(11) ++#define _IO_WORD_ BIT(12) ++#define _IO_SYNC_ BIT(13) ++#define _IO_CMDMASK_ (0x1F80) ++ ++ ++/* ++ For prompt mode accessing, caller shall free io_req ++ Otherwise, io_handler will free io_req ++*/ ++ ++ ++ ++/* IO STATUS TYPE */ ++#define _IO_ERR_ BIT(2) ++#define _IO_SUCCESS_ BIT(1) ++#define _IO_DONE_ BIT(0) ++ ++ ++#define IO_RD32 (_IO_SYNC_ | _IO_WORD_) ++#define IO_RD16 (_IO_SYNC_ | _IO_HW_) ++#define IO_RD8 (_IO_SYNC_ | _IO_BYTE_) ++ ++#define IO_RD32_ASYNC (_IO_WORD_) ++#define IO_RD16_ASYNC (_IO_HW_) ++#define IO_RD8_ASYNC (_IO_BYTE_) ++ ++#define IO_WR32 (_IO_WRITE_ | _IO_SYNC_ | _IO_WORD_) ++#define IO_WR16 (_IO_WRITE_ | _IO_SYNC_ | _IO_HW_) ++#define IO_WR8 (_IO_WRITE_ | _IO_SYNC_ | _IO_BYTE_) ++ ++#define IO_WR32_ASYNC (_IO_WRITE_ | _IO_WORD_) ++#define IO_WR16_ASYNC (_IO_WRITE_ | _IO_HW_) ++#define IO_WR8_ASYNC (_IO_WRITE_ | _IO_BYTE_) ++ ++/* ++ ++ Only Sync. burst accessing is provided. ++ ++*/ ++ ++#define IO_WR_BURST(x) (_IO_WRITE_ | _IO_SYNC_ | _IO_BURST_ | ((x) & _IOSZ_MASK_)) ++#define IO_RD_BURST(x) (_IO_SYNC_ | _IO_BURST_ | ((x) & _IOSZ_MASK_)) ++ ++ ++ ++/* below is for the intf_option bit defition... */ ++ ++#define _INTF_ASYNC_ BIT(0) /* support async io */ ++ ++struct intf_priv; ++struct intf_hdl; ++struct io_queue; ++ ++struct _io_ops { ++ u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr); ++ u16 (*_read16)(struct intf_hdl *pintfhdl, u32 addr); ++ u32 (*_read32)(struct intf_hdl *pintfhdl, u32 addr); ++ ++ int (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val); ++ int (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val); ++ int (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val); ++ int (*_writeN)(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata); ++ ++ int (*_write8_async)(struct intf_hdl *pintfhdl, u32 addr, u8 val); ++ int (*_write16_async)(struct intf_hdl *pintfhdl, u32 addr, u16 val); ++ int (*_write32_async)(struct intf_hdl *pintfhdl, u32 addr, u32 val); ++ ++ void (*_read_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++ void (*_write_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++ ++ void (*_sync_irp_protocol_rw)(struct io_queue *pio_q); ++ ++ u32 (*_read_interrupt)(struct intf_hdl *pintfhdl, u32 addr); ++ ++ u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++ u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++ ++ u32 (*_write_scsi)(struct intf_hdl *pintfhdl, u32 cnt, u8 *pmem); ++ ++ void (*_read_port_cancel)(struct intf_hdl *pintfhdl); ++ void (*_write_port_cancel)(struct intf_hdl *pintfhdl); ++ ++ u8 (*_sd_f0_read8)(struct intf_hdl *pintfhdl, u32 addr); ++}; ++ ++struct io_req { ++ struct list_head list; ++ u32 addr; ++ volatile u32 val; ++ u32 command; ++ u32 status; ++ u8 *pbuf; ++ _sema sema; ++ ++ void (*_async_io_callback)(struct adapter *padater, struct io_req *pio_req, u8 *cnxt); ++ u8 *cnxt; ++}; ++ ++struct intf_hdl { ++ struct adapter *padapter; ++ struct dvobj_priv *pintf_dev;/* pointer to &(padapter->dvobjpriv); */ ++ ++ struct _io_ops io_ops; ++}; ++ ++struct reg_protocol_rd { ++ ++#ifdef __LITTLE_ENDIAN ++ ++ /* DW1 */ ++ u32 NumOfTrans:4; ++ u32 Reserved1:4; ++ u32 Reserved2:24; ++ /* DW2 */ ++ u32 ByteCount:7; ++ u32 WriteEnable:1; /* 0:read, 1:write */ ++ u32 FixOrContinuous:1; /* 0:continuous, 1: Fix */ ++ u32 BurstMode:1; ++ u32 Byte1Access:1; ++ u32 Byte2Access:1; ++ u32 Byte4Access:1; ++ u32 Reserved3:3; ++ u32 Reserved4:16; ++ /* DW3 */ ++ u32 BusAddress; ++ /* DW4 */ ++ /* u32 Value; */ ++#else ++ ++ ++/* DW1 */ ++ u32 Reserved1 :4; ++ u32 NumOfTrans :4; ++ ++ u32 Reserved2 :24; ++ ++ /* DW2 */ ++ u32 WriteEnable : 1; ++ u32 ByteCount :7; ++ ++ ++ u32 Reserved3 : 3; ++ u32 Byte4Access : 1; ++ ++ u32 Byte2Access : 1; ++ u32 Byte1Access : 1; ++ u32 BurstMode :1 ; ++ u32 FixOrContinuous : 1; ++ ++ u32 Reserved4 : 16; ++ ++ /* DW3 */ ++ u32 BusAddress; ++ ++ /* DW4 */ ++ /* u32 Value; */ ++ ++#endif ++ ++}; ++ ++ ++struct reg_protocol_wt { ++ ++ ++#ifdef __LITTLE_ENDIAN ++ ++ /* DW1 */ ++ u32 NumOfTrans:4; ++ u32 Reserved1:4; ++ u32 Reserved2:24; ++ /* DW2 */ ++ u32 ByteCount:7; ++ u32 WriteEnable:1; /* 0:read, 1:write */ ++ u32 FixOrContinuous:1; /* 0:continuous, 1: Fix */ ++ u32 BurstMode:1; ++ u32 Byte1Access:1; ++ u32 Byte2Access:1; ++ u32 Byte4Access:1; ++ u32 Reserved3:3; ++ u32 Reserved4:16; ++ /* DW3 */ ++ u32 BusAddress; ++ /* DW4 */ ++ u32 Value; ++ ++#else ++ /* DW1 */ ++ u32 Reserved1 :4; ++ u32 NumOfTrans :4; ++ ++ u32 Reserved2 :24; ++ ++ /* DW2 */ ++ u32 WriteEnable : 1; ++ u32 ByteCount :7; ++ ++ u32 Reserved3 : 3; ++ u32 Byte4Access : 1; ++ ++ u32 Byte2Access : 1; ++ u32 Byte1Access : 1; ++ u32 BurstMode :1 ; ++ u32 FixOrContinuous : 1; ++ ++ u32 Reserved4 : 16; ++ ++ /* DW3 */ ++ u32 BusAddress; ++ ++ /* DW4 */ ++ u32 Value; ++ ++#endif ++ ++}; ++#define SD_IO_TRY_CNT (8) ++#define MAX_CONTINUAL_IO_ERR SD_IO_TRY_CNT ++ ++int rtw_inc_and_chk_continual_io_error(struct dvobj_priv *dvobj); ++void rtw_reset_continual_io_error(struct dvobj_priv *dvobj); ++ ++/* ++Below is the data structure used by _io_handler ++ ++*/ ++ ++struct io_queue { ++ _lock lock; ++ struct list_head free_ioreqs; ++ struct list_head pending; /* The io_req list that will be served in the single protocol read/write. */ ++ struct list_head processing; ++ u8 *free_ioreqs_buf; /* 4-byte aligned */ ++ u8 *pallocated_free_ioreqs_buf; ++ struct intf_hdl intf; ++}; ++ ++struct io_priv{ ++ ++ struct adapter *padapter; ++ ++ struct intf_hdl intf; ++ ++}; ++ ++extern uint ioreq_flush(struct adapter *adapter, struct io_queue *ioqueue); ++extern void sync_ioreq_enqueue(struct io_req *preq, struct io_queue *ioqueue); ++extern uint sync_ioreq_flush(struct adapter *adapter, struct io_queue *ioqueue); ++ ++ ++extern uint free_ioreq(struct io_req *preq, struct io_queue *pio_queue); ++extern struct io_req *alloc_ioreq(struct io_queue *pio_q); ++ ++extern uint register_intf_hdl(u8 *dev, struct intf_hdl *pintfhdl); ++extern void unregister_intf_hdl(struct intf_hdl *pintfhdl); ++ ++extern void _rtw_attrib_read(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++extern void _rtw_attrib_write(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++ ++extern u8 _rtw_read8(struct adapter *adapter, u32 addr); ++extern u16 _rtw_read16(struct adapter *adapter, u32 addr); ++extern u32 _rtw_read32(struct adapter *adapter, u32 addr); ++ ++extern int _rtw_write8(struct adapter *adapter, u32 addr, u8 val); ++extern int _rtw_write16(struct adapter *adapter, u32 addr, u16 val); ++extern int _rtw_write32(struct adapter *adapter, u32 addr, u32 val); ++ ++extern u8 _rtw_sd_f0_read8(struct adapter *adapter, u32 addr); ++ ++extern u32 _rtw_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++ ++#define rtw_read8(adapter, addr) _rtw_read8((adapter), (addr)) ++#define rtw_read16(adapter, addr) _rtw_read16((adapter), (addr)) ++#define rtw_read32(adapter, addr) _rtw_read32((adapter), (addr)) ++ ++#define rtw_write8(adapter, addr, val) _rtw_write8((adapter), (addr), (val)) ++#define rtw_write16(adapter, addr, val) _rtw_write16((adapter), (addr), (val)) ++#define rtw_write32(adapter, addr, val) _rtw_write32((adapter), (addr), (val)) ++ ++#define rtw_write_port(adapter, addr, cnt, mem) _rtw_write_port((adapter), (addr), (cnt), (mem)) ++ ++#define rtw_sd_f0_read8(adapter, addr) _rtw_sd_f0_read8((adapter), (addr)) ++ ++extern void rtw_write_scsi(struct adapter *adapter, u32 cnt, u8 *pmem); ++ ++/* ioreq */ ++extern void ioreq_read8(struct adapter *adapter, u32 addr, u8 *pval); ++extern void ioreq_read16(struct adapter *adapter, u32 addr, u16 *pval); ++extern void ioreq_read32(struct adapter *adapter, u32 addr, u32 *pval); ++extern void ioreq_write8(struct adapter *adapter, u32 addr, u8 val); ++extern void ioreq_write16(struct adapter *adapter, u32 addr, u16 val); ++extern void ioreq_write32(struct adapter *adapter, u32 addr, u32 val); ++ ++ ++extern uint async_read8(struct adapter *adapter, u32 addr, u8 *pbuff, ++ void (*_async_io_callback)(struct adapter *padater, struct io_req *pio_req, u8 *cnxt), u8 *cnxt); ++extern uint async_read16(struct adapter *adapter, u32 addr, u8 *pbuff, ++ void (*_async_io_callback)(struct adapter *padater, struct io_req *pio_req, u8 *cnxt), u8 *cnxt); ++extern uint async_read32(struct adapter *adapter, u32 addr, u8 *pbuff, ++ void (*_async_io_callback)(struct adapter *padater, struct io_req *pio_req, u8 *cnxt), u8 *cnxt); ++ ++extern void async_read_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++extern void async_read_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++ ++extern void async_write8(struct adapter *adapter, u32 addr, u8 val, ++ void (*_async_io_callback)(struct adapter *padater, struct io_req *pio_req, u8 *cnxt), u8 *cnxt); ++extern void async_write16(struct adapter *adapter, u32 addr, u16 val, ++ void (*_async_io_callback)(struct adapter *padater, struct io_req *pio_req, u8 *cnxt), u8 *cnxt); ++extern void async_write32(struct adapter *adapter, u32 addr, u32 val, ++ void (*_async_io_callback)(struct adapter *padater, struct io_req *pio_req, u8 *cnxt), u8 *cnxt); ++ ++extern void async_write_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++extern void async_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++ ++ ++int rtw_init_io_priv(struct adapter *padapter, void (*set_intf_ops)(struct adapter *padapter, struct _io_ops *pops)); ++ ++ ++extern uint alloc_io_queue(struct adapter *adapter); ++extern void free_io_queue(struct adapter *adapter); ++extern void async_bus_io(struct io_queue *pio_q); ++extern void bus_sync_io(struct io_queue *pio_q); ++extern u32 _ioreq2rwmem(struct io_queue *pio_q); ++extern void dev_power_down(struct adapter * Adapter, u8 bpwrup); ++ ++#define PlatformEFIOWrite1Byte(_a, _b, _c) \ ++ rtw_write8(_a, _b, _c) ++#define PlatformEFIOWrite2Byte(_a, _b, _c) \ ++ rtw_write16(_a, _b, _c) ++#define PlatformEFIOWrite4Byte(_a, _b, _c) \ ++ rtw_write32(_a, _b, _c) ++ ++#define PlatformEFIORead1Byte(_a, _b) \ ++ rtw_read8(_a, _b) ++#define PlatformEFIORead2Byte(_a, _b) \ ++ rtw_read16(_a, _b) ++#define PlatformEFIORead4Byte(_a, _b) \ ++ rtw_read32(_a, _b) ++ ++#endif /* _RTL8711_IO_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_mlme_ext.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_mlme_ext.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_mlme_ext.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_mlme_ext.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,888 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTW_MLME_EXT_H_ ++#define __RTW_MLME_EXT_H_ ++ ++ ++/* Commented by Albert 20101105 */ ++/* Increase the SURVEY_TO value from 100 to 150 (100ms to 150ms) */ ++/* The Realtek 8188CE SoftAP will spend around 100ms to send the probe response after receiving the probe request. */ ++/* So, this driver tried to extend the dwell time for each scanning channel. */ ++/* This will increase the chance to receive the probe response from SoftAP. */ ++ ++#define SURVEY_TO (100) ++#define REAUTH_TO (300) /* 50) */ ++#define REASSOC_TO (300) /* 50) */ ++/* define DISCONNECT_TO (3000) */ ++#define ADDBA_TO (2000) ++ ++#define LINKED_TO (1) /* unit:2 sec, 1x2 =2 sec */ ++ ++#define REAUTH_LIMIT (4) ++#define REASSOC_LIMIT (4) ++#define READDBA_LIMIT (2) ++ ++#define ROAMING_LIMIT 8 ++/* define IOCMD_REG0 0x10250370 */ ++/* define IOCMD_REG1 0x10250374 */ ++/* define IOCMD_REG2 0x10250378 */ ++ ++/* define FW_DYNAMIC_FUN_SWITCH 0x10250364 */ ++ ++/* define WRITE_BB_CMD 0xF0000001 */ ++/* define SET_CHANNEL_CMD 0xF3000000 */ ++/* define UPDATE_RA_CMD 0xFD0000A2 */ ++ ++#define DYNAMIC_FUNC_DISABLE (0x0) ++ ++/* ====== ODM_ABILITY_E ======== */ ++/* BB ODM section BIT 0-15 */ ++#define DYNAMIC_BB_DIG BIT0 /* ODM_BB_DIG */ ++#define DYNAMIC_BB_RA_MASK BIT1 /* ODM_BB_RA_MASK */ ++#define DYNAMIC_BB_DYNAMIC_TXPWR BIT2 /* ODM_BB_DYNAMIC_TXPWR */ ++#define DYNAMIC_BB_BB_FA_CNT BIT3 /* ODM_BB_FA_CNT */ ++#define DYNAMIC_BB_RSSI_MONITOR BIT4 /* ODM_BB_RSSI_MONITOR */ ++#define DYNAMIC_BB_CCK_PD BIT5 /* ODM_BB_CCK_PD */ ++#define DYNAMIC_BB_ANT_DIV BIT6 /* ODM_BB_ANT_DIV */ ++#define DYNAMIC_BB_PWR_SAVE BIT7 /* ODM_BB_PWR_SAVE */ ++#define DYNAMIC_BB_PWR_TRAIN BIT8 /* ODM_BB_PWR_TRAIN */ ++#define DYNAMIC_BB_RATE_ADAPTIVE BIT9 /* ODM_BB_RATE_ADAPTIVE */ ++#define DYNAMIC_BB_PATH_DIV BIT10/* ODM_BB_PATH_DIV */ ++#define DYNAMIC_BB_PSD BIT11/* ODM_BB_PSD */ ++#define DYNAMIC_BB_RXHP BIT12/* ODM_BB_RXHP */ ++#define DYNAMIC_BB_ADAPTIVITY BIT13/* ODM_BB_ADAPTIVITY */ ++#define DYNAMIC_BB_DYNAMIC_ATC BIT14/* ODM_BB_DYNAMIC_ATC */ ++ ++/* MAC DM section BIT 16-23 */ ++#define DYNAMIC_MAC_EDCA_TURBO BIT16/* ODM_MAC_EDCA_TURBO */ ++#define DYNAMIC_MAC_EARLY_MODE BIT17/* ODM_MAC_EARLY_MODE */ ++ ++/* RF ODM section BIT 24-31 */ ++#define DYNAMIC_RF_TX_PWR_TRACK BIT24/* ODM_RF_TX_PWR_TRACK */ ++#define DYNAMIC_RF_RX_GAIN_TRACK BIT25/* ODM_RF_RX_GAIN_TRACK */ ++#define DYNAMIC_RF_CALIBRATION BIT26/* ODM_RF_CALIBRATION */ ++ ++#define DYNAMIC_ALL_FUNC_ENABLE 0xFFFFFFF ++ ++#define _HW_STATE_NOLINK_ 0x00 ++#define _HW_STATE_ADHOC_ 0x01 ++#define _HW_STATE_STATION_ 0x02 ++#define _HW_STATE_AP_ 0x03 ++ ++ ++#define _1M_RATE_ 0 ++#define _2M_RATE_ 1 ++#define _5M_RATE_ 2 ++#define _11M_RATE_ 3 ++#define _6M_RATE_ 4 ++#define _9M_RATE_ 5 ++#define _12M_RATE_ 6 ++#define _18M_RATE_ 7 ++#define _24M_RATE_ 8 ++#define _36M_RATE_ 9 ++#define _48M_RATE_ 10 ++#define _54M_RATE_ 11 ++ ++/******************************************************** ++MCS rate definitions ++*********************************************************/ ++#define MCS_RATE_1R (0x000000ff) ++#define MCS_RATE_2R (0x0000ffff) ++#define MCS_RATE_3R (0x00ffffff) ++#define MCS_RATE_4R (0xffffffff) ++#define MCS_RATE_2R_13TO15_OFF (0x00001fff) ++ ++ ++extern unsigned char RTW_WPA_OUI[]; ++extern unsigned char WMM_OUI[]; ++extern unsigned char WPS_OUI[]; ++extern unsigned char WFD_OUI[]; ++extern unsigned char P2P_OUI[]; ++ ++extern unsigned char WMM_INFO_OUI[]; ++extern unsigned char WMM_PARA_OUI[]; ++ ++ ++/* */ ++/* Channel Plan Type. */ ++/* Note: */ ++/* We just add new channel plan when the new channel plan is different from any of the following */ ++/* channel plan. */ ++/* If you just wnat to customize the acitions(scan period or join actions) about one of the channel plan, */ ++/* customize them in RT_CHANNEL_INFO in the RT_CHANNEL_LIST. */ ++/* */ ++typedef enum _RT_CHANNEL_DOMAIN ++{ ++ /* old channel plan mapping ===== */ ++ RT_CHANNEL_DOMAIN_FCC = 0x00, ++ RT_CHANNEL_DOMAIN_IC = 0x01, ++ RT_CHANNEL_DOMAIN_ETSI = 0x02, ++ RT_CHANNEL_DOMAIN_SPAIN = 0x03, ++ RT_CHANNEL_DOMAIN_FRANCE = 0x04, ++ RT_CHANNEL_DOMAIN_MKK = 0x05, ++ RT_CHANNEL_DOMAIN_MKK1 = 0x06, ++ RT_CHANNEL_DOMAIN_ISRAEL = 0x07, ++ RT_CHANNEL_DOMAIN_TELEC = 0x08, ++ RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN = 0x09, ++ RT_CHANNEL_DOMAIN_WORLD_WIDE_13 = 0x0A, ++ RT_CHANNEL_DOMAIN_TAIWAN = 0x0B, ++ RT_CHANNEL_DOMAIN_CHINA = 0x0C, ++ RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO = 0x0D, ++ RT_CHANNEL_DOMAIN_KOREA = 0x0E, ++ RT_CHANNEL_DOMAIN_TURKEY = 0x0F, ++ RT_CHANNEL_DOMAIN_JAPAN = 0x10, ++ RT_CHANNEL_DOMAIN_FCC_NO_DFS = 0x11, ++ RT_CHANNEL_DOMAIN_JAPAN_NO_DFS = 0x12, ++ RT_CHANNEL_DOMAIN_WORLD_WIDE_5G = 0x13, ++ RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS = 0x14, ++ ++ /* new channel plan mapping, (2GDOMAIN_5GDOMAIN) ===== */ ++ RT_CHANNEL_DOMAIN_WORLD_NULL = 0x20, ++ RT_CHANNEL_DOMAIN_ETSI1_NULL = 0x21, ++ RT_CHANNEL_DOMAIN_FCC1_NULL = 0x22, ++ RT_CHANNEL_DOMAIN_MKK1_NULL = 0x23, ++ RT_CHANNEL_DOMAIN_ETSI2_NULL = 0x24, ++ RT_CHANNEL_DOMAIN_FCC1_FCC1 = 0x25, ++ RT_CHANNEL_DOMAIN_WORLD_ETSI1 = 0x26, ++ RT_CHANNEL_DOMAIN_MKK1_MKK1 = 0x27, ++ RT_CHANNEL_DOMAIN_WORLD_KCC1 = 0x28, ++ RT_CHANNEL_DOMAIN_WORLD_FCC2 = 0x29, ++ RT_CHANNEL_DOMAIN_WORLD_FCC3 = 0x30, ++ RT_CHANNEL_DOMAIN_WORLD_FCC4 = 0x31, ++ RT_CHANNEL_DOMAIN_WORLD_FCC5 = 0x32, ++ RT_CHANNEL_DOMAIN_WORLD_FCC6 = 0x33, ++ RT_CHANNEL_DOMAIN_FCC1_FCC7 = 0x34, ++ RT_CHANNEL_DOMAIN_WORLD_ETSI2 = 0x35, ++ RT_CHANNEL_DOMAIN_WORLD_ETSI3 = 0x36, ++ RT_CHANNEL_DOMAIN_MKK1_MKK2 = 0x37, ++ RT_CHANNEL_DOMAIN_MKK1_MKK3 = 0x38, ++ RT_CHANNEL_DOMAIN_FCC1_NCC1 = 0x39, ++ RT_CHANNEL_DOMAIN_FCC1_NCC2 = 0x40, ++ RT_CHANNEL_DOMAIN_GLOBAL_NULL = 0x41, ++ RT_CHANNEL_DOMAIN_ETSI1_ETSI4 = 0x42, ++ RT_CHANNEL_DOMAIN_FCC1_FCC2 = 0x43, ++ RT_CHANNEL_DOMAIN_FCC1_NCC3 = 0x44, ++ RT_CHANNEL_DOMAIN_WORLD_ETSI5 = 0x45, ++ RT_CHANNEL_DOMAIN_FCC1_FCC8 = 0x46, ++ RT_CHANNEL_DOMAIN_WORLD_ETSI6 = 0x47, ++ RT_CHANNEL_DOMAIN_WORLD_ETSI7 = 0x48, ++ RT_CHANNEL_DOMAIN_WORLD_ETSI8 = 0x49, ++ RT_CHANNEL_DOMAIN_WORLD_ETSI9 = 0x50, ++ RT_CHANNEL_DOMAIN_WORLD_ETSI10 = 0x51, ++ RT_CHANNEL_DOMAIN_WORLD_ETSI11 = 0x52, ++ RT_CHANNEL_DOMAIN_FCC1_NCC4 = 0x53, ++ RT_CHANNEL_DOMAIN_WORLD_ETSI12 = 0x54, ++ RT_CHANNEL_DOMAIN_FCC1_FCC9 = 0x55, ++ RT_CHANNEL_DOMAIN_WORLD_ETSI13 = 0x56, ++ RT_CHANNEL_DOMAIN_FCC1_FCC10 = 0x57, ++ /* Add new channel plan above this line =============== */ ++ RT_CHANNEL_DOMAIN_MAX, ++ RT_CHANNEL_DOMAIN_REALTEK_DEFINE = 0x7F, ++}RT_CHANNEL_DOMAIN, *PRT_CHANNEL_DOMAIN; ++ ++typedef enum _RT_CHANNEL_DOMAIN_2G ++{ ++ RT_CHANNEL_DOMAIN_2G_WORLD = 0x00, /* Worldwird 13 */ ++ RT_CHANNEL_DOMAIN_2G_ETSI1 = 0x01, /* Europe */ ++ RT_CHANNEL_DOMAIN_2G_FCC1 = 0x02, /* US */ ++ RT_CHANNEL_DOMAIN_2G_MKK1 = 0x03, /* Japan */ ++ RT_CHANNEL_DOMAIN_2G_ETSI2 = 0x04, /* France */ ++ RT_CHANNEL_DOMAIN_2G_GLOBAL = 0x05, /* Global domain */ ++ RT_CHANNEL_DOMAIN_2G_NULL = 0x06, ++ /* Add new channel plan above this line =============== */ ++ RT_CHANNEL_DOMAIN_2G_MAX, ++}RT_CHANNEL_DOMAIN_2G, *PRT_CHANNEL_DOMAIN_2G; ++ ++typedef enum _RT_CHANNEL_DOMAIN_5G ++{ ++ RT_CHANNEL_DOMAIN_5G_NULL = 0x00, ++ RT_CHANNEL_DOMAIN_5G_ETSI1 = 0x01, /* Europe */ ++ RT_CHANNEL_DOMAIN_5G_ETSI2 = 0x02, /* Australia, New Zealand */ ++ RT_CHANNEL_DOMAIN_5G_ETSI3 = 0x03, /* Russia */ ++ RT_CHANNEL_DOMAIN_5G_FCC1 = 0x04, /* US */ ++ RT_CHANNEL_DOMAIN_5G_FCC2 = 0x05, /* FCC o/w DFS Channels */ ++ RT_CHANNEL_DOMAIN_5G_FCC3 = 0x06, /* India, Mexico */ ++ RT_CHANNEL_DOMAIN_5G_FCC4 = 0x07, /* Venezuela */ ++ RT_CHANNEL_DOMAIN_5G_FCC5 = 0x08, /* China */ ++ RT_CHANNEL_DOMAIN_5G_FCC6 = 0x09, /* Israel */ ++ RT_CHANNEL_DOMAIN_5G_FCC7_IC1 = 0x0A, /* US, Canada */ ++ RT_CHANNEL_DOMAIN_5G_KCC1 = 0x0B, /* Korea */ ++ RT_CHANNEL_DOMAIN_5G_MKK1 = 0x0C, /* Japan */ ++ RT_CHANNEL_DOMAIN_5G_MKK2 = 0x0D, /* Japan (W52, W53) */ ++ RT_CHANNEL_DOMAIN_5G_MKK3 = 0x0E, /* Japan (W56) */ ++ RT_CHANNEL_DOMAIN_5G_NCC1 = 0x0F, /* Taiwan */ ++ RT_CHANNEL_DOMAIN_5G_NCC2 = 0x10, /* Taiwan o/w DFS */ ++ RT_CHANNEL_DOMAIN_5G_NCC3 = 0x11, /* Taiwan w/o DFS, Band4 only */ ++ RT_CHANNEL_DOMAIN_5G_ETSI4 = 0x12, /* Europe w/o DFS, Band1 only */ ++ RT_CHANNEL_DOMAIN_5G_ETSI5 = 0x13, /* Australia, New Zealand(w/o Weather radar) */ ++ RT_CHANNEL_DOMAIN_5G_FCC8 = 0x14, /* Latin America */ ++ RT_CHANNEL_DOMAIN_5G_ETSI6 = 0x15, /* Israel, Bahrain, Egypt, India, China, Malaysia */ ++ RT_CHANNEL_DOMAIN_5G_ETSI7 = 0x16, /* China */ ++ RT_CHANNEL_DOMAIN_5G_ETSI8 = 0x17, /* Jordan */ ++ RT_CHANNEL_DOMAIN_5G_ETSI9 = 0x18, /* Lebanon */ ++ RT_CHANNEL_DOMAIN_5G_ETSI10 = 0x19, /* Qatar */ ++ RT_CHANNEL_DOMAIN_5G_ETSI11 = 0x1A, /* Russia */ ++ RT_CHANNEL_DOMAIN_5G_NCC4 = 0x1B, /* Taiwan, (w/o Weather radar) */ ++ RT_CHANNEL_DOMAIN_5G_ETSI12 = 0x1C, /* Indonesia */ ++ RT_CHANNEL_DOMAIN_5G_FCC9 = 0x1D, /* w/o Weather radar) */ ++ RT_CHANNEL_DOMAIN_5G_ETSI13 = 0x1E, /* w/o Weather radar) */ ++ RT_CHANNEL_DOMAIN_5G_FCC10 = 0x1F, /* Argentina (w/o Weather radar) */ ++ /* Add new channel plan above this line =============== */ ++ /* Driver Self Defined ===== */ ++ RT_CHANNEL_DOMAIN_5G_FCC = 0x20, ++ RT_CHANNEL_DOMAIN_5G_JAPAN_NO_DFS = 0x21, ++ RT_CHANNEL_DOMAIN_5G_FCC4_NO_DFS = 0x22, ++ RT_CHANNEL_DOMAIN_5G_MAX, ++}RT_CHANNEL_DOMAIN_5G, *PRT_CHANNEL_DOMAIN_5G; ++ ++#define rtw_is_channel_plan_valid(chplan) (chplansurvey_timer, (ms)); \ ++ } while (0) ++ ++#define set_link_timer(mlmeext, ms) \ ++ do { \ ++ /*DBG_871X("%s set_link_timer(%p, %d)\n", __func__, (mlmeext), (ms));*/ \ ++ _set_timer(&(mlmeext)->link_timer, (ms)); \ ++ } while (0) ++#define set_sa_query_timer(mlmeext, ms) \ ++ do { \ ++ DBG_871X("%s set_sa_query_timer(%p, %d)\n", __func__, (mlmeext), (ms)); \ ++ _set_timer(&(mlmeext)->sa_query_timer, (ms)); \ ++ } while (0) ++extern int cckrates_included(unsigned char *rate, int ratelen); ++extern int cckratesonly_included(unsigned char *rate, int ratelen); ++ ++extern void process_addba_req(struct adapter *padapter, u8 *paddba_req, u8 *addr); ++ ++extern void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len); ++extern void correct_TSF(struct adapter *padapter, struct mlme_ext_priv *pmlmeext); ++extern void adaptive_early_32k(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len); ++extern u8 traffic_status_watchdog(struct adapter *padapter, u8 from_timer); ++ ++int rtw_chk_start_clnt_join(struct adapter *padapter, u8 *ch, u8 *bw, u8 *offset); ++int rtw_get_ch_setting_union(struct adapter *adapter, u8 *ch, u8 *bw, u8 *offset); ++ ++struct cmd_hdl { ++ uint parmsize; ++ u8 (*h2cfuns)(struct adapter *padapter, u8 *pbuf); ++}; ++ ++ ++u8 read_macreg_hdl(struct adapter *padapter, u8 *pbuf); ++u8 write_macreg_hdl(struct adapter *padapter, u8 *pbuf); ++u8 read_bbreg_hdl(struct adapter *padapter, u8 *pbuf); ++u8 write_bbreg_hdl(struct adapter *padapter, u8 *pbuf); ++u8 read_rfreg_hdl(struct adapter *padapter, u8 *pbuf); ++u8 write_rfreg_hdl(struct adapter *padapter, u8 *pbuf); ++ ++ ++u8 NULL_hdl(struct adapter *padapter, u8 *pbuf); ++u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf); ++u8 disconnect_hdl(struct adapter *padapter, u8 *pbuf); ++u8 createbss_hdl(struct adapter *padapter, u8 *pbuf); ++u8 setopmode_hdl(struct adapter *padapter, u8 *pbuf); ++u8 sitesurvey_cmd_hdl(struct adapter *padapter, u8 *pbuf); ++u8 setauth_hdl(struct adapter *padapter, u8 *pbuf); ++u8 setkey_hdl(struct adapter *padapter, u8 *pbuf); ++u8 set_stakey_hdl(struct adapter *padapter, u8 *pbuf); ++u8 set_assocsta_hdl(struct adapter *padapter, u8 *pbuf); ++u8 del_assocsta_hdl(struct adapter *padapter, u8 *pbuf); ++u8 add_ba_hdl(struct adapter *padapter, unsigned char *pbuf); ++ ++u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf); ++u8 h2c_msg_hdl(struct adapter *padapter, unsigned char *pbuf); ++u8 chk_bmc_sleepq_hdl(struct adapter *padapter, unsigned char *pbuf); ++u8 tx_beacon_hdl(struct adapter *padapter, unsigned char *pbuf); ++u8 set_ch_hdl(struct adapter *padapter, u8 *pbuf); ++u8 set_chplan_hdl(struct adapter *padapter, unsigned char *pbuf); ++u8 led_blink_hdl(struct adapter *padapter, unsigned char *pbuf); ++u8 set_csa_hdl(struct adapter *padapter, unsigned char *pbuf); /* Kurt: Handling DFS channel switch announcement ie. */ ++u8 tdls_hdl(struct adapter *padapter, unsigned char *pbuf); ++u8 run_in_thread_hdl(struct adapter *padapter, u8 *pbuf); ++ ++ ++#define GEN_DRV_CMD_HANDLER(size, cmd) {size, &cmd ## _hdl}, ++#define GEN_MLME_EXT_HANDLER(size, cmd) {size, cmd}, ++ ++struct C2HEvent_Header ++{ ++ ++#ifdef __LITTLE_ENDIAN ++ ++ unsigned int len:16; ++ unsigned int ID:8; ++ unsigned int seq:8; ++#else ++ unsigned int seq:8; ++ unsigned int ID:8; ++ unsigned int len:16; ++#endif ++ unsigned int rsvd; ++}; ++ ++void rtw_dummy_event_callback(struct adapter *adapter , u8 *pbuf); ++void rtw_fwdbg_event_callback(struct adapter *adapter , u8 *pbuf); ++ ++enum rtw_c2h_event ++{ ++ GEN_EVT_CODE(_Read_MACREG) = 0, /*0*/ ++ GEN_EVT_CODE(_Read_BBREG), ++ GEN_EVT_CODE(_Read_RFREG), ++ GEN_EVT_CODE(_Read_EEPROM), ++ GEN_EVT_CODE(_Read_EFUSE), ++ GEN_EVT_CODE(_Read_CAM), /*5*/ ++ GEN_EVT_CODE(_Get_BasicRate), ++ GEN_EVT_CODE(_Get_DataRate), ++ GEN_EVT_CODE(_Survey), /*8*/ ++ GEN_EVT_CODE(_SurveyDone), /*9*/ ++ ++ GEN_EVT_CODE(_JoinBss) , /*10*/ ++ GEN_EVT_CODE(_AddSTA), ++ GEN_EVT_CODE(_DelSTA), ++ GEN_EVT_CODE(_AtimDone) , ++ GEN_EVT_CODE(_TX_Report), ++ GEN_EVT_CODE(_CCX_Report), /*15*/ ++ GEN_EVT_CODE(_DTM_Report), ++ GEN_EVT_CODE(_TX_Rate_Statistics), ++ GEN_EVT_CODE(_C2HLBK), ++ GEN_EVT_CODE(_FWDBG), ++ GEN_EVT_CODE(_C2HFEEDBACK), /*20*/ ++ GEN_EVT_CODE(_ADDBA), ++ GEN_EVT_CODE(_C2HBCN), ++ GEN_EVT_CODE(_ReportPwrState), /* filen: only for PCIE, USB */ ++ GEN_EVT_CODE(_CloseRF), /* filen: only for PCIE, work around ASPM */ ++ GEN_EVT_CODE(_WMM), /*25*/ ++ MAX_C2HEVT ++}; ++ ++ ++#ifdef _RTW_MLME_EXT_C_ ++ ++static struct fwevent wlanevents[] = ++{ ++ {0, rtw_dummy_event_callback}, /*0*/ ++ {0, NULL}, ++ {0, NULL}, ++ {0, NULL}, ++ {0, NULL}, ++ {0, NULL}, ++ {0, NULL}, ++ {0, NULL}, ++ {0, &rtw_survey_event_callback}, /*8*/ ++ {sizeof (struct surveydone_event), &rtw_surveydone_event_callback}, /*9*/ ++ ++ {0, &rtw_joinbss_event_callback}, /*10*/ ++ {sizeof(struct stassoc_event), &rtw_stassoc_event_callback}, ++ {sizeof(struct stadel_event), &rtw_stadel_event_callback}, ++ {0, &rtw_atimdone_event_callback}, ++ {0, rtw_dummy_event_callback}, ++ {0, NULL}, /*15*/ ++ {0, NULL}, ++ {0, NULL}, ++ {0, NULL}, ++ {0, rtw_fwdbg_event_callback}, ++ {0, NULL}, /*20*/ ++ {0, NULL}, ++ {0, NULL}, ++ {0, &rtw_cpwm_event_callback}, ++ {0, NULL}, ++ {0, &rtw_wmm_event_callback}, ++ ++}; ++ ++#endif/* _RTL8192C_CMD_C_ */ ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_mlme.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_mlme.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_mlme.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_mlme.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,695 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTW_MLME_H_ ++#define __RTW_MLME_H_ ++ ++ ++#define MAX_BSS_CNT 128 ++/* define MAX_JOIN_TIMEOUT 2000 */ ++/* define MAX_JOIN_TIMEOUT 2500 */ ++#define MAX_JOIN_TIMEOUT 6500 ++ ++/* Commented by Albert 20101105 */ ++/* Increase the scanning timeout because of increasing the SURVEY_TO value. */ ++ ++#define SCANNING_TIMEOUT 8000 ++ ++#ifdef PALTFORM_OS_WINCE ++#define SCANQUEUE_LIFETIME 12000000 /* unit:us */ ++#else ++#define SCANQUEUE_LIFETIME 20000 /* 20sec, unit:msec */ ++#endif ++ ++#define WIFI_NULL_STATE 0x00000000 ++#define WIFI_ASOC_STATE 0x00000001 /* Under Linked state... */ ++#define WIFI_REASOC_STATE 0x00000002 ++#define WIFI_SLEEP_STATE 0x00000004 ++#define WIFI_STATION_STATE 0x00000008 ++#define WIFI_AP_STATE 0x00000010 ++#define WIFI_ADHOC_STATE 0x00000020 ++#define WIFI_ADHOC_MASTER_STATE 0x00000040 ++#define WIFI_UNDER_LINKING 0x00000080 ++ ++#define WIFI_UNDER_WPS 0x00000100 ++/* define WIFI_UNDER_CMD 0x00000200 */ ++/* define WIFI_UNDER_P2P 0x00000400 */ ++#define WIFI_STA_ALIVE_CHK_STATE 0x00000400 ++#define WIFI_SITE_MONITOR 0x00000800 /* to indicate the station is under site surveying */ ++#ifdef WDS ++#define WIFI_WDS 0x00001000 ++#define WIFI_WDS_RX_BEACON 0x00002000 /* already rx WDS AP beacon */ ++#endif ++#ifdef AUTO_CONFIG ++#define WIFI_AUTOCONF 0x00004000 ++#define WIFI_AUTOCONF_IND 0x00008000 ++#endif ++ ++/** ++* ========== P2P Section Start =============== ++#define WIFI_P2P_LISTEN_STATE 0x00010000 ++#define WIFI_P2P_GROUP_FORMATION_STATE 0x00020000 ++ ========== P2P Section End =============== ++*/ ++ ++/* ifdef UNDER_MPTEST */ ++#define WIFI_MP_STATE 0x00010000 ++#define WIFI_MP_CTX_BACKGROUND 0x00020000 /* in continous tx background */ ++#define WIFI_MP_CTX_ST 0x00040000 /* in continous tx with single-tone */ ++#define WIFI_MP_CTX_BACKGROUND_PENDING 0x00080000 /* pending in continous tx background due to out of skb */ ++#define WIFI_MP_CTX_CCK_HW 0x00100000 /* in continous tx */ ++#define WIFI_MP_CTX_CCK_CS 0x00200000 /* in continous tx with carrier suppression */ ++#define WIFI_MP_LPBK_STATE 0x00400000 ++/* endif */ ++ ++/* define _FW_UNDER_CMD WIFI_UNDER_CMD */ ++#define _FW_UNDER_LINKING WIFI_UNDER_LINKING ++#define _FW_LINKED WIFI_ASOC_STATE ++#define _FW_UNDER_SURVEY WIFI_SITE_MONITOR ++ ++ ++enum dot11AuthAlgrthmNum { ++ dot11AuthAlgrthm_Open = 0, ++ dot11AuthAlgrthm_Shared, ++ dot11AuthAlgrthm_8021X, ++ dot11AuthAlgrthm_Auto, ++ dot11AuthAlgrthm_WAPI, ++ dot11AuthAlgrthm_MaxNum ++}; ++ ++/* Scan type including active and passive scan. */ ++typedef enum _RT_SCAN_TYPE ++{ ++ SCAN_PASSIVE, ++ SCAN_ACTIVE, ++ SCAN_MIX, ++}RT_SCAN_TYPE, *PRT_SCAN_TYPE; ++ ++enum _BAND ++{ ++ GHZ24_50 = 0, ++ GHZ_50, ++ GHZ_24, ++ GHZ_MAX, ++}; ++ ++#define rtw_band_valid(band) ((band) >= GHZ24_50 && (band) < GHZ_MAX) ++ ++enum DriverInterface { ++ DRIVER_WEXT = 1, ++ DRIVER_CFG80211 = 2 ++}; ++ ++enum SCAN_RESULT_TYPE ++{ ++ SCAN_RESULT_P2P_ONLY = 0, /* Will return all the P2P devices. */ ++ SCAN_RESULT_ALL = 1, /* Will return all the scanned device, include AP. */ ++ SCAN_RESULT_WFD_TYPE = 2 /* Will just return the correct WFD device. */ ++ /* If this device is Miracast sink device, it will just return all the Miracast source devices. */ ++}; ++ ++/* ++ ++there are several "locks" in mlme_priv, ++since mlme_priv is a shared resource between many threads, ++like ISR/Call-Back functions, the OID handlers, and even timer functions. ++ ++ ++Each struct __queue has its own locks, already. ++Other items are protected by mlme_priv.lock. ++ ++To avoid possible dead lock, any thread trying to modifiying mlme_priv ++SHALL not lock up more than one locks at a time! ++ ++*/ ++ ++ ++#define traffic_threshold 10 ++#define traffic_scan_period 500 ++ ++struct sitesurvey_ctrl { ++ u64 last_tx_pkts; ++ uint last_rx_pkts; ++ sint traffic_busy; ++ _timer sitesurvey_ctrl_timer; ++}; ++ ++typedef struct _RT_LINK_DETECT_T{ ++ u32 NumTxOkInPeriod; ++ u32 NumRxOkInPeriod; ++ u32 NumRxUnicastOkInPeriod; ++ bool bBusyTraffic; ++ bool bTxBusyTraffic; ++ bool bRxBusyTraffic; ++ bool bHigherBusyTraffic; /* For interrupt migration purpose. */ ++ bool bHigherBusyRxTraffic; /* We may disable Tx interrupt according as Rx traffic. */ ++ bool bHigherBusyTxTraffic; /* We may disable Tx interrupt according as Tx traffic. */ ++ /* u8 TrafficBusyState; */ ++ u8 TrafficTransitionCount; ++ u32 LowPowerTransitionCount; ++}RT_LINK_DETECT_T, *PRT_LINK_DETECT_T; ++ ++struct profile_info { ++ u8 ssidlen; ++ u8 ssid[ WLAN_SSID_MAXLEN ]; ++ u8 peermac[ ETH_ALEN ]; ++}; ++ ++struct tx_invite_req_info{ ++ u8 token; ++ u8 benable; ++ u8 go_ssid[ WLAN_SSID_MAXLEN ]; ++ u8 ssidlen; ++ u8 go_bssid[ ETH_ALEN ]; ++ u8 peer_macaddr[ ETH_ALEN ]; ++ u8 operating_ch; /* This information will be set by using the p2p_set op_ch =x */ ++ u8 peer_ch; /* The listen channel for peer P2P device */ ++ ++}; ++ ++struct tx_invite_resp_info{ ++ u8 token; /* Used to record the dialog token of p2p invitation request frame. */ ++}; ++ ++struct tx_provdisc_req_info{ ++ u16 wps_config_method_request; /* Used when sending the provisioning request frame */ ++ u16 peer_channel_num[2]; /* The channel number which the receiver stands. */ ++ struct ndis_802_11_ssid ssid; ++ u8 peerDevAddr[ ETH_ALEN ]; /* Peer device address */ ++ u8 peerIFAddr[ ETH_ALEN ]; /* Peer interface address */ ++ u8 benable; /* This provision discovery request frame is trigger to send or not */ ++}; ++ ++struct rx_provdisc_req_info{ /* When peer device issue prov_disc_req first, we should store the following informations */ ++ u8 peerDevAddr[ ETH_ALEN ]; /* Peer device address */ ++ u8 strconfig_method_desc_of_prov_disc_req[4]; /* description for the config method located in the provisioning discovery request frame. */ ++ /* The UI must know this information to know which config method the remote p2p device is requiring. */ ++}; ++ ++struct tx_nego_req_info{ ++ u16 peer_channel_num[2]; /* The channel number which the receiver stands. */ ++ u8 peerDevAddr[ ETH_ALEN ]; /* Peer device address */ ++ u8 benable; /* This negoitation request frame is trigger to send or not */ ++}; ++ ++struct group_id_info{ ++ u8 go_device_addr[ ETH_ALEN ]; /* The GO's device address of this P2P group */ ++ u8 ssid[ WLAN_SSID_MAXLEN ]; /* The SSID of this P2P group */ ++}; ++ ++struct scan_limit_info{ ++ u8 scan_op_ch_only; /* When this flag is set, the driver should just scan the operation channel */ ++ u8 operation_ch[2]; /* Store the operation channel of invitation request frame */ ++}; ++ ++struct cfg80211_wifidirect_info{ ++ _timer remain_on_ch_timer; ++ u8 restore_channel; ++ struct ieee80211_channel remain_on_ch_channel; ++ enum nl80211_channel_type remain_on_ch_type; ++ u64 remain_on_ch_cookie; ++ bool is_ro_ch; ++ unsigned long last_ro_ch_time; /* this will be updated at the beginning and end of ro_ch */ ++}; ++ ++struct wifidirect_info{ ++ struct adapter * padapter; ++ _timer find_phase_timer; ++ _timer restore_p2p_state_timer; ++ ++ /* Used to do the scanning. After confirming the peer is availalble, the driver transmits the P2P frame to peer. */ ++ _timer pre_tx_scan_timer; ++ _timer reset_ch_sitesurvey; ++ _timer reset_ch_sitesurvey2; /* Just for resetting the scan limit function by using p2p nego */ ++ struct tx_provdisc_req_info tx_prov_disc_info; ++ struct rx_provdisc_req_info rx_prov_disc_info; ++ struct tx_invite_req_info invitereq_info; ++ struct profile_info profileinfo[ P2P_MAX_PERSISTENT_GROUP_NUM ]; /* Store the profile information of persistent group */ ++ struct tx_invite_resp_info inviteresp_info; ++ struct tx_nego_req_info nego_req_info; ++ struct group_id_info groupid_info; /* Store the group id information when doing the group negotiation handshake. */ ++ struct scan_limit_info rx_invitereq_info; /* Used for get the limit scan channel from the Invitation procedure */ ++ struct scan_limit_info p2p_info; /* Used for get the limit scan channel from the P2P negotiation handshake */ ++ enum P2P_ROLE role; ++ enum P2P_STATE pre_p2p_state; ++ enum P2P_STATE p2p_state; ++ u8 device_addr[ETH_ALEN]; /* The device address should be the mac address of this device. */ ++ u8 interface_addr[ETH_ALEN]; ++ u8 social_chan[4]; ++ u8 listen_channel; ++ u8 operating_channel; ++ u8 listen_dwell; /* This value should be between 1 and 3 */ ++ u8 support_rate[8]; ++ u8 p2p_wildcard_ssid[P2P_WILDCARD_SSID_LEN]; ++ u8 intent; /* should only include the intent value. */ ++ u8 p2p_peer_interface_addr[ ETH_ALEN ]; ++ u8 p2p_peer_device_addr[ ETH_ALEN ]; ++ u8 peer_intent; /* Included the intent value and tie breaker value. */ ++ u8 device_name[ WPS_MAX_DEVICE_NAME_LEN ]; /* Device name for displaying on searching device screen */ ++ u8 device_name_len; ++ u8 profileindex; /* Used to point to the index of profileinfo array */ ++ u8 peer_operating_ch; ++ u8 find_phase_state_exchange_cnt; ++ u16 device_password_id_for_nego; /* The device password ID for group negotation */ ++ u8 negotiation_dialog_token; ++ u8 nego_ssid[ WLAN_SSID_MAXLEN ]; /* SSID information for group negotitation */ ++ u8 nego_ssidlen; ++ u8 p2p_group_ssid[WLAN_SSID_MAXLEN]; ++ u8 p2p_group_ssid_len; ++ u8 persistent_supported; /* Flag to know the persistent function should be supported or not. */ ++ /* In the Sigma test, the Sigma will provide this enable from the sta_set_p2p CAPI. */ ++ /* 0: disable */ ++ /* 1: enable */ ++ u8 session_available; /* Flag to set the WFD session available to enable or disable "by Sigma" */ ++ /* In the Sigma test, the Sigma will disable the session available by using the sta_preset CAPI. */ ++ /* 0: disable */ ++ /* 1: enable */ ++ ++ u8 wfd_tdls_enable; /* Flag to enable or disable the TDLS by WFD Sigma */ ++ /* 0: disable */ ++ /* 1: enable */ ++ u8 wfd_tdls_weaksec; /* Flag to enable or disable the weak security function for TDLS by WFD Sigma */ ++ /* 0: disable */ ++ /* In this case, the driver can't issue the tdsl setup request frame. */ ++ /* 1: enable */ ++ /* In this case, the driver can issue the tdls setup request frame */ ++ /* even the current security is weak security. */ ++ ++ enum P2P_WPSINFO ui_got_wps_info; /* This field will store the WPS value (PIN value or PBC) that UI had got from the user. */ ++ u16 supported_wps_cm; /* This field describes the WPS config method which this driver supported. */ ++ /* The value should be the combination of config method defined in page104 of WPS v2.0 spec. */ ++ u8 external_uuid; /* UUID flag */ ++ u8 uuid[16]; /* UUID */ ++ uint channel_list_attr_len; /* This field will contain the length of body of P2P Channel List attribute of group negotitation response frame. */ ++ u8 channel_list_attr[100]; /* This field will contain the body of P2P Channel List attribute of group negotitation response frame. */ ++ /* We will use the channel_cnt and channel_list fields when constructing the group negotitation confirm frame. */ ++ u8 driver_interface; /* Indicate DRIVER_WEXT or DRIVER_CFG80211 */ ++}; ++ ++struct tdls_ss_record{ /* signal strength record */ ++ u8 macaddr[ETH_ALEN]; ++ u8 RxPWDBAll; ++ u8 is_tdls_sta; /* true: direct link sta, false: else */ ++}; ++ ++struct tdls_info{ ++ u8 ap_prohibited; ++ u8 link_established; ++ u8 sta_cnt; ++ u8 sta_maximum; /* 1:tdls sta is equal (NUM_STA-1), reach max direct link number; 0: else; */ ++ struct tdls_ss_record ss_record; ++ u8 ch_sensing; ++ u8 cur_channel; ++ u8 candidate_ch; ++ u8 collect_pkt_num[MAX_CHANNEL_NUM]; ++ _lock cmd_lock; ++ _lock hdl_lock; ++ u8 watchdog_count; ++ u8 dev_discovered; /* WFD_TDLS: for sigma test */ ++ u8 tdls_enable; ++ u8 external_setup; /* true: setup is handled by wpa_supplicant */ ++}; ++ ++struct tdls_txmgmt { ++ u8 peer[ETH_ALEN]; ++ u8 action_code; ++ u8 dialog_token; ++ u16 status_code; ++ u8 *buf; ++ size_t len; ++ u8 external_support; ++}; ++ ++/* used for mlme_priv.roam_flags */ ++enum { ++ RTW_ROAM_ON_EXPIRED = BIT0, ++ RTW_ROAM_ON_RESUME = BIT1, ++ RTW_ROAM_ACTIVE = BIT2, ++}; ++ ++struct mlme_priv { ++ ++ _lock lock; ++ sint fw_state; /* shall we protect this variable? maybe not necessarily... */ ++ u8 bScanInProcess; ++ u8 to_join; /* flag */ ++ ++ u8 to_roam; /* roaming trying times */ ++ struct wlan_network *roam_network; /* the target of active roam */ ++ u8 roam_flags; ++ u8 roam_rssi_diff_th; /* rssi difference threshold for active scan candidate selection */ ++ u32 roam_scan_int_ms; /* scan interval for active roam */ ++ u32 roam_scanr_exp_ms; /* scan result expire time in ms for roam */ ++ u8 roam_tgt_addr[ETH_ALEN]; /* request to roam to speicific target without other consideration */ ++ ++ u8 *nic_hdl; ++ ++ u8 not_indic_disco; ++ struct list_head *pscanned; ++ struct __queue free_bss_pool; ++ struct __queue scanned_queue; ++ u8 *free_bss_buf; ++ u32 num_of_scanned; ++ ++ struct ndis_802_11_ssid assoc_ssid; ++ u8 assoc_bssid[6]; ++ ++ struct wlan_network cur_network; ++ struct wlan_network *cur_network_scanned; ++ ++ /* uint wireless_mode; no used, remove it */ ++ ++ u32 auto_scan_int_ms; ++ ++ _timer assoc_timer; ++ ++ uint assoc_by_bssid; ++ uint assoc_by_rssi; ++ ++ _timer scan_to_timer; /* driver itself handles scan_timeout status. */ ++ unsigned long scan_start_time; /* used to evaluate the time spent in scanning */ ++ ++ _timer set_scan_deny_timer; ++ atomic_t set_scan_deny; /* 0: allowed, 1: deny */ ++ ++ struct qos_priv qospriv; ++ ++ /* Number of non-HT AP/stations */ ++ int num_sta_no_ht; ++ ++ /* Number of HT AP/stations 20 MHz */ ++ /* int num_sta_ht_20mhz; */ ++ ++ ++ int num_FortyMHzIntolerant; ++ ++ struct ht_priv htpriv; ++ ++ RT_LINK_DETECT_T LinkDetectInfo; ++ _timer dynamic_chk_timer; /* dynamic/periodic check timer */ ++ ++ u8 acm_mask; /* for wmm acm mask */ ++ u8 ChannelPlan; ++ RT_SCAN_TYPE scan_mode; /* active: 1, passive: 0 */ ++ ++ u8 *wps_probe_req_ie; ++ u32 wps_probe_req_ie_len; ++ ++ /* Number of associated Non-ERP stations (i.e., stations using 802.11b ++ * in 802.11g BSS) */ ++ int num_sta_non_erp; ++ ++ /* Number of associated stations that do not support Short Slot Time */ ++ int num_sta_no_short_slot_time; ++ ++ /* Number of associated stations that do not support Short Preamble */ ++ int num_sta_no_short_preamble; ++ ++ int olbc; /* Overlapping Legacy BSS Condition */ ++ ++ /* Number of HT associated stations that do not support greenfield */ ++ int num_sta_ht_no_gf; ++ ++ /* Number of associated non-HT stations */ ++ /* int num_sta_no_ht; */ ++ ++ /* Number of HT associated stations 20 MHz */ ++ int num_sta_ht_20mhz; ++ ++ /* Overlapping BSS information */ ++ int olbc_ht; ++ ++ u16 ht_op_mode; ++ ++ u8 *assoc_req; ++ u32 assoc_req_len; ++ u8 *assoc_rsp; ++ u32 assoc_rsp_len; ++ ++ u8 *wps_beacon_ie; ++ /* u8 *wps_probe_req_ie; */ ++ u8 *wps_probe_resp_ie; ++ u8 *wps_assoc_resp_ie; /* for CONFIG_IOCTL_CFG80211, this IE could include p2p ie / wfd ie */ ++ ++ u32 wps_beacon_ie_len; ++ /* u32 wps_probe_req_ie_len; */ ++ u32 wps_probe_resp_ie_len; ++ u32 wps_assoc_resp_ie_len; /* for CONFIG_IOCTL_CFG80211, this IE len could include p2p ie / wfd ie */ ++ ++ u8 *p2p_beacon_ie; ++ u8 *p2p_probe_req_ie; ++ u8 *p2p_probe_resp_ie; ++ u8 *p2p_go_probe_resp_ie; /* for GO */ ++ u8 *p2p_assoc_req_ie; ++ ++ u32 p2p_beacon_ie_len; ++ u32 p2p_probe_req_ie_len; ++ u32 p2p_probe_resp_ie_len; ++ u32 p2p_go_probe_resp_ie_len; /* for GO */ ++ u32 p2p_assoc_req_ie_len; ++ ++ _lock bcn_update_lock; ++ u8 update_bcn; ++ ++#ifdef CONFIG_INTEL_WIDI ++ int widi_state; ++ int listen_state; ++ _timer listen_timer; ++ atomic_t rx_probe_rsp; /* 1:receive probe respone from RDS source. */ ++ u8 *l2sdTaBuffer; ++ u8 channel_idx; ++ u8 group_cnt; /* In WiDi 3.5, they specified another scan algo. for WFD/RDS co-existed */ ++ u8 sa_ext[L2SDTA_SERVICE_VE_LEN]; ++ ++ u8 widi_enable; ++ /** ++ * For WiDi 4; upper layer would set ++ * p2p_primary_device_type_category_id ++ * p2p_primary_device_type_sub_category_id ++ * p2p_secondary_device_type_category_id ++ * p2p_secondary_device_type_sub_category_id ++ */ ++ u16 p2p_pdt_cid; ++ u16 p2p_pdt_scid; ++ u8 num_p2p_sdt; ++ u16 p2p_sdt_cid[MAX_NUM_P2P_SDT]; ++ u16 p2p_sdt_scid[MAX_NUM_P2P_SDT]; ++ u8 p2p_reject_disable; /* When starting NL80211 wpa_supplicant/hostapd, it will call netdev_close */ ++ /* such that it will cause p2p disabled. Use this flag to reject. */ ++#endif /* CONFIG_INTEL_WIDI */ ++ ++ u8 NumOfBcnInfoChkFail; ++ unsigned long timeBcnInfoChkStart; ++}; ++ ++#define rtw_mlme_set_auto_scan_int(adapter, ms) \ ++ do { \ ++ adapter->mlmepriv.auto_scan_int_ms = ms; \ ++ while (0) ++ ++void rtw_mlme_reset_auto_scan_int(struct adapter *adapter); ++ ++struct hostapd_priv ++{ ++ struct adapter *padapter; ++}; ++ ++extern int hostapd_mode_init(struct adapter *padapter); ++extern void hostapd_mode_unload(struct adapter *padapter); ++ ++extern void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf); ++extern void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf); ++extern void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf); ++extern void rtw_joinbss_event_callback(struct adapter *adapter, u8 *pbuf); ++extern void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf); ++extern void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf); ++extern void rtw_atimdone_event_callback(struct adapter *adapter, u8 *pbuf); ++extern void rtw_cpwm_event_callback(struct adapter *adapter, u8 *pbuf); ++extern void rtw_wmm_event_callback(struct adapter *padapter, u8 *pbuf); ++ ++extern void rtw_join_timeout_handler(RTW_TIMER_HDL_ARGS); ++extern void _rtw_scan_timeout_handler(RTW_TIMER_HDL_ARGS); ++ ++int event_thread(void *context); ++ ++extern void rtw_free_network_queue(struct adapter *adapter, u8 isfreeall); ++extern int rtw_init_mlme_priv(struct adapter *adapter);/* (struct mlme_priv *pmlmepriv); */ ++ ++extern void rtw_free_mlme_priv (struct mlme_priv *pmlmepriv); ++ ++ ++extern sint rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv); ++extern sint rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, sint keyid, u8 set_tx, bool enqueue); ++extern sint rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv); ++ ++__inline static u8 *get_bssid(struct mlme_priv *pmlmepriv) ++{ /* if sta_mode:pmlmepriv->cur_network.network.MacAddress => bssid */ ++ /* if adhoc_mode:pmlmepriv->cur_network.network.MacAddress => ibss mac address */ ++ return pmlmepriv->cur_network.network.MacAddress; ++} ++ ++__inline static sint check_fwstate(struct mlme_priv *pmlmepriv, sint state) ++{ ++ if (pmlmepriv->fw_state & state) ++ return true; ++ ++ return false; ++} ++ ++__inline static sint get_fwstate(struct mlme_priv *pmlmepriv) ++{ ++ return pmlmepriv->fw_state; ++} ++ ++/* ++ * No Limit on the calling context, ++ * therefore set it to be the critical section... ++ * ++ * ### NOTE:#### (!!!!) ++ * MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock ++ */ ++__inline static void set_fwstate(struct mlme_priv *pmlmepriv, sint state) ++{ ++ pmlmepriv->fw_state |= state; ++ /* FOR HW integration */ ++ if (_FW_UNDER_SURVEY ==state) { ++ pmlmepriv->bScanInProcess = true; ++ } ++} ++ ++__inline static void _clr_fwstate_(struct mlme_priv *pmlmepriv, sint state) ++{ ++ pmlmepriv->fw_state &= ~state; ++ /* FOR HW integration */ ++ if (_FW_UNDER_SURVEY ==state) { ++ pmlmepriv->bScanInProcess = false; ++ } ++} ++ ++/* ++ * No Limit on the calling context, ++ * therefore set it to be the critical section... ++ */ ++__inline static void clr_fwstate(struct mlme_priv *pmlmepriv, sint state) ++{ ++ spin_lock_bh(&pmlmepriv->lock); ++ if (check_fwstate(pmlmepriv, state) == true) ++ pmlmepriv->fw_state ^= state; ++ spin_unlock_bh(&pmlmepriv->lock); ++} ++ ++__inline static void set_scanned_network_val(struct mlme_priv *pmlmepriv, sint val) ++{ ++ spin_lock_bh(&pmlmepriv->lock); ++ pmlmepriv->num_of_scanned = val; ++ spin_unlock_bh(&pmlmepriv->lock); ++} ++ ++extern u16 rtw_get_capability(struct wlan_bssid_ex *bss); ++extern void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *target); ++extern void rtw_disconnect_hdl_under_linked(struct adapter * adapter, struct sta_info *psta, u8 free_assoc); ++extern void rtw_generate_random_ibss(u8 *pibss); ++extern struct wlan_network* rtw_find_network(struct __queue *scanned_queue, u8 *addr); ++extern struct wlan_network* rtw_get_oldest_wlan_network(struct __queue *scanned_queue); ++struct wlan_network *_rtw_find_same_network(struct __queue *scanned_queue, struct wlan_network *network); ++ ++extern void rtw_free_assoc_resources(struct adapter * adapter, int lock_scanned_queue); ++extern void rtw_indicate_disconnect(struct adapter * adapter); ++extern void rtw_indicate_connect(struct adapter * adapter); ++void rtw_indicate_scan_done(struct adapter *padapter, bool aborted); ++void rtw_scan_abort(struct adapter *adapter); ++ ++extern int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len); ++extern int rtw_restruct_wmm_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len, uint initial_out_len); ++extern void rtw_init_registrypriv_dev_network(struct adapter *adapter); ++ ++extern void rtw_update_registrypriv_dev_network(struct adapter *adapter); ++ ++extern void rtw_get_encrypt_decrypt_from_registrypriv(struct adapter *adapter); ++ ++extern void _rtw_join_timeout_handler(struct adapter *adapter); ++extern void rtw_scan_timeout_handler(struct adapter *adapter); ++ ++extern void rtw_dynamic_check_timer_handlder(struct adapter *adapter); ++bool rtw_is_scan_deny(struct adapter *adapter); ++void rtw_clear_scan_deny(struct adapter *adapter); ++void rtw_set_scan_deny_timer_hdl(struct adapter *adapter); ++void rtw_set_scan_deny(struct adapter *adapter, u32 ms); ++ ++extern int _rtw_init_mlme_priv(struct adapter *padapter); ++ ++void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv); ++ ++extern void _rtw_free_mlme_priv(struct mlme_priv *pmlmepriv); ++ ++/* extern struct wlan_network* _rtw_dequeue_network(struct __queue *queue); */ ++ ++extern struct wlan_network* _rtw_alloc_network(struct mlme_priv *pmlmepriv); ++ ++ ++extern void _rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork, u8 isfreeall); ++extern void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork); ++ ++ ++extern struct wlan_network* _rtw_find_network(struct __queue *scanned_queue, u8 *addr); ++ ++extern void _rtw_free_network_queue(struct adapter *padapter, u8 isfreeall); ++ ++extern sint rtw_if_up(struct adapter *padapter); ++ ++sint rtw_linked_check(struct adapter *padapter); ++ ++u8 *rtw_get_capability_from_ie(u8 *ie); ++u8 *rtw_get_beacon_interval_from_ie(u8 *ie); ++ ++ ++void rtw_joinbss_reset(struct adapter *padapter); ++ ++void rtw_ht_use_default_setting(struct adapter *padapter); ++void rtw_build_wmm_ie_ht(struct adapter *padapter, u8 *out_ie, uint *pout_len); ++unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len, u8 channel); ++void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channel); ++void rtw_issue_addbareq_cmd(struct adapter *padapter, struct xmit_frame *pxmitframe); ++void rtw_append_exented_cap(struct adapter *padapter, u8 *out_ie, uint *pout_len); ++ ++int rtw_is_same_ibss(struct adapter *adapter, struct wlan_network *pnetwork); ++int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst, u8 feature); ++ ++#define rtw_roam_flags(adapter) ((adapter)->mlmepriv.roam_flags) ++#define rtw_chk_roam_flags(adapter, flags) ((adapter)->mlmepriv.roam_flags & flags) ++#define rtw_clr_roam_flags(adapter, flags) \ ++ do { \ ++ ((adapter)->mlmepriv.roam_flags &= ~flags); \ ++ } while (0) ++ ++#define rtw_set_roam_flags(adapter, flags) \ ++ do { \ ++ ((adapter)->mlmepriv.roam_flags |= flags); \ ++ } while (0) ++ ++#define rtw_assign_roam_flags(adapter, flags) \ ++ do { \ ++ ((adapter)->mlmepriv.roam_flags = flags); \ ++ } while (0) ++ ++void _rtw_roaming(struct adapter *adapter, struct wlan_network *tgt_network); ++void rtw_roaming(struct adapter *adapter, struct wlan_network *tgt_network); ++void rtw_set_to_roam(struct adapter *adapter, u8 to_roam); ++u8 rtw_dec_to_roam(struct adapter *adapter); ++u8 rtw_to_roam(struct adapter *adapter); ++int rtw_select_roaming_candidate(struct mlme_priv *pmlmepriv); ++ ++void rtw_sta_media_status_rpt(struct adapter *adapter, struct sta_info *psta, u32 mstatus); ++ ++#endif /* __RTL871X_MLME_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_mp.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_mp.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_mp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_mp.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,512 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef _RTW_MP_H_ ++#define _RTW_MP_H_ ++ ++#define MAX_MP_XMITBUF_SZ 2048 ++#define NR_MP_XMITFRAME 8 ++ ++struct mp_xmit_frame ++{ ++ struct list_head list; ++ ++ struct pkt_attrib attrib; ++ ++ _pkt *pkt; ++ ++ int frame_tag; ++ ++ struct adapter *padapter; ++ ++ uint mem[(MAX_MP_XMITBUF_SZ >> 2)]; ++}; ++ ++struct mp_wiparam ++{ ++ u32 bcompleted; ++ u32 act_type; ++ u32 io_offset; ++ u32 io_value; ++}; ++ ++typedef void(*wi_act_func)(void* padapter); ++ ++struct mp_tx ++{ ++ u8 stop; ++ u32 count, sended; ++ u8 payload; ++ struct pkt_attrib attrib; ++ /* struct tx_desc desc; */ ++ /* u8 resvdtx[7]; */ ++ u8 desc[TXDESC_SIZE]; ++ u8 *pallocated_buf; ++ u8 *buf; ++ u32 buf_size, write_size; ++ void *PktTxThread; ++}; ++ ++#define MP_MAX_LINES 1000 ++#define MP_MAX_LINES_BYTES 256 ++ ++typedef void (*MPT_WORK_ITEM_HANDLER)(void *Adapter); ++typedef struct _MPT_CONTEXT ++{ ++ /* Indicate if we have started Mass Production Test. */ ++ bool bMassProdTest; ++ ++ /* Indicate if the driver is unloading or unloaded. */ ++ bool bMptDrvUnload; ++ ++ _sema MPh2c_Sema; ++ _timer MPh2c_timeout_timer; ++/* Event used to sync H2c for BT control */ ++ ++ bool MptH2cRspEvent; ++ bool MptBtC2hEvent; ++ bool bMPh2c_timeout; ++ ++ /* 8190 PCI does not support NDIS_WORK_ITEM. */ ++ /* Work Item for Mass Production Test. */ ++ /* NDIS_WORK_ITEM MptWorkItem; */ ++/* RT_WORK_ITEM MptWorkItem; */ ++ /* Event used to sync the case unloading driver and MptWorkItem is still in progress. */ ++/* NDIS_EVENT MptWorkItemEvent; */ ++ /* To protect the following variables. */ ++/* NDIS_SPIN_LOCK MptWorkItemSpinLock; */ ++ /* Indicate a MptWorkItem is scheduled and not yet finished. */ ++ bool bMptWorkItemInProgress; ++ /* An instance which implements function and context of MptWorkItem. */ ++ MPT_WORK_ITEM_HANDLER CurrMptAct; ++ ++ /* 1 =Start, 0 =Stop from UI. */ ++ u32 MptTestStart; ++ /* _TEST_MODE, defined in MPT_Req2.h */ ++ u32 MptTestItem; ++ /* Variable needed in each implementation of CurrMptAct. */ ++ u32 MptActType; /* Type of action performed in CurrMptAct. */ ++ /* The Offset of IO operation is depend of MptActType. */ ++ u32 MptIoOffset; ++ /* The Value of IO operation is depend of MptActType. */ ++ u32 MptIoValue; ++ /* The RfPath of IO operation is depend of MptActType. */ ++ u32 MptRfPath; ++ ++ enum WIRELESS_MODE MptWirelessModeToSw; /* Wireless mode to switch. */ ++ u8 MptChannelToSw; /* Channel to switch. */ ++ u8 MptInitGainToSet; /* Initial gain to set. */ ++ u32 MptBandWidth; /* bandwidth to switch. */ ++ u32 MptRateIndex; /* rate index. */ ++ /* Register value kept for Single Carrier Tx test. */ ++ u8 btMpCckTxPower; ++ /* Register value kept for Single Carrier Tx test. */ ++ u8 btMpOfdmTxPower; ++ /* For MP Tx Power index */ ++ u8 TxPwrLevel[2]; /* rf-A, rf-B */ ++ u32 RegTxPwrLimit; ++ /* Content of RCR Regsiter for Mass Production Test. */ ++ u32 MptRCR; ++ /* true if we only receive packets with specific pattern. */ ++ bool bMptFilterPattern; ++ /* Rx OK count, statistics used in Mass Production Test. */ ++ u32 MptRxOkCnt; ++ /* Rx CRC32 error count, statistics used in Mass Production Test. */ ++ u32 MptRxCrcErrCnt; ++ ++ bool bCckContTx; /* true if we are in CCK Continuous Tx test. */ ++ bool bOfdmContTx; /* true if we are in OFDM Continuous Tx test. */ ++ bool bStartContTx; /* true if we have start Continuous Tx test. */ ++ /* true if we are in Single Carrier Tx test. */ ++ bool bSingleCarrier; ++ /* true if we are in Carrier Suppression Tx Test. */ ++ bool bCarrierSuppression; ++ /* true if we are in Single Tone Tx test. */ ++ bool bSingleTone; ++ ++ /* ACK counter asked by K.Y.. */ ++ bool bMptEnableAckCounter; ++ u32 MptAckCounter; ++ ++ /* SD3 Willis For 8192S to save 1T/2T RF table for ACUT Only fro ACUT delete later ~~~! */ ++ /* s8 BufOfLines[2][MAX_LINES_HWCONFIG_TXT][MAX_BYTES_LINE_HWCONFIG_TXT]; */ ++ /* s8 BufOfLines[2][MP_MAX_LINES][MP_MAX_LINES_BYTES]; */ ++ /* s32 RfReadLine[2]; */ ++ ++ u8 APK_bound[2]; /* for APK path A/path B */ ++ bool bMptIndexEven; ++ ++ u8 backup0xc50; ++ u8 backup0xc58; ++ u8 backup0xc30; ++ u8 backup0x52_RF_A; ++ u8 backup0x52_RF_B; ++ ++ u32 backup0x58_RF_A; ++ u32 backup0x58_RF_B; ++ ++ u8 h2cReqNum; ++ u8 c2hBuf[32]; ++ ++ u8 btInBuf[100]; ++ u32 mptOutLen; ++ u8 mptOutBuf[100]; ++ ++}MPT_CONTEXT, *PMPT_CONTEXT; ++/* endif */ ++ ++/* E-Fuse */ ++#define EFUSE_MAP_SIZE 512 ++ ++#define EFUSE_MAX_SIZE 512 ++/* end of E-Fuse */ ++ ++/* define RTPRIV_IOCTL_MP (SIOCIWFIRSTPRIV + 0x17) */ ++enum { ++ WRITE_REG = 1, ++ READ_REG, ++ WRITE_RF, ++ READ_RF, ++ MP_START, ++ MP_STOP, ++ MP_RATE, ++ MP_CHANNEL, ++ MP_BANDWIDTH, ++ MP_TXPOWER, ++ MP_ANT_TX, ++ MP_ANT_RX, ++ MP_CTX, ++ MP_QUERY, ++ MP_ARX, ++ MP_PSD, ++ MP_PWRTRK, ++ MP_THER, ++ MP_IOCTL, ++ EFUSE_GET, ++ EFUSE_SET, ++ MP_RESET_STATS, ++ MP_DUMP, ++ MP_PHYPARA, ++ MP_SetRFPathSwh, ++ MP_QueryDrvStats, ++ MP_SetBT, ++ CTA_TEST, ++ MP_DISABLE_BT_COEXIST, ++ MP_PwrCtlDM, ++#ifdef CONFIG_WOWLAN ++ MP_WOW_ENABLE, ++#endif ++#ifdef CONFIG_AP_WOWLAN ++ MP_AP_WOW_ENABLE, ++#endif ++ MP_NULL, ++ MP_GET_TXPOWER_INX, ++}; ++ ++struct mp_priv ++{ ++ struct adapter *papdater; ++ ++ /* Testing Flag */ ++ u32 mode;/* 0 for normal type packet, 1 for loopback packet (16bytes TXCMD) */ ++ ++ u32 prev_fw_state; ++ ++ /* OID cmd handler */ ++ struct mp_wiparam workparam; ++/* u8 act_in_progress; */ ++ ++ /* Tx Section */ ++ u8 TID; ++ u32 tx_pktcount; ++ u32 pktInterval; ++ struct mp_tx tx; ++ ++ /* Rx Section */ ++ u32 rx_bssidpktcount; ++ u32 rx_pktcount; ++ u32 rx_pktcount_filter_out; ++ u32 rx_crcerrpktcount; ++ u32 rx_pktloss; ++ bool rx_bindicatePkt; ++ struct recv_stat rxstat; ++ ++ /* RF/BB relative */ ++ u8 channel; ++ u8 bandwidth; ++ u8 prime_channel_offset; ++ u8 txpoweridx; ++ u8 txpoweridx_b; ++ u8 rateidx; ++ u32 preamble; ++/* u8 modem; */ ++ u32 CrystalCap; ++/* u32 curr_crystalcap; */ ++ ++ u16 antenna_tx; ++ u16 antenna_rx; ++/* u8 curr_rfpath; */ ++ ++ u8 check_mp_pkt; ++ ++ u8 bSetTxPower; ++/* uint ForcedDataRate; */ ++ u8 mp_dm; ++ u8 mac_filter[ETH_ALEN]; ++ u8 bmac_filter; ++ ++ struct wlan_network mp_network; ++ NDIS_802_11_MAC_ADDRESS network_macaddr; ++ ++ u8 *pallocated_mp_xmitframe_buf; ++ u8 *pmp_xmtframe_buf; ++ struct __queue free_mp_xmitqueue; ++ u32 free_mp_xmitframe_cnt; ++ bool bSetRxBssid; ++ bool bTxBufCkFail; ++ ++ MPT_CONTEXT MptCtx; ++ ++ u8 *TXradomBuffer; ++}; ++ ++typedef struct _IOCMD_STRUCT_ { ++ u8 cmdclass; ++ u16 value; ++ u8 index; ++}IOCMD_STRUCT; ++ ++struct rf_reg_param { ++ u32 path; ++ u32 offset; ++ u32 value; ++}; ++ ++struct bb_reg_param { ++ u32 offset; ++ u32 value; ++}; ++ ++#define LOWER true ++#define RAISE false ++ ++/* Hardware Registers */ ++#define BB_REG_BASE_ADDR 0x800 ++ ++/* MP variables */ ++enum MP_MODE { ++ MP_OFF, ++ MP_ON, ++ MP_ERR, ++ MP_CONTINUOUS_TX, ++ MP_SINGLE_CARRIER_TX, ++ MP_CARRIER_SUPPRISSION_TX, ++ MP_SINGLE_TONE_TX, ++ MP_PACKET_TX, ++ MP_PACKET_RX ++}; ++ ++#define MAX_RF_PATH_NUMS RF_PATH_MAX ++ ++extern u8 mpdatarate[NumRates]; ++ ++/* MP set force data rate base on the definition. */ ++enum MPT_RATE_INDEX { ++ /* CCK rate. */ ++ MPT_RATE_1M = 0 , /* 0 */ ++ MPT_RATE_2M, ++ MPT_RATE_55M, ++ MPT_RATE_11M, /* 3 */ ++ ++ /* OFDM rate. */ ++ MPT_RATE_6M, /* 4 */ ++ MPT_RATE_9M, ++ MPT_RATE_12M, ++ MPT_RATE_18M, ++ MPT_RATE_24M, ++ MPT_RATE_36M, ++ MPT_RATE_48M, ++ MPT_RATE_54M, /* 11 */ ++ ++ /* HT rate. */ ++ MPT_RATE_MCS0, /* 12 */ ++ MPT_RATE_MCS1, ++ MPT_RATE_MCS2, ++ MPT_RATE_MCS3, ++ MPT_RATE_MCS4, ++ MPT_RATE_MCS5, ++ MPT_RATE_MCS6, ++ MPT_RATE_MCS7, /* 19 */ ++ MPT_RATE_MCS8, ++ MPT_RATE_MCS9, ++ MPT_RATE_MCS10, ++ MPT_RATE_MCS11, ++ MPT_RATE_MCS12, ++ MPT_RATE_MCS13, ++ MPT_RATE_MCS14, ++ MPT_RATE_MCS15, /* 27 */ ++ /* VHT rate. Total: 20*/ ++ MPT_RATE_VHT1SS_MCS0 = 100,/* To reserve MCS16~MCS31, the index starts from #100. */ ++ MPT_RATE_VHT1SS_MCS1, /* #101 */ ++ MPT_RATE_VHT1SS_MCS2, ++ MPT_RATE_VHT1SS_MCS3, ++ MPT_RATE_VHT1SS_MCS4, ++ MPT_RATE_VHT1SS_MCS5, ++ MPT_RATE_VHT1SS_MCS6, /* #106 */ ++ MPT_RATE_VHT1SS_MCS7, ++ MPT_RATE_VHT1SS_MCS8, ++ MPT_RATE_VHT1SS_MCS9, ++ MPT_RATE_VHT2SS_MCS0, ++ MPT_RATE_VHT2SS_MCS1, /* #111 */ ++ MPT_RATE_VHT2SS_MCS2, ++ MPT_RATE_VHT2SS_MCS3, ++ MPT_RATE_VHT2SS_MCS4, ++ MPT_RATE_VHT2SS_MCS5, ++ MPT_RATE_VHT2SS_MCS6, /* #116 */ ++ MPT_RATE_VHT2SS_MCS7, ++ MPT_RATE_VHT2SS_MCS8, ++ MPT_RATE_VHT2SS_MCS9, ++ MPT_RATE_LAST ++}; ++ ++#define MAX_TX_PWR_INDEX_N_MODE 64 /* 0x3F */ ++ ++enum POWER_MODE { ++ POWER_LOW = 0, ++ POWER_NORMAL ++}; ++ ++/* The following enumeration is used to define the value of Reg0xD00[30:28] or JaguarReg0x914[18:16]. */ ++enum OFDM_TX_MODE { ++ OFDM_ALL_OFF = 0, ++ OFDM_ContinuousTx = 1, ++ OFDM_SingleCarrier = 2, ++ OFDM_SingleTone = 4, ++}; ++ ++#define RX_PKT_BROADCAST 1 ++#define RX_PKT_DEST_ADDR 2 ++#define RX_PKT_PHY_MATCH 3 ++ ++#define Mac_OFDM_OK 0x00000000 ++#define Mac_OFDM_Fail 0x10000000 ++#define Mac_OFDM_FasleAlarm 0x20000000 ++#define Mac_CCK_OK 0x30000000 ++#define Mac_CCK_Fail 0x40000000 ++#define Mac_CCK_FasleAlarm 0x50000000 ++#define Mac_HT_OK 0x60000000 ++#define Mac_HT_Fail 0x70000000 ++#define Mac_HT_FasleAlarm 0x90000000 ++#define Mac_DropPacket 0xA0000000 ++ ++enum ENCRY_CTRL_STATE { ++ HW_CONTROL, /* hw encryption& decryption */ ++ SW_CONTROL, /* sw encryption& decryption */ ++ HW_ENCRY_SW_DECRY, /* hw encryption & sw decryption */ ++ SW_ENCRY_HW_DECRY /* sw encryption & hw decryption */ ++}; ++ ++enum MPT_TXPWR_DEF { ++ MPT_CCK, ++ MPT_OFDM, /* L and HT OFDM */ ++ MPT_VHT_OFDM ++}; ++ ++#define REG_RF_BB_GAIN_OFFSET 0x7f ++#define RF_GAIN_OFFSET_MASK 0xfffff ++ ++/* */ ++/* struct mp_xmit_frame *alloc_mp_xmitframe(struct mp_priv *pmp_priv); */ ++/* int free_mp_xmitframe(struct xmit_priv *pxmitpriv, struct mp_xmit_frame *pmp_xmitframe); */ ++ ++s32 init_mp_priv(struct adapter *padapter); ++void free_mp_priv(struct mp_priv *pmp_priv); ++s32 MPT_InitializeAdapter(struct adapter *padapter, u8 Channel); ++void MPT_DeInitAdapter(struct adapter *padapter); ++s32 mp_start_test(struct adapter *padapter); ++void mp_stop_test(struct adapter *padapter); ++ ++u32 _read_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 bitmask); ++void _write_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 bitmask, u32 val); ++ ++u32 read_macreg(struct adapter *padapter, u32 addr, u32 sz); ++void write_macreg(struct adapter *padapter, u32 addr, u32 val, u32 sz); ++u32 read_bbreg(struct adapter *padapter, u32 addr, u32 bitmask); ++void write_bbreg(struct adapter *padapter, u32 addr, u32 bitmask, u32 val); ++u32 read_rfreg(struct adapter *padapter, u8 rfpath, u32 addr); ++void write_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 val); ++ ++void SetChannel(struct adapter *padapter); ++void SetBandwidth(struct adapter *padapter); ++int SetTxPower(struct adapter *padapter); ++void SetAntennaPathPower(struct adapter *padapter); ++void SetDataRate(struct adapter *padapter); ++ ++void SetAntenna(struct adapter *padapter); ++ ++s32 SetThermalMeter(struct adapter *padapter, u8 target_ther); ++void GetThermalMeter(struct adapter *padapter, u8 *value); ++ ++void SetContinuousTx(struct adapter *padapter, u8 bStart); ++void SetSingleCarrierTx(struct adapter *padapter, u8 bStart); ++void SetSingleToneTx(struct adapter *padapter, u8 bStart); ++void SetCarrierSuppressionTx(struct adapter *padapter, u8 bStart); ++void PhySetTxPowerLevel(struct adapter *padapter); ++ ++void fill_txdesc_for_mp(struct adapter *padapter, u8 *ptxdesc); ++void SetPacketTx(struct adapter *padapter); ++void SetPacketRx(struct adapter *padapter, u8 bStartRx); ++ ++void ResetPhyRxPktCount(struct adapter *padapter); ++u32 GetPhyRxPktReceived(struct adapter *padapter); ++u32 GetPhyRxPktCRC32Error(struct adapter *padapter); ++ ++s32 SetPowerTracking(struct adapter *padapter, u8 enable); ++void GetPowerTracking(struct adapter *padapter, u8 *enable); ++ ++u32 mp_query_psd(struct adapter *padapter, u8 *data); ++ ++void Hal_SetAntenna(struct adapter *padapter); ++void Hal_SetBandwidth(struct adapter *padapter); ++ ++void Hal_SetTxPower(struct adapter *padapter); ++void Hal_SetCarrierSuppressionTx(struct adapter *padapter, u8 bStart); ++void Hal_SetSingleToneTx (struct adapter *padapter , u8 bStart); ++void Hal_SetSingleCarrierTx (struct adapter *padapter, u8 bStart); ++void Hal_SetContinuousTx (struct adapter *padapter, u8 bStart); ++void Hal_SetBandwidth(struct adapter *padapter); ++ ++void Hal_SetDataRate(struct adapter *padapter); ++void Hal_SetChannel(struct adapter *padapter); ++void Hal_SetAntennaPathPower(struct adapter *padapter); ++s32 Hal_SetThermalMeter(struct adapter *padapter, u8 target_ther); ++s32 Hal_SetPowerTracking(struct adapter *padapter, u8 enable); ++void Hal_GetPowerTracking(struct adapter *padapter, u8 * enable); ++void Hal_GetThermalMeter(struct adapter *padapter, u8 *value); ++void Hal_mpt_SwitchRfSetting(struct adapter *padapter); ++void Hal_MPT_CCKTxPowerAdjust(struct adapter * Adapter, bool bInCH14); ++void Hal_MPT_CCKTxPowerAdjustbyIndex(struct adapter *padapter, bool beven); ++void Hal_SetCCKTxPower(struct adapter *padapter, u8 * TxPower); ++void Hal_SetOFDMTxPower(struct adapter *padapter, u8 * TxPower); ++void Hal_TriggerRFThermalMeter(struct adapter *padapter); ++u8 Hal_ReadRFThermalMeter(struct adapter *padapter); ++void Hal_SetCCKContinuousTx(struct adapter *padapter, u8 bStart); ++void Hal_SetOFDMContinuousTx(struct adapter *padapter, u8 bStart); ++void Hal_ProSetCrystalCap (struct adapter *padapter , u32 CrystalCapVal); ++void MP_PHY_SetRFPathSwitch(struct adapter *padapter , bool bMain); ++u32 mpt_ProQueryCalTxPower(struct adapter *padapter, u8 RfPath); ++void MPT_PwrCtlDM(struct adapter *padapter, u32 bstart); ++u8 MptToMgntRate(u32 MptRateIdx); ++ ++#endif /* _RTW_MP_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_odm.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_odm.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_odm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_odm.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,36 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2013 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTW_ODM_H__ ++#define __RTW_ODM_H__ ++ ++#include ++ ++/* ++* This file provides utilities/wrappers for rtw driver to use ODM ++*/ ++ ++void rtw_odm_dbg_comp_msg(void *sel, struct adapter *adapter); ++void rtw_odm_dbg_comp_set(struct adapter *adapter, u64 comps); ++void rtw_odm_dbg_level_msg(void *sel, struct adapter *adapter); ++void rtw_odm_dbg_level_set(struct adapter *adapter, u32 level); ++ ++void rtw_odm_ability_msg(void *sel, struct adapter *adapter); ++void rtw_odm_ability_set(struct adapter *adapter, u32 ability); ++ ++void rtw_odm_adaptivity_parm_msg(void *sel, struct adapter *adapter); ++void rtw_odm_adaptivity_parm_set(struct adapter *adapter, s8 TH_L2H_ini, s8 TH_EDCCA_HL_diff, ++ s8 IGI_Base, bool ForceEDCCA, u8 AdapEn_RSSI, u8 IGI_LowerBound); ++void rtw_odm_get_perpkt_rssi(void *sel, struct adapter *adapter); ++#endif /* __RTW_ODM_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_pwrctrl.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_pwrctrl.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_pwrctrl.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_pwrctrl.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,375 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTW_PWRCTRL_H_ ++#define __RTW_PWRCTRL_H_ ++ ++ ++#define FW_PWR0 0 ++#define FW_PWR1 1 ++#define FW_PWR2 2 ++#define FW_PWR3 3 ++ ++ ++#define HW_PWR0 7 ++#define HW_PWR1 6 ++#define HW_PWR2 2 ++#define HW_PWR3 0 ++#define HW_PWR4 8 ++ ++#define FW_PWRMSK 0x7 ++ ++ ++#define XMIT_ALIVE BIT(0) ++#define RECV_ALIVE BIT(1) ++#define CMD_ALIVE BIT(2) ++#define EVT_ALIVE BIT(3) ++#define BTCOEX_ALIVE BIT(4) ++ ++ ++enum Power_Mgnt ++{ ++ PS_MODE_ACTIVE = 0 , ++ PS_MODE_MIN , ++ PS_MODE_MAX , ++ PS_MODE_DTIM , /* PS_MODE_SELF_DEFINED */ ++ PS_MODE_VOIP , ++ PS_MODE_UAPSD_WMM , ++ PS_MODE_UAPSD , ++ PS_MODE_IBSS , ++ PS_MODE_WWLAN , ++ PM_Radio_Off , ++ PM_Card_Disable , ++ PS_MODE_NUM, ++}; ++ ++#ifdef CONFIG_PNO_SUPPORT ++#define MAX_PNO_LIST_COUNT 16 ++#define MAX_SCAN_LIST_COUNT 14 /* 2.4G only */ ++#endif ++ ++/* ++ BIT[2:0] = HW state ++ BIT[3] = Protocol PS state, 0: register active state , 1: register sleep state ++ BIT[4] = sub-state ++*/ ++ ++#define PS_DPS BIT(0) ++#define PS_LCLK (PS_DPS) ++#define PS_RF_OFF BIT(1) ++#define PS_ALL_ON BIT(2) ++#define PS_ST_ACTIVE BIT(3) ++ ++#define PS_ISR_ENABLE BIT(4) ++#define PS_IMR_ENABLE BIT(5) ++#define PS_ACK BIT(6) ++#define PS_TOGGLE BIT(7) ++ ++#define PS_STATE_MASK (0x0F) ++#define PS_STATE_HW_MASK (0x07) ++#define PS_SEQ_MASK (0xc0) ++ ++#define PS_STATE(x) (PS_STATE_MASK & (x)) ++#define PS_STATE_HW(x) (PS_STATE_HW_MASK & (x)) ++#define PS_SEQ(x) (PS_SEQ_MASK & (x)) ++ ++#define PS_STATE_S0 (PS_DPS) ++#define PS_STATE_S1 (PS_LCLK) ++#define PS_STATE_S2 (PS_RF_OFF) ++#define PS_STATE_S3 (PS_ALL_ON) ++#define PS_STATE_S4 ((PS_ST_ACTIVE) | (PS_ALL_ON)) ++ ++ ++#define PS_IS_RF_ON(x) ((x) & (PS_ALL_ON)) ++#define PS_IS_ACTIVE(x) ((x) & (PS_ST_ACTIVE)) ++#define CLR_PS_STATE(x) ((x) = ((x) & (0xF0))) ++ ++ ++struct reportpwrstate_parm { ++ unsigned char mode; ++ unsigned char state; /* the CPWM value */ ++ unsigned short rsvd; ++}; ++ ++ ++typedef _sema _pwrlock; ++ ++ ++#define LPS_DELAY_TIME 1*HZ /* 1 sec */ ++ ++#define EXE_PWR_NONE 0x01 ++#define EXE_PWR_IPS 0x02 ++#define EXE_PWR_LPS 0x04 ++ ++/* RF state. */ ++enum rt_rf_power_state { ++ rf_on, /* RF is on after RFSleep or RFOff */ ++ rf_sleep, /* 802.11 Power Save mode */ ++ rf_off, /* HW/SW Radio OFF or Inactive Power Save */ ++ /* Add the new RF state above this line ===== */ ++ rf_max ++}; ++ ++/* RF Off Level for IPS or HW/SW radio off */ ++#define RT_RF_OFF_LEVL_ASPM BIT(0) /* PCI ASPM */ ++#define RT_RF_OFF_LEVL_CLK_REQ BIT(1) /* PCI clock request */ ++#define RT_RF_OFF_LEVL_PCI_D3 BIT(2) /* PCI D3 mode */ ++#define RT_RF_OFF_LEVL_HALT_NIC BIT(3) /* NIC halt, re-initialize hw parameters */ ++#define RT_RF_OFF_LEVL_FREE_FW BIT(4) /* FW free, re-download the FW */ ++#define RT_RF_OFF_LEVL_FW_32K BIT(5) /* FW in 32k */ ++#define RT_RF_PS_LEVEL_ALWAYS_ASPM BIT(6) /* Always enable ASPM and Clock Req in initialization. */ ++#define RT_RF_LPS_DISALBE_2R BIT(30) /* When LPS is on, disable 2R if no packet is received or transmittd. */ ++#define RT_RF_LPS_LEVEL_ASPM BIT(31) /* LPS with ASPM */ ++ ++#define RT_IN_PS_LEVEL(ppsc, _PS_FLAG) ((ppsc->cur_ps_level & _PS_FLAG) ? true : false) ++#define RT_CLEAR_PS_LEVEL(ppsc, _PS_FLAG) (ppsc->cur_ps_level &= (~(_PS_FLAG))) ++#define RT_SET_PS_LEVEL(ppsc, _PS_FLAG) (ppsc->cur_ps_level |= _PS_FLAG) ++ ++/* ASPM OSC Control bit, added by Roger, 2013.03.29. */ ++#define RT_PCI_ASPM_OSC_IGNORE 0 /* PCI ASPM ignore OSC control in default */ ++#define RT_PCI_ASPM_OSC_ENABLE BIT0 /* PCI ASPM controlled by OS according to ACPI Spec 5.0 */ ++#define RT_PCI_ASPM_OSC_DISABLE BIT1 /* PCI ASPM controlled by driver or BIOS, i.e., force enable ASPM */ ++ ++ ++enum _PS_BBRegBackup_ { ++ PSBBREG_RF0 = 0, ++ PSBBREG_RF1, ++ PSBBREG_RF2, ++ PSBBREG_AFE0, ++ PSBBREG_TOTALCNT ++}; ++ ++enum { /* for ips_mode */ ++ IPS_NONE = 0, ++ IPS_NORMAL, ++ IPS_LEVEL_2, ++ IPS_NUM ++}; ++ ++/* Design for pwrctrl_priv.ips_deny, 32 bits for 32 reasons at most */ ++enum PS_DENY_REASON { ++ PS_DENY_DRV_INITIAL = 0, ++ PS_DENY_SCAN, ++ PS_DENY_JOIN, ++ PS_DENY_DISCONNECT, ++ PS_DENY_SUSPEND, ++ PS_DENY_IOCTL, ++ PS_DENY_MGNT_TX, ++ PS_DENY_DRV_REMOVE = 30, ++ PS_DENY_OTHERS = 31 ++}; ++ ++#ifdef CONFIG_PNO_SUPPORT ++typedef struct pno_nlo_info ++{ ++ u32 fast_scan_period; /* Fast scan period */ ++ u32 ssid_num; /* number of entry */ ++ u32 slow_scan_period; /* slow scan period */ ++ u32 fast_scan_iterations; /* Fast scan iterations */ ++ u8 ssid_length[MAX_PNO_LIST_COUNT]; /* SSID Length Array */ ++ u8 ssid_cipher_info[MAX_PNO_LIST_COUNT]; /* Cipher information for security */ ++ u8 ssid_channel_info[MAX_PNO_LIST_COUNT]; /* channel information */ ++}pno_nlo_info_t; ++ ++typedef struct pno_ssid { ++ u32 SSID_len; ++ u8 SSID[32]; ++} pno_ssid_t; ++ ++typedef struct pno_ssid_list { ++ pno_ssid_t node[MAX_PNO_LIST_COUNT]; ++}pno_ssid_list_t; ++ ++typedef struct pno_scan_channel_info ++{ ++ u8 channel; ++ u8 tx_power; ++ u8 timeout; ++ u8 active; /* set 1 means active scan, or pasivite scan. */ ++}pno_scan_channel_info_t; ++ ++typedef struct pno_scan_info ++{ ++ u8 enableRFE; /* Enable RFE */ ++ u8 period_scan_time; /* exclusive with fast_scan_period and slow_scan_period */ ++ u8 periodScan; /* exclusive with fast_scan_period and slow_scan_period */ ++ u8 orig_80_offset; /* original channel 80 offset */ ++ u8 orig_40_offset; /* original channel 40 offset */ ++ u8 orig_bw; /* original bandwidth */ ++ u8 orig_ch; /* original channel */ ++ u8 channel_num; /* number of channel */ ++ u64 rfe_type; /* rfe_type && 0x00000000000000ff */ ++ pno_scan_channel_info_t ssid_channel_info[MAX_SCAN_LIST_COUNT]; ++}pno_scan_info_t; ++#endif /* CONFIG_PNO_SUPPORT */ ++ ++struct pwrctrl_priv ++{ ++ _pwrlock lock; ++ _pwrlock check_32k_lock; ++ volatile u8 rpwm; /* requested power state for fw */ ++ volatile u8 cpwm; /* fw current power state. updated when 1. read from HCPWM 2. driver lowers power level */ ++ volatile u8 tog; /* toggling */ ++ volatile u8 cpwm_tog; /* toggling */ ++ ++ u8 pwr_mode; ++ u8 smart_ps; ++ u8 bcn_ant_mode; ++ u8 dtim; ++ ++ u32 alives; ++ _workitem cpwm_event; ++ u8 brpwmtimeout; ++ _workitem rpwmtimeoutwi; ++ _timer pwr_rpwm_timer; ++ u8 bpower_saving; /* for LPS/IPS */ ++ ++ u8 b_hw_radio_off; ++ u8 reg_rfoff; ++ u8 reg_pdnmode; /* powerdown mode */ ++ u32 rfoff_reason; ++ ++ /* RF OFF Level */ ++ u32 cur_ps_level; ++ u32 reg_rfps_level; ++ ++ uint ips_enter_cnts; ++ uint ips_leave_cnts; ++ ++ u8 ips_mode; ++ u8 ips_org_mode; ++ u8 ips_mode_req; /* used to accept the mode setting request, will update to ipsmode later */ ++ uint bips_processing; ++ unsigned long ips_deny_time; /* will deny IPS when system time is smaller than this */ ++ u8 pre_ips_type;/* 0: default flow, 1: carddisbale flow */ ++ ++ /* ps_deny: if 0, power save is free to go; otherwise deny all kinds of power save. */ ++ /* Use PS_DENY_REASON to decide reason. */ ++ /* Don't access this variable directly without control function, */ ++ /* and this variable should be protected by lock. */ ++ u32 ps_deny; ++ ++ u8 ps_processing; /* temporarily used to mark whether in rtw_ps_processor */ ++ ++ u8 fw_psmode_iface_id; ++ u8 bLeisurePs; ++ u8 LpsIdleCount; ++ u8 power_mgnt; ++ u8 org_power_mgnt; ++ u8 bFwCurrentInPSMode; ++ unsigned long DelayLPSLastTimeStamp; ++ s32 pnp_current_pwr_state; ++ u8 pnp_bstop_trx; ++ ++ ++ u8 bInternalAutoSuspend; ++ u8 bInSuspend; ++ ++ u8 bAutoResume; ++ u8 autopm_cnt; ++ ++ u8 bSupportRemoteWakeup; ++ u8 wowlan_wake_reason; ++ u8 wowlan_ap_mode; ++ u8 wowlan_mode; ++#ifdef CONFIG_WOWLAN ++ u8 wowlan_pattern; ++ u8 wowlan_magic; ++ u8 wowlan_unicast; ++ u8 wowlan_pattern_idx; ++ u8 wowlan_pno_enable; ++#ifdef CONFIG_PNO_SUPPORT ++ u8 pno_in_resume; ++ u8 pno_inited; ++ pno_nlo_info_t *pnlo_info; ++ pno_scan_info_t *pscan_info; ++ pno_ssid_list_t *pno_ssid_list; ++#endif ++ u32 wowlan_pattern_context[8][5]; ++ u64 wowlan_fw_iv; ++#endif /* CONFIG_WOWLAN */ ++ _timer pwr_state_check_timer; ++ int pwr_state_check_interval; ++ u8 pwr_state_check_cnts; ++ ++ int ps_flag; /* used by autosuspend */ ++ ++ enum rt_rf_power_state rf_pwrstate;/* cur power state, only for IPS */ ++ /* rt_rf_power_state current_rfpwrstate; */ ++ enum rt_rf_power_state change_rfpwrstate; ++ ++ u8 bHWPowerdown; /* power down mode selection. 0:radio off, 1:power down */ ++ u8 bHWPwrPindetect; /* come from registrypriv.hwpwrp_detect. enable power down function. 0:disable, 1:enable */ ++ u8 bkeepfwalive; ++ u8 brfoffbyhw; ++ unsigned long PS_BBRegBackup[PSBBREG_TOTALCNT]; ++}; ++ ++#define rtw_get_ips_mode_req(pwrctl) \ ++ (pwrctl)->ips_mode_req ++ ++#define rtw_ips_mode_req(pwrctl, ips_mode) \ ++ (pwrctl)->ips_mode_req = (ips_mode) ++ ++#define RTW_PWR_STATE_CHK_INTERVAL 2000 ++ ++#define _rtw_set_pwr_state_check_timer(pwrctl, ms) \ ++ do { \ ++ /*DBG_871X("%s _rtw_set_pwr_state_check_timer(%p, %d)\n", __func__, (pwrctl), (ms));*/ \ ++ _set_timer(&(pwrctl)->pwr_state_check_timer, (ms)); \ ++ } while (0) ++ ++#define rtw_set_pwr_state_check_timer(pwrctl) \ ++ _rtw_set_pwr_state_check_timer((pwrctl), (pwrctl)->pwr_state_check_interval) ++ ++extern void rtw_init_pwrctrl_priv(struct adapter *adapter); ++extern void rtw_free_pwrctrl_priv(struct adapter * adapter); ++ ++s32 rtw_register_task_alive(struct adapter *, u32 task); ++void rtw_unregister_task_alive(struct adapter *, u32 task); ++extern s32 rtw_register_tx_alive(struct adapter *padapter); ++extern void rtw_unregister_tx_alive(struct adapter *padapter); ++extern s32 rtw_register_cmd_alive(struct adapter *padapter); ++extern void rtw_unregister_cmd_alive(struct adapter *padapter); ++extern void cpwm_int_hdl(struct adapter *padapter, struct reportpwrstate_parm *preportpwrstate); ++extern void LPS_Leave_check(struct adapter *padapter); ++ ++extern void LeaveAllPowerSaveMode(struct adapter * Adapter); ++extern void LeaveAllPowerSaveModeDirect(struct adapter * Adapter); ++void _ips_enter(struct adapter *padapter); ++void ips_enter(struct adapter *padapter); ++int _ips_leave(struct adapter *padapter); ++int ips_leave(struct adapter *padapter); ++ ++void rtw_ps_processor(struct adapter *padapter); ++ ++s32 LPS_RF_ON_check(struct adapter *padapter, u32 delay_ms); ++void LPS_Enter(struct adapter *padapter, const char *msg); ++void LPS_Leave(struct adapter *padapter, const char *msg); ++void traffic_check_for_leave_lps(struct adapter *padapter, u8 tx, u32 tx_packets); ++void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_ant_mode, const char *msg); ++void rtw_set_rpwm(struct adapter *padapter, u8 val8); ++ ++void rtw_set_ips_deny(struct adapter *padapter, u32 ms); ++int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *caller); ++#define rtw_pwr_wakeup(adapter) _rtw_pwr_wakeup(adapter, RTW_PWR_STATE_CHK_INTERVAL, __func__) ++#define rtw_pwr_wakeup_ex(adapter, ips_deffer_ms) _rtw_pwr_wakeup(adapter, ips_deffer_ms, __func__) ++int rtw_pm_set_ips(struct adapter *padapter, u8 mode); ++int rtw_pm_set_lps(struct adapter *padapter, u8 mode); ++ ++void rtw_ps_deny(struct adapter *padapter, enum PS_DENY_REASON reason); ++void rtw_ps_deny_cancel(struct adapter *padapter, enum PS_DENY_REASON reason); ++u32 rtw_ps_deny_get(struct adapter *padapter); ++ ++#endif /* __RTL871X_PWRCTRL_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_qos.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_qos.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_qos.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_qos.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,27 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++ ++#ifndef _RTW_QOS_H_ ++#define _RTW_QOS_H_ ++ ++ ++ ++struct qos_priv { ++ unsigned int qos_option; /* bit mask option: u-apsd, s-apsd, ts, block ack... */ ++}; ++ ++ ++#endif /* _RTL871X_QOS_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_recv.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_recv.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_recv.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_recv.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,553 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef _RTW_RECV_H_ ++#define _RTW_RECV_H_ ++ ++ #ifdef CONFIG_SINGLE_RECV_BUF ++ #define NR_RECVBUFF (1) ++ #else ++ #define NR_RECVBUFF (8) ++ #endif /* CONFIG_SINGLE_RECV_BUF */ ++ ++ #define NR_PREALLOC_RECV_SKB (8) ++ ++#define NR_RECVFRAME 256 ++ ++#define RXFRAME_ALIGN 8 ++#define RXFRAME_ALIGN_SZ (1<network.PhyInfo.SignalStrength); */ ++ #ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA ++ struct rx_raw_rssi raw_rssi_info; ++ #endif ++ /* s8 rxpwdb; */ ++ s16 noise; ++ /* int RxSNRdB[2]; */ ++ /* s8 RxRssi[2]; */ ++ /* int FalseAlmCnt_all; */ ++ ++ ++ _timer signal_stat_timer; ++ u32 signal_stat_sampling_interval; ++ /* u32 signal_stat_converging_constant; */ ++ struct signal_stat signal_qual_data; ++ struct signal_stat signal_strength_data; ++}; ++ ++#define rtw_set_signal_stat_timer(recvpriv) _set_timer(&(recvpriv)->signal_stat_timer, (recvpriv)->signal_stat_sampling_interval) ++ ++struct sta_recv_priv { ++ ++ _lock lock; ++ sint option; ++ ++ /* struct __queue blk_strms[MAX_RX_NUMBLKS]; */ ++ struct __queue defrag_q; /* keeping the fragment frame until defrag */ ++ ++ struct stainfo_rxcache rxcache; ++ ++ /* uint sta_rx_bytes; */ ++ /* uint sta_rx_pkts; */ ++ /* uint sta_rx_fail; */ ++ ++}; ++ ++ ++struct recv_buf ++{ ++ struct list_head list; ++ ++ _lock recvbuf_lock; ++ ++ u32 ref_cnt; ++ ++ struct adapter * adapter; ++ ++ u8 *pbuf; ++ u8 *pallocated_buf; ++ ++ u32 len; ++ u8 *phead; ++ u8 *pdata; ++ u8 *ptail; ++ u8 *pend; ++ ++ _pkt *pskb; ++ u8 reuse; ++}; ++ ++ ++/* ++ head -----> ++ ++ data -----> ++ ++ payload ++ ++ tail -----> ++ ++ ++ end -----> ++ ++ len = (unsigned int)(tail - data); ++ ++*/ ++struct recv_frame_hdr ++{ ++ struct list_head list; ++#ifndef CONFIG_BSD_RX_USE_MBUF ++ struct sk_buff *pkt; ++ struct sk_buff *pkt_newalloc; ++#else /* CONFIG_BSD_RX_USE_MBUF */ ++ _pkt *pkt; ++ _pkt *pkt_newalloc; ++#endif /* CONFIG_BSD_RX_USE_MBUF */ ++ ++ struct adapter *adapter; ++ ++ u8 fragcnt; ++ ++ int frame_tag; ++ ++ struct rx_pkt_attrib attrib; ++ ++ uint len; ++ u8 *rx_head; ++ u8 *rx_data; ++ u8 *rx_tail; ++ u8 *rx_end; ++ ++ void *precvbuf; ++ ++ ++ /* */ ++ struct sta_info *psta; ++ ++ /* for A-MPDU Rx reordering buffer control */ ++ struct recv_reorder_ctrl *preorder_ctrl; ++}; ++ ++ ++union recv_frame{ ++ union{ ++ struct list_head list; ++ struct recv_frame_hdr hdr; ++ uint mem[RECVFRAME_HDR_ALIGN>>2]; ++ }u; ++ ++ /* uint mem[MAX_RXSZ>>2]; */ ++ ++}; ++ ++enum RX_PACKET_TYPE { ++ NORMAL_RX,/* Normal rx packet */ ++ TX_REPORT1,/* CCX */ ++ TX_REPORT2,/* TX RPT */ ++ HIS_REPORT,/* USB HISR RPT */ ++ C2H_PACKET ++}; ++ ++extern union recv_frame *_rtw_alloc_recvframe (struct __queue *pfree_recv_queue); /* get a free recv_frame from pfree_recv_queue */ ++extern union recv_frame *rtw_alloc_recvframe (struct __queue *pfree_recv_queue); /* get a free recv_frame from pfree_recv_queue */ ++extern int rtw_free_recvframe(union recv_frame *precvframe, struct __queue *pfree_recv_queue); ++ ++#define rtw_dequeue_recvframe(queue) rtw_alloc_recvframe(queue) ++extern int _rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue); ++extern int rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue); ++ ++extern void rtw_free_recvframe_queue(struct __queue *pframequeue, struct __queue *pfree_recv_queue); ++u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter); ++ ++sint rtw_enqueue_recvbuf_to_head(struct recv_buf *precvbuf, struct __queue *queue); ++sint rtw_enqueue_recvbuf(struct recv_buf *precvbuf, struct __queue *queue); ++struct recv_buf *rtw_dequeue_recvbuf (struct __queue *queue); ++ ++void rtw_reordering_ctrl_timeout_handler(void *pcontext); ++ ++__inline static u8 *get_rxmem(union recv_frame *precvframe) ++{ ++ /* always return rx_head... */ ++ if (precvframe == NULL) ++ return NULL; ++ ++ return precvframe->u.hdr.rx_head; ++} ++ ++__inline static u8 *get_recvframe_data(union recv_frame *precvframe) ++{ ++ ++ /* alwasy return rx_data */ ++ if (precvframe == NULL) ++ return NULL; ++ ++ return precvframe->u.hdr.rx_data; ++ ++} ++ ++__inline static u8 *recvframe_pull(union recv_frame *precvframe, sint sz) ++{ ++ /* rx_data += sz; move rx_data sz bytes hereafter */ ++ ++ /* used for extract sz bytes from rx_data, update rx_data and return the updated rx_data to the caller */ ++ ++ ++ if (precvframe == NULL) ++ return NULL; ++ ++ ++ precvframe->u.hdr.rx_data += sz; ++ ++ if (precvframe->u.hdr.rx_data > precvframe->u.hdr.rx_tail) ++ { ++ precvframe->u.hdr.rx_data -= sz; ++ return NULL; ++ } ++ ++ precvframe->u.hdr.len -=sz; ++ ++ return precvframe->u.hdr.rx_data; ++ ++} ++ ++__inline static u8 *recvframe_put(union recv_frame *precvframe, sint sz) ++{ ++ /* rx_tai += sz; move rx_tail sz bytes hereafter */ ++ ++ /* used for append sz bytes from ptr to rx_tail, update rx_tail and return the updated rx_tail to the caller */ ++ /* after putting, rx_tail must be still larger than rx_end. */ ++ unsigned char * prev_rx_tail; ++ ++ if (precvframe == NULL) ++ return NULL; ++ ++ prev_rx_tail = precvframe->u.hdr.rx_tail; ++ ++ precvframe->u.hdr.rx_tail += sz; ++ ++ if (precvframe->u.hdr.rx_tail > precvframe->u.hdr.rx_end) ++ { ++ precvframe->u.hdr.rx_tail = prev_rx_tail; ++ return NULL; ++ } ++ ++ precvframe->u.hdr.len +=sz; ++ ++ return precvframe->u.hdr.rx_tail; ++ ++} ++ ++ ++ ++__inline static u8 *recvframe_pull_tail(union recv_frame *precvframe, sint sz) ++{ ++ /* rmv data from rx_tail (by yitsen) */ ++ ++ /* used for extract sz bytes from rx_end, update rx_end and return the updated rx_end to the caller */ ++ /* after pulling, rx_end must be still larger than rx_data. */ ++ ++ if (precvframe == NULL) ++ return NULL; ++ ++ precvframe->u.hdr.rx_tail -= sz; ++ ++ if (precvframe->u.hdr.rx_tail < precvframe->u.hdr.rx_data) ++ { ++ precvframe->u.hdr.rx_tail += sz; ++ return NULL; ++ } ++ ++ precvframe->u.hdr.len -=sz; ++ ++ return precvframe->u.hdr.rx_tail; ++ ++} ++ ++__inline static union recv_frame *rxmem_to_recvframe(u8 *rxmem) ++{ ++ /* due to the design of 2048 bytes alignment of recv_frame, we can reference the union recv_frame */ ++ /* from any given member of recv_frame. */ ++ /* rxmem indicates the any member/address in recv_frame */ ++ ++ return (union recv_frame*)(((SIZE_PTR)rxmem >> RXFRAME_ALIGN) << RXFRAME_ALIGN); ++ ++} ++ ++__inline static sint get_recvframe_len(union recv_frame *precvframe) ++{ ++ return precvframe->u.hdr.len; ++} ++ ++ ++__inline static s32 translate_percentage_to_dbm(u32 SignalStrengthIndex) ++{ ++ s32 SignalPower; /* in dBm. */ ++ ++#ifdef CONFIG_SKIP_SIGNAL_SCALE_MAPPING ++ /* Translate to dBm (x =y-100) */ ++ SignalPower = SignalStrengthIndex - 100; ++#else ++ /* Translate to dBm (x = 0.5y-95). */ ++ SignalPower = (s32)((SignalStrengthIndex + 1) >> 1); ++ SignalPower -= 95; ++#endif ++ ++ return SignalPower; ++} ++ ++ ++struct sta_info; ++ ++extern void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv); ++ ++extern void mgt_dispatcher(struct adapter *padapter, union recv_frame *precv_frame); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_rf.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_rf.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_rf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_rf.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,159 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTW_RF_H_ ++#define __RTW_RF_H_ ++ ++ ++#define OFDM_PHY 1 ++#define MIXED_PHY 2 ++#define CCK_PHY 3 ++ ++#define NumRates 13 ++ ++/* slot time for 11g */ ++#define SHORT_SLOT_TIME 9 ++#define NON_SHORT_SLOT_TIME 20 ++ ++#define RTL8711_RF_MAX_SENS 6 ++#define RTL8711_RF_DEF_SENS 4 ++ ++/* */ ++/* We now define the following channels as the max channels in each channel plan. */ ++/* 2G, total 14 chnls */ ++/* {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14} */ ++/* 5G, total 24 chnls */ ++/* {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, ++ * 124, 128, 132, 136, 140, 149, 153, 157, 161, 165} */ ++#define MAX_CHANNEL_NUM_2G 14 ++#define MAX_CHANNEL_NUM_5G 24 ++#define MAX_CHANNEL_NUM 38/* 14+24 */ ++ ++#define NUM_REGULATORYS 1 ++ ++/* Country codes */ ++#define USA 0x555320 ++#define EUROPE 0x1 /* temp, should be provided later */ ++#define JAPAN 0x2 /* temp, should be provided later */ ++ ++struct regulatory_class { ++ u32 starting_freq; /* MHz, */ ++ u8 channel_set[MAX_CHANNEL_NUM]; ++ u8 channel_cck_power[MAX_CHANNEL_NUM];/* dbm */ ++ u8 channel_ofdm_power[MAX_CHANNEL_NUM];/* dbm */ ++ u8 txpower_limit; /* dbm */ ++ u8 channel_spacing; /* MHz */ ++ u8 modem; ++}; ++ ++enum CAPABILITY { ++ cESS = 0x0001, ++ cIBSS = 0x0002, ++ cPollable = 0x0004, ++ cPollReq = 0x0008, ++ cPrivacy = 0x0010, ++ cShortPreamble = 0x0020, ++ cPBCC = 0x0040, ++ cChannelAgility = 0x0080, ++ cSpectrumMgnt = 0x0100, ++ cQos = 0x0200, /* For HCCA, use with CF-Pollable and CF-PollReq */ ++ cShortSlotTime = 0x0400, ++ cAPSD = 0x0800, ++ cRM = 0x1000, /* RRM (Radio Request Measurement) */ ++ cDSSS_OFDM = 0x2000, ++ cDelayedBA = 0x4000, ++ cImmediateBA = 0x8000, ++}; ++ ++enum _REG_PREAMBLE_MODE { ++ PREAMBLE_LONG = 1, ++ PREAMBLE_AUTO = 2, ++ PREAMBLE_SHORT = 3, ++}; ++ ++enum _RTL8712_RF_MIMO_CONFIG_ { ++ RTL8712_RFCONFIG_1T = 0x10, ++ RTL8712_RFCONFIG_2T = 0x20, ++ RTL8712_RFCONFIG_1R = 0x01, ++ RTL8712_RFCONFIG_2R = 0x02, ++ RTL8712_RFCONFIG_1T1R = 0x11, ++ RTL8712_RFCONFIG_1T2R = 0x12, ++ RTL8712_RFCONFIG_TURBO = 0x92, ++ RTL8712_RFCONFIG_2T2R = 0x22 ++}; ++ ++enum RF90_RADIO_PATH { ++ RF90_PATH_A = 0, /* Radio Path A */ ++ RF90_PATH_B = 1, /* Radio Path B */ ++ RF90_PATH_C = 2, /* Radio Path C */ ++ RF90_PATH_D = 3 /* Radio Path D */ ++}; ++ ++/* Bandwidth Offset */ ++#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0 ++#define HAL_PRIME_CHNL_OFFSET_LOWER 1 ++#define HAL_PRIME_CHNL_OFFSET_UPPER 2 ++ ++/* Represent Channel Width in HT Capabilities */ ++enum CHANNEL_WIDTH { ++ CHANNEL_WIDTH_20 = 0, ++ CHANNEL_WIDTH_40 = 1, ++ CHANNEL_WIDTH_80 = 2, ++ CHANNEL_WIDTH_160 = 3, ++ CHANNEL_WIDTH_80_80 = 4, ++ CHANNEL_WIDTH_MAX = 5, ++}; ++ ++/* Represent Extension Channel Offset in HT Capabilities */ ++/* This is available only in 40Mhz mode. */ ++enum EXTCHNL_OFFSET { ++ EXTCHNL_OFFSET_NO_EXT = 0, ++ EXTCHNL_OFFSET_UPPER = 1, ++ EXTCHNL_OFFSET_NO_DEF = 2, ++ EXTCHNL_OFFSET_LOWER = 3, ++}; ++ ++enum VHT_DATA_SC { ++ VHT_DATA_SC_DONOT_CARE = 0, ++ VHT_DATA_SC_20_UPPER_OF_80MHZ = 1, ++ VHT_DATA_SC_20_LOWER_OF_80MHZ = 2, ++ VHT_DATA_SC_20_UPPERST_OF_80MHZ = 3, ++ VHT_DATA_SC_20_LOWEST_OF_80MHZ = 4, ++ VHT_DATA_SC_20_RECV1 = 5, ++ VHT_DATA_SC_20_RECV2 = 6, ++ VHT_DATA_SC_20_RECV3 = 7, ++ VHT_DATA_SC_20_RECV4 = 8, ++ VHT_DATA_SC_40_UPPER_OF_80MHZ = 9, ++ VHT_DATA_SC_40_LOWER_OF_80MHZ = 10, ++}; ++ ++enum PROTECTION_MODE { ++ PROTECTION_MODE_AUTO = 0, ++ PROTECTION_MODE_FORCE_ENABLE = 1, ++ PROTECTION_MODE_FORCE_DISABLE = 2, ++}; ++ ++/* 2007/11/15 MH Define different RF type. */ ++enum RT_RF_TYPE_DEFINITION { ++ RF_1T2R = 0, ++ RF_2T4R = 1, ++ RF_2T2R = 2, ++ RF_1T1R = 3, ++ RF_2T2R_GREEN = 4, ++ RF_MAX_TYPE = 5, ++}; ++ ++u32 rtw_ch2freq(u32 ch); ++ ++#endif /* _RTL8711_RF_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_security.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_security.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_security.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_security.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,440 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTW_SECURITY_H_ ++#define __RTW_SECURITY_H_ ++ ++ ++#define _NO_PRIVACY_ 0x0 ++#define _WEP40_ 0x1 ++#define _TKIP_ 0x2 ++#define _TKIP_WTMIC_ 0x3 ++#define _AES_ 0x4 ++#define _WEP104_ 0x5 ++#define _WEP_WPA_MIXED_ 0x07 /* WEP + WPA */ ++#define _SMS4_ 0x06 ++#define _BIP_ 0x8 ++#define is_wep_enc(alg) (((alg) == _WEP40_) || ((alg) == _WEP104_)) ++ ++const char *security_type_str(u8 value); ++ ++#define _WPA_IE_ID_ 0xdd ++#define _WPA2_IE_ID_ 0x30 ++ ++#define SHA256_MAC_LEN 32 ++#define AES_BLOCK_SIZE 16 ++#define AES_PRIV_SIZE (4 * 44) ++ ++#define RTW_KEK_LEN 16 ++#define RTW_KCK_LEN 16 ++#define RTW_REPLAY_CTR_LEN 8 ++ ++enum { ++ ENCRYP_PROTOCOL_OPENSYS, /* open system */ ++ ENCRYP_PROTOCOL_WEP, /* WEP */ ++ ENCRYP_PROTOCOL_WPA, /* WPA */ ++ ENCRYP_PROTOCOL_WPA2, /* WPA2 */ ++ ENCRYP_PROTOCOL_WAPI, /* WAPI: Not support in this version */ ++ ENCRYP_PROTOCOL_MAX ++}; ++ ++ ++#ifndef Ndis802_11AuthModeWPA2 ++#define Ndis802_11AuthModeWPA2 (Ndis802_11AuthModeWPANone + 1) ++#endif ++ ++#ifndef Ndis802_11AuthModeWPA2PSK ++#define Ndis802_11AuthModeWPA2PSK (Ndis802_11AuthModeWPANone + 2) ++#endif ++ ++union pn48 { ++ ++ u64 val; ++ ++#ifdef __LITTLE_ENDIAN ++ ++struct { ++ u8 TSC0; ++ u8 TSC1; ++ u8 TSC2; ++ u8 TSC3; ++ u8 TSC4; ++ u8 TSC5; ++ u8 TSC6; ++ u8 TSC7; ++} _byte_; ++#else ++struct { ++ u8 TSC7; ++ u8 TSC6; ++ u8 TSC5; ++ u8 TSC4; ++ u8 TSC3; ++ u8 TSC2; ++ u8 TSC1; ++ u8 TSC0; ++} _byte_; ++#endif ++ ++}; ++ ++union Keytype { ++ u8 skey[16]; ++ u32 lkey[4]; ++}; ++ ++ ++typedef struct _RT_PMKID_LIST ++{ ++ u8 bUsed; ++ u8 Bssid[6]; ++ u8 PMKID[16]; ++ u8 SsidBuf[33]; ++ u8* ssid_octet; ++ u16 ssid_length; ++} RT_PMKID_LIST, *PRT_PMKID_LIST; ++ ++ ++struct security_priv ++{ ++ u32 dot11AuthAlgrthm; /* 802.11 auth, could be open, shared, 8021x and authswitch */ ++ u32 dot11PrivacyAlgrthm; /* This specify the privacy for shared auth. algorithm. */ ++ ++ /* WEP */ ++ u32 dot11PrivacyKeyIndex; /* this is only valid for legendary wep, 0~3 for key id. (tx key index) */ ++ union Keytype dot11DefKey[4]; /* this is only valid for def. key */ ++ u32 dot11DefKeylen[4]; ++ u8 key_mask; /* use to restore wep key after hal_init */ ++ ++ u32 dot118021XGrpPrivacy; /* This specify the privacy algthm. used for Grp key */ ++ u32 dot118021XGrpKeyid; /* key id used for Grp Key (tx key index) */ ++ union Keytype dot118021XGrpKey[BIP_MAX_KEYID]; /* 802.1x Group Key, for inx0 and inx1 */ ++ union Keytype dot118021XGrptxmickey[BIP_MAX_KEYID]; ++ union Keytype dot118021XGrprxmickey[BIP_MAX_KEYID]; ++ union pn48 dot11Grptxpn; /* PN48 used for Grp Key xmit. */ ++ union pn48 dot11Grprxpn; /* PN48 used for Grp Key recv. */ ++ u32 dot11wBIPKeyid; /* key id used for BIP Key (tx key index) */ ++ union Keytype dot11wBIPKey[6]; /* BIP Key, for index4 and index5 */ ++ union pn48 dot11wBIPtxpn; /* PN48 used for Grp Key xmit. */ ++ union pn48 dot11wBIPrxpn; /* PN48 used for Grp Key recv. */ ++ ++ /* extend security capabilities for AP_MODE */ ++ unsigned int dot8021xalg;/* 0:disable, 1:psk, 2:802.1x */ ++ unsigned int wpa_psk;/* 0:disable, bit(0): WPA, bit(1):WPA2 */ ++ unsigned int wpa_group_cipher; ++ unsigned int wpa2_group_cipher; ++ unsigned int wpa_pairwise_cipher; ++ unsigned int wpa2_pairwise_cipher; ++ ++ u8 wps_ie[MAX_WPS_IE_LEN];/* added in assoc req */ ++ int wps_ie_len; ++ ++ ++ u8 binstallGrpkey; ++#ifdef CONFIG_GTK_OL ++ u8 binstallKCK_KEK; ++#endif /* CONFIG_GTK_OL */ ++ u8 binstallBIPkey; ++ u8 busetkipkey; ++ /* _timer tkip_timer; */ ++ u8 bcheck_grpkey; ++ u8 bgrpkey_handshake; ++ ++ s32 sw_encrypt;/* from registry_priv */ ++ s32 sw_decrypt;/* from registry_priv */ ++ ++ s32 hw_decrypted;/* if the rx packets is hw_decrypted ==false, it means the hw has not been ready. */ ++ ++ ++ /* keeps the auth_type & enc_status from upper layer ioctl(wpa_supplicant or wzc) */ ++ u32 ndisauthtype; /* enum NDIS_802_11_AUTHENTICATION_MODE */ ++ u32 ndisencryptstatus; /* NDIS_802_11_ENCRYPTION_STATUS */ ++ ++ struct wlan_bssid_ex sec_bss; /* for joinbss (h2c buffer) usage */ ++ ++ struct ndis_802_11_wep ndiswep; ++ ++ u8 assoc_info[600]; ++ u8 szofcapability[256]; /* for wpa2 usage */ ++ u8 oidassociation[512]; /* for wpa/wpa2 usage */ ++ u8 authenticator_ie[256]; /* store ap security information element */ ++ u8 supplicant_ie[256]; /* store sta security information element */ ++ ++ ++ /* for tkip countermeasure */ ++ unsigned long last_mic_err_time; ++ u8 btkip_countermeasure; ++ u8 btkip_wait_report; ++ u32 btkip_countermeasure_time; ++ ++ /* For WPA2 Pre-Authentication. */ ++ RT_PMKID_LIST PMKIDList[NUM_PMKID_CACHE]; /* Renamed from PreAuthKey[NUM_PRE_AUTH_KEY]. Annie, 2006-10-13. */ ++ u8 PMKIDIndex; ++ ++ u8 bWepDefaultKeyIdxSet; ++ ++#define DBG_SW_SEC_CNT ++#ifdef DBG_SW_SEC_CNT ++ u64 wep_sw_enc_cnt_bc; ++ u64 wep_sw_enc_cnt_mc; ++ u64 wep_sw_enc_cnt_uc; ++ u64 wep_sw_dec_cnt_bc; ++ u64 wep_sw_dec_cnt_mc; ++ u64 wep_sw_dec_cnt_uc; ++ ++ u64 tkip_sw_enc_cnt_bc; ++ u64 tkip_sw_enc_cnt_mc; ++ u64 tkip_sw_enc_cnt_uc; ++ u64 tkip_sw_dec_cnt_bc; ++ u64 tkip_sw_dec_cnt_mc; ++ u64 tkip_sw_dec_cnt_uc; ++ ++ u64 aes_sw_enc_cnt_bc; ++ u64 aes_sw_enc_cnt_mc; ++ u64 aes_sw_enc_cnt_uc; ++ u64 aes_sw_dec_cnt_bc; ++ u64 aes_sw_dec_cnt_mc; ++ u64 aes_sw_dec_cnt_uc; ++#endif /* DBG_SW_SEC_CNT */ ++}; ++ ++struct sha256_state { ++ u64 length; ++ u32 state[8], curlen; ++ u8 buf[64]; ++}; ++ ++#define GET_ENCRY_ALGO(psecuritypriv, psta, encry_algo, bmcst)\ ++do{\ ++ switch (psecuritypriv->dot11AuthAlgrthm)\ ++ {\ ++ case dot11AuthAlgrthm_Open:\ ++ case dot11AuthAlgrthm_Shared:\ ++ case dot11AuthAlgrthm_Auto:\ ++ encry_algo = (u8)psecuritypriv->dot11PrivacyAlgrthm;\ ++ break;\ ++ case dot11AuthAlgrthm_8021X:\ ++ if (bmcst)\ ++ encry_algo = (u8)psecuritypriv->dot118021XGrpPrivacy;\ ++ else\ ++ encry_algo =(u8) psta->dot118021XPrivacy;\ ++ break;\ ++ case dot11AuthAlgrthm_WAPI:\ ++ encry_algo = (u8)psecuritypriv->dot11PrivacyAlgrthm;\ ++ break;\ ++ }\ ++}while (0) ++ ++#define _AES_IV_LEN_ 8 ++ ++#define SET_ICE_IV_LEN(iv_len, icv_len, encrypt)\ ++do{\ ++ switch (encrypt)\ ++ {\ ++ case _WEP40_:\ ++ case _WEP104_:\ ++ iv_len = 4;\ ++ icv_len = 4;\ ++ break;\ ++ case _TKIP_:\ ++ iv_len = 8;\ ++ icv_len = 4;\ ++ break;\ ++ case _AES_:\ ++ iv_len = 8;\ ++ icv_len = 8;\ ++ break;\ ++ case _SMS4_:\ ++ iv_len = 18;\ ++ icv_len = 16;\ ++ break;\ ++ default:\ ++ iv_len = 0;\ ++ icv_len = 0;\ ++ break;\ ++ }\ ++}while (0) ++ ++ ++#define GET_TKIP_PN(iv, dot11txpn)\ ++do{\ ++ dot11txpn._byte_.TSC0 =iv[2];\ ++ dot11txpn._byte_.TSC1 =iv[0];\ ++ dot11txpn._byte_.TSC2 =iv[4];\ ++ dot11txpn._byte_.TSC3 =iv[5];\ ++ dot11txpn._byte_.TSC4 =iv[6];\ ++ dot11txpn._byte_.TSC5 =iv[7];\ ++}while (0) ++ ++ ++#define ROL32(A, n) (((A) << (n)) | (((A)>>(32-(n))) & ((1UL << (n)) - 1))) ++#define ROR32(A, n) ROL32((A), 32-(n)) ++ ++struct mic_data ++{ ++ u32 K0, K1; /* Key */ ++ u32 L, R; /* Current state */ ++ u32 M; /* Message accumulator (single word) */ ++ u32 nBytesInM; /* # bytes in M */ ++}; ++ ++extern const u32 Te0[256]; ++extern const u32 Te1[256]; ++extern const u32 Te2[256]; ++extern const u32 Te3[256]; ++extern const u32 Te4[256]; ++extern const u32 Td0[256]; ++extern const u32 Td1[256]; ++extern const u32 Td2[256]; ++extern const u32 Td3[256]; ++extern const u32 Td4[256]; ++extern const u32 rcon[10]; ++extern const u8 Td4s[256]; ++extern const u8 rcons[10]; ++ ++#define RCON(i) (rcons[(i)] << 24) ++ ++static inline u32 rotr(u32 val, int bits) ++{ ++ return (val >> bits) | (val << (32 - bits)); ++} ++ ++#define TE0(i) Te0[((i) >> 24) & 0xff] ++#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8) ++#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16) ++#define TE3(i) rotr(Te0[(i) & 0xff], 24) ++#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000) ++#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000) ++#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00) ++#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff) ++#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000) ++#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000) ++#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00) ++#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff) ++#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff) ++ ++#define TD0(i) Td0[((i) >> 24) & 0xff] ++#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8) ++#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16) ++#define TD3(i) rotr(Td0[(i) & 0xff], 24) ++#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24) ++#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16) ++#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8) ++#define TD44(i) (Td4s[(i) & 0xff]) ++#define TD0_(i) Td0[(i) & 0xff] ++#define TD1_(i) rotr(Td0[(i) & 0xff], 8) ++#define TD2_(i) rotr(Td0[(i) & 0xff], 16) ++#define TD3_(i) rotr(Td0[(i) & 0xff], 24) ++ ++#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \ ++ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) ++ ++#define PUTU32(ct, st) { \ ++(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \ ++(ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } ++ ++#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ ++ (((u32) (a)[2]) << 8) | ((u32) (a)[3])) ++ ++#define WPA_PUT_LE16(a, val) \ ++ do { \ ++ (a)[1] = ((u16) (val)) >> 8; \ ++ (a)[0] = ((u16) (val)) & 0xff; \ ++ } while (0) ++ ++#define WPA_PUT_BE32(a, val) \ ++ do { \ ++ (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ ++ (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ ++ (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ ++ (a)[3] = (u8) (((u32) (val)) & 0xff); \ ++ } while (0) ++ ++#define WPA_PUT_BE64(a, val) \ ++ do { \ ++ (a)[0] = (u8) (((u64) (val)) >> 56); \ ++ (a)[1] = (u8) (((u64) (val)) >> 48); \ ++ (a)[2] = (u8) (((u64) (val)) >> 40); \ ++ (a)[3] = (u8) (((u64) (val)) >> 32); \ ++ (a)[4] = (u8) (((u64) (val)) >> 24); \ ++ (a)[5] = (u8) (((u64) (val)) >> 16); \ ++ (a)[6] = (u8) (((u64) (val)) >> 8); \ ++ (a)[7] = (u8) (((u64) (val)) & 0xff); \ ++ } while (0) ++ ++/* ===== start - public domain SHA256 implementation ===== */ ++ ++/* This is based on SHA256 implementation in LibTomCrypt that was released into ++ * public domain by Tom St Denis. */ ++ ++/* the K array */ ++static const unsigned long K[64] = { ++ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, ++ 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, ++ 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, ++ 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, ++ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, ++ 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, ++ 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, ++ 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, ++ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, ++ 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, ++ 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, ++ 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, ++ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL ++}; ++ ++ ++/* Various logical functions */ ++#define RORc(x, y) \ ++(((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \ ++ ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL) ++#define Ch(x, y, z) (z ^ (x & (y ^ z))) ++#define Maj(x, y, z) (((x | y) & z) | (x & y)) ++#define S(x, n) RORc((x), (n)) ++#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) ++#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) ++#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) ++#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) ++#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) ++#ifndef MIN ++#define MIN(x, y) (((x) < (y)) ? (x) : (y)) ++#endif ++int omac1_aes_128(u8 *key, u8 *data, size_t data_len, u8 *mac); ++void rtw_secmicsetkey(struct mic_data *pmicdata, u8 * key); ++void rtw_secmicappendbyte(struct mic_data *pmicdata, u8 b); ++void rtw_secmicappend(struct mic_data *pmicdata, u8 * src, u32 nBytes); ++void rtw_secgetmic(struct mic_data *pmicdata, u8 * dst); ++ ++void rtw_seccalctkipmic( ++ u8 * key, ++ u8 *header, ++ u8 *data, ++ u32 data_len, ++ u8 *Miccode, ++ u8 priority); ++ ++u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe); ++u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe); ++void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe); ++ ++u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe); ++u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe); ++void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe); ++u32 rtw_BIP_verify(struct adapter *padapter, u8 *precvframe); ++ ++void rtw_sec_restore_wep_key(struct adapter *adapter); ++u8 rtw_handle_tkip_countermeasure(struct adapter * adapter, const char *caller); ++ ++#endif /* __RTL871X_SECURITY_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_version.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_version.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_version.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_version.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,2 @@ ++#define DRIVERVERSION "v4.3.5.5_12290.20140916_BTCOEX20140507-4E40" ++#define BTCOEXVERSION "BTCOEX20140507-4E40" +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_wifi_regd.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_wifi_regd.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_wifi_regd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_wifi_regd.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,28 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ *****************************************************************************/ ++ ++#ifndef __RTW_WIFI_REGD_H__ ++#define __RTW_WIFI_REGD_H__ ++ ++struct country_code_to_enum_rd { ++ u16 countrycode; ++ const char *iso_name; ++}; ++ ++enum country_code_type_t { ++ COUNTRY_CODE_USER = 0, ++ ++ /*add new channel plan above this line */ ++ COUNTRY_CODE_MAX ++}; ++ ++int rtw_regd_init(struct adapter *padapter, ++ void (*reg_notifier)(struct wiphy *wiphy, ++ struct regulatory_request *request)); ++void rtw_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); ++ ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/rtw_xmit.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_xmit.h +--- linux-4.3/3rdparty/rtl8723bs/include/rtw_xmit.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/rtw_xmit.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,528 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef _RTW_XMIT_H_ ++#define _RTW_XMIT_H_ ++ ++ ++#define MAX_XMITBUF_SZ (20480) /* 20k */ ++ ++#define NR_XMITBUFF (16) ++ ++#define XMITBUF_ALIGN_SZ 512 ++ ++/* xmit extension buff defination */ ++#define MAX_XMIT_EXTBUF_SZ (1536) ++#define NR_XMIT_EXTBUFF (32) ++ ++#define MAX_CMDBUF_SZ (5120) /* 4096) */ ++ ++#define MAX_NUMBLKS (1) ++ ++#define XMIT_VO_QUEUE (0) ++#define XMIT_VI_QUEUE (1) ++#define XMIT_BE_QUEUE (2) ++#define XMIT_BK_QUEUE (3) ++ ++#define VO_QUEUE_INX 0 ++#define VI_QUEUE_INX 1 ++#define BE_QUEUE_INX 2 ++#define BK_QUEUE_INX 3 ++#define BCN_QUEUE_INX 4 ++#define MGT_QUEUE_INX 5 ++#define HIGH_QUEUE_INX 6 ++#define TXCMD_QUEUE_INX 7 ++ ++#define HW_QUEUE_ENTRY 8 ++ ++#define WEP_IV(pattrib_iv, dot11txpn, keyidx)\ ++do{\ ++ pattrib_iv[0] = dot11txpn._byte_.TSC0;\ ++ pattrib_iv[1] = dot11txpn._byte_.TSC1;\ ++ pattrib_iv[2] = dot11txpn._byte_.TSC2;\ ++ pattrib_iv[3] = ((keyidx & 0x3)<<6);\ ++ dot11txpn.val = (dot11txpn.val == 0xffffff) ? 0: (dot11txpn.val+1);\ ++}while (0) ++ ++ ++#define TKIP_IV(pattrib_iv, dot11txpn, keyidx)\ ++do{\ ++ pattrib_iv[0] = dot11txpn._byte_.TSC1;\ ++ pattrib_iv[1] = (dot11txpn._byte_.TSC1 | 0x20) & 0x7f;\ ++ pattrib_iv[2] = dot11txpn._byte_.TSC0;\ ++ pattrib_iv[3] = BIT(5) | ((keyidx & 0x3)<<6);\ ++ pattrib_iv[4] = dot11txpn._byte_.TSC2;\ ++ pattrib_iv[5] = dot11txpn._byte_.TSC3;\ ++ pattrib_iv[6] = dot11txpn._byte_.TSC4;\ ++ pattrib_iv[7] = dot11txpn._byte_.TSC5;\ ++ dot11txpn.val = dot11txpn.val == 0xffffffffffffULL ? 0: (dot11txpn.val+1);\ ++}while (0) ++ ++#define AES_IV(pattrib_iv, dot11txpn, keyidx)\ ++do{\ ++ pattrib_iv[0] = dot11txpn._byte_.TSC0;\ ++ pattrib_iv[1] = dot11txpn._byte_.TSC1;\ ++ pattrib_iv[2] = 0;\ ++ pattrib_iv[3] = BIT(5) | ((keyidx & 0x3)<<6);\ ++ pattrib_iv[4] = dot11txpn._byte_.TSC2;\ ++ pattrib_iv[5] = dot11txpn._byte_.TSC3;\ ++ pattrib_iv[6] = dot11txpn._byte_.TSC4;\ ++ pattrib_iv[7] = dot11txpn._byte_.TSC5;\ ++ dot11txpn.val = dot11txpn.val == 0xffffffffffffULL ? 0: (dot11txpn.val+1);\ ++}while (0) ++ ++ ++#define HWXMIT_ENTRY 4 ++ ++/* For Buffer Descriptor ring architecture */ ++#define TXDESC_SIZE 40 ++ ++#define TXDESC_OFFSET TXDESC_SIZE ++ ++enum TXDESC_SC{ ++ SC_DONT_CARE = 0x00, ++ SC_UPPER = 0x01, ++ SC_LOWER = 0x02, ++ SC_DUPLICATE = 0x03 ++}; ++ ++#define TXDESC_40_BYTES ++ ++struct tx_desc { ++ __le32 txdw0; ++ __le32 txdw1; ++ __le32 txdw2; ++ __le32 txdw3; ++ __le32 txdw4; ++ __le32 txdw5; ++ __le32 txdw6; ++ __le32 txdw7; ++ ++#if defined(TXDESC_40_BYTES) || defined(TXDESC_64_BYTES) ++ __le32 txdw8; ++ __le32 txdw9; ++#endif /* TXDESC_40_BYTES */ ++ ++#ifdef TXDESC_64_BYTES ++ __le32 txdw10; ++ __le32 txdw11; ++ ++ /* 2008/05/15 MH Because PCIE HW memory R/W 4K limit. And now, our descriptor */ ++ /* size is 40 bytes. If you use more than 102 descriptor(103*40>4096), HW will execute */ ++ /* memoryR/W CRC error. And then all DMA fetch will fail. We must decrease descriptor */ ++ /* number or enlarge descriptor size as 64 bytes. */ ++ __le32 txdw12; ++ __le32 txdw13; ++ __le32 txdw14; ++ __le32 txdw15; ++#endif ++}; ++ ++union txdesc { ++ struct tx_desc txdesc; ++ unsigned int value[TXDESC_SIZE>>2]; ++}; ++ ++struct hw_xmit { ++ /* _lock xmit_lock; */ ++ /* struct list_head pending; */ ++ struct __queue *sta_queue; ++ /* struct hw_txqueue *phwtxqueue; */ ++ /* sint txcmdcnt; */ ++ int accnt; ++}; ++ ++/* reduce size */ ++struct pkt_attrib ++{ ++ u8 type; ++ u8 subtype; ++ u8 bswenc; ++ u8 dhcp_pkt; ++ u16 ether_type; ++ u16 seqnum; ++ u16 pkt_hdrlen; /* the original 802.3 pkt header len */ ++ u16 hdrlen; /* the WLAN Header Len */ ++ u32 pktlen; /* the original 802.3 pkt raw_data len (not include ether_hdr data) */ ++ u32 last_txcmdsz; ++ u8 nr_frags; ++ u8 encrypt; /* when 0 indicate no encrypt. when non-zero, indicate the encrypt algorith */ ++ u8 iv_len; ++ u8 icv_len; ++ u8 iv[18]; ++ u8 icv[16]; ++ u8 priority; ++ u8 ack_policy; ++ u8 mac_id; ++ u8 vcs_mode; /* virtual carrier sense method */ ++ u8 dst[ETH_ALEN]; ++ u8 src[ETH_ALEN]; ++ u8 ta[ETH_ALEN]; ++ u8 ra[ETH_ALEN]; ++ u8 key_idx; ++ u8 qos_en; ++ u8 ht_en; ++ u8 raid;/* rate adpative id */ ++ u8 bwmode; ++ u8 ch_offset;/* PRIME_CHNL_OFFSET */ ++ u8 sgi;/* short GI */ ++ u8 ampdu_en;/* tx ampdu enable */ ++ u8 ampdu_spacing; /* ampdu_min_spacing for peer sta's rx */ ++ u8 mdata;/* more data bit */ ++ u8 pctrl;/* per packet txdesc control enable */ ++ u8 triggered;/* for ap mode handling Power Saving sta */ ++ u8 qsel; ++ u8 order;/* order bit */ ++ u8 eosp; ++ u8 rate; ++ u8 intel_proxim; ++ u8 retry_ctrl; ++ u8 mbssid; ++ u8 ldpc; ++ u8 stbc; ++ struct sta_info * psta; ++ ++ u8 rtsen; ++ u8 cts2self; ++ union Keytype dot11tkiptxmickey; ++ /* union Keytype dot11tkiprxmickey; */ ++ union Keytype dot118021x_UncstKey; ++ ++ u8 icmp_pkt; ++ ++}; ++ ++#define WLANHDR_OFFSET 64 ++ ++#define NULL_FRAMETAG (0x0) ++#define DATA_FRAMETAG 0x01 ++#define L2_FRAMETAG 0x02 ++#define MGNT_FRAMETAG 0x03 ++#define AMSDU_FRAMETAG 0x04 ++ ++#define EII_FRAMETAG 0x05 ++#define IEEE8023_FRAMETAG 0x06 ++ ++#define MP_FRAMETAG 0x07 ++ ++#define TXAGG_FRAMETAG 0x08 ++ ++enum { ++ XMITBUF_DATA = 0, ++ XMITBUF_MGNT = 1, ++ XMITBUF_CMD = 2, ++}; ++ ++struct submit_ctx{ ++ unsigned long submit_time; /* */ ++ u32 timeout_ms; /* <0: not synchronous, 0: wait forever, >0: up to ms waiting */ ++ int status; /* status for operation */ ++ struct completion done; ++}; ++ ++enum { ++ RTW_SCTX_SUBMITTED = -1, ++ RTW_SCTX_DONE_SUCCESS = 0, ++ RTW_SCTX_DONE_UNKNOWN, ++ RTW_SCTX_DONE_TIMEOUT, ++ RTW_SCTX_DONE_BUF_ALLOC, ++ RTW_SCTX_DONE_BUF_FREE, ++ RTW_SCTX_DONE_WRITE_PORT_ERR, ++ RTW_SCTX_DONE_TX_DESC_NA, ++ RTW_SCTX_DONE_TX_DENY, ++ RTW_SCTX_DONE_CCX_PKT_FAIL, ++ RTW_SCTX_DONE_DRV_STOP, ++ RTW_SCTX_DONE_DEV_REMOVE, ++ RTW_SCTX_DONE_CMD_ERROR, ++}; ++ ++ ++void rtw_sctx_init(struct submit_ctx *sctx, int timeout_ms); ++int rtw_sctx_wait(struct submit_ctx *sctx, const char *msg); ++void rtw_sctx_done_err(struct submit_ctx **sctx, int status); ++void rtw_sctx_done(struct submit_ctx **sctx); ++ ++struct xmit_buf ++{ ++ struct list_head list; ++ ++ struct adapter *padapter; ++ ++ u8 *pallocated_buf; ++ ++ u8 *pbuf; ++ ++ void *priv_data; ++ ++ u16 buf_tag; /* 0: Normal xmitbuf, 1: extension xmitbuf, 2:cmd xmitbuf */ ++ u16 flags; ++ u32 alloc_sz; ++ ++ u32 len; ++ ++ struct submit_ctx *sctx; ++ ++ u8 *phead; ++ u8 *pdata; ++ u8 *ptail; ++ u8 *pend; ++ u32 ff_hwaddr; ++ u8 pg_num; ++ u8 agg_num; ++ ++#if defined(DBG_XMIT_BUF)|| defined(DBG_XMIT_BUF_EXT) ++ u8 no; ++#endif ++ ++}; ++ ++ ++struct xmit_frame ++{ ++ struct list_head list; ++ ++ struct pkt_attrib attrib; ++ ++ _pkt *pkt; ++ ++ int frame_tag; ++ ++ struct adapter *padapter; ++ ++ u8 *buf_addr; ++ ++ struct xmit_buf *pxmitbuf; ++ ++ u8 pg_num; ++ u8 agg_num; ++ ++ u8 ack_report; ++ ++ u8 *alloc_addr; /* the actual address this xmitframe allocated */ ++ u8 ext_tag; /* 0:data, 1:mgmt */ ++ ++}; ++ ++struct tx_servq { ++ struct list_head tx_pending; ++ struct __queue sta_pending; ++ int qcnt; ++}; ++ ++ ++struct sta_xmit_priv ++{ ++ _lock lock; ++ sint option; ++ sint apsd_setting; /* When bit mask is on, the associated edca queue supports APSD. */ ++ ++ ++ /* struct tx_servq blk_q[MAX_NUMBLKS]; */ ++ struct tx_servq be_q; /* priority == 0, 3 */ ++ struct tx_servq bk_q; /* priority == 1, 2 */ ++ struct tx_servq vi_q; /* priority == 4, 5 */ ++ struct tx_servq vo_q; /* priority == 6, 7 */ ++ struct list_head legacy_dz; ++ struct list_head apsd; ++ ++ u16 txseq_tid[16]; ++ ++ /* uint sta_tx_bytes; */ ++ /* u64 sta_tx_pkts; */ ++ /* uint sta_tx_fail; */ ++ ++ ++}; ++ ++ ++struct hw_txqueue { ++ volatile sint head; ++ volatile sint tail; ++ volatile sint free_sz; /* in units of 64 bytes */ ++ volatile sint free_cmdsz; ++ volatile sint txsz[8]; ++ uint ff_hwaddr; ++ uint cmd_hwaddr; ++ sint ac_tag; ++}; ++ ++struct agg_pkt_info{ ++ u16 offset; ++ u16 pkt_len; ++}; ++ ++enum cmdbuf_type { ++ CMDBUF_BEACON = 0x00, ++ CMDBUF_RSVD, ++ CMDBUF_MAX ++}; ++ ++struct xmit_priv { ++ ++ _lock lock; ++ ++ _sema xmit_sema; ++ _sema terminate_xmitthread_sema; ++ ++ /* struct __queue blk_strms[MAX_NUMBLKS]; */ ++ struct __queue be_pending; ++ struct __queue bk_pending; ++ struct __queue vi_pending; ++ struct __queue vo_pending; ++ struct __queue bm_pending; ++ ++ /* struct __queue legacy_dz_queue; */ ++ /* struct __queue apsd_queue; */ ++ ++ u8 *pallocated_frame_buf; ++ u8 *pxmit_frame_buf; ++ uint free_xmitframe_cnt; ++ struct __queue free_xmit_queue; ++ ++ /* uint mapping_addr; */ ++ /* uint pkt_sz; */ ++ ++ u8 *xframe_ext_alloc_addr; ++ u8 *xframe_ext; ++ uint free_xframe_ext_cnt; ++ struct __queue free_xframe_ext_queue; ++ ++ /* struct hw_txqueue be_txqueue; */ ++ /* struct hw_txqueue bk_txqueue; */ ++ /* struct hw_txqueue vi_txqueue; */ ++ /* struct hw_txqueue vo_txqueue; */ ++ /* struct hw_txqueue bmc_txqueue; */ ++ ++ uint frag_len; ++ ++ struct adapter *adapter; ++ ++ u8 vcs_setting; ++ u8 vcs; ++ u8 vcs_type; ++ /* u16 rts_thresh; */ ++ ++ u64 tx_bytes; ++ u64 tx_pkts; ++ u64 tx_drop; ++ u64 last_tx_pkts; ++ ++ struct hw_xmit *hwxmits; ++ u8 hwxmit_entry; ++ ++ u8 wmm_para_seq[4];/* sequence for wmm ac parameter strength from large to small. it's value is 0->vo, 1->vi, 2->be, 3->bk. */ ++ ++#ifdef CONFIG_SDIO_TX_TASKLET ++ struct tasklet_struct xmit_tasklet; ++#else ++ void *SdioXmitThread; ++ _sema SdioXmitSema; ++ _sema SdioXmitTerminateSema; ++#endif /* CONFIG_SDIO_TX_TASKLET */ ++ ++ struct __queue free_xmitbuf_queue; ++ struct __queue pending_xmitbuf_queue; ++ u8 *pallocated_xmitbuf; ++ u8 *pxmitbuf; ++ uint free_xmitbuf_cnt; ++ ++ struct __queue free_xmit_extbuf_queue; ++ u8 *pallocated_xmit_extbuf; ++ u8 *pxmit_extbuf; ++ uint free_xmit_extbuf_cnt; ++ ++ struct xmit_buf pcmd_xmitbuf[CMDBUF_MAX]; ++ ++ u16 nqos_ssn; ++ ++ int ack_tx; ++ _mutex ack_tx_mutex; ++ struct submit_ctx ack_tx_ops; ++ u8 seq_no; ++ _lock lock_sctx; ++}; ++ ++extern struct xmit_frame *__rtw_alloc_cmdxmitframe(struct xmit_priv *pxmitpriv, ++ enum cmdbuf_type buf_type); ++#define rtw_alloc_cmdxmitframe(p) __rtw_alloc_cmdxmitframe(p, CMDBUF_RSVD) ++#define rtw_alloc_bcnxmitframe(p) __rtw_alloc_cmdxmitframe(p, CMDBUF_BEACON) ++ ++extern struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv); ++extern s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf); ++ ++extern struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv); ++extern s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf); ++ ++void rtw_count_tx_stats(struct adapter *padapter, struct xmit_frame *pxmitframe, int sz); ++extern void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len); ++extern s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattrib); ++extern s32 rtw_put_snap(u8 *data, u16 h_proto); ++ ++extern struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv); ++struct xmit_frame *rtw_alloc_xmitframe_ext(struct xmit_priv *pxmitpriv); ++struct xmit_frame *rtw_alloc_xmitframe_once(struct xmit_priv *pxmitpriv); ++extern s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitframe); ++extern void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, struct __queue *pframequeue); ++struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info *psta, sint up, u8 *ac); ++extern s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe); ++ ++extern s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe); ++extern u32 rtw_calculate_wlan_pkt_size_by_attribue(struct pkt_attrib *pattrib); ++#define rtw_wlan_pkt_size(f) rtw_calculate_wlan_pkt_size_by_attribue(&f->attrib) ++extern s32 rtw_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_frame *pxmitframe); ++extern s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_frame *pxmitframe); ++s32 _rtw_init_hw_txqueue(struct hw_txqueue* phw_txqueue, u8 ac_tag); ++void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv); ++ ++ ++s32 rtw_txframes_pending(struct adapter *padapter); ++void rtw_init_hwxmits(struct hw_xmit *phwxmit, sint entry); ++ ++ ++s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter); ++void _rtw_free_xmit_priv (struct xmit_priv *pxmitpriv); ++ ++ ++void rtw_alloc_hwxmits(struct adapter *padapter); ++void rtw_free_hwxmits(struct adapter *padapter); ++ ++ ++s32 rtw_xmit(struct adapter *padapter, _pkt **pkt); ++bool xmitframe_hiq_filter(struct xmit_frame *xmitframe); ++ ++sint xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_frame *pxmitframe); ++void stop_sta_xmit(struct adapter *padapter, struct sta_info *psta); ++void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta); ++void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *psta); ++ ++u8 query_ra_short_GI(struct sta_info *psta); ++ ++u8 qos_acm(u8 acm_mask, u8 priority); ++ ++void enqueue_pending_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf); ++void enqueue_pending_xmitbuf_to_head(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf); ++struct xmit_buf*dequeue_pending_xmitbuf(struct xmit_priv *pxmitpriv); ++struct xmit_buf*dequeue_pending_xmitbuf_under_survey(struct xmit_priv *pxmitpriv); ++sint check_pending_xmitbuf(struct xmit_priv *pxmitpriv); ++int rtw_xmit_thread(void *context); ++ ++u32 rtw_get_ff_hwaddr(struct xmit_frame *pxmitframe); ++ ++int rtw_ack_tx_wait(struct xmit_priv *pxmitpriv, u32 timeout_ms); ++void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status); ++ ++/* include after declaring struct xmit_buf, in order to avoid warning */ ++#include ++ ++#endif /* _RTL871X_XMIT_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/sdio_hal.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/sdio_hal.h +--- linux-4.3/3rdparty/rtl8723bs/include/sdio_hal.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/sdio_hal.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,28 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __SDIO_HAL_H__ ++#define __SDIO_HAL_H__ ++ ++ ++extern u8 sd_hal_bus_init(struct adapter *padapter); ++extern u8 sd_hal_bus_deinit(struct adapter *padapter); ++ ++u8 sd_int_isr(struct adapter *padapter); ++void sd_int_dpc(struct adapter *padapter); ++void rtw_set_hal_ops(struct adapter *padapter); ++ ++void rtl8723bs_set_hal_ops(struct adapter *padapter); ++ ++#endif /* __SDIO_HAL_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/sdio_ops.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/sdio_ops.h +--- linux-4.3/3rdparty/rtl8723bs/include/sdio_ops.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/sdio_ops.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,49 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __SDIO_OPS_H__ ++#define __SDIO_OPS_H__ ++ ++ ++#include ++ ++extern void sdio_set_intf_ops(struct adapter *padapter, struct _io_ops *pops); ++ ++/* extern void sdio_func1cmd52_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem); */ ++/* extern void sdio_func1cmd52_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem); */ ++extern u8 SdioLocalCmd52Read1Byte(struct adapter *padapter, u32 addr); ++extern void SdioLocalCmd52Write1Byte(struct adapter *padapter, u32 addr, u8 v); ++extern s32 sdio_local_read(struct adapter *padapter, u32 addr, u32 cnt, u8 *pbuf); ++extern s32 sdio_local_write(struct adapter *padapter, u32 addr, u32 cnt, u8 *pbuf); ++ ++u32 _sdio_read32(struct adapter *padapter, u32 addr); ++s32 _sdio_write32(struct adapter *padapter, u32 addr, u32 val); ++ ++extern void sd_int_hdl(struct adapter *padapter); ++extern u8 CheckIPSStatus(struct adapter *padapter); ++ ++#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) ++extern u8 RecvOnePkt(struct adapter *padapter, u32 size); ++#endif /* CONFIG_WOWLAN */ ++extern void InitInterrupt8723BSdio(struct adapter *padapter); ++extern void InitSysInterrupt8723BSdio(struct adapter *padapter); ++extern void EnableInterrupt8723BSdio(struct adapter *padapter); ++extern void DisableInterrupt8723BSdio(struct adapter *padapter); ++extern u8 HalQueryTxBufferStatus8723BSdio(struct adapter *padapter); ++extern u8 HalQueryTxOQTBufferStatus8723BSdio(struct adapter *padapter); ++#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) ++extern void ClearInterrupt8723BSdio(struct adapter *padapter); ++#endif /* CONFIG_WOWLAN */ ++ ++#endif /* !__SDIO_OPS_H__ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/sdio_ops_linux.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/sdio_ops_linux.h +--- linux-4.3/3rdparty/rtl8723bs/include/sdio_ops_linux.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/sdio_ops_linux.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,40 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __SDIO_OPS_LINUX_H__ ++#define __SDIO_OPS_LINUX_H__ ++ ++#define SDIO_ERR_VAL8 0xEA ++#define SDIO_ERR_VAL16 0xEAEA ++#define SDIO_ERR_VAL32 0xEAEAEAEA ++ ++u8 sd_f0_read8(struct intf_hdl *pintfhdl, u32 addr, s32 *err); ++ ++s32 _sd_cmd52_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata); ++s32 _sd_cmd52_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata); ++s32 sd_cmd52_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata); ++s32 sd_cmd52_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata); ++ ++u8 sd_read8(struct intf_hdl *pintfhdl, u32 addr, s32 *err); ++u32 sd_read32(struct intf_hdl *pintfhdl, u32 addr, s32 *err); ++s32 _sd_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata); ++s32 sd_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata); ++void sd_write8(struct intf_hdl *pintfhdl, u32 addr, u8 v, s32 *err); ++void sd_write32(struct intf_hdl *pintfhdl, u32 addr, u32 v, s32 *err); ++s32 _sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata); ++s32 sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata); ++ ++ ++void rtw_sdio_set_irq_thd(struct dvobj_priv *dvobj, void *thd_hdl); ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/sdio_osintf.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/sdio_osintf.h +--- linux-4.3/3rdparty/rtl8723bs/include/sdio_osintf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/sdio_osintf.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,24 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __SDIO_OSINTF_H__ ++#define __SDIO_OSINTF_H__ ++ ++ ++ ++u8 sd_hal_bus_init(struct adapter *padapter); ++u8 sd_hal_bus_deinit(struct adapter *padapter); ++void sd_c2h_hdl(struct adapter *padapter); ++ ++#endif +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/sta_info.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/sta_info.h +--- linux-4.3/3rdparty/rtl8723bs/include/sta_info.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/sta_info.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,392 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __STA_INFO_H_ ++#define __STA_INFO_H_ ++ ++ ++#define IBSS_START_MAC_ID 2 ++#define NUM_STA 32 ++#define NUM_ACL 16 ++ ++ ++/* if mode == 0, then the sta is allowed once the addr is hit. */ ++/* if mode == 1, then the sta is rejected once the addr is non-hit. */ ++struct rtw_wlan_acl_node { ++ struct list_head list; ++ u8 addr[ETH_ALEN]; ++ u8 valid; ++}; ++ ++/* mode = 0, disable */ ++/* mode = 1, accept unless in deny list */ ++/* mode =2, deny unless in accept list */ ++struct wlan_acl_pool { ++ int mode; ++ int num; ++ struct rtw_wlan_acl_node aclnode[NUM_ACL]; ++ struct __queue acl_node_q; ++}; ++ ++typedef struct _RSSI_STA{ ++ s32 UndecoratedSmoothedPWDB; ++ s32 UndecoratedSmoothedCCK; ++ s32 UndecoratedSmoothedOFDM; ++ u64 PacketMap; ++ u8 ValidBit; ++}RSSI_STA, *PRSSI_STA; ++ ++struct stainfo_stats { ++ ++ u64 rx_mgnt_pkts; ++ u64 rx_beacon_pkts; ++ u64 rx_probereq_pkts; ++ u64 rx_probersp_pkts; ++ u64 rx_probersp_bm_pkts; ++ u64 rx_probersp_uo_pkts; ++ u64 rx_ctrl_pkts; ++ u64 rx_data_pkts; ++ ++ u64 last_rx_mgnt_pkts; ++ u64 last_rx_beacon_pkts; ++ u64 last_rx_probereq_pkts; ++ u64 last_rx_probersp_pkts; ++ u64 last_rx_probersp_bm_pkts; ++ u64 last_rx_probersp_uo_pkts; ++ u64 last_rx_ctrl_pkts; ++ u64 last_rx_data_pkts; ++ ++ u64 rx_bytes; ++ u64 rx_drops; ++ ++ u64 tx_pkts; ++ u64 tx_bytes; ++ u64 tx_drops; ++}; ++ ++struct sta_info { ++ ++ _lock lock; ++ struct list_head list; /* free_sta_queue */ ++ struct list_head hash_list; /* sta_hash */ ++ struct adapter *padapter; ++ ++ struct sta_xmit_priv sta_xmitpriv; ++ struct sta_recv_priv sta_recvpriv; ++ ++ struct __queue sleep_q; ++ unsigned int sleepq_len; ++ ++ uint state; ++ uint aid; ++ uint mac_id; ++ uint qos_option; ++ u8 hwaddr[ETH_ALEN]; ++ ++ uint ieee8021x_blocked; /* 0: allowed, 1:blocked */ ++ uint dot118021XPrivacy; /* aes, tkip... */ ++ union Keytype dot11tkiptxmickey; ++ union Keytype dot11tkiprxmickey; ++ union Keytype dot118021x_UncstKey; ++ union pn48 dot11txpn; /* PN48 used for Unicast xmit */ ++#ifdef CONFIG_GTK_OL ++ u8 kek[RTW_KEK_LEN]; ++ u8 kck[RTW_KCK_LEN]; ++ u8 replay_ctr[RTW_REPLAY_CTR_LEN]; ++#endif /* CONFIG_GTK_OL */ ++ union pn48 dot11wtxpn; /* PN48 used for Unicast mgmt xmit. */ ++ union pn48 dot11rxpn; /* PN48 used for Unicast recv. */ ++ ++ ++ u8 bssrateset[16]; ++ u32 bssratelen; ++ s32 rssi; ++ s32 signal_quality; ++ ++ u8 cts2self; ++ u8 rtsen; ++ ++ u8 raid; ++ u8 init_rate; ++ u32 ra_mask; ++ u8 wireless_mode; /* NETWORK_TYPE */ ++ u8 bw_mode; ++ ++ u8 ldpc; ++ u8 stbc; ++ ++ struct stainfo_stats sta_stats; ++ ++ /* for A-MPDU TX, ADDBA timeout check */ ++ _timer addba_retry_timer; ++ ++ /* for A-MPDU Rx reordering buffer control */ ++ struct recv_reorder_ctrl recvreorder_ctrl[16]; ++ ++ /* for A-MPDU Tx */ ++ /* unsigned char ampdu_txen_bitmap; */ ++ u16 BA_starting_seqctrl[16]; ++ ++ ++ struct ht_priv htpriv; ++ ++ /* Notes: */ ++ /* STA_Mode: */ ++ /* curr_network(mlme_priv/security_priv/qos/ht) + sta_info: (STA & AP) CAP/INFO */ ++ /* scan_q: AP CAP/INFO */ ++ ++ /* AP_Mode: */ ++ /* curr_network(mlme_priv/security_priv/qos/ht) : AP CAP/INFO */ ++ /* sta_info: (AP & STA) CAP/INFO */ ++ ++ struct list_head asoc_list; ++ struct list_head auth_list; ++ ++ unsigned int expire_to; ++ unsigned int auth_seq; ++ unsigned int authalg; ++ unsigned char chg_txt[128]; ++ ++ u16 capability; ++ int flags; ++ ++ int dot8021xalg;/* 0:disable, 1:psk, 2:802.1x */ ++ int wpa_psk;/* 0:disable, bit(0): WPA, bit(1):WPA2 */ ++ int wpa_group_cipher; ++ int wpa2_group_cipher; ++ int wpa_pairwise_cipher; ++ int wpa2_pairwise_cipher; ++ ++ u8 bpairwise_key_installed; ++ ++ u8 wpa_ie[32]; ++ ++ u8 nonerp_set; ++ u8 no_short_slot_time_set; ++ u8 no_short_preamble_set; ++ u8 no_ht_gf_set; ++ u8 no_ht_set; ++ u8 ht_20mhz_set; ++ ++ unsigned int tx_ra_bitmap; ++ u8 qos_info; ++ ++ u8 max_sp_len; ++ u8 uapsd_bk;/* BIT(0): Delivery enabled, BIT(1): Trigger enabled */ ++ u8 uapsd_be; ++ u8 uapsd_vi; ++ u8 uapsd_vo; ++ ++ u8 has_legacy_ac; ++ unsigned int sleepq_ac_len; ++ ++ u8 under_exist_checking; ++ ++ u8 keep_alive_trycnt; ++ ++#ifdef CONFIG_AUTO_AP_MODE ++ u8 isrc; /* this device is rc */ ++ u16 pid; /* pairing id */ ++#endif ++ ++ u8 *passoc_req; ++ u32 assoc_req_len; ++ ++ /* for DM */ ++ RSSI_STA rssi_stat; ++ ++ /* ODM_STA_INFO_T */ ++ /* ================ODM Relative Info ======================= */ ++ /* Please be care, dont declare too much structure here. It will cost memory * STA support num. */ ++ /* */ ++ /* */ ++ /* 2011/10/20 MH Add for ODM STA info. */ ++ /* */ ++ /* Driver Write */ ++ u8 bValid; /* record the sta status link or not? */ ++ u8 IOTPeer; /* Enum value. HT_IOT_PEER_E */ ++ /* ODM Write */ ++ /* 1 PHY_STATUS_INFO */ ++ u8 RSSI_Path[4]; /* */ ++ u8 RSSI_Ave; ++ u8 RXEVM[4]; ++ u8 RXSNR[4]; ++ ++ u8 rssi_level; /* for Refresh RA mask */ ++ /* ODM Write */ ++ /* 1 TX_INFO (may changed by IC) */ ++ /* TX_INFO_T pTxInfo; Define in IC folder. Move lower layer. */ ++ /* */ ++ /* ================ODM Relative Info ======================= */ ++ /* */ ++ ++ /* To store the sequence number of received management frame */ ++ u16 RxMgmtFrameSeqNum; ++}; ++ ++#define sta_rx_pkts(sta) \ ++ (sta->sta_stats.rx_mgnt_pkts \ ++ + sta->sta_stats.rx_ctrl_pkts \ ++ + sta->sta_stats.rx_data_pkts) ++ ++#define sta_last_rx_pkts(sta) \ ++ (sta->sta_stats.last_rx_mgnt_pkts \ ++ + sta->sta_stats.last_rx_ctrl_pkts \ ++ + sta->sta_stats.last_rx_data_pkts) ++ ++#define sta_rx_data_pkts(sta) \ ++ (sta->sta_stats.rx_data_pkts) ++ ++#define sta_last_rx_data_pkts(sta) \ ++ (sta->sta_stats.last_rx_data_pkts) ++ ++#define sta_rx_mgnt_pkts(sta) \ ++ (sta->sta_stats.rx_mgnt_pkts) ++ ++#define sta_last_rx_mgnt_pkts(sta) \ ++ (sta->sta_stats.last_rx_mgnt_pkts) ++ ++#define sta_rx_beacon_pkts(sta) \ ++ (sta->sta_stats.rx_beacon_pkts) ++ ++#define sta_last_rx_beacon_pkts(sta) \ ++ (sta->sta_stats.last_rx_beacon_pkts) ++ ++#define sta_rx_probereq_pkts(sta) \ ++ (sta->sta_stats.rx_probereq_pkts) ++ ++#define sta_last_rx_probereq_pkts(sta) \ ++ (sta->sta_stats.last_rx_probereq_pkts) ++ ++#define sta_rx_probersp_pkts(sta) \ ++ (sta->sta_stats.rx_probersp_pkts) ++ ++#define sta_last_rx_probersp_pkts(sta) \ ++ (sta->sta_stats.last_rx_probersp_pkts) ++ ++#define sta_rx_probersp_bm_pkts(sta) \ ++ (sta->sta_stats.rx_probersp_bm_pkts) ++ ++#define sta_last_rx_probersp_bm_pkts(sta) \ ++ (sta->sta_stats.last_rx_probersp_bm_pkts) ++ ++#define sta_rx_probersp_uo_pkts(sta) \ ++ (sta->sta_stats.rx_probersp_uo_pkts) ++ ++#define sta_last_rx_probersp_uo_pkts(sta) \ ++ (sta->sta_stats.last_rx_probersp_uo_pkts) ++ ++#define sta_update_last_rx_pkts(sta) \ ++ do { \ ++ sta->sta_stats.last_rx_mgnt_pkts = sta->sta_stats.rx_mgnt_pkts; \ ++ sta->sta_stats.last_rx_beacon_pkts = sta->sta_stats.rx_beacon_pkts; \ ++ sta->sta_stats.last_rx_probereq_pkts = sta->sta_stats.rx_probereq_pkts; \ ++ sta->sta_stats.last_rx_probersp_pkts = sta->sta_stats.rx_probersp_pkts; \ ++ sta->sta_stats.last_rx_probersp_bm_pkts = sta->sta_stats.rx_probersp_bm_pkts; \ ++ sta->sta_stats.last_rx_probersp_uo_pkts = sta->sta_stats.rx_probersp_uo_pkts; \ ++ sta->sta_stats.last_rx_ctrl_pkts = sta->sta_stats.rx_ctrl_pkts; \ ++ sta->sta_stats.last_rx_data_pkts = sta->sta_stats.rx_data_pkts; \ ++ } while (0) ++ ++#define STA_RX_PKTS_ARG(sta) \ ++ sta->sta_stats.rx_mgnt_pkts \ ++ , sta->sta_stats.rx_ctrl_pkts \ ++ , sta->sta_stats.rx_data_pkts ++ ++#define STA_LAST_RX_PKTS_ARG(sta) \ ++ sta->sta_stats.last_rx_mgnt_pkts \ ++ , sta->sta_stats.last_rx_ctrl_pkts \ ++ , sta->sta_stats.last_rx_data_pkts ++ ++#define STA_RX_PKTS_DIFF_ARG(sta) \ ++ sta->sta_stats.rx_mgnt_pkts - sta->sta_stats.last_rx_mgnt_pkts \ ++ , sta->sta_stats.rx_ctrl_pkts - sta->sta_stats.last_rx_ctrl_pkts \ ++ , sta->sta_stats.rx_data_pkts -sta->sta_stats.last_rx_data_pkts ++ ++#define STA_PKTS_FMT "(m:%llu, c:%llu, d:%llu)" ++ ++struct sta_priv { ++ ++ u8 *pallocated_stainfo_buf; ++ u8 *pstainfo_buf; ++ struct __queue free_sta_queue; ++ ++ _lock sta_hash_lock; ++ struct list_head sta_hash[NUM_STA]; ++ int asoc_sta_count; ++ struct __queue sleep_q; ++ struct __queue wakeup_q; ++ ++ struct adapter *padapter; ++ ++ struct list_head asoc_list; ++ struct list_head auth_list; ++ _lock asoc_list_lock; ++ _lock auth_list_lock; ++ u8 asoc_list_cnt; ++ u8 auth_list_cnt; ++ ++ unsigned int auth_to; /* sec, time to expire in authenticating. */ ++ unsigned int assoc_to; /* sec, time to expire before associating. */ ++ unsigned int expire_to; /* sec , time to expire after associated. */ ++ ++ /* pointers to STA info; based on allocated AID or NULL if AID free ++ * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1 ++ * and so on ++ */ ++ struct sta_info *sta_aid[NUM_STA]; ++ ++ u16 sta_dz_bitmap;/* only support 15 stations, staion aid bitmap for sleeping sta. */ ++ u16 tim_bitmap;/* only support 15 stations, aid = 0~15 mapping bit0~bit15 */ ++ ++ u16 max_num_sta; ++ ++ struct wlan_acl_pool acl_list; ++}; ++ ++ ++__inline static u32 wifi_mac_hash(u8 *mac) ++{ ++ u32 x; ++ ++ x = mac[0]; ++ x = (x << 2) ^ mac[1]; ++ x = (x << 2) ^ mac[2]; ++ x = (x << 2) ^ mac[3]; ++ x = (x << 2) ^ mac[4]; ++ x = (x << 2) ^ mac[5]; ++ ++ x ^= x >> 8; ++ x = x & (NUM_STA - 1); ++ ++ return x; ++} ++ ++ ++extern u32 _rtw_init_sta_priv(struct sta_priv *pstapriv); ++extern u32 _rtw_free_sta_priv(struct sta_priv *pstapriv); ++ ++#define stainfo_offset_valid(offset) (offset < NUM_STA && offset >= 0) ++int rtw_stainfo_offset(struct sta_priv *stapriv, struct sta_info *sta); ++struct sta_info *rtw_get_stainfo_by_offset(struct sta_priv *stapriv, int offset); ++ ++extern struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr); ++extern u32 rtw_free_stainfo(struct adapter *padapter , struct sta_info *psta); ++extern void rtw_free_all_stainfo(struct adapter *padapter); ++extern struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr); ++extern u32 rtw_init_bcmc_stainfo(struct adapter *padapter); ++extern struct sta_info* rtw_get_bcmc_stainfo(struct adapter *padapter); ++extern u8 rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr); ++ ++#endif /* _STA_INFO_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/wifi.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/wifi.h +--- linux-4.3/3rdparty/rtl8723bs/include/wifi.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/wifi.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,1158 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef _WIFI_H_ ++#define _WIFI_H_ ++ ++ ++#ifdef BIT ++/* error "BIT define occurred earlier elsewhere!\n" */ ++#undef BIT ++#endif ++#define BIT(x) (1 << (x)) ++ ++ ++#define WLAN_ETHHDR_LEN 14 ++#define WLAN_ETHADDR_LEN 6 ++#define WLAN_IEEE_OUI_LEN 3 ++#define WLAN_ADDR_LEN 6 ++#define WLAN_CRC_LEN 4 ++#define WLAN_BSSID_LEN 6 ++#define WLAN_BSS_TS_LEN 8 ++#define WLAN_HDR_A3_LEN 24 ++#define WLAN_HDR_A4_LEN 30 ++#define WLAN_HDR_A3_QOS_LEN 26 ++#define WLAN_HDR_A4_QOS_LEN 32 ++#define WLAN_SSID_MAXLEN 32 ++#define WLAN_DATA_MAXLEN 2312 ++ ++#define WLAN_A3_PN_OFFSET 24 ++#define WLAN_A4_PN_OFFSET 30 ++ ++#define WLAN_MIN_ETHFRM_LEN 60 ++#define WLAN_MAX_ETHFRM_LEN 1514 ++#define WLAN_ETHHDR_LEN 14 ++#define WLAN_WMM_LEN 24 ++ ++#define P80211CAPTURE_VERSION 0x80211001 ++ ++/* This value is tested by WiFi 11n Test Plan 5.2.3. */ ++/* This test verifies the WLAN NIC can update the NAV through sending the CTS with large duration. */ ++#define WiFiNavUpperUs 30000 /* 30 ms */ ++ ++enum WIFI_FRAME_TYPE { ++ WIFI_MGT_TYPE = (0), ++ WIFI_CTRL_TYPE = (BIT(2)), ++ WIFI_DATA_TYPE = (BIT(3)), ++ WIFI_QOS_DATA_TYPE = (BIT(7)|BIT(3)), /* QoS Data */ ++}; ++ ++enum WIFI_FRAME_SUBTYPE { ++ ++ /* below is for mgt frame */ ++ WIFI_ASSOCREQ = (0 | WIFI_MGT_TYPE), ++ WIFI_ASSOCRSP = (BIT(4) | WIFI_MGT_TYPE), ++ WIFI_REASSOCREQ = (BIT(5) | WIFI_MGT_TYPE), ++ WIFI_REASSOCRSP = (BIT(5) | BIT(4) | WIFI_MGT_TYPE), ++ WIFI_PROBEREQ = (BIT(6) | WIFI_MGT_TYPE), ++ WIFI_PROBERSP = (BIT(6) | BIT(4) | WIFI_MGT_TYPE), ++ WIFI_BEACON = (BIT(7) | WIFI_MGT_TYPE), ++ WIFI_ATIM = (BIT(7) | BIT(4) | WIFI_MGT_TYPE), ++ WIFI_DISASSOC = (BIT(7) | BIT(5) | WIFI_MGT_TYPE), ++ WIFI_AUTH = (BIT(7) | BIT(5) | BIT(4) | WIFI_MGT_TYPE), ++ WIFI_DEAUTH = (BIT(7) | BIT(6) | WIFI_MGT_TYPE), ++ WIFI_ACTION = (BIT(7) | BIT(6) | BIT(4) | WIFI_MGT_TYPE), ++ WIFI_ACTION_NOACK = (BIT(7) | BIT(6) | BIT(5) | WIFI_MGT_TYPE), ++ ++ /* below is for control frame */ ++ WIFI_NDPA = (BIT(6) | BIT(4) | WIFI_CTRL_TYPE), ++ WIFI_PSPOLL = (BIT(7) | BIT(5) | WIFI_CTRL_TYPE), ++ WIFI_RTS = (BIT(7) | BIT(5) | BIT(4) | WIFI_CTRL_TYPE), ++ WIFI_CTS = (BIT(7) | BIT(6) | WIFI_CTRL_TYPE), ++ WIFI_ACK = (BIT(7) | BIT(6) | BIT(4) | WIFI_CTRL_TYPE), ++ WIFI_CFEND = (BIT(7) | BIT(6) | BIT(5) | WIFI_CTRL_TYPE), ++ WIFI_CFEND_CFACK = (BIT(7) | BIT(6) | BIT(5) | BIT(4) | WIFI_CTRL_TYPE), ++ ++ /* below is for data frame */ ++ WIFI_DATA = (0 | WIFI_DATA_TYPE), ++ WIFI_DATA_CFACK = (BIT(4) | WIFI_DATA_TYPE), ++ WIFI_DATA_CFPOLL = (BIT(5) | WIFI_DATA_TYPE), ++ WIFI_DATA_CFACKPOLL = (BIT(5) | BIT(4) | WIFI_DATA_TYPE), ++ WIFI_DATA_NULL = (BIT(6) | WIFI_DATA_TYPE), ++ WIFI_CF_ACK = (BIT(6) | BIT(4) | WIFI_DATA_TYPE), ++ WIFI_CF_POLL = (BIT(6) | BIT(5) | WIFI_DATA_TYPE), ++ WIFI_CF_ACKPOLL = (BIT(6) | BIT(5) | BIT(4) | WIFI_DATA_TYPE), ++ WIFI_QOS_DATA_NULL = (BIT(6) | WIFI_QOS_DATA_TYPE), ++}; ++ ++enum WIFI_REASON_CODE { ++ _RSON_RESERVED_ = 0, ++ _RSON_UNSPECIFIED_ = 1, ++ _RSON_AUTH_NO_LONGER_VALID_ = 2, ++ _RSON_DEAUTH_STA_LEAVING_ = 3, ++ _RSON_INACTIVITY_ = 4, ++ _RSON_UNABLE_HANDLE_ = 5, ++ _RSON_CLS2_ = 6, ++ _RSON_CLS3_ = 7, ++ _RSON_DISAOC_STA_LEAVING_ = 8, ++ _RSON_ASOC_NOT_AUTH_ = 9, ++ ++ /* WPA reason */ ++ _RSON_INVALID_IE_ = 13, ++ _RSON_MIC_FAILURE_ = 14, ++ _RSON_4WAY_HNDSHK_TIMEOUT_ = 15, ++ _RSON_GROUP_KEY_UPDATE_TIMEOUT_ = 16, ++ _RSON_DIFF_IE_ = 17, ++ _RSON_MLTCST_CIPHER_NOT_VALID_ = 18, ++ _RSON_UNICST_CIPHER_NOT_VALID_ = 19, ++ _RSON_AKMP_NOT_VALID_ = 20, ++ _RSON_UNSUPPORT_RSNE_VER_ = 21, ++ _RSON_INVALID_RSNE_CAP_ = 22, ++ _RSON_IEEE_802DOT1X_AUTH_FAIL_ = 23, ++ ++ /* belowing are Realtek definition */ ++ _RSON_PMK_NOT_AVAILABLE_ = 24, ++ _RSON_TDLS_TEAR_TOOFAR_ = 25, ++ _RSON_TDLS_TEAR_UN_RSN_ = 26, ++}; ++ ++/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */ ++/* IEEE 802.11h */ ++#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10 ++#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11 ++ ++enum WIFI_STATUS_CODE { ++ _STATS_SUCCESSFUL_ = 0, ++ _STATS_FAILURE_ = 1, ++ _STATS_CAP_FAIL_ = 10, ++ _STATS_NO_ASOC_ = 11, ++ _STATS_OTHER_ = 12, ++ _STATS_NO_SUPP_ALG_ = 13, ++ _STATS_OUT_OF_AUTH_SEQ_ = 14, ++ _STATS_CHALLENGE_FAIL_ = 15, ++ _STATS_AUTH_TIMEOUT_ = 16, ++ _STATS_UNABLE_HANDLE_STA_ = 17, ++ _STATS_RATE_FAIL_ = 18, ++}; ++ ++/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */ ++/* entended */ ++/* IEEE 802.11b */ ++#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 ++#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 ++#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 ++/* IEEE 802.11h */ ++#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22 ++#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23 ++#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24 ++/* IEEE 802.11g */ ++#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25 ++#define WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC 26 ++#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27 ++/* IEEE 802.11w */ ++#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30 ++#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31 ++/* IEEE 802.11i */ ++#define WLAN_STATUS_INVALID_IE 40 ++#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41 ++#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42 ++#define WLAN_STATUS_AKMP_NOT_VALID 43 ++#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44 ++#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45 ++#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46 ++#define WLAN_STATUS_TS_NOT_CREATED 47 ++#define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48 ++#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49 ++#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50 ++#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51 ++/* IEEE 802.11r */ ++#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52 ++#define WLAN_STATUS_INVALID_PMKID 53 ++#define WLAN_STATUS_INVALID_MDIE 54 ++#define WLAN_STATUS_INVALID_FTIE 55 ++ ++ ++enum WIFI_REG_DOMAIN { ++ DOMAIN_FCC = 1, ++ DOMAIN_IC = 2, ++ DOMAIN_ETSI = 3, ++ DOMAIN_SPAIN = 4, ++ DOMAIN_FRANCE = 5, ++ DOMAIN_MKK = 6, ++ DOMAIN_ISRAEL = 7, ++ DOMAIN_MKK1 = 8, ++ DOMAIN_MKK2 = 9, ++ DOMAIN_MKK3 = 10, ++ DOMAIN_MAX ++}; ++ ++#define _TO_DS_ BIT(8) ++#define _FROM_DS_ BIT(9) ++#define _MORE_FRAG_ BIT(10) ++#define _RETRY_ BIT(11) ++#define _PWRMGT_ BIT(12) ++#define _MORE_DATA_ BIT(13) ++#define _PRIVACY_ BIT(14) ++#define _ORDER_ BIT(15) ++ ++#define SetToDs(pbuf) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16(_TO_DS_) ++ ++#define GetToDs(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_TO_DS_)) != 0) ++ ++#define ClearToDs(pbuf) \ ++ *(__le16 *)(pbuf) &= (~cpu_to_le16(_TO_DS_)) ++ ++#define SetFrDs(pbuf) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16(_FROM_DS_) ++ ++#define GetFrDs(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_FROM_DS_)) != 0) ++ ++#define ClearFrDs(pbuf) \ ++ *(__le16 *)(pbuf) &= (~cpu_to_le16(_FROM_DS_)) ++ ++#define get_tofr_ds(pframe) ((GetToDs(pframe) << 1) | GetFrDs(pframe)) ++ ++#define SetMFrag(pbuf) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16(_MORE_FRAG_) ++ ++#define GetMFrag(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_MORE_FRAG_)) != 0) ++ ++#define ClearMFrag(pbuf) \ ++ *(__le16 *)(pbuf) &= (~cpu_to_le16(_MORE_FRAG_)) ++ ++#define SetRetry(pbuf) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16(_RETRY_) ++ ++#define GetRetry(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_RETRY_)) != 0) ++ ++#define ClearRetry(pbuf) \ ++ *(__le16 *)(pbuf) &= (~cpu_to_le16(_RETRY_)) ++ ++#define SetPwrMgt(pbuf) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16(_PWRMGT_) ++ ++#define GetPwrMgt(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_PWRMGT_)) != 0) ++ ++#define ClearPwrMgt(pbuf) \ ++ *(__le16 *)(pbuf) &= (~cpu_to_le16(_PWRMGT_)) ++ ++#define SetMData(pbuf) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16(_MORE_DATA_) ++ ++#define GetMData(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_MORE_DATA_)) != 0) ++ ++#define ClearMData(pbuf) \ ++ *(__le16 *)(pbuf) &= (~cpu_to_le16(_MORE_DATA_)) ++ ++#define SetPrivacy(pbuf) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16(_PRIVACY_) ++ ++#define GetPrivacy(pbuf) \ ++ (((*(__le16 *)(pbuf)) & cpu_to_le16(_PRIVACY_)) != 0) ++ ++#define ClearPrivacy(pbuf) \ ++ *(__le16 *)(pbuf) &= (~cpu_to_le16(_PRIVACY_)) ++ ++ ++#define GetOrder(pbuf) \ ++ (((*(__le16 *)(pbuf)) & cpu_to_le16(_ORDER_)) != 0) ++ ++#define GetFrameType(pbuf) \ ++ (le16_to_cpu(*(__le16 *)(pbuf)) & (BIT(3) | BIT(2))) ++ ++#define SetFrameType(pbuf, type) \ ++ do { \ ++ *(unsigned short *)(pbuf) &= __constant_cpu_to_le16(~(BIT(3) | BIT(2))); \ ++ *(unsigned short *)(pbuf) |= __constant_cpu_to_le16(type); \ ++ } while (0) ++ ++#define GetFrameSubType(pbuf) (le16_to_cpu(*(__le16 *)(pbuf)) & (BIT(7) |\ ++ BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2))) ++ ++#define SetFrameSubType(pbuf, type) \ ++ do { \ ++ *(__le16 *)(pbuf) &= cpu_to_le16(~(BIT(7) | BIT(6) | \ ++ BIT(5) | BIT(4) | BIT(3) | BIT(2))); \ ++ *(__le16 *)(pbuf) |= cpu_to_le16(type); \ ++ } while (0) ++ ++#define GetSequence(pbuf) \ ++ (le16_to_cpu(*(__le16 *)((size_t)(pbuf) + 22)) >> 4) ++ ++#define GetFragNum(pbuf) \ ++ (le16_to_cpu(*(__le16 *)((size_t)(pbuf) + 22)) & 0x0f) ++ ++#define GetTupleCache(pbuf) \ ++ (cpu_to_le16(*(unsigned short *)((size_t)(pbuf) + 22))) ++ ++#define SetFragNum(pbuf, num) \ ++ do { \ ++ *(unsigned short *)((size_t)(pbuf) + 22) = \ ++ ((*(unsigned short *)((size_t)(pbuf) + 22)) & \ ++ le16_to_cpu(~(0x000f))) | \ ++ cpu_to_le16(0x0f & (num)); \ ++ } while (0) ++ ++#define SetSeqNum(pbuf, num) \ ++ do { \ ++ *(__le16 *)((size_t)(pbuf) + 22) = \ ++ ((*(__le16 *)((size_t)(pbuf) + 22)) & cpu_to_le16((unsigned short)0x000f)) | \ ++ cpu_to_le16((unsigned short)(0xfff0 & (num << 4))); \ ++ } while (0) ++ ++#define SetDuration(pbuf, dur) \ ++ *(__le16 *)((size_t)(pbuf) + 2) = cpu_to_le16(0xffff & (dur)) ++ ++ ++#define SetPriority(pbuf, tid) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16(tid & 0xf) ++ ++#define GetPriority(pbuf) ((le16_to_cpu(*(__le16 *)(pbuf))) & 0xf) ++ ++#define SetEOSP(pbuf, eosp) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16((eosp & 1) << 4) ++ ++#define SetAckpolicy(pbuf, ack) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16((ack & 3) << 5) ++ ++#define GetAckpolicy(pbuf) (((le16_to_cpu(*(__le16 *)pbuf)) >> 5) & 0x3) ++ ++#define GetAMsdu(pbuf) (((le16_to_cpu(*(__le16 *)pbuf)) >> 7) & 0x1) ++ ++#define SetAMsdu(pbuf, amsdu) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16((amsdu & 1) << 7) ++ ++#define GetAid(pbuf) (le16_to_cpu(*(__le16 *)((size_t)(pbuf) + 2)) & 0x3fff) ++ ++#define GetTid(pbuf) (le16_to_cpu(*(__le16 *)((size_t)(pbuf) + \ ++ (((GetToDs(pbuf)<<1) | GetFrDs(pbuf)) == 3 ? \ ++ 30 : 24))) & 0x000f) ++ ++#define GetAddr1Ptr(pbuf) ((unsigned char *)((size_t)(pbuf) + 4)) ++ ++#define GetAddr2Ptr(pbuf) ((unsigned char *)((size_t)(pbuf) + 10)) ++ ++#define GetAddr3Ptr(pbuf) ((unsigned char *)((size_t)(pbuf) + 16)) ++ ++#define GetAddr4Ptr(pbuf) ((unsigned char *)((size_t)(pbuf) + 24)) ++ ++#define MacAddr_isBcst(addr) \ ++ (\ ++ ((addr[0] == 0xff) && (addr[1] == 0xff) && \ ++ (addr[2] == 0xff) && (addr[3] == 0xff) && \ ++ (addr[4] == 0xff) && (addr[5] == 0xff)) ? true : false \ ++) ++ ++__inline static int IS_MCAST(unsigned char *da) ++{ ++ if ((*da) & 0x01) ++ return true; ++ else ++ return false; ++} ++ ++__inline static unsigned char * get_ra(unsigned char *pframe) ++{ ++ unsigned char *ra; ++ ra = GetAddr1Ptr(pframe); ++ return ra; ++} ++__inline static unsigned char * get_ta(unsigned char *pframe) ++{ ++ unsigned char *ta; ++ ta = GetAddr2Ptr(pframe); ++ return ta; ++} ++ ++__inline static unsigned char * get_da(unsigned char *pframe) ++{ ++ unsigned char *da; ++ unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe); ++ ++ switch (to_fr_ds) { ++ case 0x00: /* ToDs = 0, FromDs = 0 */ ++ da = GetAddr1Ptr(pframe); ++ break; ++ case 0x01: /* ToDs = 0, FromDs = 1 */ ++ da = GetAddr1Ptr(pframe); ++ break; ++ case 0x02: /* ToDs = 1, FromDs = 0 */ ++ da = GetAddr3Ptr(pframe); ++ break; ++ default: /* ToDs = 1, FromDs = 1 */ ++ da = GetAddr3Ptr(pframe); ++ break; ++ } ++ ++ return da; ++} ++ ++ ++__inline static unsigned char * get_sa(unsigned char *pframe) ++{ ++ unsigned char *sa; ++ unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe); ++ ++ switch (to_fr_ds) { ++ case 0x00: /* ToDs = 0, FromDs = 0 */ ++ sa = GetAddr2Ptr(pframe); ++ break; ++ case 0x01: /* ToDs = 0, FromDs = 1 */ ++ sa = GetAddr3Ptr(pframe); ++ break; ++ case 0x02: /* ToDs = 1, FromDs = 0 */ ++ sa = GetAddr2Ptr(pframe); ++ break; ++ default: /* ToDs = 1, FromDs = 1 */ ++ sa = GetAddr4Ptr(pframe); ++ break; ++ } ++ ++ return sa; ++} ++ ++__inline static unsigned char * get_hdr_bssid(unsigned char *pframe) ++{ ++ unsigned char *sa = NULL; ++ unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe); ++ ++ switch (to_fr_ds) { ++ case 0x00: /* ToDs = 0, FromDs = 0 */ ++ sa = GetAddr3Ptr(pframe); ++ break; ++ case 0x01: /* ToDs = 0, FromDs = 1 */ ++ sa = GetAddr2Ptr(pframe); ++ break; ++ case 0x02: /* ToDs = 1, FromDs = 0 */ ++ sa = GetAddr1Ptr(pframe); ++ break; ++ case 0x03: /* ToDs = 1, FromDs = 1 */ ++ sa = GetAddr1Ptr(pframe); ++ break; ++ } ++ ++ return sa; ++} ++ ++ ++__inline static int IsFrameTypeCtrl(unsigned char *pframe) ++{ ++ if (WIFI_CTRL_TYPE == GetFrameType(pframe)) ++ return true; ++ else ++ return false; ++} ++/*----------------------------------------------------------------------------- ++ Below is for the security related definition ++------------------------------------------------------------------------------*/ ++#define _RESERVED_FRAME_TYPE_ 0 ++#define _SKB_FRAME_TYPE_ 2 ++#define _PRE_ALLOCMEM_ 1 ++#define _PRE_ALLOCHDR_ 3 ++#define _PRE_ALLOCLLCHDR_ 4 ++#define _PRE_ALLOCICVHDR_ 5 ++#define _PRE_ALLOCMICHDR_ 6 ++ ++#define _SIFSTIME_ ((priv->pmib->dot11BssType.net_work_type&WIRELESS_11A)?16:10) ++#define _ACKCTSLNG_ 14 /* 14 bytes long, including crclng */ ++#define _CRCLNG_ 4 ++ ++#define _ASOCREQ_IE_OFFSET_ 4 /* excluding wlan_hdr */ ++#define _ASOCRSP_IE_OFFSET_ 6 ++#define _REASOCREQ_IE_OFFSET_ 10 ++#define _REASOCRSP_IE_OFFSET_ 6 ++#define _PROBEREQ_IE_OFFSET_ 0 ++#define _PROBERSP_IE_OFFSET_ 12 ++#define _AUTH_IE_OFFSET_ 6 ++#define _DEAUTH_IE_OFFSET_ 0 ++#define _BEACON_IE_OFFSET_ 12 ++#define _PUBLIC_ACTION_IE_OFFSET_ 8 ++ ++#define _FIXED_IE_LENGTH_ _BEACON_IE_OFFSET_ ++ ++#define _SSID_IE_ 0 ++#define _SUPPORTEDRATES_IE_ 1 ++#define _DSSET_IE_ 3 ++#define _TIM_IE_ 5 ++#define _IBSS_PARA_IE_ 6 ++#define _COUNTRY_IE_ 7 ++#define _CHLGETXT_IE_ 16 ++#define _SUPPORTED_CH_IE_ 36 ++#define _CH_SWTICH_ANNOUNCE_ 37 /* Secondary Channel Offset */ ++#define _RSN_IE_2_ 48 ++#define _SSN_IE_1_ 221 ++#define _ERPINFO_IE_ 42 ++#define _EXT_SUPPORTEDRATES_IE_ 50 ++ ++#define _HT_CAPABILITY_IE_ 45 ++#define _FTIE_ 55 ++#define _TIMEOUT_ITVL_IE_ 56 ++#define _SRC_IE_ 59 ++#define _HT_EXTRA_INFO_IE_ 61 ++#define _HT_ADD_INFO_IE_ 61 /* _HT_EXTRA_INFO_IE_ */ ++#define _WAPI_IE_ 68 ++ ++#define _RIC_Descriptor_IE_ 75 ++#define _MME_IE_ 76 /* 802.11w Management MIC element */ ++#define _LINK_ID_IE_ 101 ++#define _CH_SWITCH_TIMING_ 104 ++#define _PTI_BUFFER_STATUS_ 106 ++#define _EXT_CAP_IE_ 127 ++#define _VENDOR_SPECIFIC_IE_ 221 ++ ++#define _RESERVED47_ 47 ++ ++enum ELEMENT_ID { ++ EID_SsId = 0, /* service set identifier (0:32) */ ++ EID_SupRates = 1, /* supported rates (1:8) */ ++ EID_FHParms = 2, /* FH parameter set (5) */ ++ EID_DSParms = 3, /* DS parameter set (1) */ ++ EID_CFParms = 4, /* CF parameter set (6) */ ++ EID_Tim = 5, /* Traffic Information Map (4:254) */ ++ EID_IbssParms = 6, /* IBSS parameter set (2) */ ++ EID_Country = 7, /* */ ++ ++ /* Form 7.3.2: Information elements in 802.11E/D13.0, page 46. */ ++ EID_QBSSLoad = 11, ++ EID_EDCAParms = 12, ++ EID_TSpec = 13, ++ EID_TClass = 14, ++ EID_Schedule = 15, ++ /* */ ++ ++ EID_Ctext = 16, /* challenge text*/ ++ EID_POWER_CONSTRAINT = 32, /* Power Constraint*/ ++ ++ /* vivi for WIFITest, 802.11h AP, 20100427 */ ++ /* 2010/12/26 MH The definition we can declare always!! */ ++ EID_PowerCap = 33, ++ EID_SupportedChannels = 36, ++ EID_ChlSwitchAnnounce = 37, ++ ++ EID_MeasureRequest = 38, /* Measurement Request */ ++ EID_MeasureReport = 39, /* Measurement Report */ ++ ++ EID_ERPInfo = 42, ++ ++ /* Form 7.3.2: Information elements in 802.11E/D13.0, page 46. */ ++ EID_TSDelay = 43, ++ EID_TCLASProc = 44, ++ EID_HTCapability = 45, ++ EID_QoSCap = 46, ++ /* */ ++ ++ EID_WPA2 = 48, ++ EID_ExtSupRates = 50, ++ ++ EID_FTIE = 55, /* Defined in 802.11r */ ++ EID_Timeout = 56, /* Defined in 802.11r */ ++ ++ EID_SupRegulatory = 59, /* Supported Requlatory Classes 802.11y */ ++ EID_HTInfo = 61, ++ EID_SecondaryChnlOffset = 62, ++ ++ EID_BSSCoexistence = 72, /* 20/40 BSS Coexistence */ ++ EID_BSSIntolerantChlReport = 73, ++ EID_OBSS = 74, /* Overlapping BSS Scan Parameters */ ++ ++ EID_LinkIdentifier = 101, /* Defined in 802.11z */ ++ EID_WakeupSchedule = 102, /* Defined in 802.11z */ ++ EID_ChnlSwitchTimeing = 104, /* Defined in 802.11z */ ++ EID_PTIControl = 105, /* Defined in 802.11z */ ++ EID_PUBufferStatus = 106, /* Defined in 802.11z */ ++ ++ EID_EXTCapability = 127, /* Extended Capabilities */ ++ /* From S19:Aironet IE and S21:AP IP address IE in CCX v1.13, p16 and p18. */ ++ EID_Aironet = 133, /* 0x85: Aironet Element for Cisco CCX */ ++ EID_CiscoIP = 149, /* 0x95: IP Address IE for Cisco CCX */ ++ ++ EID_CellPwr = 150, /* 0x96: Cell Power Limit IE. Ref. 0x96. */ ++ ++ EID_CCKM = 156, ++ ++ EID_Vendor = 221, /* 0xDD: Vendor Specific */ ++ ++ EID_WAPI = 68, ++ EID_VHTCapability = 191, /* Based on 802.11ac D2.0 */ ++ EID_VHTOperation = 192, /* Based on 802.11ac D2.0 */ ++ EID_OpModeNotification = 199, /* Based on 802.11ac D3.0 */ ++}; ++ ++/* --------------------------------------------------------------------------- ++ Below is the fixed elements... ++-----------------------------------------------------------------------------*/ ++#define _AUTH_ALGM_NUM_ 2 ++#define _AUTH_SEQ_NUM_ 2 ++#define _BEACON_ITERVAL_ 2 ++#define _CAPABILITY_ 2 ++#define _CURRENT_APADDR_ 6 ++#define _LISTEN_INTERVAL_ 2 ++#define _RSON_CODE_ 2 ++#define _ASOC_ID_ 2 ++#define _STATUS_CODE_ 2 ++#define _TIMESTAMP_ 8 ++ ++#define AUTH_ODD_TO 0 ++#define AUTH_EVEN_TO 1 ++ ++#define WLAN_ETHCONV_ENCAP 1 ++#define WLAN_ETHCONV_RFC1042 2 ++#define WLAN_ETHCONV_8021h 3 ++ ++#define cap_ESS BIT(0) ++#define cap_IBSS BIT(1) ++#define cap_CFPollable BIT(2) ++#define cap_CFRequest BIT(3) ++#define cap_Privacy BIT(4) ++#define cap_ShortPremble BIT(5) ++#define cap_PBCC BIT(6) ++#define cap_ChAgility BIT(7) ++#define cap_SpecMgmt BIT(8) ++#define cap_QoS BIT(9) ++#define cap_ShortSlot BIT(10) ++ ++/*----------------------------------------------------------------------------- ++ Below is the definition for 802.11i / 802.1x ++------------------------------------------------------------------------------*/ ++#define _IEEE8021X_MGT_ 1 /* WPA */ ++#define _IEEE8021X_PSK_ 2 /* WPA with pre-shared key */ ++ ++#define _MME_IE_LENGTH_ 18 ++/*----------------------------------------------------------------------------- ++ Below is the definition for WMM ++------------------------------------------------------------------------------*/ ++#define _WMM_IE_Length_ 7 /* for WMM STA */ ++#define _WMM_Para_Element_Length_ 24 ++ ++ ++/*----------------------------------------------------------------------------- ++ Below is the definition for 802.11n ++------------------------------------------------------------------------------*/ ++ ++#define SetOrderBit(pbuf) \ ++ do { \ ++ *(unsigned short *)(pbuf) |= cpu_to_le16(_ORDER_); \ ++ } while (0) ++ ++#define GetOrderBit(pbuf) (((*(unsigned short *)(pbuf)) & cpu_to_le16(_ORDER_)) != 0) ++ ++#define ACT_CAT_VENDOR 0x7F/* 127 */ ++ ++/** ++ * struct rtw_ieee80211_bar - HT Block Ack Request ++ * ++ * This structure refers to "HT BlockAckReq" as ++ * described in 802.11n draft section 7.2.1.7.1 ++ */ ++struct rtw_ieee80211_bar { ++ __le16 frame_control; ++ __le16 duration; ++ unsigned char ra[6]; ++ unsigned char ta[6]; ++ __le16 control; ++ __le16 start_seq_num; ++} __attribute__((packed)); ++ ++/* 802.11 BAR control masks */ ++#define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL 0x0000 ++#define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA 0x0004 ++ ++ ++ /** ++ * struct rtw_ieee80211_ht_cap - HT capabilities ++ * ++ * This structure refers to "HT capabilities element" as ++ * described in 802.11n draft section 7.3.2.52 ++ */ ++ ++struct rtw_ieee80211_ht_cap { ++ __le16 cap_info; ++ unsigned char ampdu_params_info; ++ unsigned char supp_mcs_set[16]; ++ __le16 extended_ht_cap_info; ++ __le16 tx_BF_cap_info; ++ unsigned char antenna_selection_info; ++} __attribute__ ((packed)); ++ ++/** ++ * struct rtw_ieee80211_ht_cap - HT additional information ++ * ++ * This structure refers to "HT information element" as ++ * described in 802.11n draft section 7.3.2.53 ++ */ ++struct ieee80211_ht_addt_info { ++ unsigned char control_chan; ++ unsigned char ht_param; ++ __le16 operation_mode; ++ __le16 stbc_param; ++ unsigned char basic_set[16]; ++} __attribute__ ((packed)); ++ ++ ++struct HT_caps_element ++{ ++ union ++ { ++ struct ++ { ++ __le16 HT_caps_info; ++ unsigned char AMPDU_para; ++ unsigned char MCS_rate[16]; ++ __le16 HT_ext_caps; ++ __le16 Beamforming_caps; ++ unsigned char ASEL_caps; ++ } HT_cap_element; ++ unsigned char HT_cap[26]; ++ }u; ++} __attribute__ ((packed)); ++ ++struct HT_info_element ++{ ++ unsigned char primary_channel; ++ unsigned char infos[5]; ++ unsigned char MCS_rate[16]; ++} __attribute__ ((packed)); ++ ++struct AC_param ++{ ++ unsigned char ACI_AIFSN; ++ unsigned char CW; ++ __le16 TXOP_limit; ++} __attribute__ ((packed)); ++ ++struct WMM_para_element ++{ ++ unsigned char QoS_info; ++ unsigned char reserved; ++ struct AC_param ac_param[4]; ++} __attribute__ ((packed)); ++ ++struct ADDBA_request ++{ ++ unsigned char dialog_token; ++ __le16 BA_para_set; ++ __le16 BA_timeout_value; ++ __le16 BA_starting_seqctrl; ++} __attribute__ ((packed)); ++ ++enum HT_CAP_AMPDU_FACTOR { ++ MAX_AMPDU_FACTOR_8K = 0, ++ MAX_AMPDU_FACTOR_16K = 1, ++ MAX_AMPDU_FACTOR_32K = 2, ++ MAX_AMPDU_FACTOR_64K = 3, ++}; ++ ++/* 802.11n HT capabilities masks */ ++#define IEEE80211_HT_CAP_LDPC_CODING 0x0001 ++#define IEEE80211_HT_CAP_SUP_WIDTH 0x0002 ++#define IEEE80211_HT_CAP_SM_PS 0x000C ++#define IEEE80211_HT_CAP_GRN_FLD 0x0010 ++#define IEEE80211_HT_CAP_SGI_20 0x0020 ++#define IEEE80211_HT_CAP_SGI_40 0x0040 ++#define IEEE80211_HT_CAP_TX_STBC 0x0080 ++#define IEEE80211_HT_CAP_RX_STBC_1R 0x0100 ++#define IEEE80211_HT_CAP_RX_STBC_2R 0x0200 ++#define IEEE80211_HT_CAP_RX_STBC_3R 0x0300 ++#define IEEE80211_HT_CAP_DELAY_BA 0x0400 ++#define IEEE80211_HT_CAP_MAX_AMSDU 0x0800 ++#define IEEE80211_HT_CAP_DSSSCCK40 0x1000 ++/* 802.11n HT capability AMPDU settings */ ++#define IEEE80211_HT_CAP_AMPDU_FACTOR 0x03 ++#define IEEE80211_HT_CAP_AMPDU_DENSITY 0x1C ++/* 802.11n HT capability MSC set */ ++#define IEEE80211_SUPP_MCS_SET_UEQM 4 ++#define IEEE80211_HT_CAP_MAX_STREAMS 4 ++#define IEEE80211_SUPP_MCS_SET_LEN 10 ++/* maximum streams the spec allows */ ++#define IEEE80211_HT_CAP_MCS_TX_DEFINED 0x01 ++#define IEEE80211_HT_CAP_MCS_TX_RX_DIFF 0x02 ++#define IEEE80211_HT_CAP_MCS_TX_STREAMS 0x0C ++#define IEEE80211_HT_CAP_MCS_TX_UEQM 0x10 ++/* 802.11n HT capability TXBF capability */ ++#define IEEE80211_HT_CAP_TXBF_RX_NDP 0x00000008 ++#define IEEE80211_HT_CAP_TXBF_TX_NDP 0x00000010 ++#define IEEE80211_HT_CAP_TXBF_EXPLICIT_COMP_STEERING_CAP 0x00000400 ++ ++/* 802.11n HT IE masks */ ++#define IEEE80211_HT_IE_CHA_SEC_OFFSET 0x03 ++#define IEEE80211_HT_IE_CHA_SEC_NONE 0x00 ++#define IEEE80211_HT_IE_CHA_SEC_ABOVE 0x01 ++#define IEEE80211_HT_IE_CHA_SEC_BELOW 0x03 ++#define IEEE80211_HT_IE_CHA_WIDTH 0x04 ++#define IEEE80211_HT_IE_HT_PROTECTION 0x0003 ++#define IEEE80211_HT_IE_NON_GF_STA_PRSNT 0x0004 ++#define IEEE80211_HT_IE_NON_HT_STA_PRSNT 0x0010 ++ ++/* block-ack parameters */ ++#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002 ++#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C ++#define RTW_IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFC0 ++#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000 ++#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800 ++ ++/* ++ * A-PMDU buffer sizes ++ * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2) ++ */ ++#define IEEE80211_MIN_AMPDU_BUF 0x8 ++#define IEEE80211_MAX_AMPDU_BUF 0x40 ++ ++ ++/* Spatial Multiplexing Power Save Modes */ ++#define WLAN_HT_CAP_SM_PS_STATIC 0 ++#define WLAN_HT_CAP_SM_PS_DYNAMIC 1 ++#define WLAN_HT_CAP_SM_PS_INVALID 2 ++#define WLAN_HT_CAP_SM_PS_DISABLED 3 ++ ++ ++#define OP_MODE_PURE 0 ++#define OP_MODE_MAY_BE_LEGACY_STAS 1 ++#define OP_MODE_20MHZ_HT_STA_ASSOCED 2 ++#define OP_MODE_MIXED 3 ++ ++#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK ((u8) BIT(0) | BIT(1)) ++#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE ((u8) BIT(0)) ++#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW ((u8) BIT(0) | BIT(1)) ++#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH ((u8) BIT(2)) ++#define HT_INFO_HT_PARAM_RIFS_MODE ((u8) BIT(3)) ++#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY ((u8) BIT(4)) ++#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY ((u8) BIT(5)) ++ ++#define HT_INFO_OPERATION_MODE_OP_MODE_MASK \ ++ ((u16) (0x0001 | 0x0002)) ++#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0 ++#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT ((u8) BIT(2)) ++#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8) BIT(3)) ++#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT ((u8) BIT(4)) ++ ++#define HT_INFO_STBC_PARAM_DUAL_BEACON ((u16) BIT(6)) ++#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT ((u16) BIT(7)) ++#define HT_INFO_STBC_PARAM_SECONDARY_BCN ((u16) BIT(8)) ++#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED ((u16) BIT(9)) ++#define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16) BIT(10)) ++#define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11)) ++ ++ ++ ++/* endif */ ++ ++/* ===============WPS Section =============== */ ++/* For WPSv1.0 */ ++#define WPSOUI 0x0050f204 ++/* WPS attribute ID */ ++#define WPS_ATTR_VER1 0x104A ++#define WPS_ATTR_SIMPLE_CONF_STATE 0x1044 ++#define WPS_ATTR_RESP_TYPE 0x103B ++#define WPS_ATTR_UUID_E 0x1047 ++#define WPS_ATTR_MANUFACTURER 0x1021 ++#define WPS_ATTR_MODEL_NAME 0x1023 ++#define WPS_ATTR_MODEL_NUMBER 0x1024 ++#define WPS_ATTR_SERIAL_NUMBER 0x1042 ++#define WPS_ATTR_PRIMARY_DEV_TYPE 0x1054 ++#define WPS_ATTR_SEC_DEV_TYPE_LIST 0x1055 ++#define WPS_ATTR_DEVICE_NAME 0x1011 ++#define WPS_ATTR_CONF_METHOD 0x1008 ++#define WPS_ATTR_RF_BANDS 0x103C ++#define WPS_ATTR_DEVICE_PWID 0x1012 ++#define WPS_ATTR_REQUEST_TYPE 0x103A ++#define WPS_ATTR_ASSOCIATION_STATE 0x1002 ++#define WPS_ATTR_CONFIG_ERROR 0x1009 ++#define WPS_ATTR_VENDOR_EXT 0x1049 ++#define WPS_ATTR_SELECTED_REGISTRAR 0x1041 ++ ++/* Value of WPS attribute "WPS_ATTR_DEVICE_NAME */ ++#define WPS_MAX_DEVICE_NAME_LEN 32 ++ ++/* Value of WPS Request Type Attribute */ ++#define WPS_REQ_TYPE_ENROLLEE_INFO_ONLY 0x00 ++#define WPS_REQ_TYPE_ENROLLEE_OPEN_8021X 0x01 ++#define WPS_REQ_TYPE_REGISTRAR 0x02 ++#define WPS_REQ_TYPE_WLAN_MANAGER_REGISTRAR 0x03 ++ ++/* Value of WPS Response Type Attribute */ ++#define WPS_RESPONSE_TYPE_INFO_ONLY 0x00 ++#define WPS_RESPONSE_TYPE_8021X 0x01 ++#define WPS_RESPONSE_TYPE_REGISTRAR 0x02 ++#define WPS_RESPONSE_TYPE_AP 0x03 ++ ++/* Value of WPS WiFi Simple Configuration State Attribute */ ++#define WPS_WSC_STATE_NOT_CONFIG 0x01 ++#define WPS_WSC_STATE_CONFIG 0x02 ++ ++/* Value of WPS Version Attribute */ ++#define WPS_VERSION_1 0x10 ++ ++/* Value of WPS Configuration Method Attribute */ ++#define WPS_CONFIG_METHOD_FLASH 0x0001 ++#define WPS_CONFIG_METHOD_ETHERNET 0x0002 ++#define WPS_CONFIG_METHOD_LABEL 0x0004 ++#define WPS_CONFIG_METHOD_DISPLAY 0x0008 ++#define WPS_CONFIG_METHOD_E_NFC 0x0010 ++#define WPS_CONFIG_METHOD_I_NFC 0x0020 ++#define WPS_CONFIG_METHOD_NFC 0x0040 ++#define WPS_CONFIG_METHOD_PBC 0x0080 ++#define WPS_CONFIG_METHOD_KEYPAD 0x0100 ++#define WPS_CONFIG_METHOD_VPBC 0x0280 ++#define WPS_CONFIG_METHOD_PPBC 0x0480 ++#define WPS_CONFIG_METHOD_VDISPLAY 0x2008 ++#define WPS_CONFIG_METHOD_PDISPLAY 0x4008 ++ ++/* Value of Category ID of WPS Primary Device Type Attribute */ ++#define WPS_PDT_CID_DISPLAYS 0x0007 ++#define WPS_PDT_CID_MULIT_MEDIA 0x0008 ++#define WPS_PDT_CID_RTK_WIDI WPS_PDT_CID_MULIT_MEDIA ++ ++/* Value of Sub Category ID of WPS Primary Device Type Attribute */ ++#define WPS_PDT_SCID_MEDIA_SERVER 0x0005 ++#define WPS_PDT_SCID_RTK_DMP WPS_PDT_SCID_MEDIA_SERVER ++ ++/* Value of Device Password ID */ ++#define WPS_DPID_PIN 0x0000 ++#define WPS_DPID_USER_SPEC 0x0001 ++#define WPS_DPID_MACHINE_SPEC 0x0002 ++#define WPS_DPID_REKEY 0x0003 ++#define WPS_DPID_PBC 0x0004 ++#define WPS_DPID_REGISTRAR_SPEC 0x0005 ++ ++/* Value of WPS RF Bands Attribute */ ++#define WPS_RF_BANDS_2_4_GHZ 0x01 ++#define WPS_RF_BANDS_5_GHZ 0x02 ++ ++/* Value of WPS Association State Attribute */ ++#define WPS_ASSOC_STATE_NOT_ASSOCIATED 0x00 ++#define WPS_ASSOC_STATE_CONNECTION_SUCCESS 0x01 ++#define WPS_ASSOC_STATE_CONFIGURATION_FAILURE 0x02 ++#define WPS_ASSOC_STATE_ASSOCIATION_FAILURE 0x03 ++#define WPS_ASSOC_STATE_IP_FAILURE 0x04 ++ ++/* =====================P2P Section ===================== */ ++/* For P2P */ ++#define P2POUI 0x506F9A09 ++ ++/* P2P Attribute ID */ ++#define P2P_ATTR_STATUS 0x00 ++#define P2P_ATTR_MINOR_REASON_CODE 0x01 ++#define P2P_ATTR_CAPABILITY 0x02 ++#define P2P_ATTR_DEVICE_ID 0x03 ++#define P2P_ATTR_GO_INTENT 0x04 ++#define P2P_ATTR_CONF_TIMEOUT 0x05 ++#define P2P_ATTR_LISTEN_CH 0x06 ++#define P2P_ATTR_GROUP_BSSID 0x07 ++#define P2P_ATTR_EX_LISTEN_TIMING 0x08 ++#define P2P_ATTR_INTENTED_IF_ADDR 0x09 ++#define P2P_ATTR_MANAGEABILITY 0x0A ++#define P2P_ATTR_CH_LIST 0x0B ++#define P2P_ATTR_NOA 0x0C ++#define P2P_ATTR_DEVICE_INFO 0x0D ++#define P2P_ATTR_GROUP_INFO 0x0E ++#define P2P_ATTR_GROUP_ID 0x0F ++#define P2P_ATTR_INTERFACE 0x10 ++#define P2P_ATTR_OPERATING_CH 0x11 ++#define P2P_ATTR_INVITATION_FLAGS 0x12 ++ ++/* Value of Status Attribute */ ++#define P2P_STATUS_SUCCESS 0x00 ++#define P2P_STATUS_FAIL_INFO_UNAVAILABLE 0x01 ++#define P2P_STATUS_FAIL_INCOMPATIBLE_PARAM 0x02 ++#define P2P_STATUS_FAIL_LIMIT_REACHED 0x03 ++#define P2P_STATUS_FAIL_INVALID_PARAM 0x04 ++#define P2P_STATUS_FAIL_REQUEST_UNABLE 0x05 ++#define P2P_STATUS_FAIL_PREVOUS_PROTO_ERR 0x06 ++#define P2P_STATUS_FAIL_NO_COMMON_CH 0x07 ++#define P2P_STATUS_FAIL_UNKNOWN_P2PGROUP 0x08 ++#define P2P_STATUS_FAIL_BOTH_GOINTENT_15 0x09 ++#define P2P_STATUS_FAIL_INCOMPATIBLE_PROVSION 0x0A ++#define P2P_STATUS_FAIL_USER_REJECT 0x0B ++ ++/* Value of Inviation Flags Attribute */ ++#define P2P_INVITATION_FLAGS_PERSISTENT BIT(0) ++ ++#define DMP_P2P_DEVCAP_SUPPORT (P2P_DEVCAP_SERVICE_DISCOVERY | \ ++ P2P_DEVCAP_CLIENT_DISCOVERABILITY | \ ++ P2P_DEVCAP_CONCURRENT_OPERATION | \ ++ P2P_DEVCAP_INVITATION_PROC) ++ ++#define DMP_P2P_GRPCAP_SUPPORT (P2P_GRPCAP_INTRABSS) ++ ++/* Value of Device Capability Bitmap */ ++#define P2P_DEVCAP_SERVICE_DISCOVERY BIT(0) ++#define P2P_DEVCAP_CLIENT_DISCOVERABILITY BIT(1) ++#define P2P_DEVCAP_CONCURRENT_OPERATION BIT(2) ++#define P2P_DEVCAP_INFRA_MANAGED BIT(3) ++#define P2P_DEVCAP_DEVICE_LIMIT BIT(4) ++#define P2P_DEVCAP_INVITATION_PROC BIT(5) ++ ++/* Value of Group Capability Bitmap */ ++#define P2P_GRPCAP_GO BIT(0) ++#define P2P_GRPCAP_PERSISTENT_GROUP BIT(1) ++#define P2P_GRPCAP_GROUP_LIMIT BIT(2) ++#define P2P_GRPCAP_INTRABSS BIT(3) ++#define P2P_GRPCAP_CROSS_CONN BIT(4) ++#define P2P_GRPCAP_PERSISTENT_RECONN BIT(5) ++#define P2P_GRPCAP_GROUP_FORMATION BIT(6) ++ ++/* P2P Public Action Frame (Management Frame) */ ++#define P2P_PUB_ACTION_ACTION 0x09 ++ ++/* P2P Public Action Frame Type */ ++#define P2P_GO_NEGO_REQ 0 ++#define P2P_GO_NEGO_RESP 1 ++#define P2P_GO_NEGO_CONF 2 ++#define P2P_INVIT_REQ 3 ++#define P2P_INVIT_RESP 4 ++#define P2P_DEVDISC_REQ 5 ++#define P2P_DEVDISC_RESP 6 ++#define P2P_PROVISION_DISC_REQ 7 ++#define P2P_PROVISION_DISC_RESP 8 ++ ++/* P2P Action Frame Type */ ++#define P2P_NOTICE_OF_ABSENCE 0 ++#define P2P_PRESENCE_REQUEST 1 ++#define P2P_PRESENCE_RESPONSE 2 ++#define P2P_GO_DISC_REQUEST 3 ++ ++ ++#define P2P_MAX_PERSISTENT_GROUP_NUM 10 ++ ++#define P2P_PROVISIONING_SCAN_CNT 3 ++ ++#define P2P_WILDCARD_SSID_LEN 7 ++ ++#define P2P_FINDPHASE_EX_NONE 0 /* default value, used when: (1)p2p disabed or (2)p2p enabled but only do 1 scan phase */ ++#define P2P_FINDPHASE_EX_FULL 1 /* used when p2p enabled and want to do 1 scan phase and P2P_FINDPHASE_EX_MAX-1 find phase */ ++#define P2P_FINDPHASE_EX_SOCIAL_FIRST (P2P_FINDPHASE_EX_FULL+1) ++#define P2P_FINDPHASE_EX_MAX 4 ++#define P2P_FINDPHASE_EX_SOCIAL_LAST P2P_FINDPHASE_EX_MAX ++ ++#define P2P_PROVISION_TIMEOUT 5000 /* 5 seconds timeout for sending the provision discovery request */ ++#define P2P_CONCURRENT_PROVISION_TIMEOUT 3000 /* 3 seconds timeout for sending the provision discovery request under concurrent mode */ ++#define P2P_GO_NEGO_TIMEOUT 5000 /* 5 seconds timeout for receiving the group negotation response */ ++#define P2P_CONCURRENT_GO_NEGO_TIMEOUT 3000 /* 3 seconds timeout for sending the negotiation request under concurrent mode */ ++#define P2P_TX_PRESCAN_TIMEOUT 100 /* 100ms */ ++#define P2P_INVITE_TIMEOUT 5000 /* 5 seconds timeout for sending the invitation request */ ++#define P2P_CONCURRENT_INVITE_TIMEOUT 3000 /* 3 seconds timeout for sending the invitation request under concurrent mode */ ++#define P2P_RESET_SCAN_CH 25000 /* 25 seconds timeout to reset the scan channel (based on channel plan) */ ++#define P2P_MAX_INTENT 15 ++ ++#define P2P_MAX_NOA_NUM 2 ++ ++/* WPS Configuration Method */ ++#define WPS_CM_NONE 0x0000 ++#define WPS_CM_LABEL 0x0004 ++#define WPS_CM_DISPLYA 0x0008 ++#define WPS_CM_EXTERNAL_NFC_TOKEN 0x0010 ++#define WPS_CM_INTEGRATED_NFC_TOKEN 0x0020 ++#define WPS_CM_NFC_INTERFACE 0x0040 ++#define WPS_CM_PUSH_BUTTON 0x0080 ++#define WPS_CM_KEYPAD 0x0100 ++#define WPS_CM_SW_PUHS_BUTTON 0x0280 ++#define WPS_CM_HW_PUHS_BUTTON 0x0480 ++#define WPS_CM_SW_DISPLAY_PIN 0x2008 ++#define WPS_CM_LCD_DISPLAY_PIN 0x4008 ++ ++enum P2P_ROLE { ++ P2P_ROLE_DISABLE = 0, ++ P2P_ROLE_DEVICE = 1, ++ P2P_ROLE_CLIENT = 2, ++ P2P_ROLE_GO = 3 ++}; ++ ++enum P2P_STATE { ++ P2P_STATE_NONE = 0, /* P2P disable */ ++ P2P_STATE_IDLE = 1, /* P2P had enabled and do nothing */ ++ P2P_STATE_LISTEN = 2, /* In pure listen state */ ++ P2P_STATE_SCAN = 3, /* In scan phase */ ++ P2P_STATE_FIND_PHASE_LISTEN = 4, /* In the listen state of find phase */ ++ P2P_STATE_FIND_PHASE_SEARCH = 5, /* In the search state of find phase */ ++ P2P_STATE_TX_PROVISION_DIS_REQ = 6, /* In P2P provisioning discovery */ ++ P2P_STATE_RX_PROVISION_DIS_RSP = 7, ++ P2P_STATE_RX_PROVISION_DIS_REQ = 8, ++ P2P_STATE_GONEGO_ING = 9, /* Doing the group owner negoitation handshake */ ++ P2P_STATE_GONEGO_OK = 10, /* finish the group negoitation handshake with success */ ++ P2P_STATE_GONEGO_FAIL = 11, /* finish the group negoitation handshake with failure */ ++ P2P_STATE_RECV_INVITE_REQ_MATCH = 12, /* receiving the P2P Inviation request and match with the profile. */ ++ P2P_STATE_PROVISIONING_ING = 13, /* Doing the P2P WPS */ ++ P2P_STATE_PROVISIONING_DONE = 14, /* Finish the P2P WPS */ ++ P2P_STATE_TX_INVITE_REQ = 15, /* Transmit the P2P Invitation request */ ++ P2P_STATE_RX_INVITE_RESP_OK = 16, /* Receiving the P2P Invitation response */ ++ P2P_STATE_RECV_INVITE_REQ_DISMATCH = 17, /* receiving the P2P Inviation request and dismatch with the profile. */ ++ P2P_STATE_RECV_INVITE_REQ_GO = 18, /* receiving the P2P Inviation request and this wifi is GO. */ ++ P2P_STATE_RECV_INVITE_REQ_JOIN = 19, /* receiving the P2P Inviation request to join an existing P2P Group. */ ++ P2P_STATE_RX_INVITE_RESP_FAIL = 20, /* recveing the P2P Inviation response with failure */ ++ P2P_STATE_RX_INFOR_NOREADY = 21, /* receiving p2p negoitation response with information is not available */ ++ P2P_STATE_TX_INFOR_NOREADY = 22, /* sending p2p negoitation response with information is not available */ ++}; ++ ++enum P2P_WPSINFO { ++ P2P_NO_WPSINFO = 0, ++ P2P_GOT_WPSINFO_PEER_DISPLAY_PIN = 1, ++ P2P_GOT_WPSINFO_SELF_DISPLAY_PIN = 2, ++ P2P_GOT_WPSINFO_PBC = 3, ++}; ++ ++#define P2P_PRIVATE_IOCTL_SET_LEN 64 ++ ++enum P2P_PROTO_WK_ID ++{ ++ P2P_FIND_PHASE_WK = 0, ++ P2P_RESTORE_STATE_WK = 1, ++ P2P_PRE_TX_PROVDISC_PROCESS_WK = 2, ++ P2P_PRE_TX_NEGOREQ_PROCESS_WK = 3, ++ P2P_PRE_TX_INVITEREQ_PROCESS_WK = 4, ++ P2P_AP_P2P_CH_SWITCH_PROCESS_WK =5, ++ P2P_RO_CH_WK = 6, ++}; ++ ++/* =====================WFD Section ===================== */ ++/* For Wi-Fi Display */ ++#define WFD_ATTR_DEVICE_INFO 0x00 ++#define WFD_ATTR_ASSOC_BSSID 0x01 ++#define WFD_ATTR_COUPLED_SINK_INFO 0x06 ++#define WFD_ATTR_LOCAL_IP_ADDR 0x08 ++#define WFD_ATTR_SESSION_INFO 0x09 ++#define WFD_ATTR_ALTER_MAC 0x0a ++ ++/* For WFD Device Information Attribute */ ++#define WFD_DEVINFO_SOURCE 0x0000 ++#define WFD_DEVINFO_PSINK 0x0001 ++#define WFD_DEVINFO_SSINK 0x0002 ++#define WFD_DEVINFO_DUAL 0x0003 ++ ++#define WFD_DEVINFO_SESSION_AVAIL 0x0010 ++#define WFD_DEVINFO_WSD 0x0040 ++#define WFD_DEVINFO_PC_TDLS 0x0080 ++#define WFD_DEVINFO_HDCP_SUPPORT 0x0100 ++ ++#define IP_MCAST_MAC(mac) ((mac[0]== 0x01) && (mac[1]== 0x00) && (mac[2]== 0x5e)) ++#define ICMPV6_MCAST_MAC(mac) ((mac[0]== 0x33) && (mac[1]== 0x33) && (mac[2]!= 0xff)) ++ ++/* Regulatroy Domain */ ++struct regd_pair_mapping { ++ u16 reg_dmnenum; ++ u16 reg_2ghz_ctl; ++}; ++ ++struct rtw_regulatory { ++ char alpha2[2]; ++ u16 country_code; ++ u16 max_power_level; ++ u32 tp_scale; ++ u16 current_rd; ++ u16 current_rd_ext; ++ int16_t power_limit; ++ struct regd_pair_mapping *regpair; ++}; ++ ++#endif /* _WIFI_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/wlan_bssdef.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/wlan_bssdef.h +--- linux-4.3/3rdparty/rtl8723bs/include/wlan_bssdef.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/wlan_bssdef.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,278 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __WLAN_BSSDEF_H__ ++#define __WLAN_BSSDEF_H__ ++ ++ ++#define MAX_IE_SZ 768 ++ ++ ++#define NDIS_802_11_LENGTH_SSID 32 ++#define NDIS_802_11_LENGTH_RATES 8 ++#define NDIS_802_11_LENGTH_RATES_EX 16 ++ ++typedef unsigned char NDIS_802_11_MAC_ADDRESS[6]; ++typedef unsigned char NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; /* Set of 8 data rates */ ++typedef unsigned char NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; /* Set of 16 data rates */ ++ ++struct ndis_802_11_ssid { ++ u32 SsidLength; ++ u8 Ssid[32]; ++}; ++ ++enum NDIS_802_11_NETWORK_TYPE { ++ Ndis802_11FH, ++ Ndis802_11DS, ++ Ndis802_11OFDM5, ++ Ndis802_11OFDM24, ++ Ndis802_11NetworkTypeMax /* not a real type, defined as an upper bound */ ++}; ++ ++struct ndis_802_11_conf_fh { ++ u32 Length; /* Length of structure */ ++ u32 HopPattern; /* As defined by 802.11, MSB set */ ++ u32 HopSet; /* to one if non-802.11 */ ++ u32 DwellTime; /* units are Kusec */ ++}; ++ ++/* ++ FW will only save the channel number in DSConfig. ++ ODI Handler will convert the channel number to freq. number. ++*/ ++struct ndis_802_11_conf { ++ u32 Length; /* Length of structure */ ++ u32 BeaconPeriod; /* units are Kusec */ ++ u32 ATIMWindow; /* units are Kusec */ ++ u32 DSConfig; /* Frequency, units are kHz */ ++ struct ndis_802_11_conf_fh FHConfig; ++}; ++ ++enum NDIS_802_11_NETWORK_INFRASTRUCTURE { ++ Ndis802_11IBSS, ++ Ndis802_11Infrastructure, ++ Ndis802_11AutoUnknown, ++ Ndis802_11InfrastructureMax, /* Not a real value, defined as upper bound */ ++ Ndis802_11APMode, ++}; ++ ++struct ndis_802_11_fix_ie { ++ u8 Timestamp[8]; ++ u16 BeaconInterval; ++ u16 Capabilities; ++}; ++ ++struct ndis_80211_var_ie { ++ u8 ElementID; ++ u8 Length; ++ u8 data[1]; ++}; ++ ++/* Length is the 4 bytes multiples of the sum of ++ * sizeof (NDIS_802_11_MAC_ADDRESS) + 2 + ++ * sizeof (struct ndis_802_11_ssid) + sizeof (u32) + ++ * sizeof (long) + sizeof (enum NDIS_802_11_NETWORK_TYPE) + ++ * sizeof (struct ndis_802_11_conf) + sizeof (NDIS_802_11_RATES_EX) + IELength ++ * ++ * Except for IELength, all other fields are fixed length. Therefore, we can ++ * define a macro to present the partial sum. ++ */ ++enum NDIS_802_11_AUTHENTICATION_MODE { ++ Ndis802_11AuthModeOpen, ++ Ndis802_11AuthModeShared, ++ Ndis802_11AuthModeAutoSwitch, ++ Ndis802_11AuthModeWPA, ++ Ndis802_11AuthModeWPAPSK, ++ Ndis802_11AuthModeWPANone, ++ Ndis802_11AuthModeWAPI, ++ Ndis802_11AuthModeMax /* Not a real mode, defined as upper bound */ ++}; ++ ++enum NDIS_802_11_WEP_STATUS { ++ Ndis802_11WEPEnabled, ++ Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, ++ Ndis802_11WEPDisabled, ++ Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, ++ Ndis802_11WEPKeyAbsent, ++ Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, ++ Ndis802_11WEPNotSupported, ++ Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, ++ Ndis802_11Encryption2Enabled, ++ Ndis802_11Encryption2KeyAbsent, ++ Ndis802_11Encryption3Enabled, ++ Ndis802_11Encryption3KeyAbsent, ++ Ndis802_11_EncrypteionWAPI ++}; ++ ++#define NDIS_802_11_AI_REQFI_CAPABILITIES 1 ++#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2 ++#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4 ++ ++#define NDIS_802_11_AI_RESFI_CAPABILITIES 1 ++#define NDIS_802_11_AI_RESFI_STATUSCODE 2 ++#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4 ++ ++struct ndis_802_11_ai_reqfi { ++ u16 Capabilities; ++ u16 ListenInterval; ++ NDIS_802_11_MAC_ADDRESS CurrentAPAddress; ++}; ++ ++struct ndis_801_11_ai_resfi { ++ u16 Capabilities; ++ u16 StatusCode; ++ u16 AssociationId; ++}; ++ ++typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION ++{ ++ u32 Length; ++ u16 AvailableRequestFixedIEs; ++ struct ndis_802_11_ai_reqfi RequestFixedIEs; ++ u32 RequestIELength; ++ u32 OffsetRequestIEs; ++ u16 AvailableResponseFixedIEs; ++ struct ndis_801_11_ai_resfi ResponseFixedIEs; ++ u32 ResponseIELength; ++ u32 OffsetResponseIEs; ++} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION; ++ ++enum NDIS_802_11_RELOAD_DEFAULTS { ++ Ndis802_11ReloadWEPKeys ++}; ++ ++ ++/* Key mapping keys require a BSSID */ ++typedef struct _NDIS_802_11_KEY ++{ ++ u32 Length; /* Length of this structure */ ++ u32 KeyIndex; ++ u32 KeyLength; /* length of key in bytes */ ++ NDIS_802_11_MAC_ADDRESS BSSID; ++ unsigned long long KeyRSC; ++ u8 KeyMaterial[32]; /* variable length depending on above field */ ++} NDIS_802_11_KEY, *PNDIS_802_11_KEY; ++ ++typedef struct _NDIS_802_11_REMOVE_KEY ++{ ++ u32 Length; /* Length of this structure */ ++ u32 KeyIndex; ++ NDIS_802_11_MAC_ADDRESS BSSID; ++} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY; ++ ++struct ndis_802_11_wep { ++ u32 Length; /* Length of this structure */ ++ u32 KeyIndex; /* 0 is the per-client key, 1-N are the global keys */ ++ u32 KeyLength; /* length of key in bytes */ ++ u8 KeyMaterial[16];/* variable length depending on above field */ ++}; ++ ++/* mask for authentication/integrity fields */ ++#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f ++#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01 ++#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02 ++#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06 ++#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E ++ ++/* MIC check time, 60 seconds. */ ++#define MIC_CHECK_TIME 60000000 ++ ++#ifndef Ndis802_11APMode ++#define Ndis802_11APMode (Ndis802_11InfrastructureMax+1) ++#endif ++ ++struct wlan_phy_info { ++ u8 SignalStrength;/* in percentage) */ ++ u8 SignalQuality;/* in percentage) */ ++ u8 Optimum_antenna; /* for Antenna diversity */ ++ u8 Reserved_0; ++}; ++ ++struct wlan_bcn_info { ++ /* these infor get from rtw_get_encrypt_info when ++ * * translate scan to UI */ ++ u8 encryp_protocol;/* ENCRYP_PROTOCOL_E: OPEN/WEP/WPA/WPA2/WAPI */ ++ int group_cipher; /* WPA/WPA2 group cipher */ ++ int pairwise_cipher;/* WPA/WPA2/WEP pairwise cipher */ ++ int is_8021x; ++ ++ /* bwmode 20/40 and ch_offset UP/LOW */ ++ unsigned short ht_cap_info; ++ unsigned char ht_info_infos_0; ++}; ++ ++/* temporally add #pragma pack for structure alignment issue of ++* struct wlan_bssid_ex and get_wlan_bssid_ex_sz() ++*/ ++struct wlan_bssid_ex { ++ u32 Length; ++ NDIS_802_11_MAC_ADDRESS MacAddress; ++ u8 Reserved[2];/* 0]: IS beacon frame */ ++ struct ndis_802_11_ssid Ssid; ++ u32 Privacy; ++ long Rssi;/* in dBM, raw data , get from PHY) */ ++ enum NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; ++ struct ndis_802_11_conf Configuration; ++ enum NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; ++ NDIS_802_11_RATES_EX SupportedRates; ++ struct wlan_phy_info PhyInfo; ++ u32 IELength; ++ u8 IEs[MAX_IE_SZ]; /* timestamp, beacon interval, and capability information) */ ++} __packed; ++ ++__inline static uint get_wlan_bssid_ex_sz(struct wlan_bssid_ex *bss) ++{ ++ return (sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + bss->IELength); ++} ++ ++struct wlan_network { ++ struct list_head list; ++ int network_type; /* refer to ieee80211.h for WIRELESS_11A/B/G */ ++ int fixed; /* set to fixed when not to be removed as site-surveying */ ++ unsigned long last_scanned; /* timestamp for the network */ ++ int aid; /* will only be valid when a BSS is joinned. */ ++ int join_res; ++ struct wlan_bssid_ex network; /* must be the last item */ ++ struct wlan_bcn_info BcnInfo; ++}; ++ ++enum VRTL_CARRIER_SENSE { ++ DISABLE_VCS, ++ ENABLE_VCS, ++ AUTO_VCS ++}; ++ ++enum VCS_TYPE { ++ NONE_VCS, ++ RTS_CTS, ++ CTS_TO_SELF ++}; ++ ++#define PWR_CAM 0 ++#define PWR_MINPS 1 ++#define PWR_MAXPS 2 ++#define PWR_UAPSD 3 ++#define PWR_VOIP 4 ++ ++enum UAPSD_MAX_SP { ++ NO_LIMIT, ++ TWO_MSDU, ++ FOUR_MSDU, ++ SIX_MSDU ++}; ++ ++#define NUM_PRE_AUTH_KEY 16 ++#define NUM_PMKID_CACHE NUM_PRE_AUTH_KEY ++ ++#endif /* ifndef WLAN_BSSDEF_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/include/xmit_osdep.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/xmit_osdep.h +--- linux-4.3/3rdparty/rtl8723bs/include/xmit_osdep.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/include/xmit_osdep.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,54 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __XMIT_OSDEP_H_ ++#define __XMIT_OSDEP_H_ ++ ++ ++struct pkt_file { ++ _pkt *pkt; ++ __kernel_size_t pkt_len; /* the remainder length of the open_file */ ++ _buffer *cur_buffer; ++ u8 *buf_start; ++ u8 *cur_addr; ++ __kernel_size_t buf_len; ++}; ++ ++#define NR_XMITFRAME 256 ++ ++struct xmit_priv; ++struct pkt_attrib; ++struct sta_xmit_priv; ++struct xmit_frame; ++struct xmit_buf; ++ ++extern int _rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev); ++extern int rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev); ++ ++void rtw_os_xmit_schedule(struct adapter *padapter); ++ ++int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz, u8 flag); ++void rtw_os_xmit_resource_free(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 free_sz, u8 flag); ++ ++extern void rtw_set_tx_chksum_offload(_pkt *pkt, struct pkt_attrib *pattrib); ++ ++extern uint rtw_remainder_len(struct pkt_file *pfile); ++extern void _rtw_open_pktfile(_pkt *pkt, struct pkt_file *pfile); ++extern uint _rtw_pktfile_read (struct pkt_file *pfile, u8 *rmem, uint rlen); ++extern sint rtw_endofpktfile (struct pkt_file *pfile); ++ ++extern void rtw_os_pkt_complete(struct adapter *padapter, _pkt *pkt); ++extern void rtw_os_xmit_complete(struct adapter *padapter, struct xmit_frame *pxframe); ++ ++#endif /* __XMIT_OSDEP_H_ */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/Kconfig linux-4.3-rtl8723bs/3rdparty/rtl8723bs/Kconfig +--- linux-4.3/3rdparty/rtl8723bs/Kconfig 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/Kconfig 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,11 @@ ++config RTL8723BS ++ tristate "Realtek 8723B SDIO or SPI WiFi" ++ ---help--- ++ Help message of RTL8723BS ++ ++config WLAN_SDIO ++ bool "Enable SDIO interface for Realtek" ++ depends on RTL8723AS || RTL8723BS ++ default n ++ ---help--- ++ Use memory preallocated in platform +diff -Nurp linux-4.3/3rdparty/rtl8723bs/Makefile linux-4.3-rtl8723bs/3rdparty/rtl8723bs/Makefile +--- linux-4.3/3rdparty/rtl8723bs/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/Makefile 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,250 @@ ++EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS) ++EXTRA_CFLAGS += -O1 ++#EXTRA_CFLAGS += -O3 ++EXTRA_CFLAGS += -Wall ++#EXTRA_CFLAGS += -Wextra ++#EXTRA_CFLAGS += -Werror ++#EXTRA_CFLAGS += -pedantic ++#EXTRA_CFLAGS += -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes ++ ++EXTRA_CFLAGS += -I$(src)/include -I$(src)/hal -g ++ ++ccflags-y += -D__CHECK_ENDIAN__ ++ ++#EXTRA_LDFLAGS += --strip-debug ++ ++########################## Features ########################### ++CONFIG_HW_PWRP_DETECTION = n ++CONFIG_INTEL_WIDI = n ++CONFIG_EXT_CLK = n ++CONFIG_TRAFFIC_PROTECT = y ++CONFIG_LOAD_PHY_PARA_FROM_FILE = y ++CONFIG_CALIBRATE_TX_POWER_BY_REGULATORY = n ++CONFIG_CALIBRATE_TX_POWER_TO_MAX = n ++CONFIG_ODM_ADAPTIVITY = n ++CONFIG_SKIP_SIGNAL_SCALE_MAPPING = n ++######################## Wake On Lan ########################## ++CONFIG_WOWLAN = n ++CONFIG_GPIO_WAKEUP = n ++CONFIG_PNO_SUPPORT = n ++CONFIG_PNO_SET_DEBUG = n ++CONFIG_AP_WOWLAN = n ++######### Notify SDIO Host Keep Power During Syspend ########## ++CONFIG_RTW_SDIO_PM_KEEP_POWER = y ++###################### Platform Related ####################### ++CONFIG_PLATFORM_I386_PC = y ++############################################################### ++ ++########### COMMON ################################# ++ ++_OS_INTFS_FILES := os_dep/osdep_service.o \ ++ os_dep/os_intfs.o \ ++ os_dep/sdio_intf.o \ ++ os_dep/sdio_ops_linux.o \ ++ os_dep/ioctl_linux.o \ ++ os_dep/xmit_linux.o \ ++ os_dep/mlme_linux.o \ ++ os_dep/recv_linux.o \ ++ os_dep/ioctl_cfg80211.o \ ++ os_dep/wifi_regd.o \ ++ os_dep/rtw_proc.o \ ++ os_dep/sdio_ops_linux.o ++ ++_HAL_INTFS_FILES := hal/hal_intf.o \ ++ hal/hal_com.o \ ++ hal/hal_com_phycfg.o \ ++ hal/hal_btcoex.o \ ++ hal/hal_sdio.o ++ ++_OUTSRC_FILES := hal/odm_debug.o \ ++ hal/odm_HWConfig.o\ ++ hal/odm.o\ ++ hal/HalPhyRf.o\ ++ hal/odm_EdcaTurboCheck.o\ ++ hal/odm_DIG.o\ ++ hal/odm_PathDiv.o\ ++ hal/odm_DynamicBBPowerSaving.o\ ++ hal/odm_DynamicTxPower.o\ ++ hal/odm_CfoTracking.o\ ++ hal/odm_NoiseMonitor.o ++ ++EXTRA_CFLAGS += -I$(src)/hal/OUTSRC-BTCoexist ++_OUTSRC_FILES += \ ++ hal/HalBtc8723b1Ant.o \ ++ hal/HalBtc8723b2Ant.o ++ ++########### HAL_RTL8723B ################################# ++MODULE_NAME = r8723bs ++ ++_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ ++ hal/Hal8723BPwrSeq.o ++ ++_HAL_INTFS_FILES += hal/rtl8723b_hal_init.o \ ++ hal/rtl8723b_phycfg.o \ ++ hal/rtl8723b_rf6052.o \ ++ hal/rtl8723b_dm.o \ ++ hal/rtl8723b_rxdesc.o \ ++ hal/rtl8723b_cmd.o \ ++ ++_HAL_INTFS_FILES += \ ++ hal/sdio_halinit.o \ ++ hal/rtl8723bs_xmit.o \ ++ hal/rtl8723bs_recv.o ++ ++_HAL_INTFS_FILES += hal/sdio_ops.o ++ ++_OUTSRC_FILES += hal/HalHWImg8723B_BB.o\ ++ hal/HalHWImg8723B_MAC.o\ ++ hal/HalHWImg8723B_RF.o\ ++ hal/odm_RegConfig8723B.o\ ++ hal/HalPhyRf_8723B.o\ ++ hal/odm_RTL8723B.o ++ ++########### END OF PATH ################################# ++ ++ ++ifeq ($(CONFIG_HW_PWRP_DETECTION), y) ++EXTRA_CFLAGS += -DCONFIG_HW_PWRP_DETECTION ++endif ++ ++ifeq ($(CONFIG_INTEL_WIDI), y) ++EXTRA_CFLAGS += -DCONFIG_INTEL_WIDI ++endif ++ ++ifeq ($(CONFIG_EXT_CLK), y) ++EXTRA_CFLAGS += -DCONFIG_EXT_CLK ++endif ++ ++ifeq ($(CONFIG_TRAFFIC_PROTECT), y) ++EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT ++endif ++ ++ifeq ($(CONFIG_LOAD_PHY_PARA_FROM_FILE), y) ++EXTRA_CFLAGS += -DCONFIG_LOAD_PHY_PARA_FROM_FILE ++endif ++ ++ifeq ($(CONFIG_CALIBRATE_TX_POWER_BY_REGULATORY), y) ++EXTRA_CFLAGS += -DCONFIG_CALIBRATE_TX_POWER_BY_REGULATORY ++endif ++ ++ifeq ($(CONFIG_CALIBRATE_TX_POWER_TO_MAX), y) ++EXTRA_CFLAGS += -DCONFIG_CALIBRATE_TX_POWER_TO_MAX ++endif ++ ++ifeq ($(CONFIG_ODM_ADAPTIVITY), y) ++EXTRA_CFLAGS += -DCONFIG_ODM_ADAPTIVITY ++endif ++ ++ifeq ($(CONFIG_SKIP_SIGNAL_SCALE_MAPPING), y) ++EXTRA_CFLAGS += -DCONFIG_SKIP_SIGNAL_SCALE_MAPPING ++endif ++ ++ifeq ($(CONFIG_WOWLAN), y) ++EXTRA_CFLAGS += -DCONFIG_WOWLAN ++EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER ++endif ++ ++ifeq ($(CONFIG_AP_WOWLAN), y) ++EXTRA_CFLAGS += -DCONFIG_AP_WOWLAN ++EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER ++endif ++ ++ifeq ($(CONFIG_PNO_SUPPORT), y) ++EXTRA_CFLAGS += -DCONFIG_PNO_SUPPORT ++ifeq ($(CONFIG_PNO_SET_DEBUG), y) ++EXTRA_CFLAGS += -DCONFIG_PNO_SET_DEBUG ++endif ++endif ++ ++ifeq ($(CONFIG_GPIO_WAKEUP), y) ++EXTRA_CFLAGS += -DCONFIG_GPIO_WAKEUP ++endif ++ ++ifeq ($(CONFIG_RTW_SDIO_PM_KEEP_POWER), y) ++EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER ++endif ++ ++ifeq ($(CONFIG_PLATFORM_I386_PC), y) ++SUBARCH := $(shell uname -m | sed -e s/i.86/i386/) ++ARCH ?= $(SUBARCH) ++CROSS_COMPILE ?= ++KVER := $(shell uname -r) ++KSRC := /lib/modules/$(KVER)/build ++MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ ++INSTALL_PREFIX := ++endif ++ ++ifneq ($(KERNELRELEASE),) ++ ++rtk_core := core/rtw_cmd.o \ ++ core/rtw_security.o \ ++ core/rtw_debug.o \ ++ core/rtw_io.o \ ++ core/rtw_ioctl_set.o \ ++ core/rtw_ieee80211.o \ ++ core/rtw_mlme.o \ ++ core/rtw_mlme_ext.o \ ++ core/rtw_wlan_util.o \ ++ core/rtw_pwrctrl.o \ ++ core/rtw_rf.o \ ++ core/rtw_recv.o \ ++ core/rtw_sta_mgt.o \ ++ core/rtw_ap.o \ ++ core/rtw_xmit.o \ ++ core/rtw_btcoex.o \ ++ core/rtw_odm.o \ ++ core/rtw_efuse.o ++ ++$(MODULE_NAME)-y += $(rtk_core) ++ ++$(MODULE_NAME)-$(CONFIG_INTEL_WIDI) += core/rtw_intel_widi.o ++ ++$(MODULE_NAME)-y += $(_OS_INTFS_FILES) ++$(MODULE_NAME)-y += $(_HAL_INTFS_FILES) ++$(MODULE_NAME)-y += $(_OUTSRC_FILES) ++$(MODULE_NAME)-y += $(_PLATFORM_FILES) ++ ++obj-$(CONFIG_RTL8723BS) := $(MODULE_NAME).o ++ ++endif ++ ++export CONFIG_RTL8723BS = m ++ ++all: modules ++ ++modules: ++ $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KSRC) M=$(shell pwd) modules ++ ++strip: ++ $(CROSS_COMPILE)strip $(MODULE_NAME).ko --strip-unneeded ++ ++install: ++ install -p -m 644 $(MODULE_NAME).ko $(MODDESTDIR) ++ @cp -n rtl8723bs_nic.bin /lib/firmware/rtlwifi/rtl8723bs_nic.bin ++ @cp -n rtl8723bs_wowlan.bin /lib/firmware/rtlwifi/rtl8723bs_wowlan.bin ++ /sbin/depmod -a ${KVER} ++ ++uninstall: ++ rm -f $(MODDESTDIR)/$(MODULE_NAME).ko ++ /sbin/depmod -a ${KVER} ++ ++config_r: ++ @echo "make config" ++ /bin/bash script/Configure script/config.in ++ ++cppcheck: cppcheck.log ++ ++cppcheck.log: ++ @echo "Creating cppcheck.log" ++ cppcheck -f --enable=all -Iinclude -Ihal -Ios_dep . 2> cppcheck.log ++ ++.PHONY: modules clean ++ ++clean: ++ @rm -fr hal/*/*.mod.c hal/*/*.mod hal/*/*.o hal/*/.*.cmd hal/*/*.ko \ ++ hal/*.mod.c hal/*.mod hal/*.o hal/.*.cmd hal/*.ko \ ++ core/*.mod.c core/*.mod *.o core/.*.cmd core/*.ko \ ++ os_dep/*.mod.c os_dep/*.mod os_dep/*.o os_dep/.*.cmd *.ko \ ++ platform/*.mod.c platform/*.mod platform/*.o platform/.*.cmd platform/*.ko \ ++ Module.symvers Module.markers modules.order *.mod.c *.mod *.o .*.cmd *.ko *~ .tmp_versions \ ++ cppcheck.log +diff -Nurp linux-4.3/3rdparty/rtl8723bs/os_dep/ioctl_cfg80211.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/ioctl_cfg80211.c +--- linux-4.3/3rdparty/rtl8723bs/os_dep/ioctl_cfg80211.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/ioctl_cfg80211.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,3599 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _IOCTL_CFG80211_C_ ++ ++#include ++#include ++#include ++ ++#include ++ ++#define RTW_MAX_MGMT_TX_CNT (8) ++ ++#define RTW_SCAN_IE_LEN_MAX 2304 ++#define RTW_MAX_REMAIN_ON_CHANNEL_DURATION 5000 /* ms */ ++#define RTW_MAX_NUM_PMKIDS 4 ++ ++#define RTW_CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */ ++ ++static const u32 rtw_cipher_suites[] = { ++ WLAN_CIPHER_SUITE_WEP40, ++ WLAN_CIPHER_SUITE_WEP104, ++ WLAN_CIPHER_SUITE_TKIP, ++ WLAN_CIPHER_SUITE_CCMP, ++ WLAN_CIPHER_SUITE_AES_CMAC, ++}; ++ ++#define RATETAB_ENT(_rate, _rateid, _flags) \ ++ { \ ++ .bitrate = (_rate), \ ++ .hw_value = (_rateid), \ ++ .flags = (_flags), \ ++ } ++ ++#define CHAN2G(_channel, _freq, _flags) { \ ++ .band = IEEE80211_BAND_2GHZ, \ ++ .center_freq = (_freq), \ ++ .hw_value = (_channel), \ ++ .flags = (_flags), \ ++ .max_antenna_gain = 0, \ ++ .max_power = 30, \ ++} ++ ++/* if wowlan is not supported, kernel generate a disconnect at each suspend ++ * cf: /net/wireless/sysfs.c, so register a stub wowlan. ++ * Moreover wowlan has to be enabled via a the nl80211_set_wowlan callback. ++ * (from user space, e.g. iw phy0 wowlan enable) ++ */ ++static const struct wiphy_wowlan_support wowlan_stub = { ++ .flags = WIPHY_WOWLAN_ANY, ++ .n_patterns = 0, ++ .pattern_max_len = 0, ++ .pattern_min_len = 0, ++ .max_pkt_offset = 0, ++}; ++ ++static struct ieee80211_rate rtw_rates[] = { ++ RATETAB_ENT(10, 0x1, 0), ++ RATETAB_ENT(20, 0x2, 0), ++ RATETAB_ENT(55, 0x4, 0), ++ RATETAB_ENT(110, 0x8, 0), ++ RATETAB_ENT(60, 0x10, 0), ++ RATETAB_ENT(90, 0x20, 0), ++ RATETAB_ENT(120, 0x40, 0), ++ RATETAB_ENT(180, 0x80, 0), ++ RATETAB_ENT(240, 0x100, 0), ++ RATETAB_ENT(360, 0x200, 0), ++ RATETAB_ENT(480, 0x400, 0), ++ RATETAB_ENT(540, 0x800, 0), ++}; ++ ++#define rtw_a_rates (rtw_rates + 4) ++#define RTW_A_RATES_NUM 8 ++#define rtw_g_rates (rtw_rates + 0) ++#define RTW_G_RATES_NUM 12 ++ ++#define RTW_2G_CHANNELS_NUM 14 ++#define RTW_5G_CHANNELS_NUM 37 ++ ++static struct ieee80211_channel rtw_2ghz_channels[] = { ++ CHAN2G(1, 2412, 0), ++ CHAN2G(2, 2417, 0), ++ CHAN2G(3, 2422, 0), ++ CHAN2G(4, 2427, 0), ++ CHAN2G(5, 2432, 0), ++ CHAN2G(6, 2437, 0), ++ CHAN2G(7, 2442, 0), ++ CHAN2G(8, 2447, 0), ++ CHAN2G(9, 2452, 0), ++ CHAN2G(10, 2457, 0), ++ CHAN2G(11, 2462, 0), ++ CHAN2G(12, 2467, 0), ++ CHAN2G(13, 2472, 0), ++ CHAN2G(14, 2484, 0), ++}; ++ ++static void rtw_2g_channels_init(struct ieee80211_channel *channels) ++{ ++ memcpy((void*)channels, (void*)rtw_2ghz_channels, ++ sizeof(struct ieee80211_channel)*RTW_2G_CHANNELS_NUM ++ ); ++} ++ ++static void rtw_2g_rates_init(struct ieee80211_rate *rates) ++{ ++ memcpy(rates, rtw_g_rates, ++ sizeof(struct ieee80211_rate)*RTW_G_RATES_NUM ++ ); ++} ++ ++static struct ieee80211_supported_band *rtw_spt_band_alloc( ++ enum ieee80211_band band ++ ) ++{ ++ struct ieee80211_supported_band *spt_band = NULL; ++ int n_channels, n_bitrates; ++ ++ if (band == IEEE80211_BAND_2GHZ) ++ { ++ n_channels = RTW_2G_CHANNELS_NUM; ++ n_bitrates = RTW_G_RATES_NUM; ++ } ++ else ++ { ++ goto exit; ++ } ++ ++ spt_band = (struct ieee80211_supported_band *)rtw_zmalloc( ++ sizeof(struct ieee80211_supported_band) ++ + sizeof(struct ieee80211_channel)*n_channels ++ + sizeof(struct ieee80211_rate)*n_bitrates ++ ); ++ if (!spt_band) ++ goto exit; ++ ++ spt_band->channels = (struct ieee80211_channel*)(((u8 *)spt_band)+sizeof(struct ieee80211_supported_band)); ++ spt_band->bitrates = (struct ieee80211_rate*)(((u8 *)spt_band->channels)+sizeof(struct ieee80211_channel)*n_channels); ++ spt_band->band = band; ++ spt_band->n_channels = n_channels; ++ spt_band->n_bitrates = n_bitrates; ++ ++ if (band == IEEE80211_BAND_2GHZ) ++ { ++ rtw_2g_channels_init(spt_band->channels); ++ rtw_2g_rates_init(spt_band->bitrates); ++ } ++ ++ /* spt_band.ht_cap */ ++ ++exit: ++ ++ return spt_band; ++} ++ ++static void rtw_spt_band_free(struct ieee80211_supported_band *spt_band) ++{ ++ u32 size = 0; ++ ++ if (!spt_band) ++ return; ++ ++ if (spt_band->band == IEEE80211_BAND_2GHZ) ++ { ++ size = sizeof(struct ieee80211_supported_band) ++ + sizeof(struct ieee80211_channel)*RTW_2G_CHANNELS_NUM ++ + sizeof(struct ieee80211_rate)*RTW_G_RATES_NUM; ++ } ++ kfree((u8 *)spt_band); ++} ++ ++static const struct ieee80211_txrx_stypes ++rtw_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { ++ [NL80211_IFTYPE_ADHOC] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_STATION] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) ++ }, ++ [NL80211_IFTYPE_AP] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ++ BIT(IEEE80211_STYPE_DISASSOC >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4) | ++ BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_AP_VLAN] = { ++ /* copy AP */ ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ++ BIT(IEEE80211_STYPE_DISASSOC >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4) | ++ BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_P2P_CLIENT] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) ++ }, ++ [NL80211_IFTYPE_P2P_GO] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ++ BIT(IEEE80211_STYPE_DISASSOC >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4) | ++ BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++}; ++ ++static int rtw_ieee80211_channel_to_frequency(int chan, int band) ++{ ++ /* see 802.11 17.3.8.3.2 and Annex J ++ * there are overlapping channel numbers in 5GHz and 2GHz bands */ ++ if (band == IEEE80211_BAND_2GHZ) { ++ if (chan == 14) ++ return 2484; ++ else if (chan < 14) ++ return 2407 + chan * 5; ++ } ++ ++ return 0; /* not supported */ ++} ++ ++static u64 rtw_get_systime_us(void) ++{ ++ struct timespec ts; ++ get_monotonic_boottime(&ts); ++ return ((u64)ts.tv_sec*1000000) + ts.tv_nsec / 1000; ++} ++ ++#define MAX_BSSINFO_LEN 1000 ++struct cfg80211_bss *rtw_cfg80211_inform_bss(struct adapter *padapter, struct wlan_network *pnetwork) ++{ ++ struct ieee80211_channel *notify_channel; ++ struct cfg80211_bss *bss = NULL; ++ /* struct ieee80211_supported_band *band; */ ++ u16 channel; ++ u32 freq; ++ u64 notify_timestamp; ++ u16 notify_capability; ++ u16 notify_interval; ++ u8 *notify_ie; ++ size_t notify_ielen; ++ s32 notify_signal; ++ u8 *buf = NULL, *pbuf; ++ size_t len, bssinf_len = 0; ++ struct ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ struct wireless_dev *wdev = padapter->rtw_wdev; ++ struct wiphy *wiphy = wdev->wiphy; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ ++ /* DBG_8192C("%s\n", __func__); */ ++ ++ bssinf_len = pnetwork->network.IELength+sizeof (struct ieee80211_hdr_3addr); ++ if (bssinf_len > MAX_BSSINFO_LEN) { ++ DBG_871X("%s IE Length too long > %d byte\n", __func__, MAX_BSSINFO_LEN); ++ goto exit; ++ } ++ ++ { ++ u16 wapi_len = 0; ++ ++ if (rtw_get_wapi_ie(pnetwork->network.IEs, pnetwork->network.IELength, NULL, &wapi_len)>0) ++ { ++ if (wapi_len > 0) ++ { ++ DBG_871X("%s, no support wapi!\n", __func__); ++ goto exit; ++ } ++ } ++ } ++ ++ /* To reduce PBC Overlap rate */ ++ /* spin_lock_bh(&pwdev_priv->scan_req_lock); */ ++ if (adapter_wdev_data(padapter)->scan_request != NULL) ++ { ++ u8 *psr = NULL, sr = 0; ++ struct ndis_802_11_ssid *pssid = &pnetwork->network.Ssid; ++ struct cfg80211_scan_request *request = adapter_wdev_data(padapter)->scan_request; ++ struct cfg80211_ssid *ssids = request->ssids; ++ u32 wpsielen = 0; ++ u8 *wpsie = NULL; ++ ++ wpsie = rtw_get_wps_ie(pnetwork->network.IEs+_FIXED_IE_LENGTH_, pnetwork->network.IELength-_FIXED_IE_LENGTH_, NULL, &wpsielen); ++ ++ if (wpsie && wpsielen>0) ++ psr = rtw_get_wps_attr_content(wpsie, wpsielen, WPS_ATTR_SELECTED_REGISTRAR, (u8 *)(&sr), NULL); ++ ++ if (sr != 0) ++ { ++ if (request->n_ssids == 1 && request->n_channels == 1) /* it means under processing WPS */ ++ { ++ DBG_8192C("ssid =%s, len =%d\n", pssid->Ssid, pssid->SsidLength); ++ ++ if (ssids[0].ssid_len == 0) { ++ } ++ else if (pssid->SsidLength == ssids[0].ssid_len && ++ !memcmp(pssid->Ssid, ssids[0].ssid, ssids[0].ssid_len)) ++ { ++ DBG_871X("%s, got sr and ssid match!\n", __func__); ++ } ++ else ++ { ++ if (psr != NULL) ++ *psr = 0; /* clear sr */ ++ } ++ } ++ } ++ } ++ /* spin_unlock_bh(&pwdev_priv->scan_req_lock); */ ++ ++ ++ channel = pnetwork->network.Configuration.DSConfig; ++ freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); ++ ++ notify_channel = ieee80211_get_channel(wiphy, freq); ++ ++ notify_timestamp = rtw_get_systime_us(); ++ ++ notify_interval = le16_to_cpu(*(__le16 *)rtw_get_beacon_interval_from_ie(pnetwork->network.IEs)); ++ notify_capability = le16_to_cpu(*(__le16 *)rtw_get_capability_from_ie(pnetwork->network.IEs)); ++ ++ notify_ie = pnetwork->network.IEs+_FIXED_IE_LENGTH_; ++ notify_ielen = pnetwork->network.IELength-_FIXED_IE_LENGTH_; ++ ++ /* We've set wiphy's signal_type as CFG80211_SIGNAL_TYPE_MBM: signal strength in mBm (100*dBm) */ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == true && ++ is_same_network(&pmlmepriv->cur_network.network, &pnetwork->network, 0)) { ++ notify_signal = 100*translate_percentage_to_dbm(padapter->recvpriv.signal_strength);/* dbm */ ++ } else { ++ notify_signal = 100*translate_percentage_to_dbm(pnetwork->network.PhyInfo.SignalStrength);/* dbm */ ++ } ++ ++ buf = kzalloc(MAX_BSSINFO_LEN, GFP_ATOMIC); ++ if (!buf) ++ goto exit; ++ pbuf = buf; ++ ++ pwlanhdr = (struct ieee80211_hdr *)pbuf; ++ fctrl = &(pwlanhdr->frame_control); ++ *(fctrl) = 0; ++ ++ SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); ++ /* pmlmeext->mgnt_seq++; */ ++ ++ if (pnetwork->network.Reserved[0] == 1) { /* WIFI_BEACON */ ++ memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); ++ SetFrameSubType(pbuf, WIFI_BEACON); ++ } else { ++ memcpy(pwlanhdr->addr1, myid(&(padapter->eeprompriv)), ETH_ALEN); ++ SetFrameSubType(pbuf, WIFI_PROBERSP); ++ } ++ ++ memcpy(pwlanhdr->addr2, pnetwork->network.MacAddress, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, pnetwork->network.MacAddress, ETH_ALEN); ++ ++ ++ pbuf += sizeof(struct ieee80211_hdr_3addr); ++ len = sizeof (struct ieee80211_hdr_3addr); ++ ++ memcpy(pbuf, pnetwork->network.IEs, pnetwork->network.IELength); ++ len += pnetwork->network.IELength; ++ ++ *((__le64*)pbuf) = cpu_to_le64(notify_timestamp); ++ ++ bss = cfg80211_inform_bss_frame(wiphy, notify_channel, (struct ieee80211_mgmt *)buf, ++ len, notify_signal, GFP_ATOMIC); ++ ++ if (unlikely(!bss)) { ++ DBG_8192C(FUNC_ADPT_FMT" bss NULL\n", FUNC_ADPT_ARG(padapter)); ++ goto exit; ++ } ++ ++ cfg80211_put_bss(wiphy, bss); ++ kfree(buf); ++ ++exit: ++ return bss; ++ ++} ++ ++/* ++ Check the given bss is valid by kernel API cfg80211_get_bss() ++ @padapter : the given adapter ++ ++ return true if bss is valid, false for not found. ++*/ ++int rtw_cfg80211_check_bss(struct adapter *padapter) ++{ ++ struct wlan_bssid_ex *pnetwork = &(padapter->mlmeextpriv.mlmext_info.network); ++ struct cfg80211_bss *bss = NULL; ++ struct ieee80211_channel *notify_channel = NULL; ++ u32 freq; ++ ++ if (!(pnetwork) || !(padapter->rtw_wdev)) ++ return false; ++ ++ freq = rtw_ieee80211_channel_to_frequency(pnetwork->Configuration.DSConfig, IEEE80211_BAND_2GHZ); ++ ++ notify_channel = ieee80211_get_channel(padapter->rtw_wdev->wiphy, freq); ++ bss = cfg80211_get_bss(padapter->rtw_wdev->wiphy, notify_channel, ++ pnetwork->MacAddress, pnetwork->Ssid.Ssid, ++ pnetwork->Ssid.SsidLength, ++ WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); ++ ++ cfg80211_put_bss(padapter->rtw_wdev->wiphy, bss); ++ ++ return (bss!= NULL); ++} ++ ++void rtw_cfg80211_ibss_indicate_connect(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *cur_network = &(pmlmepriv->cur_network); ++ struct wireless_dev *pwdev = padapter->rtw_wdev; ++ struct wiphy *wiphy = pwdev->wiphy; ++ int freq = (int)cur_network->network.Configuration.DSConfig; ++ struct ieee80211_channel *chan; ++ ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); ++ if (pwdev->iftype != NL80211_IFTYPE_ADHOC) ++ { ++ return; ++ } ++ ++ if (!rtw_cfg80211_check_bss(padapter)) { ++ struct wlan_bssid_ex *pnetwork = &(padapter->mlmeextpriv.mlmext_info.network); ++ struct wlan_network *scanned = pmlmepriv->cur_network_scanned; ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ==true) ++ { ++ ++ memcpy(&cur_network->network, pnetwork, sizeof(struct wlan_bssid_ex)); ++ if (!rtw_cfg80211_inform_bss(padapter, cur_network)) ++ DBG_871X(FUNC_ADPT_FMT" inform fail !!\n", FUNC_ADPT_ARG(padapter)); ++ else ++ DBG_871X(FUNC_ADPT_FMT" inform success !!\n", FUNC_ADPT_ARG(padapter)); ++ } ++ else ++ { ++ if (scanned == NULL) ++ rtw_warn_on(1); ++ ++ if (!memcmp(&(scanned->network.Ssid), &(pnetwork->Ssid), sizeof(struct ndis_802_11_ssid)) ++ && !memcmp(scanned->network.MacAddress, pnetwork->MacAddress, sizeof(NDIS_802_11_MAC_ADDRESS)) ++ ) { ++ if (!rtw_cfg80211_inform_bss(padapter, scanned)) { ++ DBG_871X(FUNC_ADPT_FMT" inform fail !!\n", FUNC_ADPT_ARG(padapter)); ++ } else { ++ /* DBG_871X(FUNC_ADPT_FMT" inform success !!\n", FUNC_ADPT_ARG(padapter)); */ ++ } ++ } else { ++ DBG_871X("scanned & pnetwork compare fail\n"); ++ rtw_warn_on(1); ++ } ++ } ++ ++ if (!rtw_cfg80211_check_bss(padapter)) ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" BSS not found !!\n", FUNC_ADPT_ARG(padapter)); ++ } ++ /* notify cfg80211 that device joined an IBSS */ ++ chan = ieee80211_get_channel(wiphy, freq); ++ cfg80211_ibss_joined(padapter->pnetdev, cur_network->network.MacAddress, chan, GFP_ATOMIC); ++} ++ ++void rtw_cfg80211_indicate_connect(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *cur_network = &(pmlmepriv->cur_network); ++ struct wireless_dev *pwdev = padapter->rtw_wdev; ++ ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); ++ if (pwdev->iftype != NL80211_IFTYPE_STATION ++ && pwdev->iftype != NL80211_IFTYPE_P2P_CLIENT ++ ) { ++ return; ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ++ return; ++ ++ { ++ struct wlan_bssid_ex *pnetwork = &(padapter->mlmeextpriv.mlmext_info.network); ++ struct wlan_network *scanned = pmlmepriv->cur_network_scanned; ++ ++ /* DBG_871X(FUNC_ADPT_FMT" BSS not found\n", FUNC_ADPT_ARG(padapter)); */ ++ ++ if (scanned == NULL) { ++ rtw_warn_on(1); ++ goto check_bss; ++ } ++ ++ if (!memcmp(scanned->network.MacAddress, pnetwork->MacAddress, sizeof(NDIS_802_11_MAC_ADDRESS)) ++ && !memcmp(&(scanned->network.Ssid), &(pnetwork->Ssid), sizeof(struct ndis_802_11_ssid)) ++ ) { ++ if (!rtw_cfg80211_inform_bss(padapter, scanned)) { ++ DBG_871X(FUNC_ADPT_FMT" inform fail !!\n", FUNC_ADPT_ARG(padapter)); ++ } else { ++ /* DBG_871X(FUNC_ADPT_FMT" inform success !!\n", FUNC_ADPT_ARG(padapter)); */ ++ } ++ } else { ++ DBG_871X("scanned: %s("MAC_FMT"), cur: %s("MAC_FMT")\n", ++ scanned->network.Ssid.Ssid, MAC_ARG(scanned->network.MacAddress), ++ pnetwork->Ssid.Ssid, MAC_ARG(pnetwork->MacAddress) ++ ); ++ rtw_warn_on(1); ++ } ++ } ++ ++check_bss: ++ if (!rtw_cfg80211_check_bss(padapter)) ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" BSS not found !!\n", FUNC_ADPT_ARG(padapter)); ++ ++ if (rtw_to_roam(padapter) > 0) { ++ struct wiphy *wiphy = pwdev->wiphy; ++ struct ieee80211_channel *notify_channel; ++ u32 freq; ++ u16 channel = cur_network->network.Configuration.DSConfig; ++ ++ freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); ++ ++ notify_channel = ieee80211_get_channel(wiphy, freq); ++ ++ DBG_871X(FUNC_ADPT_FMT" call cfg80211_roamed\n", FUNC_ADPT_ARG(padapter)); ++ cfg80211_roamed(padapter->pnetdev ++ , notify_channel ++ , cur_network->network.MacAddress ++ , pmlmepriv->assoc_req+sizeof(struct ieee80211_hdr_3addr)+2 ++ , pmlmepriv->assoc_req_len-sizeof(struct ieee80211_hdr_3addr)-2 ++ , pmlmepriv->assoc_rsp+sizeof(struct ieee80211_hdr_3addr)+6 ++ , pmlmepriv->assoc_rsp_len-sizeof(struct ieee80211_hdr_3addr)-6 ++ , GFP_ATOMIC); ++ } ++ else ++ { ++ cfg80211_connect_result(padapter->pnetdev, cur_network->network.MacAddress ++ , pmlmepriv->assoc_req+sizeof(struct ieee80211_hdr_3addr)+2 ++ , pmlmepriv->assoc_req_len-sizeof(struct ieee80211_hdr_3addr)-2 ++ , pmlmepriv->assoc_rsp+sizeof(struct ieee80211_hdr_3addr)+6 ++ , pmlmepriv->assoc_rsp_len-sizeof(struct ieee80211_hdr_3addr)-6 ++ , WLAN_STATUS_SUCCESS, GFP_ATOMIC); ++ } ++} ++ ++void rtw_cfg80211_indicate_disconnect(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wireless_dev *pwdev = padapter->rtw_wdev; ++ ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); ++ ++ if (pwdev->iftype != NL80211_IFTYPE_STATION ++ && pwdev->iftype != NL80211_IFTYPE_P2P_CLIENT ++ ) { ++ return; ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ++ return; ++ ++ if (!padapter->mlmepriv.not_indic_disco) { ++ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) ++ cfg80211_disconnected(padapter->pnetdev, 0, ++ NULL, 0, true, GFP_ATOMIC); ++#else ++ cfg80211_disconnected(padapter->pnetdev, 0, NULL, 0, GFP_ATOMIC); ++#endif ++ } else { ++ cfg80211_connect_result(padapter->pnetdev, NULL, NULL, 0, NULL, 0, ++ WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_ATOMIC/*GFP_KERNEL*/); ++ } ++ } ++} ++ ++ ++static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len) ++{ ++ int ret = 0; ++ u32 wep_key_idx, wep_key_len; ++ struct sta_info *psta = NULL, *pbcmc_sta = NULL; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv* psecuritypriv =&(padapter->securitypriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ DBG_8192C("%s\n", __func__); ++ ++ param->u.crypt.err = 0; ++ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; ++ ++ if (param_len != sizeof(struct ieee_param) + param->u.crypt.key_len) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ 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) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ } ++ else ++ { ++ psta = rtw_get_stainfo(pstapriv, param->sta_addr); ++ if (!psta) ++ { ++ /* ret = -EINVAL; */ ++ DBG_8192C("rtw_set_encryption(), sta has already been removed or never been added\n"); ++ goto exit; ++ } ++ } ++ ++ if (strcmp(param->u.crypt.alg, "none") == 0 && (psta == NULL)) ++ { ++ /* todo:clear default encryption keys */ ++ ++ DBG_8192C("clear default encryption keys, keyid =%d\n", param->u.crypt.idx); ++ ++ goto exit; ++ } ++ ++ ++ if (strcmp(param->u.crypt.alg, "WEP") == 0 && (psta == NULL)) ++ { ++ DBG_8192C("r871x_set_encryption, crypt.alg = WEP\n"); ++ ++ wep_key_idx = param->u.crypt.idx; ++ wep_key_len = param->u.crypt.key_len; ++ ++ DBG_8192C("r871x_set_encryption, wep_key_idx =%d, len =%d\n", wep_key_idx, wep_key_len); ++ ++ if ((wep_key_idx >= WEP_KEYS) || (wep_key_len<= 0)) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (wep_key_len > 0) ++ { ++ wep_key_len = wep_key_len <= 5 ? 5 : 13; ++ } ++ ++ if (psecuritypriv->bWepDefaultKeyIdxSet == 0) ++ { ++ /* wep default key has not been set, so use this key index as default key. */ ++ ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; ++ psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; ++ psecuritypriv->dot118021XGrpPrivacy = _WEP40_; ++ ++ if (wep_key_len == 13) ++ { ++ psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; ++ psecuritypriv->dot118021XGrpPrivacy = _WEP104_; ++ } ++ ++ psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx; ++ } ++ ++ memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), param->u.crypt.key, wep_key_len); ++ ++ psecuritypriv->dot11DefKeylen[wep_key_idx] = wep_key_len; ++ ++ rtw_ap_set_wep_key(padapter, param->u.crypt.key, wep_key_len, wep_key_idx, 1); ++ ++ goto exit; ++ ++ } ++ ++ ++ if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) /* group key */ ++ { ++ if (param->u.crypt.set_tx == 0) /* group key */ ++ { ++ if (strcmp(param->u.crypt.alg, "WEP") == 0) ++ { ++ DBG_8192C("%s, set group_key, WEP\n", __func__); ++ ++ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _WEP40_; ++ if (param->u.crypt.key_len == 13) ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _WEP104_; ++ } ++ ++ } ++ else if (strcmp(param->u.crypt.alg, "TKIP") == 0) ++ { ++ DBG_8192C("%s, set group_key, TKIP\n", __func__); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _TKIP_; ++ ++ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ ++ /* set mic key */ ++ memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8); ++ memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8); ++ ++ psecuritypriv->busetkipkey = true; ++ ++ } ++ else if (strcmp(param->u.crypt.alg, "CCMP") == 0) ++ { ++ DBG_8192C("%s, set group_key, CCMP\n", __func__); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _AES_; ++ ++ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ } ++ else ++ { ++ DBG_8192C("%s, set group_key, none\n", __func__); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ } ++ ++ psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx; ++ ++ psecuritypriv->binstallGrpkey = true; ++ ++ psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;/* */ ++ ++ rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx); ++ ++ pbcmc_sta =rtw_get_bcmc_stainfo(padapter); ++ if (pbcmc_sta) ++ { ++ pbcmc_sta->ieee8021x_blocked = false; ++ pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;/* rx will use bmc_sta's dot118021XPrivacy */ ++ } ++ ++ } ++ ++ goto exit; ++ ++ } ++ ++ if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && psta) /* psk/802_1x */ ++ { ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ { ++ if (param->u.crypt.set_tx == 1) /* pairwise key */ ++ { ++ memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ if (strcmp(param->u.crypt.alg, "WEP") == 0) ++ { ++ DBG_8192C("%s, set pairwise key, WEP\n", __func__); ++ ++ psta->dot118021XPrivacy = _WEP40_; ++ if (param->u.crypt.key_len == 13) ++ { ++ psta->dot118021XPrivacy = _WEP104_; ++ } ++ } ++ else if (strcmp(param->u.crypt.alg, "TKIP") == 0) ++ { ++ DBG_8192C("%s, set pairwise key, TKIP\n", __func__); ++ ++ psta->dot118021XPrivacy = _TKIP_; ++ ++ /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ ++ /* set mic key */ ++ memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8); ++ memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8); ++ ++ psecuritypriv->busetkipkey = true; ++ ++ } ++ else if (strcmp(param->u.crypt.alg, "CCMP") == 0) ++ { ++ ++ DBG_8192C("%s, set pairwise key, CCMP\n", __func__); ++ ++ psta->dot118021XPrivacy = _AES_; ++ } ++ else ++ { ++ DBG_8192C("%s, set pairwise key, none\n", __func__); ++ ++ psta->dot118021XPrivacy = _NO_PRIVACY_; ++ } ++ ++ rtw_ap_set_pairwise_key(padapter, psta); ++ ++ psta->ieee8021x_blocked = false; ++ ++ psta->bpairwise_key_installed = true; ++ ++ } ++ else/* group key??? */ ++ { ++ if (strcmp(param->u.crypt.alg, "WEP") == 0) ++ { ++ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _WEP40_; ++ if (param->u.crypt.key_len == 13) ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _WEP104_; ++ } ++ } ++ else if (strcmp(param->u.crypt.alg, "TKIP") == 0) ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _TKIP_; ++ ++ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ ++ /* set mic key */ ++ memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8); ++ memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8); ++ ++ psecuritypriv->busetkipkey = true; ++ ++ } ++ else if (strcmp(param->u.crypt.alg, "CCMP") == 0) ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _AES_; ++ ++ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ } ++ else ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ } ++ ++ psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx; ++ ++ psecuritypriv->binstallGrpkey = true; ++ ++ psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;/* */ ++ ++ rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx); ++ ++ pbcmc_sta =rtw_get_bcmc_stainfo(padapter); ++ if (pbcmc_sta) ++ { ++ pbcmc_sta->ieee8021x_blocked = false; ++ pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;/* rx will use bmc_sta's dot118021XPrivacy */ ++ } ++ ++ } ++ ++ } ++ ++ } ++ ++exit: ++ ++ return ret; ++ ++} ++ ++static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len) ++{ ++ int ret = 0; ++ u32 wep_key_idx, wep_key_len; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ DBG_8192C("%s\n", __func__); ++ ++ param->u.crypt.err = 0; ++ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; ++ ++ if (param_len < (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ 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 ++ && param->u.crypt.idx > BIP_MAX_KEYID ++ ) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ } else { ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ } ++ ++ if (strcmp(param->u.crypt.alg, "WEP") == 0) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("wpa_set_encryption, crypt.alg = WEP\n")); ++ DBG_8192C("wpa_set_encryption, crypt.alg = WEP\n"); ++ ++ wep_key_idx = param->u.crypt.idx; ++ wep_key_len = param->u.crypt.key_len; ++ ++ if ((wep_key_idx > WEP_KEYS) || (wep_key_len <= 0)) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (psecuritypriv->bWepDefaultKeyIdxSet == 0) ++ { ++ /* wep default key has not been set, so use this key index as default key. */ ++ ++ wep_key_len = wep_key_len <= 5 ? 5 : 13; ++ ++ psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; ++ psecuritypriv->dot118021XGrpPrivacy = _WEP40_; ++ ++ if (wep_key_len == 13) ++ { ++ psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; ++ psecuritypriv->dot118021XGrpPrivacy = _WEP104_; ++ } ++ ++ psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx; ++ } ++ ++ memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), param->u.crypt.key, wep_key_len); ++ ++ psecuritypriv->dot11DefKeylen[wep_key_idx] = wep_key_len; ++ ++ rtw_set_key(padapter, psecuritypriv, wep_key_idx, 0, true); ++ ++ goto exit; ++ } ++ ++ if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) /* 802_1x */ ++ { ++ struct sta_info * psta,*pbcmc_sta; ++ struct sta_priv * pstapriv = &padapter->stapriv; ++ ++ /* DBG_8192C("%s, : dot11AuthAlgrthm == dot11AuthAlgrthm_8021X\n", __func__); */ ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE) == true) /* sta mode */ ++ { ++ psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv)); ++ if (psta == NULL) { ++ /* DEBUG_ERR(("Set wpa_set_encryption: Obtain Sta_info fail\n")); */ ++ DBG_8192C("%s, : Obtain Sta_info fail\n", __func__); ++ } ++ else ++ { ++ /* Jeff: don't disable ieee8021x_blocked while clearing key */ ++ if (strcmp(param->u.crypt.alg, "none") != 0) ++ psta->ieee8021x_blocked = false; ++ ++ ++ if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled)|| ++ (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) ++ { ++ psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; ++ } ++ ++ if (param->u.crypt.set_tx == 1)/* pairwise key */ ++ { ++ ++ DBG_8192C("%s, : param->u.crypt.set_tx == 1\n", __func__); ++ ++ memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ if (strcmp(param->u.crypt.alg, "TKIP") == 0)/* set mic key */ ++ { ++ /* DEBUG_ERR(("\nset key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */ ++ memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8); ++ memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8); ++ ++ padapter->securitypriv.busetkipkey =false; ++ /* _set_timer(&padapter->securitypriv.tkip_timer, 50); */ ++ } ++ ++ /* DEBUG_ERR((" param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */ ++ DBG_871X(" ~~~~set sta key:unicastkey\n"); ++ ++ rtw_setstakey_cmd(padapter, psta, true, true); ++ } ++ else/* group key */ ++ { ++ if (strcmp(param->u.crypt.alg, "TKIP") == 0 || strcmp(param->u.crypt.alg, "CCMP") == 0) ++ { ++ memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey,&(param->u.crypt.key[16]), 8); ++ memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey,&(param->u.crypt.key[24]), 8); ++ padapter->securitypriv.binstallGrpkey = true; ++ /* DEBUG_ERR((" param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */ ++ DBG_871X(" ~~~~set sta key:groupkey\n"); ++ ++ padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx; ++ rtw_set_key(padapter,&padapter->securitypriv, param->u.crypt.idx, 1, true); ++ } ++ else if (strcmp(param->u.crypt.alg, "BIP") == 0) ++ { ++ /* DBG_871X("BIP key_len =%d , index =%d @@@@@@@@@@@@@@@@@@\n", param->u.crypt.key_len, param->u.crypt.idx); */ ++ /* save the IGTK key, length 16 bytes */ ++ memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ /*DBG_871X("IGTK key below:\n"); ++ for (no = 0;no<16;no++) ++ printk(" %02x ", padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey[no]); ++ DBG_871X("\n");*/ ++ padapter->securitypriv.dot11wBIPKeyid = param->u.crypt.idx; ++ padapter->securitypriv.binstallBIPkey = true; ++ DBG_871X(" ~~~~set sta key:IGKT\n"); ++ } ++ } ++ } ++ ++ pbcmc_sta =rtw_get_bcmc_stainfo(padapter); ++ if (pbcmc_sta == NULL) ++ { ++ /* DEBUG_ERR(("Set OID_802_11_ADD_KEY: bcmc stainfo is null\n")); */ ++ } ++ else ++ { ++ /* Jeff: don't disable ieee8021x_blocked while clearing key */ ++ if (strcmp(param->u.crypt.alg, "none") != 0) ++ pbcmc_sta->ieee8021x_blocked = false; ++ ++ if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled)|| ++ (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) ++ { ++ pbcmc_sta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; ++ } ++ } ++ } ++ else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) /* adhoc mode */ ++ { ++ } ++ } ++ ++exit: ++ ++ DBG_8192C("%s, ret =%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct net_device *ndev, ++ u8 key_index, bool pairwise, const u8 *mac_addr, ++ struct key_params *params) ++{ ++ char *alg_name; ++ u32 param_len; ++ struct ieee_param *param = NULL; ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(ndev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ DBG_871X(FUNC_NDEV_FMT" adding key for %pM\n", FUNC_NDEV_ARG(ndev), mac_addr); ++ DBG_871X("cipher = 0x%x\n", params->cipher); ++ DBG_871X("key_len = 0x%x\n", params->key_len); ++ DBG_871X("seq_len = 0x%x\n", params->seq_len); ++ DBG_871X("key_index =%d\n", key_index); ++ DBG_871X("pairwise =%d\n", pairwise); ++ ++ param_len = sizeof(struct ieee_param) + params->key_len; ++ param = (struct ieee_param *)rtw_malloc(param_len); ++ if (param == NULL) ++ return -1; ++ ++ memset(param, 0, param_len); ++ ++ param->cmd = IEEE_CMD_SET_ENCRYPTION; ++ memset(param->sta_addr, 0xff, ETH_ALEN); ++ ++ switch (params->cipher) { ++ case IW_AUTH_CIPHER_NONE: ++ /* todo: remove key */ ++ /* remove = 1; */ ++ alg_name = "none"; ++ break; ++ case WLAN_CIPHER_SUITE_WEP40: ++ case WLAN_CIPHER_SUITE_WEP104: ++ alg_name = "WEP"; ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ alg_name = "TKIP"; ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ alg_name = "CCMP"; ++ break; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ alg_name = "BIP"; ++ break; ++ default: ++ ret = -ENOTSUPP; ++ goto addkey_end; ++ } ++ ++ strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN); ++ ++ ++ if (!mac_addr || is_broadcast_ether_addr(mac_addr)) ++ { ++ param->u.crypt.set_tx = 0; /* for wpa/wpa2 group key */ ++ } else { ++ param->u.crypt.set_tx = 1; /* for wpa/wpa2 pairwise key */ ++ } ++ ++ param->u.crypt.idx = key_index; ++ ++ if (params->seq_len && params->seq) ++ { ++ memcpy(param->u.crypt.seq, (u8 *)params->seq, params->seq_len); ++ } ++ ++ if (params->key_len && params->key) ++ { ++ param->u.crypt.key_len = params->key_len; ++ memcpy(param->u.crypt.key, (u8 *)params->key, params->key_len); ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) ++ { ++ ret = rtw_cfg80211_set_encryption(ndev, param, param_len); ++ } ++ else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ++ { ++ if (mac_addr) ++ memcpy(param->sta_addr, (void*)mac_addr, ETH_ALEN); ++ ++ ret = rtw_cfg80211_ap_set_encryption(ndev, param, param_len); ++ } ++ else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true ++ || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) ++ { ++ /* DBG_8192C("@@@@@@@@@@ fw_state = 0x%x, iftype =%d\n", pmlmepriv->fw_state, rtw_wdev->iftype); */ ++ ret = rtw_cfg80211_set_encryption(ndev, param, param_len); ++ } ++ else ++ { ++ DBG_8192C("error!\n"); ++ ++ } ++ ++addkey_end: ++ if (param) ++ { ++ kfree((u8 *)param); ++ } ++ ++ return ret; ++ ++} ++ ++static int cfg80211_rtw_get_key(struct wiphy *wiphy, struct net_device *ndev, ++ u8 key_index, bool pairwise, const u8 *mac_addr, ++ void *cookie, ++ void (*callback)(void *cookie, ++ struct key_params*)) ++{ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ return 0; ++} ++ ++static int cfg80211_rtw_del_key(struct wiphy *wiphy, struct net_device *ndev, ++ u8 key_index, bool pairwise, const u8 *mac_addr) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(ndev); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ DBG_871X(FUNC_NDEV_FMT" key_index =%d\n", FUNC_NDEV_ARG(ndev), key_index); ++ ++ if (key_index == psecuritypriv->dot11PrivacyKeyIndex) ++ { ++ /* clear the flag of wep default key set. */ ++ psecuritypriv->bWepDefaultKeyIdxSet = 0; ++ } ++ ++ return 0; ++} ++ ++static int cfg80211_rtw_set_default_key(struct wiphy *wiphy, ++ struct net_device *ndev, u8 key_index ++ , bool unicast, bool multicast ++ ) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(ndev); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ DBG_871X(FUNC_NDEV_FMT" key_index =%d" ++ ", unicast =%d, multicast =%d" ++ ".\n", FUNC_NDEV_ARG(ndev), key_index ++ , unicast, multicast ++ ); ++ ++ if ((key_index < WEP_KEYS) && ((psecuritypriv->dot11PrivacyAlgrthm == _WEP40_) || (psecuritypriv->dot11PrivacyAlgrthm == _WEP104_))) /* set wep default key */ ++ { ++ psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ ++ psecuritypriv->dot11PrivacyKeyIndex = key_index; ++ ++ psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; ++ psecuritypriv->dot118021XGrpPrivacy = _WEP40_; ++ if (psecuritypriv->dot11DefKeylen[key_index] == 13) ++ { ++ psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; ++ psecuritypriv->dot118021XGrpPrivacy = _WEP104_; ++ } ++ ++ psecuritypriv->bWepDefaultKeyIdxSet = 1; /* set the flag to represent that wep default key has been set */ ++ } ++ ++ return 0; ++ ++} ++ ++static int cfg80211_rtw_get_station(struct wiphy *wiphy, ++ struct net_device *ndev, ++ const u8 *mac, ++ struct station_info *sinfo) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(ndev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ sinfo->filled = 0; ++ ++ if (!mac) { ++ DBG_871X(FUNC_NDEV_FMT" mac ==%p\n", FUNC_NDEV_ARG(ndev), mac); ++ ret = -ENOENT; ++ goto exit; ++ } ++ ++ psta = rtw_get_stainfo(pstapriv, (u8 *)mac); ++ if (psta == NULL) { ++ DBG_8192C("%s, sta_info is null\n", __func__); ++ ret = -ENOENT; ++ goto exit; ++ } ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X(FUNC_NDEV_FMT" mac ="MAC_FMT"\n", FUNC_NDEV_ARG(ndev), MAC_ARG(mac)); ++#endif ++ ++ /* for infra./P2PClient mode */ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) ++ && check_fwstate(pmlmepriv, _FW_LINKED) ++ ) ++ { ++ struct wlan_network *cur_network = &(pmlmepriv->cur_network); ++ ++ if (memcmp((u8 *)mac, cur_network->network.MacAddress, ETH_ALEN)) { ++ DBG_871X("%s, mismatch bssid ="MAC_FMT"\n", __func__, MAC_ARG(cur_network->network.MacAddress)); ++ ret = -ENOENT; ++ goto exit; ++ } ++ ++ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); ++ sinfo->signal = translate_percentage_to_dbm(padapter->recvpriv.signal_strength); ++ ++ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); ++ sinfo->txrate.legacy = rtw_get_cur_max_rate(padapter); ++ ++ sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS); ++ sinfo->rx_packets = sta_rx_data_pkts(psta); ++ ++ sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS); ++ sinfo->tx_packets = psta->sta_stats.tx_pkts; ++ ++ } ++ ++ /* for Ad-Hoc/AP mode */ ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ++ ||check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ++ ||check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ && check_fwstate(pmlmepriv, _FW_LINKED) ++ ) ++ { ++ /* TODO: should acquire station info... */ ++ } ++ ++exit: ++ return ret; ++} ++ ++extern int netdev_open(struct net_device *pnetdev); ++ ++static int cfg80211_rtw_change_iface(struct wiphy *wiphy, ++ struct net_device *ndev, ++ enum nl80211_iftype type, u32 *flags, ++ struct vif_params *params) ++{ ++ enum nl80211_iftype old_type; ++ enum NDIS_802_11_NETWORK_INFRASTRUCTURE networkType; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(ndev); ++ struct wireless_dev *rtw_wdev = padapter->rtw_wdev; ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ int ret = 0; ++ u8 change = false; ++ ++ DBG_871X(FUNC_NDEV_FMT" type =%d\n", FUNC_NDEV_ARG(ndev), type); ++ ++ if (adapter_to_dvobj(padapter)->processing_dev_remove == true) ++ { ++ ret = -EPERM; ++ goto exit; ++ } ++ ++ { ++ DBG_871X(FUNC_NDEV_FMT" call netdev_open\n", FUNC_NDEV_ARG(ndev)); ++ if (netdev_open(ndev) != 0) { ++ DBG_871X(FUNC_NDEV_FMT" call netdev_open fail\n", FUNC_NDEV_ARG(ndev)); ++ ret = -EPERM; ++ goto exit; ++ } ++ } ++ ++ if (_FAIL == rtw_pwr_wakeup(padapter)) { ++ DBG_871X(FUNC_NDEV_FMT" call rtw_pwr_wakeup fail\n", FUNC_NDEV_ARG(ndev)); ++ ret = -EPERM; ++ goto exit; ++ } ++ ++ old_type = rtw_wdev->iftype; ++ DBG_871X(FUNC_NDEV_FMT" old_iftype =%d, new_iftype =%d\n", ++ FUNC_NDEV_ARG(ndev), old_type, type); ++ ++ if (old_type != type) ++ { ++ change = true; ++ pmlmeext->action_public_rxseq = 0xffff; ++ pmlmeext->action_public_dialog_token = 0xff; ++ } ++ ++ switch (type) { ++ case NL80211_IFTYPE_ADHOC: ++ networkType = Ndis802_11IBSS; ++ break; ++ case NL80211_IFTYPE_STATION: ++ networkType = Ndis802_11Infrastructure; ++ break; ++ case NL80211_IFTYPE_AP: ++ networkType = Ndis802_11APMode; ++ break; ++ default: ++ ret = -EOPNOTSUPP; ++ goto exit; ++ } ++ ++ rtw_wdev->iftype = type; ++ ++ if (rtw_set_802_11_infrastructure_mode(padapter, networkType) ==false) ++ { ++ rtw_wdev->iftype = old_type; ++ ret = -EPERM; ++ goto exit; ++ } ++ ++ rtw_setopmode_cmd(padapter, networkType, true); ++ ++exit: ++ ++ DBG_871X(FUNC_NDEV_FMT" ret:%d\n", FUNC_NDEV_ARG(ndev), ret); ++ return ret; ++} ++ ++void rtw_cfg80211_indicate_scan_done(struct adapter *adapter, bool aborted) ++{ ++ struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(adapter); ++ ++ spin_lock_bh(&pwdev_priv->scan_req_lock); ++ if (pwdev_priv->scan_request != NULL) { ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X("%s with scan req\n", __func__); ++ #endif ++ ++ /* avoid WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); */ ++ if (pwdev_priv->scan_request->wiphy != pwdev_priv->rtw_wdev->wiphy) ++ { ++ DBG_8192C("error wiphy compare\n"); ++ } ++ else ++ { ++ cfg80211_scan_done(pwdev_priv->scan_request, aborted); ++ } ++ ++ pwdev_priv->scan_request = NULL; ++ } else { ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X("%s without scan req\n", __func__); ++ #endif ++ } ++ spin_unlock_bh(&pwdev_priv->scan_req_lock); ++} ++ ++void rtw_cfg80211_unlink_bss(struct adapter *padapter, struct wlan_network *pnetwork) ++{ ++ struct wireless_dev *pwdev = padapter->rtw_wdev; ++ struct wiphy *wiphy = pwdev->wiphy; ++ struct cfg80211_bss *bss = NULL; ++ struct wlan_bssid_ex select_network = pnetwork->network; ++ ++ bss = cfg80211_get_bss(wiphy, NULL/*notify_channel*/, ++ select_network.MacAddress, select_network.Ssid.Ssid, ++ select_network.Ssid.SsidLength, 0/*WLAN_CAPABILITY_ESS*/, ++ 0/*WLAN_CAPABILITY_ESS*/); ++ ++ if (bss) { ++ cfg80211_unlink_bss(wiphy, bss); ++ DBG_8192C("%s(): cfg80211_unlink %s!! () ", __func__, select_network.Ssid.Ssid); ++ cfg80211_put_bss(padapter->rtw_wdev->wiphy, bss); ++ } ++ return; ++} ++ ++void rtw_cfg80211_surveydone_event_callback(struct adapter *padapter) ++{ ++ struct list_head *plist, *phead; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct __queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("%s\n", __func__); ++#endif ++ ++ spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); ++ ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ while (1) ++ { ++ if (phead == plist) ++ break; ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ ++ /* report network only if the current channel set contains the channel to which this network belongs */ ++ if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, pnetwork->network.Configuration.DSConfig) >= 0 ++ && rtw_mlme_band_check(padapter, pnetwork->network.Configuration.DSConfig) == true ++ && true == rtw_validate_ssid(&(pnetwork->network.Ssid)) ++ ) ++ { ++ /* ev =translate_scan(padapter, a, pnetwork, ev, stop); */ ++ rtw_cfg80211_inform_bss(padapter, pnetwork); ++ } ++ ++ plist = get_next(plist); ++ ++ } ++ ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++} ++ ++static int rtw_cfg80211_set_probe_req_wpsp2pie(struct adapter *padapter, char *buf, int len) ++{ ++ int ret = 0; ++ uint wps_ielen = 0; ++ u8 *wps_ie; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("%s, ielen =%d\n", __func__, len); ++#endif ++ ++ if (len>0) ++ { ++ if ((wps_ie = rtw_get_wps_ie(buf, len, NULL, &wps_ielen))) ++ { ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("probe_req_wps_ielen =%d\n", wps_ielen); ++ #endif ++ ++ if (pmlmepriv->wps_probe_req_ie) ++ { ++ pmlmepriv->wps_probe_req_ie_len = 0; ++ kfree(pmlmepriv->wps_probe_req_ie); ++ pmlmepriv->wps_probe_req_ie = NULL; ++ } ++ ++ pmlmepriv->wps_probe_req_ie = rtw_malloc(wps_ielen); ++ if (pmlmepriv->wps_probe_req_ie == NULL) { ++ DBG_8192C("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__); ++ return -EINVAL; ++ ++ } ++ memcpy(pmlmepriv->wps_probe_req_ie, wps_ie, wps_ielen); ++ pmlmepriv->wps_probe_req_ie_len = wps_ielen; ++ } ++ } ++ ++ return ret; ++ ++} ++ ++static int cfg80211_rtw_scan(struct wiphy *wiphy ++ , struct cfg80211_scan_request *request) ++{ ++ struct net_device *ndev = wdev_to_ndev(request->wdev); ++ int i; ++ u8 _status = false; ++ int ret = 0; ++ struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT]; ++ struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT]; ++ u8 survey_times =3; ++ u8 survey_times_for_one_ch =6; ++ struct cfg80211_ssid *ssids = request->ssids; ++ int j = 0; ++ bool need_indicate_scan_done = false; ++ ++ struct adapter *padapter; ++ struct rtw_wdev_priv *pwdev_priv; ++ struct mlme_priv *pmlmepriv; ++ ++ if (ndev == NULL) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ padapter = (struct adapter *)rtw_netdev_priv(ndev); ++ pwdev_priv = adapter_wdev_data(padapter); ++ pmlmepriv = &padapter->mlmepriv; ++ ++/* ifdef CONFIG_DEBUG_CFG80211 */ ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); ++/* endif */ ++ ++ spin_lock_bh(&pwdev_priv->scan_req_lock); ++ pwdev_priv->scan_request = request; ++ spin_unlock_bh(&pwdev_priv->scan_req_lock); ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ++ { ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X("%s under WIFI_AP_STATE\n", __func__); ++#endif ++ ++ if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS|_FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true) ++ { ++ DBG_8192C("%s, fwstate = 0x%x\n", __func__, pmlmepriv->fw_state); ++ ++ if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) ++ { ++ DBG_8192C("AP mode process WPS\n"); ++ } ++ ++ need_indicate_scan_done = true; ++ goto check_need_indicate_scan_done; ++ } ++ } ++ ++ rtw_ps_deny(padapter, PS_DENY_SCAN); ++ if (_FAIL == rtw_pwr_wakeup(padapter)) { ++ need_indicate_scan_done = true; ++ goto check_need_indicate_scan_done; ++ } ++ ++ if (request->ie && request->ie_len>0) ++ { ++ rtw_cfg80211_set_probe_req_wpsp2pie(padapter, (u8 *)request->ie, request->ie_len); ++ } ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) { ++ DBG_8192C("%s, fwstate = 0x%x\n", __func__, pmlmepriv->fw_state); ++ need_indicate_scan_done = true; ++ goto check_need_indicate_scan_done; ++ } else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) { ++ DBG_8192C("%s, fwstate = 0x%x\n", __func__, pmlmepriv->fw_state); ++ ret = -EBUSY; ++ goto check_need_indicate_scan_done; ++ } ++ ++ if (pmlmepriv->LinkDetectInfo.bBusyTraffic == true) ++ { ++ static unsigned long lastscantime = 0; ++ unsigned long passtime; ++ ++ passtime = jiffies_to_msecs(jiffies - lastscantime); ++ lastscantime = jiffies; ++ if (passtime > 12000) ++ { ++ DBG_871X("%s: bBusyTraffic == true\n", __func__); ++ need_indicate_scan_done = true; ++ goto check_need_indicate_scan_done; ++ } ++ } ++ ++ if (rtw_is_scan_deny(padapter)) { ++ DBG_871X(FUNC_ADPT_FMT ": scan deny\n", FUNC_ADPT_ARG(padapter)); ++ need_indicate_scan_done = true; ++ goto check_need_indicate_scan_done; ++ } ++ ++ memset(ssid, 0, sizeof(struct ndis_802_11_ssid)*RTW_SSID_SCAN_AMOUNT); ++ /* parsing request ssids, n_ssids */ ++ for (i = 0; i < request->n_ssids && i < RTW_SSID_SCAN_AMOUNT; i++) { ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("ssid =%s, len =%d\n", ssids[i].ssid, ssids[i].ssid_len); ++ #endif ++ memcpy(ssid[i].Ssid, ssids[i].ssid, ssids[i].ssid_len); ++ ssid[i].SsidLength = ssids[i].ssid_len; ++ } ++ ++ /* parsing channels, n_channels */ ++ memset(ch, 0, sizeof(struct rtw_ieee80211_channel)*RTW_CHANNEL_SCAN_AMOUNT); ++ for (i = 0;in_channels && ichannels[i])); ++ #endif ++ ch[i].hw_value = request->channels[i]->hw_value; ++ ch[i].flags = request->channels[i]->flags; ++ } ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ if (request->n_channels == 1) { ++ for (i = 1;in_channels <= 4) { ++ for (j =request->n_channels-1;j>= 0;j--) ++ for (i = 0;in_channels); ++ } else { ++ _status = rtw_sitesurvey_cmd(padapter, ssid, RTW_SSID_SCAN_AMOUNT, NULL, 0); ++ } ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++ ++ if (_status == false) ++ { ++ ret = -1; ++ } ++ ++check_need_indicate_scan_done: ++ if (true == need_indicate_scan_done) ++ { ++ rtw_cfg80211_surveydone_event_callback(padapter); ++ rtw_cfg80211_indicate_scan_done(padapter, false); ++ } ++ ++ rtw_ps_deny_cancel(padapter, PS_DENY_SCAN); ++ ++exit: ++ return ret; ++ ++} ++ ++static int cfg80211_rtw_set_wiphy_params(struct wiphy *wiphy, u32 changed) ++{ ++ DBG_8192C("%s\n", __func__); ++ return 0; ++} ++ ++ ++ ++static int rtw_cfg80211_set_wpa_version(struct security_priv *psecuritypriv, u32 wpa_version) ++{ ++ DBG_8192C("%s, wpa_version =%d\n", __func__, wpa_version); ++ ++ if (!wpa_version) { ++ psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen; ++ return 0; ++ } ++ ++ ++ if (wpa_version & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) ++ { ++ psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPAPSK; ++ } ++ ++ return 0; ++ ++} ++ ++static int rtw_cfg80211_set_auth_type(struct security_priv *psecuritypriv, ++ enum nl80211_auth_type sme_auth_type) ++{ ++ DBG_8192C("%s, nl80211_auth_type =%d\n", __func__, sme_auth_type); ++ ++ ++ switch (sme_auth_type) { ++ case NL80211_AUTHTYPE_AUTOMATIC: ++ ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; ++ ++ break; ++ case NL80211_AUTHTYPE_OPEN_SYSTEM: ++ ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; ++ ++ if (psecuritypriv->ndisauthtype>Ndis802_11AuthModeWPA) ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; ++ ++ break; ++ case NL80211_AUTHTYPE_SHARED_KEY: ++ ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Shared; ++ ++ psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ ++ ++ break; ++ default: ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; ++ /* return -ENOTSUPP; */ ++ } ++ ++ return 0; ++ ++} ++ ++static int rtw_cfg80211_set_cipher(struct security_priv *psecuritypriv, u32 cipher, bool ucast) ++{ ++ u32 ndisencryptstatus = Ndis802_11EncryptionDisabled; ++ ++ u32 *profile_cipher = ucast ? &psecuritypriv->dot11PrivacyAlgrthm : ++ &psecuritypriv->dot118021XGrpPrivacy; ++ ++ DBG_8192C("%s, ucast =%d, cipher = 0x%x\n", __func__, ucast, cipher); ++ ++ ++ if (!cipher) { ++ *profile_cipher = _NO_PRIVACY_; ++ psecuritypriv->ndisencryptstatus = ndisencryptstatus; ++ return 0; ++ } ++ ++ switch (cipher) { ++ case IW_AUTH_CIPHER_NONE: ++ *profile_cipher = _NO_PRIVACY_; ++ ndisencryptstatus = Ndis802_11EncryptionDisabled; ++ break; ++ case WLAN_CIPHER_SUITE_WEP40: ++ *profile_cipher = _WEP40_; ++ ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ case WLAN_CIPHER_SUITE_WEP104: ++ *profile_cipher = _WEP104_; ++ ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ *profile_cipher = _TKIP_; ++ ndisencryptstatus = Ndis802_11Encryption2Enabled; ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ *profile_cipher = _AES_; ++ ndisencryptstatus = Ndis802_11Encryption3Enabled; ++ break; ++ default: ++ DBG_8192C("Unsupported cipher: 0x%x\n", cipher); ++ return -ENOTSUPP; ++ } ++ ++ if (ucast) ++ { ++ psecuritypriv->ndisencryptstatus = ndisencryptstatus; ++ ++ /* if (psecuritypriv->dot11PrivacyAlgrthm >= _AES_) */ ++ /* psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPA2PSK; */ ++ } ++ ++ return 0; ++} ++ ++static int rtw_cfg80211_set_key_mgt(struct security_priv *psecuritypriv, u32 key_mgt) ++{ ++ DBG_8192C("%s, key_mgt = 0x%x\n", __func__, key_mgt); ++ ++ if (key_mgt == WLAN_AKM_SUITE_8021X) ++ /* auth_type = UMAC_AUTH_TYPE_8021X; */ ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; ++ else if (key_mgt == WLAN_AKM_SUITE_PSK) { ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; ++ } ++ else { ++ DBG_8192C("Invalid key mgt: 0x%x\n", key_mgt); ++ /* return -EINVAL; */ ++ } ++ ++ return 0; ++} ++ ++static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t ielen) ++{ ++ u8 *buf = NULL, *pos = NULL; ++ int group_cipher = 0, pairwise_cipher = 0; ++ int ret = 0; ++ int wpa_ielen = 0; ++ int wpa2_ielen = 0; ++ u8 *pwpa, *pwpa2; ++ u8 null_addr[]= {0, 0, 0, 0, 0, 0}; ++ ++ if (pie == NULL || !ielen) { ++ /* Treat this as normal case, but need to clear WIFI_UNDER_WPS */ ++ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); ++ goto exit; ++ } ++ ++ if (ielen > MAX_WPA_IE_LEN+MAX_WPS_IE_LEN+MAX_P2P_IE_LEN) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ buf = rtw_zmalloc(ielen); ++ if (buf == NULL) { ++ ret = -ENOMEM; ++ goto exit; ++ } ++ ++ memcpy(buf, pie , ielen); ++ ++ /* dump */ ++ { ++ int i; ++ DBG_8192C("set wpa_ie(length:%zu):\n", ielen); ++ for (i = 0;i0) ++ { ++ if (rtw_parse_wpa_ie(pwpa, wpa_ielen+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) ++ { ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; ++ padapter->securitypriv.ndisauthtype =Ndis802_11AuthModeWPAPSK; ++ memcpy(padapter->securitypriv.supplicant_ie, &pwpa[0], wpa_ielen+2); ++ ++ DBG_8192C("got wpa_ie, wpa_ielen:%u\n", wpa_ielen); ++ } ++ } ++ ++ pwpa2 = rtw_get_wpa2_ie(buf, &wpa2_ielen, ielen); ++ if (pwpa2 && wpa2_ielen>0) ++ { ++ if (rtw_parse_wpa2_ie(pwpa2, wpa2_ielen+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) ++ { ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; ++ padapter->securitypriv.ndisauthtype =Ndis802_11AuthModeWPA2PSK; ++ memcpy(padapter->securitypriv.supplicant_ie, &pwpa2[0], wpa2_ielen+2); ++ ++ DBG_8192C("got wpa2_ie, wpa2_ielen:%u\n", wpa2_ielen); ++ } ++ } ++ ++ if (group_cipher == 0) ++ { ++ group_cipher = WPA_CIPHER_NONE; ++ } ++ if (pairwise_cipher == 0) ++ { ++ pairwise_cipher = WPA_CIPHER_NONE; ++ } ++ ++ switch (group_cipher) ++ { ++ case WPA_CIPHER_NONE: ++ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; ++ padapter->securitypriv.ndisencryptstatus =Ndis802_11EncryptionDisabled; ++ break; ++ case WPA_CIPHER_WEP40: ++ padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ case WPA_CIPHER_TKIP: ++ padapter->securitypriv.dot118021XGrpPrivacy = _TKIP_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; ++ break; ++ case WPA_CIPHER_CCMP: ++ padapter->securitypriv.dot118021XGrpPrivacy = _AES_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; ++ break; ++ case WPA_CIPHER_WEP104: ++ padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ } ++ ++ switch (pairwise_cipher) ++ { ++ case WPA_CIPHER_NONE: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ padapter->securitypriv.ndisencryptstatus =Ndis802_11EncryptionDisabled; ++ break; ++ case WPA_CIPHER_WEP40: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ case WPA_CIPHER_TKIP: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _TKIP_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; ++ break; ++ case WPA_CIPHER_CCMP: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _AES_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; ++ break; ++ case WPA_CIPHER_WEP104: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ } ++ ++ {/* handle wps_ie */ ++ uint wps_ielen; ++ u8 *wps_ie; ++ ++ wps_ie = rtw_get_wps_ie(buf, ielen, NULL, &wps_ielen); ++ if (wps_ie && wps_ielen > 0) { ++ DBG_8192C("got wps_ie, wps_ielen:%u\n", wps_ielen); ++ padapter->securitypriv.wps_ie_len = wps_ielensecuritypriv.wps_ie, wps_ie, padapter->securitypriv.wps_ie_len); ++ set_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS); ++ } else { ++ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); ++ } ++ } ++ ++ /* TKIP and AES disallow multicast packets until installing group key */ ++ if (padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_ ++ || padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_WTMIC_ ++ || padapter->securitypriv.dot11PrivacyAlgrthm == _AES_) ++ /* WPS open need to enable multicast */ ++ /* check_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS) == true) */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_OFF_RCR_AM, null_addr); ++ ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ++ ("rtw_set_wpa_ie: pairwise_cipher = 0x%08x padapter->securitypriv.ndisencryptstatus =%d padapter->securitypriv.ndisauthtype =%d\n", ++ pairwise_cipher, padapter->securitypriv.ndisencryptstatus, padapter->securitypriv.ndisauthtype)); ++ ++exit: ++ if (buf) ++ kfree(buf); ++ if (ret) ++ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); ++ return ret; ++} ++ ++static int cfg80211_rtw_join_ibss(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_ibss_params *params) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(ndev); ++ struct ndis_802_11_ssid ndis_ssid; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ int ret = 0; ++ ++ if (_FAIL == rtw_pwr_wakeup(padapter)) { ++ ret = -EPERM; ++ goto exit; ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ ret = -EPERM; ++ goto exit; ++ } ++ ++ if (!params->ssid || !params->ssid_len) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (params->ssid_len > IW_ESSID_MAX_SIZE) { ++ ++ ret = -E2BIG; ++ goto exit; ++ } ++ ++ memset(&ndis_ssid, 0, sizeof(struct ndis_802_11_ssid)); ++ ndis_ssid.SsidLength = params->ssid_len; ++ memcpy(ndis_ssid.Ssid, (u8 *)params->ssid, params->ssid_len); ++ ++ /* DBG_8192C("ssid =%s, len =%zu\n", ndis_ssid.Ssid, params->ssid_len); */ ++ ++ psecuritypriv->ndisencryptstatus = Ndis802_11EncryptionDisabled; ++ psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */ ++ psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen; ++ ++ ret = rtw_cfg80211_set_auth_type(psecuritypriv, NL80211_AUTHTYPE_OPEN_SYSTEM); ++ rtw_set_802_11_authentication_mode(padapter, psecuritypriv->ndisauthtype); ++ ++ if (rtw_set_802_11_ssid(padapter, &ndis_ssid) == false) ++ { ++ ret = -1; ++ goto exit; ++ } ++ ++exit: ++ return ret; ++} ++ ++static int cfg80211_rtw_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(ndev); ++ struct wireless_dev *rtw_wdev = padapter->rtw_wdev; ++ enum nl80211_iftype old_type; ++ int ret = 0; ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ padapter->mlmepriv.not_indic_disco = true; ++ ++ old_type = rtw_wdev->iftype; ++ ++ rtw_set_to_roam(padapter, 0); ++ ++ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) ++ { ++ rtw_scan_abort(padapter); ++ LeaveAllPowerSaveMode(padapter); ++ ++ rtw_wdev->iftype = NL80211_IFTYPE_STATION; ++ ++ if (rtw_set_802_11_infrastructure_mode(padapter, Ndis802_11Infrastructure) ==false) ++ { ++ rtw_wdev->iftype = old_type; ++ ret = -EPERM; ++ goto leave_ibss; ++ } ++ rtw_setopmode_cmd(padapter, Ndis802_11Infrastructure, true); ++ } ++ ++leave_ibss: ++ padapter->mlmepriv.not_indic_disco = false; ++ ++ return 0; ++} ++ ++static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_connect_params *sme) ++{ ++ int ret = 0; ++ enum NDIS_802_11_AUTHENTICATION_MODE authmode; ++ struct ndis_802_11_ssid ndis_ssid; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(ndev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ padapter->mlmepriv.not_indic_disco = true; ++ ++ DBG_871X("=>"FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ DBG_871X("privacy =%d, key =%p, key_len =%d, key_idx =%d\n", ++ sme->privacy, sme->key, sme->key_len, sme->key_idx); ++ ++ ++ if (adapter_wdev_data(padapter)->block == true) ++ { ++ ret = -EBUSY; ++ DBG_871X("%s wdev_priv.block is set\n", __func__); ++ goto exit; ++ } ++ ++ rtw_ps_deny(padapter, PS_DENY_JOIN); ++ if (_FAIL == rtw_pwr_wakeup(padapter)) { ++ ret = -EPERM; ++ goto exit; ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ ret = -EPERM; ++ goto exit; ++ } ++ ++ if (!sme->ssid || !sme->ssid_len) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (sme->ssid_len > IW_ESSID_MAX_SIZE) { ++ ++ ret = -E2BIG; ++ goto exit; ++ } ++ ++ memset(&ndis_ssid, 0, sizeof(struct ndis_802_11_ssid)); ++ ndis_ssid.SsidLength = sme->ssid_len; ++ memcpy(ndis_ssid.Ssid, (u8 *)sme->ssid, sme->ssid_len); ++ ++ DBG_8192C("ssid =%s, len =%zu\n", ndis_ssid.Ssid, sme->ssid_len); ++ ++ ++ if (sme->bssid) ++ DBG_8192C("bssid ="MAC_FMT"\n", MAC_ARG(sme->bssid)); ++ ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) { ++ ret = -EBUSY; ++ DBG_8192C("%s, fw_state = 0x%x, goto exit\n", __func__, pmlmepriv->fw_state); ++ goto exit; ++ } ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) { ++ rtw_scan_abort(padapter); ++ } ++ ++ psecuritypriv->ndisencryptstatus = Ndis802_11EncryptionDisabled; ++ psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */ ++ psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen; ++ ++ ret = rtw_cfg80211_set_wpa_version(psecuritypriv, sme->crypto.wpa_versions); ++ if (ret < 0) ++ goto exit; ++ ++ ret = rtw_cfg80211_set_auth_type(psecuritypriv, sme->auth_type); ++ ++ if (ret < 0) ++ goto exit; ++ ++ DBG_8192C("%s, ie_len =%zu\n", __func__, sme->ie_len); ++ ++ ret = rtw_cfg80211_set_wpa_ie(padapter, (u8 *)sme->ie, sme->ie_len); ++ if (ret < 0) ++ goto exit; ++ ++ if (sme->crypto.n_ciphers_pairwise) { ++ ret = rtw_cfg80211_set_cipher(psecuritypriv, sme->crypto.ciphers_pairwise[0], true); ++ if (ret < 0) ++ goto exit; ++ } ++ ++ /* For WEP Shared auth */ ++ if ((psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_Shared ++ || psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_Auto) && sme->key ++ ) ++ { ++ u32 wep_key_idx, wep_key_len, wep_total_len; ++ struct ndis_802_11_wep *pwep = NULL; ++ DBG_871X("%s(): Shared/Auto WEP\n", __func__); ++ ++ wep_key_idx = sme->key_idx; ++ wep_key_len = sme->key_len; ++ ++ if (sme->key_idx > WEP_KEYS) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (wep_key_len > 0) ++ { ++ wep_key_len = wep_key_len <= 5 ? 5 : 13; ++ wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial); ++ pwep =(struct ndis_802_11_wep *) rtw_malloc(wep_total_len); ++ if (pwep == NULL) { ++ DBG_871X(" wpa_set_encryption: pwep allocate fail !!!\n"); ++ ret = -ENOMEM; ++ goto exit; ++ } ++ ++ memset(pwep, 0, wep_total_len); ++ ++ pwep->KeyLength = wep_key_len; ++ pwep->Length = wep_total_len; ++ ++ if (wep_key_len == 13) ++ { ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; ++ padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_; ++ } ++ } ++ else { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ pwep->KeyIndex = wep_key_idx; ++ pwep->KeyIndex |= 0x80000000; ++ ++ memcpy(pwep->KeyMaterial, (void *)sme->key, pwep->KeyLength); ++ ++ if (rtw_set_802_11_add_wep(padapter, pwep) == (u8)_FAIL) ++ { ++ ret = -EOPNOTSUPP ; ++ } ++ ++ kfree((u8 *)pwep); ++ ++ if (ret < 0) ++ goto exit; ++ } ++ ++ ret = rtw_cfg80211_set_cipher(psecuritypriv, sme->crypto.cipher_group, false); ++ if (ret < 0) ++ return ret; ++ ++ if (sme->crypto.n_akm_suites) { ++ ret = rtw_cfg80211_set_key_mgt(psecuritypriv, sme->crypto.akm_suites[0]); ++ if (ret < 0) ++ goto exit; ++ } ++ ++ authmode = psecuritypriv->ndisauthtype; ++ rtw_set_802_11_authentication_mode(padapter, authmode); ++ ++ /* rtw_set_802_11_encryption_mode(padapter, padapter->securitypriv.ndisencryptstatus); */ ++ ++ if (rtw_set_802_11_connect(padapter, (u8 *)sme->bssid, &ndis_ssid) == false) { ++ ret = -1; ++ goto exit; ++ } ++ ++ DBG_8192C("set ssid:dot11AuthAlgrthm =%d, dot11PrivacyAlgrthm =%d, dot118021XGrpPrivacy =%d\n", psecuritypriv->dot11AuthAlgrthm, psecuritypriv->dot11PrivacyAlgrthm, psecuritypriv->dot118021XGrpPrivacy); ++ ++exit: ++ ++ rtw_ps_deny_cancel(padapter, PS_DENY_JOIN); ++ ++ DBG_8192C("<=%s, ret %d\n", __func__, ret); ++ ++ padapter->mlmepriv.not_indic_disco = false; ++ ++ return ret; ++} ++ ++static int cfg80211_rtw_disconnect(struct wiphy *wiphy, struct net_device *ndev, ++ u16 reason_code) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(ndev); ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ padapter->mlmepriv.not_indic_disco = true; ++ ++ rtw_set_to_roam(padapter, 0); ++ ++ rtw_scan_abort(padapter); ++ LeaveAllPowerSaveMode(padapter); ++ rtw_disassoc_cmd(padapter, 500, false); ++ ++ DBG_871X("%s...call rtw_indicate_disconnect\n", __func__); ++ ++ rtw_indicate_disconnect(padapter); ++ ++ rtw_free_assoc_resources(padapter, 1); ++ rtw_pwr_wakeup(padapter); ++ ++ padapter->mlmepriv.not_indic_disco = false; ++ ++ DBG_871X(FUNC_NDEV_FMT" return 0\n", FUNC_NDEV_ARG(ndev)); ++ return 0; ++} ++ ++static int cfg80211_rtw_set_txpower(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ enum nl80211_tx_power_setting type, int mbm) ++{ ++ DBG_8192C("%s\n", __func__); ++ return 0; ++} ++ ++static int cfg80211_rtw_get_txpower(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ int *dbm) ++{ ++ DBG_8192C("%s\n", __func__); ++ ++ *dbm = (12); ++ ++ return 0; ++} ++ ++inline bool rtw_cfg80211_pwr_mgmt(struct adapter *adapter) ++{ ++ struct rtw_wdev_priv *rtw_wdev_priv = adapter_wdev_data(adapter); ++ return rtw_wdev_priv->power_mgmt; ++} ++ ++static int cfg80211_rtw_set_power_mgmt(struct wiphy *wiphy, ++ struct net_device *ndev, ++ bool enabled, int timeout) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(ndev); ++ struct rtw_wdev_priv *rtw_wdev_priv = adapter_wdev_data(padapter); ++ ++ DBG_871X(FUNC_NDEV_FMT" enabled:%u, timeout:%d\n", FUNC_NDEV_ARG(ndev), ++ enabled, timeout); ++ ++ rtw_wdev_priv->power_mgmt = enabled; ++ ++ if (!enabled) ++ LPS_Leave(padapter, "CFG80211_PWRMGMT"); ++ ++ return 0; ++} ++ ++static int cfg80211_rtw_set_pmksa(struct wiphy *wiphy, ++ struct net_device *ndev, ++ struct cfg80211_pmksa *pmksa) ++{ ++ u8 index, blInserted = false; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(ndev); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ u8 strZeroMacAddress[ ETH_ALEN ] = { 0x00 }; ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ if (!memcmp((u8 *)pmksa->bssid, strZeroMacAddress, ETH_ALEN)) ++ { ++ return -EINVAL; ++ } ++ ++ blInserted = false; ++ ++ /* overwrite PMKID */ ++ for (index = 0 ; indexPMKIDList[index].Bssid, (u8 *)pmksa->bssid, ETH_ALEN)) ++ { /* BSSID is matched, the same AP => rewrite with new PMKID. */ ++ DBG_871X(FUNC_NDEV_FMT" BSSID exists in the PMKList.\n", FUNC_NDEV_ARG(ndev)); ++ ++ memcpy(psecuritypriv->PMKIDList[index].PMKID, (u8 *)pmksa->pmkid, WLAN_PMKID_LEN); ++ psecuritypriv->PMKIDList[index].bUsed = true; ++ psecuritypriv->PMKIDIndex = index+1; ++ blInserted = true; ++ break; ++ } ++ } ++ ++ if (!blInserted) ++ { ++ /* Find a new entry */ ++ DBG_871X(FUNC_NDEV_FMT" Use the new entry index = %d for this PMKID.\n", ++ FUNC_NDEV_ARG(ndev), psecuritypriv->PMKIDIndex); ++ ++ memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].Bssid, (u8 *)pmksa->bssid, ETH_ALEN); ++ memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].PMKID, (u8 *)pmksa->pmkid, WLAN_PMKID_LEN); ++ ++ psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].bUsed = true; ++ psecuritypriv->PMKIDIndex++ ; ++ if (psecuritypriv->PMKIDIndex == 16) ++ { ++ psecuritypriv->PMKIDIndex = 0; ++ } ++ } ++ ++ return 0; ++} ++ ++static int cfg80211_rtw_del_pmksa(struct wiphy *wiphy, ++ struct net_device *ndev, ++ struct cfg80211_pmksa *pmksa) ++{ ++ u8 index, bMatched = false; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(ndev); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ for (index = 0 ; indexPMKIDList[index].Bssid, (u8 *)pmksa->bssid, ETH_ALEN)) ++ { /* BSSID is matched, the same AP => Remove this PMKID information and reset it. */ ++ memset(psecuritypriv->PMKIDList[index].Bssid, 0x00, ETH_ALEN); ++ memset(psecuritypriv->PMKIDList[index].PMKID, 0x00, WLAN_PMKID_LEN); ++ psecuritypriv->PMKIDList[index].bUsed = false; ++ bMatched = true; ++ break; ++ } ++ } ++ ++ if (false == bMatched) ++ { ++ DBG_871X(FUNC_NDEV_FMT" do not have matched BSSID\n" ++ , FUNC_NDEV_ARG(ndev)); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int cfg80211_rtw_flush_pmksa(struct wiphy *wiphy, ++ struct net_device *ndev) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(ndev); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ memset(&psecuritypriv->PMKIDList[ 0 ], 0x00, sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE); ++ psecuritypriv->PMKIDIndex = 0; ++ ++ return 0; ++} ++ ++void rtw_cfg80211_indicate_sta_assoc(struct adapter *padapter, u8 *pmgmt_frame, uint frame_len) ++{ ++ struct net_device *ndev = padapter->pnetdev; ++ ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); ++ ++ { ++ struct station_info sinfo; ++ u8 ie_offset; ++ if (GetFrameSubType(pmgmt_frame) == WIFI_ASSOCREQ) ++ ie_offset = _ASOCREQ_IE_OFFSET_; ++ else /* WIFI_REASSOCREQ */ ++ ie_offset = _REASOCREQ_IE_OFFSET_; ++ ++ sinfo.filled = 0; ++ sinfo.assoc_req_ies = pmgmt_frame + WLAN_HDR_A3_LEN + ie_offset; ++ sinfo.assoc_req_ies_len = frame_len - WLAN_HDR_A3_LEN - ie_offset; ++ cfg80211_new_sta(ndev, GetAddr2Ptr(pmgmt_frame), &sinfo, GFP_ATOMIC); ++ } ++} ++ ++void rtw_cfg80211_indicate_sta_disassoc(struct adapter *padapter, unsigned char *da, unsigned short reason) ++{ ++ struct net_device *ndev = padapter->pnetdev; ++ ++ DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); ++ ++ cfg80211_del_sta(ndev, da, GFP_ATOMIC); ++} ++ ++static int rtw_cfg80211_monitor_if_open(struct net_device *ndev) ++{ ++ int ret = 0; ++ ++ DBG_8192C("%s\n", __func__); ++ ++ return ret; ++} ++ ++static int rtw_cfg80211_monitor_if_close(struct net_device *ndev) ++{ ++ int ret = 0; ++ ++ DBG_8192C("%s\n", __func__); ++ ++ return ret; ++} ++ ++static int rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struct net_device *ndev) ++{ ++ int ret = 0; ++ int rtap_len; ++ int qos_len = 0; ++ int dot11_hdr_len = 24; ++ int snap_len = 6; ++ unsigned char *pdata; ++ u16 frame_control; ++ unsigned char src_mac_addr[6]; ++ unsigned char dst_mac_addr[6]; ++ struct ieee80211_hdr *dot11_hdr; ++ struct ieee80211_radiotap_header *rtap_hdr; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(ndev); ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ if (skb) ++ rtw_mstat_update(MSTAT_TYPE_SKB, MSTAT_ALLOC_SUCCESS, skb->truesize); ++ ++ if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) ++ goto fail; ++ ++ rtap_hdr = (struct ieee80211_radiotap_header *)skb->data; ++ if (unlikely(rtap_hdr->it_version)) ++ goto fail; ++ ++ rtap_len = ieee80211_get_radiotap_len(skb->data); ++ if (unlikely(skb->len < rtap_len)) ++ goto fail; ++ ++ if (rtap_len != 14) ++ { ++ DBG_8192C("radiotap len (should be 14): %d\n", rtap_len); ++ goto fail; ++ } ++ ++ /* Skip the ratio tap header */ ++ skb_pull(skb, rtap_len); ++ ++ dot11_hdr = (struct ieee80211_hdr *)skb->data; ++ frame_control = le16_to_cpu(dot11_hdr->frame_control); ++ /* Check if the QoS bit is set */ ++ if ((frame_control & RTW_IEEE80211_FCTL_FTYPE) == RTW_IEEE80211_FTYPE_DATA) { ++ /* Check if this ia a Wireless Distribution System (WDS) frame ++ * which has 4 MAC addresses ++ */ ++ if (frame_control & 0x0080) ++ qos_len = 2; ++ if ((frame_control & 0x0300) == 0x0300) ++ dot11_hdr_len += 6; ++ ++ memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr)); ++ memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr)); ++ ++ /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for ++ * for two MAC addresses ++ */ ++ skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2); ++ pdata = (unsigned char*)skb->data; ++ memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr)); ++ memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr)); ++ ++ DBG_8192C("should be eapol packet\n"); ++ ++ /* Use the real net device to transmit the packet */ ++ ret = _rtw_xmit_entry(skb, padapter->pnetdev); ++ ++ return ret; ++ ++ } ++ else if ((frame_control & (RTW_IEEE80211_FCTL_FTYPE|RTW_IEEE80211_FCTL_STYPE)) ++ == (RTW_IEEE80211_FTYPE_MGMT|RTW_IEEE80211_STYPE_ACTION) ++ ) ++ { ++ /* only for action frames */ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ /* u8 category, action, OUI_Subtype, dialogToken = 0; */ ++ /* unsigned char *frame_body; */ ++ struct ieee80211_hdr *pwlanhdr; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ u8 *buf = skb->data; ++ u32 len = skb->len; ++ u8 category, action; ++ ++ if (rtw_action_frame_parse(buf, len, &category, &action) == false) { ++ DBG_8192C(FUNC_NDEV_FMT" frame_control:0x%x\n", FUNC_NDEV_ARG(ndev), ++ le16_to_cpu(((struct ieee80211_hdr_3addr *)buf)->frame_control)); ++ goto fail; ++ } ++ ++ DBG_8192C("RTW_Tx:da ="MAC_FMT" via "FUNC_NDEV_FMT"\n", ++ MAC_ARG(GetAddr1Ptr(buf)), FUNC_NDEV_ARG(ndev)); ++ if (category == RTW_WLAN_CATEGORY_PUBLIC) ++ DBG_871X("RTW_Tx:%s\n", action_public_str(action)); ++ else ++ DBG_871X("RTW_Tx:category(%u), action(%u)\n", category, action); ++ ++ /* starting alloc mgmt frame to dump it */ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ goto fail; ++ } ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ pattrib->retry_ctrl = false; ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ ++ memcpy(pframe, (void*)buf, len); ++ pattrib->pktlen = len; ++ ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ /* update seq number */ ++ pmlmeext->mgnt_seq = GetSequence(pwlanhdr); ++ pattrib->seqnum = pmlmeext->mgnt_seq; ++ pmlmeext->mgnt_seq++; ++ ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++ ++ } ++ else ++ { ++ DBG_8192C("frame_control = 0x%x\n", frame_control & (RTW_IEEE80211_FCTL_FTYPE|RTW_IEEE80211_FCTL_STYPE)); ++ } ++ ++ ++fail: ++ ++ dev_kfree_skb_any(skb); ++ ++ return 0; ++ ++} ++ ++static int rtw_cfg80211_monitor_if_set_mac_address(struct net_device *ndev, void *addr) ++{ ++ int ret = 0; ++ ++ DBG_8192C("%s\n", __func__); ++ ++ return ret; ++} ++ ++static const struct net_device_ops rtw_cfg80211_monitor_if_ops = { ++ .ndo_open = rtw_cfg80211_monitor_if_open, ++ .ndo_stop = rtw_cfg80211_monitor_if_close, ++ .ndo_start_xmit = rtw_cfg80211_monitor_if_xmit_entry, ++ .ndo_set_mac_address = rtw_cfg80211_monitor_if_set_mac_address, ++}; ++ ++static int rtw_cfg80211_add_monitor_if (struct adapter *padapter, char *name, struct net_device **ndev) ++{ ++ int ret = 0; ++ struct net_device* mon_ndev = NULL; ++ struct wireless_dev* mon_wdev = NULL; ++ struct rtw_netdev_priv_indicator *pnpi; ++ struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(padapter); ++ ++ if (!name) { ++ DBG_871X(FUNC_ADPT_FMT" without specific name\n", FUNC_ADPT_ARG(padapter)); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ if (pwdev_priv->pmon_ndev) { ++ DBG_871X(FUNC_ADPT_FMT" monitor interface exist: "NDEV_FMT"\n", ++ FUNC_ADPT_ARG(padapter), NDEV_ARG(pwdev_priv->pmon_ndev)); ++ ret = -EBUSY; ++ goto out; ++ } ++ ++ mon_ndev = alloc_etherdev(sizeof(struct rtw_netdev_priv_indicator)); ++ if (!mon_ndev) { ++ DBG_871X(FUNC_ADPT_FMT" allocate ndev fail\n", FUNC_ADPT_ARG(padapter)); ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ mon_ndev->type = ARPHRD_IEEE80211_RADIOTAP; ++ strncpy(mon_ndev->name, name, IFNAMSIZ); ++ mon_ndev->name[IFNAMSIZ - 1] = 0; ++ mon_ndev->destructor = rtw_ndev_destructor; ++ ++ mon_ndev->netdev_ops = &rtw_cfg80211_monitor_if_ops; ++ ++ pnpi = netdev_priv(mon_ndev); ++ pnpi->priv = padapter; ++ pnpi->sizeof_priv = sizeof(struct adapter); ++ ++ /* wdev */ ++ mon_wdev = (struct wireless_dev *)rtw_zmalloc(sizeof(struct wireless_dev)); ++ if (!mon_wdev) { ++ DBG_871X(FUNC_ADPT_FMT" allocate mon_wdev fail\n", FUNC_ADPT_ARG(padapter)); ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ mon_wdev->wiphy = padapter->rtw_wdev->wiphy; ++ mon_wdev->netdev = mon_ndev; ++ mon_wdev->iftype = NL80211_IFTYPE_MONITOR; ++ mon_ndev->ieee80211_ptr = mon_wdev; ++ ++ ret = register_netdevice(mon_ndev); ++ if (ret) { ++ goto out; ++ } ++ ++ *ndev = pwdev_priv->pmon_ndev = mon_ndev; ++ memcpy(pwdev_priv->ifname_mon, name, IFNAMSIZ+1); ++ ++out: ++ if (ret && mon_wdev) { ++ kfree((u8 *)mon_wdev); ++ mon_wdev = NULL; ++ } ++ ++ if (ret && mon_ndev) { ++ free_netdev(mon_ndev); ++ *ndev = mon_ndev = NULL; ++ } ++ ++ return ret; ++} ++ ++static struct wireless_dev * ++ cfg80211_rtw_add_virtual_intf( ++ struct wiphy *wiphy, ++ const char *name, ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) ++ unsigned char name_assign_type, ++ #endif ++ enum nl80211_iftype type, u32 *flags, struct vif_params *params) ++{ ++ int ret = 0; ++ struct net_device* ndev = NULL; ++ struct adapter *padapter = wiphy_to_adapter(wiphy); ++ ++ DBG_871X(FUNC_ADPT_FMT " wiphy:%s, name:%s, type:%d\n", ++ FUNC_ADPT_ARG(padapter), wiphy_name(wiphy), name, type); ++ ++ switch (type) { ++ case NL80211_IFTYPE_ADHOC: ++ case NL80211_IFTYPE_AP_VLAN: ++ case NL80211_IFTYPE_WDS: ++ case NL80211_IFTYPE_MESH_POINT: ++ ret = -ENODEV; ++ break; ++ case NL80211_IFTYPE_MONITOR: ++ ret = rtw_cfg80211_add_monitor_if(padapter, (char *)name, &ndev); ++ break; ++ case NL80211_IFTYPE_P2P_CLIENT: ++ case NL80211_IFTYPE_STATION: ++ ret = -ENODEV; ++ break; ++ case NL80211_IFTYPE_P2P_GO: ++ case NL80211_IFTYPE_AP: ++ ret = -ENODEV; ++ break; ++ default: ++ ret = -ENODEV; ++ DBG_871X("Unsupported interface type\n"); ++ break; ++ } ++ ++ DBG_871X(FUNC_ADPT_FMT" ndev:%p, ret:%d\n", FUNC_ADPT_ARG(padapter), ndev, ret); ++ ++ return ndev ? ndev->ieee80211_ptr : ERR_PTR(ret); ++} ++ ++static int cfg80211_rtw_del_virtual_intf(struct wiphy *wiphy, ++ struct wireless_dev *wdev ++) ++{ ++ struct net_device *ndev = wdev_to_ndev(wdev); ++ int ret = 0; ++ struct adapter *adapter; ++ struct rtw_wdev_priv *pwdev_priv; ++ ++ if (!ndev) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ adapter = (struct adapter *)rtw_netdev_priv(ndev); ++ pwdev_priv = adapter_wdev_data(adapter); ++ ++ unregister_netdevice(ndev); ++ ++ if (ndev == pwdev_priv->pmon_ndev) { ++ pwdev_priv->pmon_ndev = NULL; ++ pwdev_priv->ifname_mon[0] = '\0'; ++ DBG_871X(FUNC_NDEV_FMT" remove monitor interface\n", FUNC_NDEV_ARG(ndev)); ++ } ++ ++exit: ++ return ret; ++} ++ ++static int rtw_add_beacon(struct adapter *adapter, const u8 *head, size_t head_len, const u8 *tail, size_t tail_len) ++{ ++ int ret = 0; ++ u8 *pbuf = NULL; ++ uint len, wps_ielen = 0; ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ ++ DBG_8192C("%s beacon_head_len =%zu, beacon_tail_len =%zu\n", __func__, head_len, tail_len); ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) ++ return -EINVAL; ++ ++ if (head_len<24) ++ return -EINVAL; ++ ++ pbuf = rtw_zmalloc(head_len+tail_len); ++ if (!pbuf) ++ return -ENOMEM; ++ ++ memcpy(pbuf, (void *)head+24, head_len-24);/* 24 =beacon header len. */ ++ memcpy(pbuf+head_len-24, (void *)tail, tail_len); ++ ++ len = head_len+tail_len-24; ++ ++ /* check wps ie if inclued */ ++ if (rtw_get_wps_ie(pbuf+_FIXED_IE_LENGTH_, len-_FIXED_IE_LENGTH_, NULL, &wps_ielen)) ++ DBG_8192C("add bcn, wps_ielen =%d\n", wps_ielen); ++ ++ /* pbss_network->IEs will not include p2p_ie, wfd ie */ ++ rtw_ies_remove_ie(pbuf, &len, _BEACON_IE_OFFSET_, _VENDOR_SPECIFIC_IE_, P2P_OUI, 4); ++ rtw_ies_remove_ie(pbuf, &len, _BEACON_IE_OFFSET_, _VENDOR_SPECIFIC_IE_, WFD_OUI, 4); ++ ++ if (rtw_check_beacon_data(adapter, pbuf, len) == _SUCCESS) ++ { ++ ret = 0; ++ } ++ else ++ { ++ ret = -EINVAL; ++ } ++ ++ ++ kfree(pbuf); ++ ++ return ret; ++} ++ ++static int cfg80211_rtw_start_ap(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_ap_settings *settings) ++{ ++ int ret = 0; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(ndev); ++ ++ DBG_871X(FUNC_NDEV_FMT" hidden_ssid:%d, auth_type:%d\n", FUNC_NDEV_ARG(ndev), ++ settings->hidden_ssid, settings->auth_type); ++ ++ ret = rtw_add_beacon(adapter, settings->beacon.head, settings->beacon.head_len, ++ settings->beacon.tail, settings->beacon.tail_len); ++ ++ adapter->mlmeextpriv.mlmext_info.hidden_ssid_mode = settings->hidden_ssid; ++ ++ if (settings->ssid && settings->ssid_len) { ++ struct wlan_bssid_ex *pbss_network = &adapter->mlmepriv.cur_network.network; ++ struct wlan_bssid_ex *pbss_network_ext = &adapter->mlmeextpriv.mlmext_info.network; ++ ++ if (0) ++ DBG_871X(FUNC_ADPT_FMT" ssid:(%s,%zu), from ie:(%s,%d)\n", FUNC_ADPT_ARG(adapter), ++ settings->ssid, settings->ssid_len, ++ pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength); ++ ++ memcpy(pbss_network->Ssid.Ssid, (void *)settings->ssid, settings->ssid_len); ++ pbss_network->Ssid.SsidLength = settings->ssid_len; ++ memcpy(pbss_network_ext->Ssid.Ssid, (void *)settings->ssid, settings->ssid_len); ++ pbss_network_ext->Ssid.SsidLength = settings->ssid_len; ++ ++ if (0) ++ DBG_871X(FUNC_ADPT_FMT" after ssid:(%s,%d), (%s,%d)\n", FUNC_ADPT_ARG(adapter), ++ pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength, ++ pbss_network_ext->Ssid.Ssid, pbss_network_ext->Ssid.SsidLength); ++ } ++ ++ return ret; ++} ++ ++static int cfg80211_rtw_change_beacon(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_beacon_data *info) ++{ ++ int ret = 0; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(ndev); ++ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ ret = rtw_add_beacon(adapter, info->head, info->head_len, info->tail, info->tail_len); ++ ++ return ret; ++} ++ ++static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev) ++{ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ return 0; ++} ++ ++static int cfg80211_rtw_add_station(struct wiphy *wiphy, struct net_device *ndev, ++ const u8 *mac, ++ struct station_parameters *params) ++{ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ return 0; ++} ++ ++static int cfg80211_rtw_del_station(struct wiphy *wiphy, struct net_device *ndev, ++ struct station_del_parameters *params) ++{ ++ int ret = 0; ++ struct list_head *phead, *plist; ++ u8 updated = false; ++ struct sta_info *psta = NULL; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(ndev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ const u8 *mac = params->mac; ++ ++ DBG_871X("+"FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) ++ { ++ DBG_8192C("%s, fw_state != FW_LINKED|WIFI_AP_STATE\n", __func__); ++ return -EINVAL; ++ } ++ ++ ++ if (!mac) ++ { ++ DBG_8192C("flush all sta, and cam_entry\n"); ++ ++ flush_all_cam_entry(padapter); /* clear CAM */ ++ ++ ret = rtw_sta_flush(padapter); ++ ++ return ret; ++ } ++ ++ ++ DBG_8192C("free sta macaddr =" MAC_FMT "\n", MAC_ARG(mac)); ++ ++ if (mac[0] == 0xff && mac[1] == 0xff && ++ mac[2] == 0xff && mac[3] == 0xff && ++ mac[4] == 0xff && mac[5] == 0xff) ++ { ++ return -EINVAL; ++ } ++ ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ ++ phead = &pstapriv->asoc_list; ++ plist = get_next(phead); ++ ++ /* check asoc_queue */ ++ while (phead != plist) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); ++ ++ plist = get_next(plist); ++ ++ if (!memcmp((u8 *)mac, psta->hwaddr, ETH_ALEN)) ++ { ++ if (psta->dot8021xalg == 1 && psta->bpairwise_key_installed == false) ++ { ++ DBG_8192C("%s, sta's dot8021xalg = 1 and key_installed = false\n", __func__); ++ } ++ else ++ { ++ DBG_8192C("free psta =%p, aid =%d\n", psta, psta->aid); ++ ++ list_del_init(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ ++ updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING); ++ ++ psta = NULL; ++ ++ break; ++ } ++ ++ } ++ ++ } ++ ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ associated_clients_update(padapter, updated); ++ ++ DBG_871X("-"FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ return ret; ++ ++} ++ ++static int cfg80211_rtw_change_station(struct wiphy *wiphy, struct net_device *ndev, ++ const u8 *mac, struct station_parameters *params) ++{ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ return 0; ++} ++ ++static struct sta_info *rtw_sta_info_get_by_idx(const int idx, struct sta_priv *pstapriv) ++ ++{ ++ struct list_head *phead, *plist; ++ struct sta_info *psta = NULL; ++ int i = 0; ++ ++ phead = &pstapriv->asoc_list; ++ plist = get_next(phead); ++ ++ /* check asoc_queue */ ++ while (phead != plist) ++ { ++ if (idx == i) psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); ++ plist = get_next(plist); ++ i++; ++ } ++ return psta; ++} ++ ++static int cfg80211_rtw_dump_station(struct wiphy *wiphy, struct net_device *ndev, ++ int idx, u8 *mac, struct station_info *sinfo) ++{ ++ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(ndev); ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ psta = rtw_sta_info_get_by_idx(idx, pstapriv); ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ if (NULL == psta) ++ { ++ DBG_871X("Station is not found\n"); ++ ret = -ENOENT; ++ goto exit; ++ } ++ memcpy(mac, psta->hwaddr, ETH_ALEN); ++ sinfo->filled = BIT(NL80211_STA_INFO_SIGNAL); ++ sinfo->signal = psta->rssi; ++ ++exit: ++ return ret; ++} ++ ++static int cfg80211_rtw_change_bss(struct wiphy *wiphy, struct net_device *ndev, ++ struct bss_parameters *params) ++{ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ return 0; ++} ++ ++void rtw_cfg80211_rx_action(struct adapter *adapter, u8 *frame, uint frame_len, const char*msg) ++{ ++ s32 freq; ++ int channel; ++ u8 category, action; ++ ++ channel = rtw_get_oper_ch(adapter); ++ ++ rtw_action_frame_parse(frame, frame_len, &category, &action); ++ ++ DBG_8192C("RTW_Rx:cur_ch =%d\n", channel); ++ if (msg) ++ DBG_871X("RTW_Rx:%s\n", msg); ++ else ++ DBG_871X("RTW_Rx:category(%u), action(%u)\n", category, action); ++ ++ freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); ++ ++ rtw_cfg80211_rx_mgmt(adapter, freq, 0, frame, frame_len, GFP_ATOMIC); ++} ++ ++static int _cfg80211_rtw_mgmt_tx(struct adapter *padapter, u8 tx_ch, const u8 *buf, size_t len) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ int ret = _FAIL; ++ bool ack = true; ++ struct ieee80211_hdr *pwlanhdr; ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ ++ rtw_set_scan_deny(padapter, 1000); ++ ++ rtw_scan_abort(padapter); ++ if (tx_ch != rtw_get_oper_ch(padapter)) { ++ if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) ++ pmlmeext->cur_channel = tx_ch; ++ set_channel_bwmode(padapter, tx_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20); ++ } ++ ++ /* starting alloc mgmt frame to dump it */ ++ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) ++ { ++ /* ret = -ENOMEM; */ ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ pattrib->retry_ctrl = false; ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ ++ memcpy(pframe, (void*)buf, len); ++ pattrib->pktlen = len; ++ ++ pwlanhdr = (struct ieee80211_hdr *)pframe; ++ /* update seq number */ ++ pmlmeext->mgnt_seq = GetSequence(pwlanhdr); ++ pattrib->seqnum = pmlmeext->mgnt_seq; ++ pmlmeext->mgnt_seq++; ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ if (dump_mgntframe_and_wait_ack(padapter, pmgntframe) != _SUCCESS) ++ { ++ ack = false; ++ ret = _FAIL; ++ ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("%s, ack == _FAIL\n", __func__); ++ #endif ++ } ++ else ++ { ++ ++ msleep(50); ++ ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("%s, ack =%d, ok!\n", __func__, ack); ++ #endif ++ ret = _SUCCESS; ++ } ++ ++exit: ++ ++ #ifdef CONFIG_DEBUG_CFG80211 ++ DBG_8192C("%s, ret =%d\n", __func__, ret); ++ #endif ++ ++ return ret; ++ ++} ++ ++static int cfg80211_rtw_mgmt_tx(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct cfg80211_mgmt_tx_params *params, ++ u64 *cookie) ++{ ++ struct net_device *ndev = wdev_to_ndev(wdev); ++ struct ieee80211_channel *chan = params->chan; ++ const u8 *buf = params->buf; ++ size_t len = params->len; ++ int ret = 0; ++ int tx_ret; ++ u32 dump_limit = RTW_MAX_MGMT_TX_CNT; ++ u32 dump_cnt = 0; ++ bool ack = true; ++ u8 tx_ch = (u8)ieee80211_frequency_to_channel(chan->center_freq); ++ u8 category, action; ++ int type = (-1); ++ struct adapter *padapter; ++ struct rtw_wdev_priv *pwdev_priv; ++ ++ if (ndev == NULL) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ padapter = (struct adapter *)rtw_netdev_priv(ndev); ++ pwdev_priv = adapter_wdev_data(padapter); ++ ++ /* cookie generation */ ++ *cookie = (unsigned long) buf; ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X(FUNC_ADPT_FMT" len =%zu, ch =%d" ++ "\n", FUNC_ADPT_ARG(padapter), ++ len, tx_ch ++ ); ++#endif /* CONFIG_DEBUG_CFG80211 */ ++ ++ /* indicate ack before issue frame to avoid racing with rsp frame */ ++ rtw_cfg80211_mgmt_tx_status(padapter, *cookie, buf, len, ack, GFP_KERNEL); ++ ++ if (rtw_action_frame_parse(buf, len, &category, &action) == false) { ++ DBG_8192C(FUNC_ADPT_FMT" frame_control:0x%x\n", FUNC_ADPT_ARG(padapter), ++ le16_to_cpu(((struct ieee80211_hdr_3addr *)buf)->frame_control)); ++ goto exit; ++ } ++ ++ DBG_8192C("RTW_Tx:tx_ch =%d, da ="MAC_FMT"\n", tx_ch, MAC_ARG(GetAddr1Ptr(buf))); ++ if (category == RTW_WLAN_CATEGORY_PUBLIC) ++ DBG_871X("RTW_Tx:%s\n", action_public_str(action)); ++ else ++ DBG_871X("RTW_Tx:category(%u), action(%u)\n", category, action); ++ ++ rtw_ps_deny(padapter, PS_DENY_MGNT_TX); ++ if (_FAIL == rtw_pwr_wakeup(padapter)) { ++ ret = -EFAULT; ++ goto cancel_ps_deny; ++ } ++ ++ do { ++ dump_cnt++; ++ tx_ret = _cfg80211_rtw_mgmt_tx(padapter, tx_ch, buf, len); ++ } while (dump_cnt < dump_limit && tx_ret != _SUCCESS); ++ ++ if (tx_ret != _SUCCESS || dump_cnt > 1) { ++ DBG_871X(FUNC_ADPT_FMT" %s (%d/%d)\n", FUNC_ADPT_ARG(padapter), ++ tx_ret == _SUCCESS?"OK":"FAIL", dump_cnt, dump_limit); ++ } ++ ++ switch (type) { ++ case P2P_GO_NEGO_CONF: ++ rtw_clear_scan_deny(padapter); ++ break; ++ case P2P_INVIT_RESP: ++ if (pwdev_priv->invit_info.flags & BIT(0) ++ && pwdev_priv->invit_info.status == 0) ++ { ++ DBG_871X(FUNC_ADPT_FMT" agree with invitation of persistent group\n", ++ FUNC_ADPT_ARG(padapter)); ++ rtw_set_scan_deny(padapter, 5000); ++ rtw_pwr_wakeup_ex(padapter, 5000); ++ rtw_clear_scan_deny(padapter); ++ } ++ break; ++ } ++ ++cancel_ps_deny: ++ rtw_ps_deny_cancel(padapter, PS_DENY_MGNT_TX); ++exit: ++ return ret; ++} ++ ++static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ u16 frame_type, bool reg) ++{ ++ struct net_device *ndev = wdev_to_ndev(wdev); ++ struct adapter *adapter; ++ ++ if (ndev == NULL) ++ goto exit; ++ ++ adapter = (struct adapter *)rtw_netdev_priv(ndev); ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ DBG_871X(FUNC_ADPT_FMT" frame_type:%x, reg:%d\n", FUNC_ADPT_ARG(adapter), ++ frame_type, reg); ++#endif ++ ++ if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) ++ return; ++exit: ++ return; ++} ++ ++#if defined(CONFIG_PNO_SUPPORT) ++static int cfg80211_rtw_sched_scan_start(struct wiphy *wiphy, ++ struct net_device *dev, ++ struct cfg80211_sched_scan_request *request) { ++ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ u8 ret; ++ ++ if (padapter->bup == false) { ++ DBG_871X("%s: net device is down.\n", __func__); ++ return -EIO; ++ } ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true || ++ check_fwstate(pmlmepriv, _FW_LINKED) == true || ++ check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) { ++ DBG_871X("%s: device is busy.\n", __func__); ++ rtw_scan_abort(padapter); ++ } ++ ++ if (request == NULL) { ++ DBG_871X("%s: invalid cfg80211_requests parameters.\n", __func__); ++ return -EINVAL; ++ } ++ ++ ret = rtw_android_cfg80211_pno_setup(dev, request->ssids, ++ request->n_ssids, request->interval); ++ ++ if (ret < 0) { ++ DBG_871X("%s ret: %d\n", __func__, ret); ++ goto exit; ++ } ++ ++ ret = rtw_android_pno_enable(dev, true); ++ if (ret < 0) { ++ DBG_871X("%s ret: %d\n", __func__, ret); ++ goto exit; ++ } ++exit: ++ return ret; ++} ++ ++static int cfg80211_rtw_sched_scan_stop(struct wiphy *wiphy, ++ struct net_device *dev) { ++ return rtw_android_pno_enable(dev, false); ++} ++#endif /* CONFIG_PNO_SUPPORT */ ++ ++static void rtw_cfg80211_init_ht_capab(struct ieee80211_sta_ht_cap *ht_cap, enum ieee80211_band band, u8 rf_type) ++{ ++ ++#define MAX_BIT_RATE_40MHZ_MCS15 300 /* Mbps */ ++#define MAX_BIT_RATE_40MHZ_MCS7 150 /* Mbps */ ++ ++ ht_cap->ht_supported = true; ++ ++ ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | ++ IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20 | ++ IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU; ++ ++ /* ++ *Maximum length of AMPDU that the STA can receive. ++ *Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) ++ */ ++ ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; ++ ++ /*Minimum MPDU start spacing , */ ++ ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; ++ ++ ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; ++ ++ /* ++ *hw->wiphy->bands[IEEE80211_BAND_2GHZ] ++ *base on ant_num ++ *rx_mask: RX mask ++ *if rx_ant = 1 rx_mask[0]= 0xff;==>MCS0-MCS7 ++ *if rx_ant =2 rx_mask[1]= 0xff;==>MCS8-MCS15 ++ *if rx_ant >=3 rx_mask[2]= 0xff; ++ *if BW_40 rx_mask[4]= 0x01; ++ *highest supported RX rate ++ */ ++ if (rf_type == RF_1T1R) ++ { ++ ht_cap->mcs.rx_mask[0] = 0xFF; ++ ht_cap->mcs.rx_mask[1] = 0x00; ++ ht_cap->mcs.rx_mask[4] = 0x01; ++ ++ ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS7); ++ } ++ else if ((rf_type == RF_1T2R) || (rf_type ==RF_2T2R)) ++ { ++ ht_cap->mcs.rx_mask[0] = 0xFF; ++ ht_cap->mcs.rx_mask[1] = 0xFF; ++ ht_cap->mcs.rx_mask[4] = 0x01; ++ ++ ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS15); ++ } ++ else ++ { ++ DBG_8192C("%s, error rf_type =%d\n", __func__, rf_type); ++ } ++ ++} ++ ++void rtw_cfg80211_init_wiphy(struct adapter *padapter) ++{ ++ u8 rf_type; ++ struct ieee80211_supported_band *bands; ++ struct wireless_dev *pwdev = padapter->rtw_wdev; ++ struct wiphy *wiphy = pwdev->wiphy; ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ ++ DBG_8192C("%s:rf_type =%d\n", __func__, rf_type); ++ ++ { ++ bands = wiphy->bands[IEEE80211_BAND_2GHZ]; ++ if (bands) ++ rtw_cfg80211_init_ht_capab(&bands->ht_cap, IEEE80211_BAND_2GHZ, rf_type); ++ } ++ ++ /* init regulary domain */ ++ rtw_regd_init(padapter, rtw_reg_notifier); ++ ++ /* copy mac_addr to wiphy */ ++ memcpy(wiphy->perm_addr, padapter->eeprompriv.mac_addr, ETH_ALEN); ++ ++} ++ ++static void rtw_cfg80211_preinit_wiphy(struct adapter *padapter, struct wiphy *wiphy) ++{ ++ ++ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; ++ ++ wiphy->max_scan_ssids = RTW_SSID_SCAN_AMOUNT; ++ wiphy->max_scan_ie_len = RTW_SCAN_IE_LEN_MAX; ++ wiphy->max_num_pmkids = RTW_MAX_NUM_PMKIDS; ++ ++ wiphy->max_remain_on_channel_duration = RTW_MAX_REMAIN_ON_CHANNEL_DURATION; ++ ++ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) ++ | BIT(NL80211_IFTYPE_ADHOC) ++ | BIT(NL80211_IFTYPE_AP) ++ | BIT(NL80211_IFTYPE_MONITOR) ++ ; ++ ++ wiphy->mgmt_stypes = rtw_cfg80211_default_mgmt_stypes; ++ ++ wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR); ++ ++ wiphy->cipher_suites = rtw_cipher_suites; ++ wiphy->n_cipher_suites = ARRAY_SIZE(rtw_cipher_suites); ++ ++ /* if (padapter->registrypriv.wireless_mode & WIRELESS_11G) */ ++ wiphy->bands[IEEE80211_BAND_2GHZ] = rtw_spt_band_alloc(IEEE80211_BAND_2GHZ); ++ ++ wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; ++ wiphy->flags |= WIPHY_FLAG_OFFCHAN_TX | WIPHY_FLAG_HAVE_AP_SME; ++ ++#if defined(CONFIG_PM) ++ wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; ++#ifdef CONFIG_PNO_SUPPORT ++ wiphy->max_sched_scan_ssids = MAX_PNO_LIST_COUNT; ++#endif ++#endif ++ ++#if defined(CONFIG_PM) ++ wiphy->wowlan = &wowlan_stub; ++#endif ++ ++ if (padapter->registrypriv.power_mgnt != PS_MODE_ACTIVE) ++ wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; ++ else ++ wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; ++} ++ ++static struct cfg80211_ops rtw_cfg80211_ops = { ++ .change_virtual_intf = cfg80211_rtw_change_iface, ++ .add_key = cfg80211_rtw_add_key, ++ .get_key = cfg80211_rtw_get_key, ++ .del_key = cfg80211_rtw_del_key, ++ .set_default_key = cfg80211_rtw_set_default_key, ++ .get_station = cfg80211_rtw_get_station, ++ .scan = cfg80211_rtw_scan, ++ .set_wiphy_params = cfg80211_rtw_set_wiphy_params, ++ .connect = cfg80211_rtw_connect, ++ .disconnect = cfg80211_rtw_disconnect, ++ .join_ibss = cfg80211_rtw_join_ibss, ++ .leave_ibss = cfg80211_rtw_leave_ibss, ++ .set_tx_power = cfg80211_rtw_set_txpower, ++ .get_tx_power = cfg80211_rtw_get_txpower, ++ .set_power_mgmt = cfg80211_rtw_set_power_mgmt, ++ .set_pmksa = cfg80211_rtw_set_pmksa, ++ .del_pmksa = cfg80211_rtw_del_pmksa, ++ .flush_pmksa = cfg80211_rtw_flush_pmksa, ++ ++ .add_virtual_intf = cfg80211_rtw_add_virtual_intf, ++ .del_virtual_intf = cfg80211_rtw_del_virtual_intf, ++ ++ .start_ap = cfg80211_rtw_start_ap, ++ .change_beacon = cfg80211_rtw_change_beacon, ++ .stop_ap = cfg80211_rtw_stop_ap, ++ ++ .add_station = cfg80211_rtw_add_station, ++ .del_station = cfg80211_rtw_del_station, ++ .change_station = cfg80211_rtw_change_station, ++ .dump_station = cfg80211_rtw_dump_station, ++ .change_bss = cfg80211_rtw_change_bss, ++ ++ .mgmt_tx = cfg80211_rtw_mgmt_tx, ++ .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register, ++ ++#if defined(CONFIG_PNO_SUPPORT) ++ .sched_scan_start = cfg80211_rtw_sched_scan_start, ++ .sched_scan_stop = cfg80211_rtw_sched_scan_stop, ++#endif /* CONFIG_PNO_SUPPORT */ ++}; ++ ++int rtw_wdev_alloc(struct adapter *padapter, struct device *dev) ++{ ++ int ret = 0; ++ struct wiphy *wiphy; ++ struct wireless_dev *wdev; ++ struct rtw_wdev_priv *pwdev_priv; ++ struct net_device *pnetdev = padapter->pnetdev; ++ ++ DBG_8192C("%s(padapter =%p)\n", __func__, padapter); ++ ++ /* wiphy */ ++ wiphy = wiphy_new(&rtw_cfg80211_ops, sizeof(struct adapter *)); ++ if (!wiphy) { ++ DBG_8192C("Couldn't allocate wiphy device\n"); ++ ret = -ENOMEM; ++ goto exit; ++ } ++ set_wiphy_dev(wiphy, dev); ++ *((struct adapter **)wiphy_priv(wiphy)) = padapter; ++ rtw_cfg80211_preinit_wiphy(padapter, wiphy); ++ ++ ret = wiphy_register(wiphy); ++ if (ret < 0) { ++ DBG_8192C("Couldn't register wiphy device\n"); ++ goto free_wiphy; ++ } ++ ++ /* wdev */ ++ wdev = (struct wireless_dev *)rtw_zmalloc(sizeof(struct wireless_dev)); ++ if (!wdev) { ++ DBG_8192C("Couldn't allocate wireless device\n"); ++ ret = -ENOMEM; ++ goto unregister_wiphy; ++ } ++ wdev->wiphy = wiphy; ++ wdev->netdev = pnetdev; ++ ++ wdev->iftype = NL80211_IFTYPE_STATION; /* will be init in rtw_hal_init() */ ++ /* Must sync with _rtw_init_mlme_priv() */ ++ /* pmlmepriv->fw_state = WIFI_STATION_STATE */ ++ padapter->rtw_wdev = wdev; ++ pnetdev->ieee80211_ptr = wdev; ++ ++ /* init pwdev_priv */ ++ pwdev_priv = adapter_wdev_data(padapter); ++ pwdev_priv->rtw_wdev = wdev; ++ pwdev_priv->pmon_ndev = NULL; ++ pwdev_priv->ifname_mon[0] = '\0'; ++ pwdev_priv->padapter = padapter; ++ pwdev_priv->scan_request = NULL; ++ spin_lock_init(&pwdev_priv->scan_req_lock); ++ ++ pwdev_priv->p2p_enabled = false; ++ pwdev_priv->provdisc_req_issued = false; ++ rtw_wdev_invit_info_init(&pwdev_priv->invit_info); ++ rtw_wdev_nego_info_init(&pwdev_priv->nego_info); ++ ++ pwdev_priv->bandroid_scan = false; ++ ++ if (padapter->registrypriv.power_mgnt != PS_MODE_ACTIVE) ++ pwdev_priv->power_mgmt = true; ++ else ++ pwdev_priv->power_mgmt = false; ++ ++ return ret; ++ ++ kfree((u8 *)wdev); ++unregister_wiphy: ++ wiphy_unregister(wiphy); ++ free_wiphy: ++ wiphy_free(wiphy); ++exit: ++ return ret; ++ ++} ++ ++void rtw_wdev_free(struct wireless_dev *wdev) ++{ ++ DBG_8192C("%s(wdev =%p)\n", __func__, wdev); ++ ++ if (!wdev) ++ return; ++ ++ rtw_spt_band_free(wdev->wiphy->bands[IEEE80211_BAND_2GHZ]); ++ ++ wiphy_free(wdev->wiphy); ++ ++ kfree((u8 *)wdev); ++} ++ ++void rtw_wdev_unregister(struct wireless_dev *wdev) ++{ ++ struct net_device *ndev; ++ struct adapter *adapter; ++ struct rtw_wdev_priv *pwdev_priv; ++ ++ DBG_8192C("%s(wdev =%p)\n", __func__, wdev); ++ ++ if (!wdev) ++ return; ++ ++ if (!(ndev = wdev_to_ndev(wdev))) ++ return; ++ ++ adapter = (struct adapter *)rtw_netdev_priv(ndev); ++ pwdev_priv = adapter_wdev_data(adapter); ++ ++ rtw_cfg80211_indicate_scan_done(adapter, true); ++ ++ if (pwdev_priv->pmon_ndev) { ++ DBG_8192C("%s, unregister monitor interface\n", __func__); ++ unregister_netdev(pwdev_priv->pmon_ndev); ++ } ++ ++ wiphy_unregister(wdev->wiphy); ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/os_dep/ioctl_linux.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/ioctl_linux.c +--- linux-4.3/3rdparty/rtl8723bs/os_dep/ioctl_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/ioctl_linux.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,5820 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _IOCTL_LINUX_C_ ++ ++#include ++#include ++#include ++#include ++ ++#define RTL_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30 ++ ++#define SCAN_ITEM_SIZE 768 ++#define MAX_CUSTOM_LEN 64 ++#define RATE_COUNT 4 ++ ++/* combo scan */ ++#define WEXT_CSCAN_AMOUNT 9 ++#define WEXT_CSCAN_BUF_LEN 360 ++#define WEXT_CSCAN_HEADER "CSCAN S\x01\x00\x00S\x00" ++#define WEXT_CSCAN_HEADER_SIZE 12 ++#define WEXT_CSCAN_SSID_SECTION 'S' ++#define WEXT_CSCAN_CHANNEL_SECTION 'C' ++#define WEXT_CSCAN_NPROBE_SECTION 'N' ++#define WEXT_CSCAN_ACTV_DWELL_SECTION 'A' ++#define WEXT_CSCAN_PASV_DWELL_SECTION 'P' ++#define WEXT_CSCAN_HOME_DWELL_SECTION 'H' ++#define WEXT_CSCAN_TYPE_SECTION 'T' ++ ++ ++extern u8 key_2char2num(u8 hch, u8 lch); ++ ++static u32 rtw_rates[] = {1000000, 2000000, 5500000, 11000000, ++ 6000000, 9000000, 12000000, 18000000, 24000000, 36000000, 48000000, 54000000}; ++ ++static const char * const iw_operation_mode[] = ++{ ++ "Auto", "Ad-Hoc", "Managed", "Master", "Repeater", "Secondary", "Monitor" ++}; ++ ++static int hex2num_i(char c) ++{ ++ if (c >= '0' && c <= '9') ++ return c - '0'; ++ if (c >= 'a' && c <= 'f') ++ return c - 'a' + 10; ++ if (c >= 'A' && c <= 'F') ++ return c - 'A' + 10; ++ return -1; ++} ++ ++/** ++ * hwaddr_aton - Convert ASCII string to MAC address ++ * @txt: MAC address as a string (e.g., "00:11:22:33:44:55") ++ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) ++ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address) ++ */ ++static int hwaddr_aton_i(const char *txt, u8 *addr) ++{ ++ int i; ++ ++ for (i = 0; i < 6; i++) { ++ int a, b; ++ ++ a = hex2num_i(*txt++); ++ if (a < 0) ++ return -1; ++ b = hex2num_i(*txt++); ++ if (b < 0) ++ return -1; ++ *addr++ = (a << 4) | b; ++ if (i < 5 && *txt++ != ':') ++ return -1; ++ } ++ ++ return 0; ++} ++ ++void indicate_wx_scan_complete_event(struct adapter *padapter) ++{ ++ union iwreq_data wrqu; ++ ++ memset(&wrqu, 0, sizeof(union iwreq_data)); ++ ++ /* DBG_871X("+rtw_indicate_wx_scan_complete_event\n"); */ ++} ++ ++ ++void rtw_indicate_wx_assoc_event(struct adapter *padapter) ++{ ++ union iwreq_data wrqu; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex*)(&(pmlmeinfo->network)); ++ ++ memset(&wrqu, 0, sizeof(union iwreq_data)); ++ ++ wrqu.ap_addr.sa_family = ARPHRD_ETHER; ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ==true) ++ memcpy(wrqu.ap_addr.sa_data, pnetwork->MacAddress, ETH_ALEN); ++ else ++ memcpy(wrqu.ap_addr.sa_data, pmlmepriv->cur_network.network.MacAddress, ETH_ALEN); ++ ++ DBG_871X_LEVEL(_drv_always_, "assoc success\n"); ++} ++ ++void rtw_indicate_wx_disassoc_event(struct adapter *padapter) ++{ ++ union iwreq_data wrqu; ++ ++ memset(&wrqu, 0, sizeof(union iwreq_data)); ++ ++ wrqu.ap_addr.sa_family = ARPHRD_ETHER; ++ memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); ++} ++ ++/* ++uint rtw_is_cckrates_included(u8 *rate) ++{ ++ u32 i = 0; ++ ++ while (rate[i]!= 0) ++ { ++ if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) || ++ (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22)) ++ return true; ++ i++; ++ } ++ ++ return false; ++} ++ ++uint rtw_is_cckratesonly_included(u8 *rate) ++{ ++ u32 i = 0; ++ ++ while (rate[i]!= 0) ++ { ++ if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && ++ (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22)) ++ return false; ++ i++; ++ } ++ ++ return true; ++} ++*/ ++ ++static char *translate_scan(struct adapter *padapter, ++ struct iw_request_info* info, struct wlan_network *pnetwork, ++ char *start, char *stop) ++{ ++ struct iw_event iwe; ++ u16 cap; ++ u32 ht_ielen = 0; ++ char *custom = NULL; ++ char *p; ++ u16 max_rate = 0, rate, ht_cap =false, vht_cap = false; ++ u32 i = 0; ++ u8 bw_40MHz = 0, short_GI = 0; ++ u16 mcs_rate = 0, vht_data_rate = 0; ++ u8 ie_offset = (pnetwork->network.Reserved[0] == 2? 0:12); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ u8 ss, sq; ++ ++ /* AP MAC address */ ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ ++ memcpy(iwe.u.ap_addr.sa_data, pnetwork->network.MacAddress, ETH_ALEN); ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); ++ ++ /* Add the ESSID */ ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.flags = 1; ++ iwe.u.data.length = min((u16)pnetwork->network.Ssid.SsidLength, (u16)32); ++ start = iwe_stream_add_point(info, start, stop, &iwe, pnetwork->network.Ssid.Ssid); ++ ++ /* parsing HT_CAP_IE */ ++ if (pnetwork->network.Reserved[0] == 2) /* Probe Request */ ++ { ++ p = rtw_get_ie(&pnetwork->network.IEs[0], _HT_CAPABILITY_IE_, &ht_ielen, pnetwork->network.IELength); ++ } ++ else ++ { ++ p = rtw_get_ie(&pnetwork->network.IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pnetwork->network.IELength-12); ++ } ++ if (p && ht_ielen>0) ++ { ++ struct rtw_ieee80211_ht_cap *pht_capie; ++ ht_cap = true; ++ pht_capie = (struct rtw_ieee80211_ht_cap *)(p+2); ++ memcpy(&mcs_rate , pht_capie->supp_mcs_set, 2); ++ bw_40MHz = (le16_to_cpu(pht_capie->cap_info) & IEEE80211_HT_CAP_SUP_WIDTH) ? 1 : 0; ++ short_GI = (le16_to_cpu(pht_capie->cap_info) & (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40)) ? 1 : 0; ++ } ++ ++ /* Add the protocol name */ ++ iwe.cmd = SIOCGIWNAME; ++ if ((rtw_is_cckratesonly_included((u8 *)&pnetwork->network.SupportedRates)) == true) ++ { ++ if (ht_cap == true) ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bn"); ++ else ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11b"); ++ } ++ else if ((rtw_is_cckrates_included((u8 *)&pnetwork->network.SupportedRates)) == true) ++ { ++ if (ht_cap == true) ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bgn"); ++ else ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bg"); ++ } ++ else ++ { ++ if (pnetwork->network.Configuration.DSConfig > 14) ++ { ++ if (vht_cap == true) ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11AC"); ++ else if (ht_cap == true) ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11an"); ++ else ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11a"); ++ } ++ else ++ { ++ if (ht_cap == true) ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11gn"); ++ else ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11g"); ++ } ++ } ++ ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); ++ ++ /* Add mode */ ++ if (pnetwork->network.Reserved[0] == 2) /* Probe Request */ ++ { ++ cap = 0; ++ } ++ else ++ { ++ __le16 le_tmp; ++ ++ iwe.cmd = SIOCGIWMODE; ++ memcpy((u8 *)&le_tmp, rtw_get_capability_from_ie(pnetwork->network.IEs), 2); ++ cap = le16_to_cpu(le_tmp); ++ } ++ ++ if (cap & (WLAN_CAPABILITY_IBSS |WLAN_CAPABILITY_BSS)) { ++ if (cap & WLAN_CAPABILITY_BSS) ++ iwe.u.mode = IW_MODE_MASTER; ++ else ++ iwe.u.mode = IW_MODE_ADHOC; ++ ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN); ++ } ++ ++ if (pnetwork->network.Configuration.DSConfig<1 /*|| pnetwork->network.Configuration.DSConfig>14*/) ++ pnetwork->network.Configuration.DSConfig = 1; ++ ++ /* Add frequency/channel */ ++ iwe.cmd = SIOCGIWFREQ; ++ iwe.u.freq.m = rtw_ch2freq(pnetwork->network.Configuration.DSConfig) * 100000; ++ iwe.u.freq.e = 1; ++ iwe.u.freq.i = pnetwork->network.Configuration.DSConfig; ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); ++ ++ /* Add encryption capability */ ++ iwe.cmd = SIOCGIWENCODE; ++ if (cap & 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; ++ start = iwe_stream_add_point(info, start, stop, &iwe, pnetwork->network.Ssid.Ssid); ++ ++ /*Add basic and extended rates */ ++ max_rate = 0; ++ custom = kzalloc(MAX_CUSTOM_LEN, GFP_ATOMIC); ++ if (!custom) ++ return start; ++ p = custom; ++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); ++ while (pnetwork->network.SupportedRates[i]!= 0) ++ { ++ rate = pnetwork->network.SupportedRates[i]&0x7F; ++ if (rate > max_rate) ++ max_rate = rate; ++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), ++ "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); ++ i++; ++ } ++ ++ if (vht_cap == true) { ++ max_rate = vht_data_rate; ++ } ++ else if (ht_cap == true) ++ { ++ if (mcs_rate&0x8000)/* MCS15 */ ++ { ++ max_rate = (bw_40MHz) ? ((short_GI)?300:270):((short_GI)?144:130); ++ ++ } ++ else if (mcs_rate&0x0080)/* MCS7 */ ++ { ++ max_rate = (bw_40MHz) ? ((short_GI)?150:135):((short_GI)?72:65); ++ } ++ else/* default MCS7 */ ++ { ++ /* DBG_871X("wx_get_scan, mcs_rate_bitmap = 0x%x\n", mcs_rate); */ ++ max_rate = (bw_40MHz) ? ((short_GI)?150:135):((short_GI)?72:65); ++ } ++ ++ max_rate = max_rate*2;/* Mbps/2; */ ++ } ++ ++ iwe.cmd = SIOCGIWRATE; ++ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; ++ iwe.u.bitrate.value = max_rate * 500000; ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_PARAM_LEN); ++ ++ /* parsing WPA/WPA2 IE */ ++ if (pnetwork->network.Reserved[0] != 2) /* Probe Request */ ++ { ++ u8 *buf; ++ u8 wpa_ie[255], rsn_ie[255]; ++ u16 wpa_len = 0, rsn_len = 0; ++ u8 *p; ++ sint out_len = 0; ++ out_len =rtw_get_sec_ie(pnetwork->network.IEs , pnetwork->network.IELength, rsn_ie,&rsn_len, wpa_ie,&wpa_len); ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan: ssid =%s\n", pnetwork->network.Ssid.Ssid)); ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len)); ++ ++ buf = kzalloc(MAX_WPA_IE_LEN*2, GFP_KERNEL); ++ if (!buf) ++ return start; ++ if (wpa_len > 0) { ++ p =buf; ++ p += sprintf(p, "wpa_ie ="); ++ for (i = 0; i < wpa_len; i++) { ++ p += sprintf(p, "%02x", wpa_ie[i]); ++ } ++ ++ if (wpa_len > 100) { ++ printk("-----------------Len %d----------------\n", wpa_len); ++ for (i = 0; i < wpa_len; i++) { ++ printk("%02x ", wpa_ie[i]); ++ } ++ printk("\n"); ++ printk("-----------------Len %d----------------\n", wpa_len); ++ } ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = strlen(buf); ++ start = iwe_stream_add_point(info, start, stop, &iwe, buf); ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd =IWEVGENIE; ++ iwe.u.data.length = wpa_len; ++ start = iwe_stream_add_point(info, start, stop, &iwe, wpa_ie); ++ } ++ if (rsn_len > 0) { ++ p = buf; ++ memset(buf, 0, MAX_WPA_IE_LEN*2); ++ p += sprintf(p, "rsn_ie ="); ++ for (i = 0; i < rsn_len; i++) ++ p += sprintf(p, "%02x", rsn_ie[i]); ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = strlen(buf); ++ start = iwe_stream_add_point(info, start, stop, &iwe, buf); ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd =IWEVGENIE; ++ iwe.u.data.length = rsn_len; ++ start = iwe_stream_add_point(info, start, stop, &iwe, rsn_ie); ++ } ++ kfree(buf); ++ } ++ ++ { /* parsing WPS IE */ ++ uint cnt = 0, total_ielen; ++ u8 *wpsie_ptr = NULL; ++ uint wps_ielen = 0; ++ ++ u8 *ie_ptr = pnetwork->network.IEs + ie_offset; ++ total_ielen = pnetwork->network.IELength - ie_offset; ++ ++ if (pnetwork->network.Reserved[0] == 2) /* Probe Request */ ++ { ++ ie_ptr = pnetwork->network.IEs; ++ total_ielen = pnetwork->network.IELength; ++ } ++ else /* Beacon or Probe Respones */ ++ { ++ ie_ptr = pnetwork->network.IEs + _FIXED_IE_LENGTH_; ++ total_ielen = pnetwork->network.IELength - _FIXED_IE_LENGTH_; ++ } ++ ++ while (cnt < total_ielen) ++ { ++ if (rtw_is_wps_ie(&ie_ptr[cnt], &wps_ielen) && (wps_ielen>2)) ++ { ++ wpsie_ptr = &ie_ptr[cnt]; ++ iwe.cmd =IWEVGENIE; ++ iwe.u.data.length = (u16)wps_ielen; ++ start = iwe_stream_add_point(info, start, stop, &iwe, wpsie_ptr); ++ } ++ cnt+=ie_ptr[cnt+1]+2; /* goto next */ ++ } ++ } ++ ++ /* Add quality statistics */ ++ iwe.cmd = IWEVQUAL; ++ iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED ++ #if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) ++ | IW_QUAL_NOISE_UPDATED ++ #else ++ | IW_QUAL_NOISE_INVALID ++ #endif ++ #ifdef CONFIG_SIGNAL_DISPLAY_DBM ++ | IW_QUAL_DBM ++ #endif ++ ; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == true && ++ is_same_network(&pmlmepriv->cur_network.network, &pnetwork->network, 0)) { ++ ss = padapter->recvpriv.signal_strength; ++ sq = padapter->recvpriv.signal_qual; ++ } else { ++ ss = pnetwork->network.PhyInfo.SignalStrength; ++ sq = pnetwork->network.PhyInfo.SignalQuality; ++ } ++ ++ ++ #ifdef CONFIG_SIGNAL_DISPLAY_DBM ++ iwe.u.qual.level = (u8) translate_percentage_to_dbm(ss);/* dbm */ ++ #else ++ #ifdef CONFIG_SKIP_SIGNAL_SCALE_MAPPING ++ { ++ /* Do signal scale mapping when using percentage as the unit of signal strength, since the scale mapping is skipped in odm */ ++ ++ struct hal_com_data *pHal = GET_HAL_DATA(padapter); ++ ++ iwe.u.qual.level = (u8)odm_SignalScaleMapping(&pHal->odmpriv, ss); ++ } ++ #else ++ iwe.u.qual.level = (u8)ss;/* */ ++ #endif ++ #endif ++ ++ iwe.u.qual.qual = (u8)sq; /* signal quality */ ++ ++ #if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) ++ { ++ s16 tmp_noise = 0; ++ rtw_hal_get_odm_var(padapter, HAL_ODM_NOISE_MONITOR,&(pnetwork->network.Configuration.DSConfig), &(tmp_noise)); ++ iwe.u.qual.noise = tmp_noise ; ++ } ++ #else ++ iwe.u.qual.noise = 0; /* noise level */ ++ #endif ++ ++ /* DBG_871X("iqual =%d, ilevel =%d, inoise =%d, iupdated =%d\n", iwe.u.qual.qual, iwe.u.qual.level , iwe.u.qual.noise, iwe.u.qual.updated); */ ++ ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); ++ ++ { ++ u8 *buf; ++ u8 *p, *pos; ++ ++ buf = kzalloc(MAX_WPA_IE_LEN, GFP_KERNEL); ++ if (!buf) ++ goto exit; ++ p = buf; ++ pos = pnetwork->network.Reserved; ++ p += sprintf(p, "fm =%02X%02X", pos[1], pos[0]); ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = strlen(buf); ++ start = iwe_stream_add_point(info, start, stop, &iwe, buf); ++ kfree(buf); ++ } ++exit: ++ kfree(custom); ++ ++ return start; ++} ++ ++static int wpa_set_auth_algs(struct net_device *dev, u32 value) ++{ ++ struct adapter *padapter = (struct adapter *) rtw_netdev_priv(dev); ++ int ret = 0; ++ ++ if ((value & AUTH_ALG_SHARED_KEY) && (value & AUTH_ALG_OPEN_SYSTEM)) ++ { ++ DBG_871X("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY and AUTH_ALG_OPEN_SYSTEM [value:0x%x]\n", value); ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch; ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; ++ } ++ else if (value & AUTH_ALG_SHARED_KEY) ++ { ++ DBG_871X("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY [value:0x%x]\n", value); ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared; ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared; ++ } ++ else if (value & AUTH_ALG_OPEN_SYSTEM) ++ { ++ DBG_871X("wpa_set_auth_algs, AUTH_ALG_OPEN_SYSTEM\n"); ++ /* padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; */ ++ if (padapter->securitypriv.ndisauthtype < Ndis802_11AuthModeWPAPSK) ++ { ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; ++ } ++ ++ } ++ else if (value & AUTH_ALG_LEAP) ++ { ++ DBG_871X("wpa_set_auth_algs, AUTH_ALG_LEAP\n"); ++ } ++ else ++ { ++ DBG_871X("wpa_set_auth_algs, error!\n"); ++ ret = -EINVAL; ++ } ++ ++ return ret; ++ ++} ++ ++static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len) ++{ ++ int ret = 0; ++ u32 wep_key_idx, wep_key_len, wep_total_len; ++ struct ndis_802_11_wep *pwep = NULL; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ param->u.crypt.err = 0; ++ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; ++ ++ if (param_len < (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ 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 && ++ param->u.crypt.idx >= BIP_MAX_KEYID) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ } ++ else ++ { ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ } ++ ++ if (strcmp(param->u.crypt.alg, "WEP") == 0) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("wpa_set_encryption, crypt.alg = WEP\n")); ++ DBG_871X("wpa_set_encryption, crypt.alg = WEP\n"); ++ ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; ++ padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_; ++ ++ wep_key_idx = param->u.crypt.idx; ++ wep_key_len = param->u.crypt.key_len; ++ ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("(1)wep_key_idx =%d\n", wep_key_idx)); ++ DBG_871X("(1)wep_key_idx =%d\n", wep_key_idx); ++ ++ if (wep_key_idx > WEP_KEYS) ++ return -EINVAL; ++ ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("(2)wep_key_idx =%d\n", wep_key_idx)); ++ ++ if (wep_key_len > 0) ++ { ++ wep_key_len = wep_key_len <= 5 ? 5 : 13; ++ wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial); ++ pwep =(struct ndis_802_11_wep *) rtw_malloc(wep_total_len); ++ if (pwep == NULL) { ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, (" wpa_set_encryption: pwep allocate fail !!!\n")); ++ goto exit; ++ } ++ ++ memset(pwep, 0, wep_total_len); ++ ++ pwep->KeyLength = wep_key_len; ++ pwep->Length = wep_total_len; ++ ++ if (wep_key_len == 13) ++ { ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; ++ padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_; ++ } ++ } ++ else { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ pwep->KeyIndex = wep_key_idx; ++ pwep->KeyIndex |= 0x80000000; ++ ++ memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength); ++ ++ if (param->u.crypt.set_tx) ++ { ++ DBG_871X("wep, set_tx = 1\n"); ++ ++ if (rtw_set_802_11_add_wep(padapter, pwep) == (u8)_FAIL) ++ { ++ ret = -EOPNOTSUPP ; ++ } ++ } ++ else ++ { ++ DBG_871X("wep, set_tx = 0\n"); ++ ++ /* don't update "psecuritypriv->dot11PrivacyAlgrthm" and */ ++ /* psecuritypriv->dot11PrivacyKeyIndex =keyid", but can rtw_set_key to fw/cam */ ++ ++ if (wep_key_idx >= WEP_KEYS) { ++ ret = -EOPNOTSUPP ; ++ goto exit; ++ } ++ ++ memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength); ++ psecuritypriv->dot11DefKeylen[wep_key_idx]=pwep->KeyLength; ++ rtw_set_key(padapter, psecuritypriv, wep_key_idx, 0, true); ++ } ++ ++ goto exit; ++ } ++ ++ if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) /* 802_1x */ ++ { ++ struct sta_info * psta,*pbcmc_sta; ++ struct sta_priv * pstapriv = &padapter->stapriv; ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE) == true) /* sta mode */ ++ { ++ psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv)); ++ if (psta == NULL) { ++ /* DEBUG_ERR(("Set wpa_set_encryption: Obtain Sta_info fail\n")); */ ++ } ++ else ++ { ++ /* Jeff: don't disable ieee8021x_blocked while clearing key */ ++ if (strcmp(param->u.crypt.alg, "none") != 0) ++ psta->ieee8021x_blocked = false; ++ ++ if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled)|| ++ (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) ++ { ++ psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; ++ } ++ ++ if (param->u.crypt.set_tx == 1)/* pairwise key */ ++ { ++ memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ if (strcmp(param->u.crypt.alg, "TKIP") == 0)/* set mic key */ ++ { ++ /* DEBUG_ERR(("\nset key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */ ++ memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8); ++ memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8); ++ ++ padapter->securitypriv.busetkipkey =false; ++ /* _set_timer(&padapter->securitypriv.tkip_timer, 50); */ ++ } ++ ++ /* DEBUG_ERR((" param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */ ++ DBG_871X(" ~~~~set sta key:unicastkey\n"); ++ ++ rtw_setstakey_cmd(padapter, psta, true, true); ++ } ++ else/* group key */ ++ { ++ if (strcmp(param->u.crypt.alg, "TKIP") == 0 || strcmp(param->u.crypt.alg, "CCMP") == 0) ++ { ++ memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ /* only TKIP group key need to install this */ ++ if (param->u.crypt.key_len > 16) ++ { ++ memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey,&(param->u.crypt.key[16]), 8); ++ memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey,&(param->u.crypt.key[24]), 8); ++ } ++ padapter->securitypriv.binstallGrpkey = true; ++ /* DEBUG_ERR((" param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */ ++ DBG_871X(" ~~~~set sta key:groupkey\n"); ++ ++ padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx; ++ ++ rtw_set_key(padapter,&padapter->securitypriv, param->u.crypt.idx, 1, true); ++ } ++ else if (strcmp(param->u.crypt.alg, "BIP") == 0) ++ { ++ /* printk("BIP key_len =%d , index =%d @@@@@@@@@@@@@@@@@@\n", param->u.crypt.key_len, param->u.crypt.idx); */ ++ /* save the IGTK key, length 16 bytes */ ++ memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ /*printk("IGTK key below:\n"); ++ for (no = 0;no<16;no++) ++ printk(" %02x ", padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey[no]); ++ printk("\n");*/ ++ padapter->securitypriv.dot11wBIPKeyid = param->u.crypt.idx; ++ padapter->securitypriv.binstallBIPkey = true; ++ DBG_871X(" ~~~~set sta key:IGKT\n"); ++ } ++ } ++ } ++ ++ pbcmc_sta =rtw_get_bcmc_stainfo(padapter); ++ if (pbcmc_sta == NULL) ++ { ++ /* DEBUG_ERR(("Set OID_802_11_ADD_KEY: bcmc stainfo is null\n")); */ ++ } ++ else ++ { ++ /* Jeff: don't disable ieee8021x_blocked while clearing key */ ++ if (strcmp(param->u.crypt.alg, "none") != 0) ++ pbcmc_sta->ieee8021x_blocked = false; ++ ++ if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled)|| ++ (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) ++ { ++ pbcmc_sta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; ++ } ++ } ++ } ++ else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) /* adhoc mode */ ++ { ++ } ++ } ++ ++exit: ++ ++ if (pwep) { ++ kfree((u8 *)pwep); ++ } ++ return ret; ++} ++ ++static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ielen) ++{ ++ u8 *buf = NULL, *pos = NULL; ++ int group_cipher = 0, pairwise_cipher = 0; ++ int ret = 0; ++ u8 null_addr[]= {0, 0, 0, 0, 0, 0}; ++ ++ if ((ielen > MAX_WPA_IE_LEN) || (pie == NULL)) { ++ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); ++ if (pie == NULL) ++ return ret; ++ else ++ return -EINVAL; ++ } ++ ++ if (ielen) ++ { ++ buf = rtw_zmalloc(ielen); ++ if (buf == NULL) { ++ ret = -ENOMEM; ++ goto exit; ++ } ++ ++ memcpy(buf, pie , ielen); ++ ++ /* dump */ ++ { ++ int i; ++ DBG_871X("\n wpa_ie(length:%d):\n", ielen); ++ for (i = 0;isecuritypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; ++ padapter->securitypriv.ndisauthtype =Ndis802_11AuthModeWPAPSK; ++ memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen); ++ } ++ ++ if (rtw_parse_wpa2_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) ++ { ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; ++ padapter->securitypriv.ndisauthtype =Ndis802_11AuthModeWPA2PSK; ++ memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen); ++ } ++ ++ if (group_cipher == 0) ++ { ++ group_cipher = WPA_CIPHER_NONE; ++ } ++ if (pairwise_cipher == 0) ++ { ++ pairwise_cipher = WPA_CIPHER_NONE; ++ } ++ ++ switch (group_cipher) ++ { ++ case WPA_CIPHER_NONE: ++ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; ++ padapter->securitypriv.ndisencryptstatus =Ndis802_11EncryptionDisabled; ++ break; ++ case WPA_CIPHER_WEP40: ++ padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ case WPA_CIPHER_TKIP: ++ padapter->securitypriv.dot118021XGrpPrivacy = _TKIP_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; ++ break; ++ case WPA_CIPHER_CCMP: ++ padapter->securitypriv.dot118021XGrpPrivacy = _AES_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; ++ break; ++ case WPA_CIPHER_WEP104: ++ padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ } ++ ++ switch (pairwise_cipher) ++ { ++ case WPA_CIPHER_NONE: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ padapter->securitypriv.ndisencryptstatus =Ndis802_11EncryptionDisabled; ++ break; ++ case WPA_CIPHER_WEP40: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ case WPA_CIPHER_TKIP: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _TKIP_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; ++ break; ++ case WPA_CIPHER_CCMP: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _AES_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; ++ break; ++ case WPA_CIPHER_WEP104: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ } ++ ++ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); ++ {/* set wps_ie */ ++ u16 cnt = 0; ++ u8 eid, wps_oui[4]={0x0, 0x50, 0xf2, 0x04}; ++ ++ while (cnt < ielen) ++ { ++ eid = buf[cnt]; ++ ++ if ((eid == _VENDOR_SPECIFIC_IE_) && (!memcmp(&buf[cnt+2], wps_oui, 4))) ++ { ++ DBG_871X("SET WPS_IE\n"); ++ ++ padapter->securitypriv.wps_ie_len = ((buf[cnt+1]+2) < MAX_WPS_IE_LEN) ? (buf[cnt+1]+2):MAX_WPS_IE_LEN; ++ ++ memcpy(padapter->securitypriv.wps_ie, &buf[cnt], padapter->securitypriv.wps_ie_len); ++ ++ set_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS); ++ ++ cnt += buf[cnt+1]+2; ++ ++ break; ++ } else { ++ cnt += buf[cnt+1]+2; /* goto next */ ++ } ++ } ++ } ++ } ++ ++ /* TKIP and AES disallow multicast packets until installing group key */ ++ if (padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_ ++ || padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_WTMIC_ ++ || padapter->securitypriv.dot11PrivacyAlgrthm == _AES_) ++ /* WPS open need to enable multicast */ ++ /* check_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS) == true) */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_OFF_RCR_AM, null_addr); ++ ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ++ ("rtw_set_wpa_ie: pairwise_cipher = 0x%08x padapter->securitypriv.ndisencryptstatus =%d padapter->securitypriv.ndisauthtype =%d\n", ++ pairwise_cipher, padapter->securitypriv.ndisencryptstatus, padapter->securitypriv.ndisauthtype)); ++ ++exit: ++ ++ if (buf) kfree(buf); ++ ++ return ret; ++} ++ ++static int rtw_wx_get_name(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ u32 ht_ielen = 0; ++ char *p; ++ u8 ht_cap =false, vht_cap =false; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; ++ NDIS_802_11_RATES_EX* prates = NULL; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("cmd_code =%x\n", info->cmd)); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true) { ++ /* parsing HT_CAP_IE */ ++ p = rtw_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pcur_bss->IELength-12); ++ if (p && ht_ielen>0) ++ { ++ ht_cap = true; ++ } ++ ++ prates = &pcur_bss->SupportedRates; ++ ++ if (rtw_is_cckratesonly_included((u8 *)prates) == true) ++ { ++ if (ht_cap == true) ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bn"); ++ else ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b"); ++ } ++ else if ((rtw_is_cckrates_included((u8 *)prates)) == true) ++ { ++ if (ht_cap == true) ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bgn"); ++ else ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bg"); ++ } ++ else ++ { ++ if (pcur_bss->Configuration.DSConfig > 14) ++ { ++ if (vht_cap == true) ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11AC"); ++ else if (ht_cap == true) ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11an"); ++ else ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11a"); ++ } ++ else ++ { ++ if (ht_cap == true) ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11gn"); ++ else ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11g"); ++ } ++ } ++ } ++ else ++ { ++ /* prates = &padapter->registrypriv.dev_network.SupportedRates; */ ++ /* snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11g"); */ ++ snprintf(wrqu->name, IFNAMSIZ, "unassociated"); ++ } ++ return 0; ++} ++ ++static int rtw_wx_set_freq(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_wx_set_freq\n")); ++ ++ return 0; ++} ++ ++static int rtw_wx_get_freq(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) ++ { ++ /* wrqu->freq.m = ieee80211_wlan_frequencies[pcur_bss->Configuration.DSConfig-1] * 100000; */ ++ wrqu->freq.m = rtw_ch2freq(pcur_bss->Configuration.DSConfig) * 100000; ++ wrqu->freq.e = 1; ++ wrqu->freq.i = pcur_bss->Configuration.DSConfig; ++ ++ } ++ else { ++ wrqu->freq.m = rtw_ch2freq(padapter->mlmeextpriv.cur_channel) * 100000; ++ wrqu->freq.e = 1; ++ wrqu->freq.i = padapter->mlmeextpriv.cur_channel; ++ } ++ ++ return 0; ++} ++ ++static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ enum NDIS_802_11_NETWORK_INFRASTRUCTURE networkType ; ++ int ret = 0; ++ ++ if (_FAIL == rtw_pwr_wakeup(padapter)) { ++ ret = -EPERM; ++ goto exit; ++ } ++ ++ if (padapter->hw_init_completed ==false) { ++ ret = -EPERM; ++ goto exit; ++ } ++ ++ switch (wrqu->mode) ++ { ++ case IW_MODE_AUTO: ++ networkType = Ndis802_11AutoUnknown; ++ DBG_871X("set_mode = IW_MODE_AUTO\n"); ++ break; ++ case IW_MODE_ADHOC: ++ networkType = Ndis802_11IBSS; ++ DBG_871X("set_mode = IW_MODE_ADHOC\n"); ++ break; ++ case IW_MODE_MASTER: ++ networkType = Ndis802_11APMode; ++ DBG_871X("set_mode = IW_MODE_MASTER\n"); ++ /* rtw_setopmode_cmd(padapter, networkType, true); */ ++ break; ++ case IW_MODE_INFRA: ++ networkType = Ndis802_11Infrastructure; ++ DBG_871X("set_mode = IW_MODE_INFRA\n"); ++ break; ++ ++ default : ++ ret = -EINVAL;; ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("\n Mode: %s is not supported \n", iw_operation_mode[wrqu->mode])); ++ goto exit; ++ } ++ ++/* ++ if (Ndis802_11APMode == networkType) ++ { ++ rtw_setopmode_cmd(padapter, networkType, true); ++ } ++ else ++ { ++ rtw_setopmode_cmd(padapter, Ndis802_11AutoUnknown, true); ++ } ++*/ ++ ++ if (rtw_set_802_11_infrastructure_mode(padapter, networkType) ==false) { ++ ++ ret = -EPERM; ++ goto exit; ++ ++ } ++ ++ rtw_setopmode_cmd(padapter, networkType, true); ++ ++exit: ++ return ret; ++} ++ ++static int rtw_wx_get_mode(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, (" rtw_wx_get_mode\n")); ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) ++ { ++ wrqu->mode = IW_MODE_INFRA; ++ } ++ else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) ++ ++ { ++ wrqu->mode = IW_MODE_ADHOC; ++ } ++ else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ++ { ++ wrqu->mode = IW_MODE_MASTER; ++ } ++ else ++ { ++ wrqu->mode = IW_MODE_AUTO; ++ } ++ return 0; ++} ++ ++ ++static int rtw_wx_set_pmkid(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ u8 j, blInserted = false; ++ int intReturn = false; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct iw_pmksa* pPMK = (struct iw_pmksa*) extra; ++ u8 strZeroMacAddress[ ETH_ALEN ] = { 0x00 }; ++ u8 strIssueBssid[ ETH_ALEN ] = { 0x00 }; ++ ++ /* ++ There are the BSSID information in the bssid.sa_data array. ++ If cmd is IW_PMKSA_FLUSH, it means the wpa_suppplicant wants to clear all the PMKID information. ++ If cmd is IW_PMKSA_ADD, it means the wpa_supplicant wants to add a PMKID/BSSID to driver. ++ If cmd is IW_PMKSA_REMOVE, it means the wpa_supplicant wants to remove a PMKID/BSSID from driver. ++ */ ++ ++ memcpy(strIssueBssid, pPMK->bssid.sa_data, ETH_ALEN); ++ if (pPMK->cmd == IW_PMKSA_ADD) ++ { ++ DBG_871X("[rtw_wx_set_pmkid] IW_PMKSA_ADD!\n"); ++ if (!memcmp(strIssueBssid, strZeroMacAddress, ETH_ALEN)) ++ { ++ return(intReturn); ++ } ++ else ++ { ++ intReturn = true; ++ } ++ blInserted = false; ++ ++ /* overwrite PMKID */ ++ for (j = 0 ; jPMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) ++ { /* BSSID is matched, the same AP => rewrite with new PMKID. */ ++ ++ DBG_871X("[rtw_wx_set_pmkid] BSSID exists in the PMKList.\n"); ++ ++ memcpy(psecuritypriv->PMKIDList[j].PMKID, pPMK->pmkid, IW_PMKID_LEN); ++ psecuritypriv->PMKIDList[ j ].bUsed = true; ++ psecuritypriv->PMKIDIndex = j+1; ++ blInserted = true; ++ break; ++ } ++ } ++ ++ if (!blInserted) ++ { ++ /* Find a new entry */ ++ DBG_871X("[rtw_wx_set_pmkid] Use the new entry index = %d for this PMKID.\n", ++ psecuritypriv->PMKIDIndex); ++ ++ memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].Bssid, strIssueBssid, ETH_ALEN); ++ memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].PMKID, pPMK->pmkid, IW_PMKID_LEN); ++ ++ psecuritypriv->PMKIDList[ psecuritypriv->PMKIDIndex ].bUsed = true; ++ psecuritypriv->PMKIDIndex++ ; ++ if (psecuritypriv->PMKIDIndex == 16) ++ { ++ psecuritypriv->PMKIDIndex = 0; ++ } ++ } ++ } ++ else if (pPMK->cmd == IW_PMKSA_REMOVE) ++ { ++ DBG_871X("[rtw_wx_set_pmkid] IW_PMKSA_REMOVE!\n"); ++ intReturn = true; ++ for (j = 0 ; jPMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) ++ { /* BSSID is matched, the same AP => Remove this PMKID information and reset it. */ ++ memset(psecuritypriv->PMKIDList[ j ].Bssid, 0x00, ETH_ALEN); ++ psecuritypriv->PMKIDList[ j ].bUsed = false; ++ break; ++ } ++ } ++ } ++ else if (pPMK->cmd == IW_PMKSA_FLUSH) ++ { ++ DBG_871X("[rtw_wx_set_pmkid] IW_PMKSA_FLUSH!\n"); ++ memset(&psecuritypriv->PMKIDList[ 0 ], 0x00, sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE); ++ psecuritypriv->PMKIDIndex = 0; ++ intReturn = true; ++ } ++ return intReturn; ++} ++ ++static int rtw_wx_get_sens(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ { ++ wrqu->sens.value = 0; ++ wrqu->sens.fixed = 0; /* no auto select */ ++ wrqu->sens.disabled = 1; ++ } ++ return 0; ++} ++ ++static int rtw_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 adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ u16 val; ++ int i; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_range. cmd_code =%x\n", info->cmd)); ++ ++ 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; ++ ++ /* signal level threshold range */ ++ ++ /* percent values between 0 and 100. */ ++ range->max_qual.qual = 100; ++ range->max_qual.level = 100; ++ range->max_qual.noise = 100; ++ 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 = 256 - 78; ++ 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] = rtw_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; ++ ++ for (i = 0, val = 0; i < MAX_CHANNEL_NUM; i++) { ++ ++ /* Include only legal frequencies for some countries */ ++ if (pmlmeext->channel_set[i].ChannelNum != 0) ++ { ++ range->freq[val].i = pmlmeext->channel_set[i].ChannelNum; ++ range->freq[val].m = rtw_ch2freq(pmlmeext->channel_set[i].ChannelNum) * 100000; ++ range->freq[val].e = 1; ++ val++; ++ } ++ ++ if (val == IW_MAX_FREQUENCIES) ++ break; ++ } ++ ++ range->num_channels = val; ++ range->num_frequency = val; ++ ++/* Commented by Albert 2009/10/13 */ ++/* The following code will proivde the security capability to network manager. */ ++/* If the driver doesn't provide this capability to network manager, */ ++/* the WPA/WPA2 routers can't be choosen in the network manager. */ ++ ++/* ++#define IW_SCAN_CAPA_NONE 0x00 ++#define IW_SCAN_CAPA_ESSID 0x01 ++#define IW_SCAN_CAPA_BSSID 0x02 ++#define IW_SCAN_CAPA_CHANNEL 0x04 ++#define IW_SCAN_CAPA_MODE 0x08 ++#define IW_SCAN_CAPA_RATE 0x10 ++#define IW_SCAN_CAPA_TYPE 0x20 ++#define IW_SCAN_CAPA_TIME 0x40 ++*/ ++ ++ range->enc_capa = IW_ENC_CAPA_WPA|IW_ENC_CAPA_WPA2| ++ IW_ENC_CAPA_CIPHER_TKIP|IW_ENC_CAPA_CIPHER_CCMP; ++ ++ range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE |IW_SCAN_CAPA_BSSID| ++ IW_SCAN_CAPA_CHANNEL|IW_SCAN_CAPA_MODE|IW_SCAN_CAPA_RATE; ++ ++ return 0; ++} ++ ++/* set bssid flow */ ++/* s1. rtw_set_802_11_infrastructure_mode() */ ++/* s2. rtw_set_802_11_authentication_mode() */ ++/* s3. set_802_11_encryption_mode() */ ++/* s4. rtw_set_802_11_bssid() */ ++static int rtw_wx_set_wap(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *awrq, ++ char *extra) ++{ ++ uint ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct sockaddr *temp = (struct sockaddr *)awrq; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct list_head *phead; ++ u8 *dst_bssid, *src_bssid; ++ struct __queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ enum NDIS_802_11_AUTHENTICATION_MODE authmode; ++ ++ rtw_ps_deny(padapter, PS_DENY_JOIN); ++ if (_FAIL == rtw_pwr_wakeup(padapter)) ++ { ++ ret = -1; ++ goto exit; ++ } ++ ++ if (!padapter->bup) { ++ ret = -1; ++ goto exit; ++ } ++ ++ ++ if (temp->sa_family != ARPHRD_ETHER) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ authmode = padapter->securitypriv.ndisauthtype; ++ spin_lock_bh(&queue->lock); ++ phead = get_list_head(queue); ++ pmlmepriv->pscanned = get_next(phead); ++ ++ while (1) { ++ if (phead == pmlmepriv->pscanned) ++ break; ++ ++ pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list); ++ ++ pmlmepriv->pscanned = get_next(pmlmepriv->pscanned); ++ ++ dst_bssid = pnetwork->network.MacAddress; ++ ++ src_bssid = temp->sa_data; ++ ++ if ((!memcmp(dst_bssid, src_bssid, ETH_ALEN))) ++ { ++ if (!rtw_set_802_11_infrastructure_mode(padapter, pnetwork->network.InfrastructureMode)) ++ { ++ ret = -1; ++ spin_unlock_bh(&queue->lock); ++ goto exit; ++ } ++ ++ break; ++ } ++ ++ } ++ spin_unlock_bh(&queue->lock); ++ ++ rtw_set_802_11_authentication_mode(padapter, authmode); ++ /* set_802_11_encryption_mode(padapter, padapter->securitypriv.ndisencryptstatus); */ ++ if (rtw_set_802_11_bssid(padapter, temp->sa_data) == false) { ++ ret = -1; ++ goto exit; ++ } ++ ++exit: ++ ++ rtw_ps_deny_cancel(padapter, PS_DENY_JOIN); ++ ++ return ret; ++} ++ ++static int rtw_wx_get_wap(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; ++ ++ wrqu->ap_addr.sa_family = ARPHRD_ETHER; ++ ++ memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_wap\n")); ++ ++ if (((check_fwstate(pmlmepriv, _FW_LINKED)) == true) || ++ ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == true) || ++ ((check_fwstate(pmlmepriv, WIFI_AP_STATE)) == true)) ++ { ++ ++ memcpy(wrqu->ap_addr.sa_data, pcur_bss->MacAddress, ETH_ALEN); ++ } ++ else ++ { ++ memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); ++ } ++ ++ return 0; ++} ++ ++static int rtw_wx_set_mlme(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ u16 reason; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct iw_mlme *mlme = (struct iw_mlme *) extra; ++ ++ ++ if (mlme == NULL) ++ return -1; ++ ++ DBG_871X("%s\n", __func__); ++ ++ reason = mlme->reason_code; ++ ++ DBG_871X("%s, cmd =%d, reason =%d\n", __func__, mlme->cmd, reason); ++ ++ switch (mlme->cmd) ++ { ++ case IW_MLME_DEAUTH: ++ if (!rtw_set_802_11_disassociate(padapter)) ++ ret = -1; ++ break; ++ case IW_MLME_DISASSOC: ++ if (!rtw_set_802_11_disassociate(padapter)) ++ ret = -1; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return ret; ++} ++ ++static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ u8 _status = false; ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT]; ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_set_scan\n")); ++ ++ #ifdef DBG_IOCTL ++ DBG_871X("DBG_IOCTL %s:%d\n", __func__, __LINE__); ++ #endif ++ ++ rtw_ps_deny(padapter, PS_DENY_SCAN); ++ if (_FAIL == rtw_pwr_wakeup(padapter)) ++ { ++ ret = -1; ++ goto exit; ++ } ++ ++ if (padapter->bDriverStopped) { ++ DBG_871X("bDriverStopped =%d\n", padapter->bDriverStopped); ++ ret = -1; ++ goto exit; ++ } ++ ++ if (!padapter->bup) { ++ ret = -1; ++ goto exit; ++ } ++ ++ if (padapter->hw_init_completed ==false) { ++ ret = -1; ++ goto exit; ++ } ++ ++ /* When Busy Traffic, driver do not site survey. So driver return success. */ ++ /* wpa_supplicant will not issue SIOCSIWSCAN cmd again after scan timeout. */ ++ /* modify by thomas 2011-02-22. */ ++ if (pmlmepriv->LinkDetectInfo.bBusyTraffic == true) ++ { ++ indicate_wx_scan_complete_event(padapter); ++ goto exit; ++ } ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true) ++ { ++ indicate_wx_scan_complete_event(padapter); ++ goto exit; ++ } ++ ++ memset(ssid, 0, sizeof(struct ndis_802_11_ssid)*RTW_SSID_SCAN_AMOUNT); ++ ++ if (wrqu->data.length == sizeof(struct iw_scan_req)) ++ { ++ struct iw_scan_req *req = (struct iw_scan_req *)extra; ++ ++ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) ++ { ++ int len = min((int)req->essid_len, IW_ESSID_MAX_SIZE); ++ ++ memcpy(ssid[0].Ssid, req->essid, len); ++ ssid[0].SsidLength = len; ++ ++ DBG_871X("IW_SCAN_THIS_ESSID, ssid =%s, len =%d\n", req->essid, req->essid_len); ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ _status = rtw_sitesurvey_cmd(padapter, ssid, 1, NULL, 0); ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++ } ++ else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) ++ { ++ DBG_871X("rtw_wx_set_scan, req->scan_type == IW_SCAN_TYPE_PASSIVE\n"); ++ } ++ ++ } ++ else if (wrqu->data.length >= WEXT_CSCAN_HEADER_SIZE ++ && !memcmp(extra, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE) ++ ) ++ { ++ int len = wrqu->data.length -WEXT_CSCAN_HEADER_SIZE; ++ char *pos = extra+WEXT_CSCAN_HEADER_SIZE; ++ char section; ++ char sec_len; ++ int ssid_index = 0; ++ ++ /* DBG_871X("%s COMBO_SCAN header is recognized\n", __func__); */ ++ ++ while (len >= 1) { ++ section = *(pos++); len-= 1; ++ ++ switch (section) { ++ case WEXT_CSCAN_SSID_SECTION: ++ /* DBG_871X("WEXT_CSCAN_SSID_SECTION\n"); */ ++ if (len < 1) { ++ len = 0; ++ break; ++ } ++ ++ sec_len = *(pos++); len-= 1; ++ ++ if (sec_len>0 && sec_len<=len) { ++ ssid[ssid_index].SsidLength = sec_len; ++ memcpy(ssid[ssid_index].Ssid, pos, ssid[ssid_index].SsidLength); ++ /* DBG_871X("%s COMBO_SCAN with specific ssid:%s, %d\n", __func__ */ ++ /* , ssid[ssid_index].Ssid, ssid[ssid_index].SsidLength); */ ++ ssid_index++; ++ } ++ ++ pos+=sec_len; len-=sec_len; ++ break; ++ ++ ++ case WEXT_CSCAN_CHANNEL_SECTION: ++ /* DBG_871X("WEXT_CSCAN_CHANNEL_SECTION\n"); */ ++ pos+= 1; len-= 1; ++ break; ++ case WEXT_CSCAN_ACTV_DWELL_SECTION: ++ /* DBG_871X("WEXT_CSCAN_ACTV_DWELL_SECTION\n"); */ ++ pos+=2; len-=2; ++ break; ++ case WEXT_CSCAN_PASV_DWELL_SECTION: ++ /* DBG_871X("WEXT_CSCAN_PASV_DWELL_SECTION\n"); */ ++ pos+=2; len-=2; ++ break; ++ case WEXT_CSCAN_HOME_DWELL_SECTION: ++ /* DBG_871X("WEXT_CSCAN_HOME_DWELL_SECTION\n"); */ ++ pos+=2; len-=2; ++ break; ++ case WEXT_CSCAN_TYPE_SECTION: ++ /* DBG_871X("WEXT_CSCAN_TYPE_SECTION\n"); */ ++ pos+= 1; len-= 1; ++ break; ++ default: ++ /* DBG_871X("Unknown CSCAN section %c\n", section); */ ++ len = 0; /* stop parsing */ ++ } ++ /* DBG_871X("len:%d\n", len); */ ++ ++ } ++ ++ /* jeff: it has still some scan paramater to parse, we only do this now... */ ++ _status = rtw_set_802_11_bssid_list_scan(padapter, ssid, RTW_SSID_SCAN_AMOUNT); ++ ++ } else ++ ++ { ++ _status = rtw_set_802_11_bssid_list_scan(padapter, NULL, 0); ++ } ++ ++ if (_status == false) ++ ret = -1; ++ ++exit: ++ ++ rtw_ps_deny_cancel(padapter, PS_DENY_SCAN); ++ ++ #ifdef DBG_IOCTL ++ DBG_871X("DBG_IOCTL %s:%d return %d\n", __func__, __LINE__, ret); ++ #endif ++ ++ return ret; ++} ++ ++static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct list_head *plist, *phead; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct __queue *queue = &(pmlmepriv->scanned_queue); ++ struct wlan_network *pnetwork = NULL; ++ char *ev = extra; ++ char *stop = ev + wrqu->data.length; ++ u32 ret = 0; ++ sint wait_status; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan\n")); ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, (" Start of Query SIOCGIWSCAN .\n")); ++ ++ #ifdef DBG_IOCTL ++ DBG_871X("DBG_IOCTL %s:%d\n", __func__, __LINE__); ++ #endif ++ ++ if (adapter_to_pwrctl(padapter)->brfoffbyhw && padapter->bDriverStopped) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ wait_status = _FW_UNDER_SURVEY | _FW_UNDER_LINKING; ++ ++ if (check_fwstate(pmlmepriv, wait_status)) ++ return -EAGAIN; ++ ++ spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); ++ ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ while (1) ++ { ++ if (phead == plist) ++ break; ++ ++ if ((stop - ev) < SCAN_ITEM_SIZE) { ++ ret = -E2BIG; ++ break; ++ } ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ ++ /* report network only if the current channel set contains the channel to which this network belongs */ ++ if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, pnetwork->network.Configuration.DSConfig) >= 0 ++ && rtw_mlme_band_check(padapter, pnetwork->network.Configuration.DSConfig) == true ++ && true == rtw_validate_ssid(&(pnetwork->network.Ssid)) ++ ) ++ { ++ ev =translate_scan(padapter, a, pnetwork, ev, stop); ++ } ++ ++ plist = get_next(plist); ++ ++ } ++ ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ ++ wrqu->data.length = ev-extra; ++ wrqu->data.flags = 0; ++ ++exit: ++ ++ #ifdef DBG_IOCTL ++ DBG_871X("DBG_IOCTL %s:%d return %d\n", __func__, __LINE__, ret); ++ #endif ++ ++ return ret ; ++ ++} ++ ++/* set ssid flow */ ++/* s1. rtw_set_802_11_infrastructure_mode() */ ++/* s2. set_802_11_authenticaion_mode() */ ++/* s3. set_802_11_encryption_mode() */ ++/* s4. rtw_set_802_11_ssid() */ ++static int rtw_wx_set_essid(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct __queue *queue = &pmlmepriv->scanned_queue; ++ struct list_head *phead; ++ struct wlan_network *pnetwork = NULL; ++ enum NDIS_802_11_AUTHENTICATION_MODE authmode; ++ struct ndis_802_11_ssid ndis_ssid; ++ u8 *dst_ssid, *src_ssid; ++ ++ uint ret = 0, len; ++ ++ #ifdef DBG_IOCTL ++ DBG_871X("DBG_IOCTL %s:%d\n", __func__, __LINE__); ++ #endif ++ ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ++ ("+rtw_wx_set_essid: fw_state = 0x%08x\n", get_fwstate(pmlmepriv))); ++ ++ rtw_ps_deny(padapter, PS_DENY_JOIN); ++ if (_FAIL == rtw_pwr_wakeup(padapter)) ++ { ++ ret = -1; ++ goto exit; ++ } ++ ++ if (!padapter->bup) { ++ ret = -1; ++ goto exit; ++ } ++ ++ if (wrqu->essid.length > IW_ESSID_MAX_SIZE) { ++ ret = -E2BIG; ++ goto exit; ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ ret = -1; ++ goto exit; ++ } ++ ++ authmode = padapter->securitypriv.ndisauthtype; ++ DBG_871X("=>%s\n", __func__); ++ if (wrqu->essid.flags && wrqu->essid.length) ++ { ++ len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? wrqu->essid.length : IW_ESSID_MAX_SIZE; ++ ++ if (wrqu->essid.length != 33) ++ DBG_871X("ssid =%s, len =%d\n", extra, wrqu->essid.length); ++ ++ memset(&ndis_ssid, 0, sizeof(struct ndis_802_11_ssid)); ++ ndis_ssid.SsidLength = len; ++ memcpy(ndis_ssid.Ssid, extra, len); ++ src_ssid = ndis_ssid.Ssid; ++ ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("rtw_wx_set_essid: ssid =[%s]\n", src_ssid)); ++ spin_lock_bh(&queue->lock); ++ phead = get_list_head(queue); ++ pmlmepriv->pscanned = get_next(phead); ++ ++ while (1) { ++ if (phead == pmlmepriv->pscanned) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_warning_, ++ ("rtw_wx_set_essid: scan_q is empty, set ssid to check if scanning again!\n")); ++ ++ break; ++ } ++ ++ pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list); ++ ++ pmlmepriv->pscanned = get_next(pmlmepriv->pscanned); ++ ++ dst_ssid = pnetwork->network.Ssid.Ssid; ++ ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ++ ("rtw_wx_set_essid: dst_ssid =%s\n", ++ pnetwork->network.Ssid.Ssid)); ++ ++ if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.SsidLength)) && ++ (pnetwork->network.Ssid.SsidLength ==ndis_ssid.SsidLength)) ++ { ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ++ ("rtw_wx_set_essid: find match, set infra mode\n")); ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) ++ { ++ if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode) ++ continue; ++ } ++ ++ if (rtw_set_802_11_infrastructure_mode(padapter, pnetwork->network.InfrastructureMode) == false) ++ { ++ ret = -1; ++ spin_unlock_bh(&queue->lock); ++ goto exit; ++ } ++ ++ break; ++ } ++ } ++ spin_unlock_bh(&queue->lock); ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ++ ("set ssid: set_802_11_auth. mode =%d\n", authmode)); ++ rtw_set_802_11_authentication_mode(padapter, authmode); ++ /* set_802_11_encryption_mode(padapter, padapter->securitypriv.ndisencryptstatus); */ ++ if (rtw_set_802_11_ssid(padapter, &ndis_ssid) == false) { ++ ret = -1; ++ goto exit; ++ } ++ } ++ ++exit: ++ ++ rtw_ps_deny_cancel(padapter, PS_DENY_JOIN); ++ ++ DBG_871X("<=%s, ret %d\n", __func__, ret); ++ ++ #ifdef DBG_IOCTL ++ DBG_871X("DBG_IOCTL %s:%d return %d\n", __func__, __LINE__, ret); ++ #endif ++ ++ return ret; ++} ++ ++static int rtw_wx_get_essid(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ u32 len, ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_essid\n")); ++ ++ if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) ++ { ++ len = pcur_bss->Ssid.SsidLength; ++ ++ wrqu->essid.length = len; ++ ++ memcpy(extra, pcur_bss->Ssid.Ssid, len); ++ ++ wrqu->essid.flags = 1; ++ } ++ else ++ { ++ ret = -1; ++ goto exit; ++ } ++ ++exit: ++ return ret; ++} ++ ++static int rtw_wx_set_rate(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int i, ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ u8 datarates[NumRates]; ++ u32 target_rate = wrqu->bitrate.value; ++ u32 fixed = wrqu->bitrate.fixed; ++ u32 ratevalue = 0; ++ u8 mpdatarate[NumRates]={11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff}; ++ ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, (" rtw_wx_set_rate\n")); ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("target_rate = %d, fixed = %d\n", target_rate, fixed)); ++ ++ if (target_rate == -1) { ++ ratevalue = 11; ++ goto set_rate; ++ } ++ target_rate = target_rate/100000; ++ ++ switch (target_rate) { ++ case 10: ++ ratevalue = 0; ++ break; ++ case 20: ++ ratevalue = 1; ++ break; ++ case 55: ++ ratevalue = 2; ++ break; ++ case 60: ++ ratevalue = 3; ++ break; ++ case 90: ++ ratevalue = 4; ++ break; ++ case 110: ++ ratevalue = 5; ++ break; ++ case 120: ++ ratevalue = 6; ++ break; ++ case 180: ++ ratevalue = 7; ++ break; ++ case 240: ++ ratevalue = 8; ++ break; ++ case 360: ++ ratevalue = 9; ++ break; ++ case 480: ++ ratevalue = 10; ++ break; ++ case 540: ++ ratevalue = 11; ++ break; ++ default: ++ ratevalue = 11; ++ break; ++ } ++ ++set_rate: ++ ++ for (i = 0; ibitrate.fixed = 0; /* no auto select */ ++ wrqu->bitrate.value = max_rate * 100000; ++ ++ return 0; ++} ++ ++static int rtw_wx_set_rts(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ if (wrqu->rts.disabled) ++ padapter->registrypriv.rts_thresh = 2347; ++ else { ++ if (wrqu->rts.value < 0 || ++ wrqu->rts.value > 2347) ++ return -EINVAL; ++ ++ padapter->registrypriv.rts_thresh = wrqu->rts.value; ++ } ++ ++ DBG_871X("%s, rts_thresh =%d\n", __func__, padapter->registrypriv.rts_thresh); ++ ++ return 0; ++} ++ ++static int rtw_wx_get_rts(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ DBG_871X("%s, rts_thresh =%d\n", __func__, padapter->registrypriv.rts_thresh); ++ ++ wrqu->rts.value = padapter->registrypriv.rts_thresh; ++ wrqu->rts.fixed = 0; /* no auto select */ ++ /* wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); */ ++ ++ return 0; ++} ++ ++static int rtw_wx_set_frag(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ if (wrqu->frag.disabled) ++ padapter->xmitpriv.frag_len = MAX_FRAG_THRESHOLD; ++ else { ++ if (wrqu->frag.value < MIN_FRAG_THRESHOLD || ++ wrqu->frag.value > MAX_FRAG_THRESHOLD) ++ return -EINVAL; ++ ++ padapter->xmitpriv.frag_len = wrqu->frag.value & ~0x1; ++ } ++ ++ DBG_871X("%s, frag_len =%d\n", __func__, padapter->xmitpriv.frag_len); ++ ++ return 0; ++ ++} ++ ++static int rtw_wx_get_frag(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ DBG_871X("%s, frag_len =%d\n", __func__, padapter->xmitpriv.frag_len); ++ ++ wrqu->frag.value = padapter->xmitpriv.frag_len; ++ wrqu->frag.fixed = 0; /* no auto select */ ++ /* wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD); */ ++ ++ return 0; ++} ++ ++static int rtw_wx_get_retry(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ /* struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); */ ++ ++ ++ wrqu->retry.value = 7; ++ wrqu->retry.fixed = 0; /* no auto select */ ++ wrqu->retry.disabled = 1; ++ ++ return 0; ++ ++} ++ ++static int rtw_wx_set_enc(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *keybuf) ++{ ++ u32 key, ret = 0; ++ u32 keyindex_provided; ++ struct ndis_802_11_wep wep; ++ enum NDIS_802_11_AUTHENTICATION_MODE authmode; ++ ++ struct iw_point *erq = &(wrqu->encoding); ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ DBG_871X("+rtw_wx_set_enc, flags = 0x%x\n", erq->flags); ++ ++ memset(&wep, 0, sizeof(struct ndis_802_11_wep)); ++ ++ key = erq->flags & IW_ENCODE_INDEX; ++ ++ if (erq->flags & IW_ENCODE_DISABLED) ++ { ++ DBG_871X("EncryptionDisabled\n"); ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; ++ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */ ++ authmode = Ndis802_11AuthModeOpen; ++ padapter->securitypriv.ndisauthtype =authmode; ++ ++ goto exit; ++ } ++ ++ if (key) { ++ if (key > WEP_KEYS) ++ return -EINVAL; ++ key--; ++ keyindex_provided = 1; ++ } ++ else ++ { ++ keyindex_provided = 0; ++ key = padapter->securitypriv.dot11PrivacyKeyIndex; ++ DBG_871X("rtw_wx_set_enc, key =%d\n", key); ++ } ++ ++ /* set authentication mode */ ++ if (erq->flags & IW_ENCODE_OPEN) ++ { ++ DBG_871X("rtw_wx_set_enc():IW_ENCODE_OPEN\n"); ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;/* Ndis802_11EncryptionDisabled; */ ++ ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; ++ ++ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; ++ authmode = Ndis802_11AuthModeOpen; ++ padapter->securitypriv.ndisauthtype =authmode; ++ } ++ else if (erq->flags & IW_ENCODE_RESTRICTED) ++ { ++ DBG_871X("rtw_wx_set_enc():IW_ENCODE_RESTRICTED\n"); ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared; ++ ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; ++ padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_; ++ authmode = Ndis802_11AuthModeShared; ++ padapter->securitypriv.ndisauthtype =authmode; ++ } ++ else ++ { ++ DBG_871X("rtw_wx_set_enc():erq->flags = 0x%x\n", erq->flags); ++ ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;/* Ndis802_11EncryptionDisabled; */ ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */ ++ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; ++ authmode = Ndis802_11AuthModeOpen; ++ padapter->securitypriv.ndisauthtype =authmode; ++ } ++ ++ wep.KeyIndex = key; ++ if (erq->length > 0) ++ { ++ wep.KeyLength = erq->length <= 5 ? 5 : 13; ++ ++ wep.Length = wep.KeyLength + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial); ++ } ++ else ++ { ++ wep.KeyLength = 0 ; ++ ++ if (keyindex_provided == 1)/* set key_id only, no given KeyMaterial(erq->length == 0). */ ++ { ++ padapter->securitypriv.dot11PrivacyKeyIndex = key; ++ ++ DBG_871X("(keyindex_provided == 1), keyid =%d, key_len =%d\n", key, padapter->securitypriv.dot11DefKeylen[key]); ++ ++ switch (padapter->securitypriv.dot11DefKeylen[key]) ++ { ++ case 5: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; ++ break; ++ case 13: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; ++ break; ++ default: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ break; ++ } ++ ++ goto exit; ++ ++ } ++ ++ } ++ ++ wep.KeyIndex |= 0x80000000; ++ ++ memcpy(wep.KeyMaterial, keybuf, wep.KeyLength); ++ ++ if (rtw_set_802_11_add_wep(padapter, &wep) == false) { ++ if (rf_on == pwrpriv->rf_pwrstate) ++ ret = -EOPNOTSUPP; ++ goto exit; ++ } ++ ++exit: ++ return ret; ++} ++ ++static int rtw_wx_get_enc(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *keybuf) ++{ ++ uint key, ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct iw_point *erq = &(wrqu->encoding); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) != true) ++ { ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) != true) ++ { ++ erq->length = 0; ++ erq->flags |= IW_ENCODE_DISABLED; ++ return 0; ++ } ++ } ++ ++ ++ key = erq->flags & IW_ENCODE_INDEX; ++ ++ if (key) { ++ if (key > WEP_KEYS) ++ return -EINVAL; ++ key--; ++ } else ++ { ++ key = padapter->securitypriv.dot11PrivacyKeyIndex; ++ } ++ ++ erq->flags = key + 1; ++ ++ /* if (padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeOpen) */ ++ /* */ ++ /* erq->flags |= IW_ENCODE_OPEN; */ ++ /* */ ++ ++ switch (padapter->securitypriv.ndisencryptstatus) ++ { ++ case Ndis802_11EncryptionNotSupported: ++ case Ndis802_11EncryptionDisabled: ++ erq->length = 0; ++ erq->flags |= IW_ENCODE_DISABLED; ++ break; ++ case Ndis802_11Encryption1Enabled: ++ erq->length = padapter->securitypriv.dot11DefKeylen[key]; ++ ++ if (erq->length) ++ { ++ memcpy(keybuf, padapter->securitypriv.dot11DefKey[key].skey, padapter->securitypriv.dot11DefKeylen[key]); ++ ++ erq->flags |= IW_ENCODE_ENABLED; ++ ++ if (padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeOpen) ++ { ++ erq->flags |= IW_ENCODE_OPEN; ++ } ++ else if (padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeShared) ++ { ++ erq->flags |= IW_ENCODE_RESTRICTED; ++ } ++ } ++ else ++ { ++ erq->length = 0; ++ erq->flags |= IW_ENCODE_DISABLED; ++ } ++ break; ++ case Ndis802_11Encryption2Enabled: ++ case Ndis802_11Encryption3Enabled: ++ erq->length = 16; ++ erq->flags |= (IW_ENCODE_ENABLED | IW_ENCODE_OPEN | IW_ENCODE_NOKEY); ++ break; ++ default: ++ erq->length = 0; ++ erq->flags |= IW_ENCODE_DISABLED; ++ break; ++ } ++ return ret; ++} ++ ++static int rtw_wx_get_power(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ /* struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); */ ++ ++ wrqu->power.value = 0; ++ wrqu->power.fixed = 0; /* no auto select */ ++ wrqu->power.disabled = 1; ++ ++ return 0; ++} ++ ++static int rtw_wx_set_gen_ie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ ret = rtw_set_wpa_ie(padapter, extra, wrqu->data.length); ++ ++ return ret; ++} ++ ++static int rtw_wx_set_auth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct iw_param *param = (struct iw_param*)&(wrqu->param); ++ int ret = 0; ++ ++ switch (param->flags & IW_AUTH_INDEX) { ++ ++ case IW_AUTH_WPA_VERSION: ++ break; ++ case IW_AUTH_CIPHER_PAIRWISE: ++ ++ break; ++ case IW_AUTH_CIPHER_GROUP: ++ ++ break; ++ case IW_AUTH_KEY_MGMT: ++ /* ++ * ??? does not use these parameters ++ */ ++ break; ++ ++ case IW_AUTH_TKIP_COUNTERMEASURES: ++ { ++ if (param->value) ++ { /* wpa_supplicant is enabling the tkip countermeasure. */ ++ padapter->securitypriv.btkip_countermeasure = true; ++ } ++ else ++ { /* wpa_supplicant is disabling the tkip countermeasure. */ ++ padapter->securitypriv.btkip_countermeasure = false; ++ } ++ break; ++ } ++ case IW_AUTH_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. ++ */ ++ ++ if (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption1Enabled) ++ { ++ break;/* it means init value, or using wep, ndisencryptstatus = Ndis802_11Encryption1Enabled, */ ++ /* then it needn't reset it; */ ++ } ++ ++ if (param->value) { ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; ++ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */ ++ padapter->securitypriv.ndisauthtype =Ndis802_11AuthModeOpen; ++ } ++ ++ break; ++ } ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ ++ /* ++ * It's the starting point of a link layer connection using wpa_supplicant ++ */ ++ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { ++ LeaveAllPowerSaveMode(padapter); ++ rtw_disassoc_cmd(padapter, 500, false); ++ DBG_871X("%s...call rtw_indicate_disconnect\n ", __func__); ++ rtw_indicate_disconnect(padapter); ++ rtw_free_assoc_resources(padapter, 1); ++ } ++ ++ ++ ret = wpa_set_auth_algs(dev, (u32)param->value); ++ ++ break; ++ ++ case IW_AUTH_WPA_ENABLED: ++ break; ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ break; ++ case IW_AUTH_PRIVACY_INVOKED: ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ return ret; ++} ++ ++static int rtw_wx_set_enc_ext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ char *alg_name; ++ u32 param_len; ++ struct ieee_param *param = NULL; ++ struct iw_point *pencoding = &wrqu->encoding; ++ struct iw_encode_ext *pext = (struct iw_encode_ext *)extra; ++ int ret = 0; ++ ++ param_len = sizeof(struct ieee_param) + pext->key_len; ++ param = (struct ieee_param *)rtw_malloc(param_len); ++ if (param == NULL) ++ return -1; ++ ++ memset(param, 0, param_len); ++ ++ param->cmd = IEEE_CMD_SET_ENCRYPTION; ++ memset(param->sta_addr, 0xff, ETH_ALEN); ++ ++ ++ switch (pext->alg) { ++ case IW_ENCODE_ALG_NONE: ++ /* todo: remove key */ ++ /* remove = 1; */ ++ alg_name = "none"; ++ break; ++ case IW_ENCODE_ALG_WEP: ++ alg_name = "WEP"; ++ break; ++ case IW_ENCODE_ALG_TKIP: ++ alg_name = "TKIP"; ++ break; ++ case IW_ENCODE_ALG_CCMP: ++ alg_name = "CCMP"; ++ break; ++ case IW_ENCODE_ALG_AES_CMAC: ++ alg_name = "BIP"; ++ break; ++ default: ++ ret = -1; ++ goto exit; ++ } ++ ++ strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN); ++ ++ if (pext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ { ++ param->u.crypt.set_tx = 1; ++ } ++ ++ /* cliW: WEP does not have group key ++ * just not checking GROUP key setting ++ */ ++ if ((pext->alg != IW_ENCODE_ALG_WEP) && ++ ((pext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) ++ || (pext->ext_flags & IW_ENCODE_ALG_AES_CMAC) ++ )) ++ { ++ param->u.crypt.set_tx = 0; ++ } ++ ++ param->u.crypt.idx = (pencoding->flags&0x00FF) -1 ; ++ ++ if (pext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) ++ { ++ memcpy(param->u.crypt.seq, pext->rx_seq, 8); ++ } ++ ++ if (pext->key_len) ++ { ++ param->u.crypt.key_len = pext->key_len; ++ /* memcpy(param + 1, pext + 1, pext->key_len); */ ++ memcpy(param->u.crypt.key, pext + 1, pext->key_len); ++ } ++ ++ if (pencoding->flags & IW_ENCODE_DISABLED) ++ { ++ /* todo: remove key */ ++ /* remove = 1; */ ++ } ++ ++ ret = wpa_set_encryption(dev, param, param_len); ++ ++exit: ++ if (param) ++ { ++ kfree((u8 *)param); ++ } ++ ++ return ret; ++} ++ ++ ++static int rtw_wx_get_nick(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ /* struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); */ ++ /* struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); */ ++ /* struct security_priv *psecuritypriv = &padapter->securitypriv; */ ++ ++ if (extra) ++ { ++ wrqu->data.length = 14; ++ wrqu->data.flags = 1; ++ memcpy(extra, "", 14); ++ } ++ return 0; ++} ++ ++static int rtw_wx_read32(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter; ++ struct iw_point *p; ++ u16 len; ++ u32 addr; ++ u32 data32; ++ u32 bytes; ++ u8 *ptmp; ++ int ret; ++ ++ ++ ret = 0; ++ padapter = (struct adapter *)rtw_netdev_priv(dev); ++ p = &wrqu->data; ++ len = p->length; ++ if (0 == len) ++ return -EINVAL; ++ ++ ptmp = (u8 *)rtw_malloc(len); ++ if (NULL == ptmp) ++ return -ENOMEM; ++ ++ if (copy_from_user(ptmp, p->pointer, len)) { ++ ret = -EFAULT; ++ goto exit; ++ } ++ ++ bytes = 0; ++ addr = 0; ++ sscanf(ptmp, "%d,%x", &bytes, &addr); ++ ++ switch (bytes) { ++ case 1: ++ data32 = rtw_read8(padapter, addr); ++ sprintf(extra, "0x%02X", data32); ++ break; ++ case 2: ++ data32 = rtw_read16(padapter, addr); ++ sprintf(extra, "0x%04X", data32); ++ break; ++ case 4: ++ data32 = rtw_read32(padapter, addr); ++ sprintf(extra, "0x%08X", data32); ++ break; ++ default: ++ DBG_871X(KERN_INFO "%s: usage> read [bytes],[address(hex)]\n", __func__); ++ ret = -EINVAL; ++ goto exit; ++ } ++ DBG_871X(KERN_INFO "%s: addr = 0x%08X data =%s\n", __func__, addr, extra); ++ ++exit: ++ kfree(ptmp); ++ ++ return 0; ++} ++ ++static int rtw_wx_write32(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ u32 addr; ++ u32 data32; ++ u32 bytes; ++ ++ ++ bytes = 0; ++ addr = 0; ++ data32 = 0; ++ sscanf(extra, "%d,%x,%x", &bytes, &addr, &data32); ++ ++ switch (bytes) { ++ case 1: ++ rtw_write8(padapter, addr, (u8)data32); ++ DBG_871X(KERN_INFO "%s: addr = 0x%08X data = 0x%02X\n", __func__, addr, (u8)data32); ++ break; ++ case 2: ++ rtw_write16(padapter, addr, (u16)data32); ++ DBG_871X(KERN_INFO "%s: addr = 0x%08X data = 0x%04X\n", __func__, addr, (u16)data32); ++ break; ++ case 4: ++ rtw_write32(padapter, addr, data32); ++ DBG_871X(KERN_INFO "%s: addr = 0x%08X data = 0x%08X\n", __func__, addr, data32); ++ break; ++ default: ++ DBG_871X(KERN_INFO "%s: usage> write [bytes],[address(hex)],[data(hex)]\n", __func__); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int rtw_wx_read_rf(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ u32 path, addr, data32; ++ ++ ++ path = *(u32*)extra; ++ addr = *((u32*)extra + 1); ++ data32 = rtw_hal_read_rfreg(padapter, path, addr, 0xFFFFF); ++ /* ++ * IMPORTANT!! ++ * Only when wireless private ioctl is at odd order, ++ * "extra" would be copied to user space. ++ */ ++ sprintf(extra, "0x%05x", data32); ++ ++ return 0; ++} ++ ++static int rtw_wx_write_rf(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ u32 path, addr, data32; ++ ++ ++ path = *(u32*)extra; ++ addr = *((u32*)extra + 1); ++ data32 = *((u32*)extra + 2); ++/* DBG_871X("%s: path =%d addr = 0x%02x data = 0x%05x\n", __func__, path, addr, data32); */ ++ rtw_hal_write_rfreg(padapter, path, addr, 0xFFFFF, data32); ++ ++ return 0; ++} ++ ++static int rtw_wx_priv_null(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ return -1; ++} ++ ++static int dummy(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ /* struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); */ ++ /* struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); */ ++ ++ /* DBG_871X("cmd_code =%x, fwstate = 0x%x\n", a->cmd, get_fwstate(pmlmepriv)); */ ++ ++ return -1; ++ ++} ++ ++static int rtw_wx_set_channel_plan(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ u8 channel_plan_req = (u8) (*((int *)wrqu)); ++ ++ if (_SUCCESS == rtw_set_chplan_cmd(padapter, channel_plan_req, 1, 1)) { ++ DBG_871X("%s set channel_plan = 0x%02X\n", __func__, channel_plan_req); ++ } else ++ return -EPERM; ++ ++ return 0; ++} ++ ++static int rtw_wx_set_mtk_wps_probe_ie(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ return 0; ++} ++ ++static int rtw_wx_get_sensitivity(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *buf) ++{ ++ return 0; ++} ++ ++static int rtw_wx_set_mtk_wps_ie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ return 0; ++} ++ ++/* ++typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++*/ ++/* ++ *For all data larger than 16 octets, we need to use a ++ *pointer to memory allocated in user space. ++ */ ++static int rtw_drvext_hdl(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ return 0; ++} ++ ++static int rtw_mp_ioctl_hdl(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ return ret; ++} ++ ++static int rtw_get_ap_info(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ u32 cnt = 0, wpa_ielen; ++ struct list_head *plist, *phead; ++ unsigned char *pbuf; ++ u8 bssid[ETH_ALEN]; ++ char data[32]; ++ struct wlan_network *pnetwork = NULL; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct __queue *queue = &(pmlmepriv->scanned_queue); ++ struct iw_point *pdata = &wrqu->data; ++ ++ DBG_871X("+rtw_get_aplist_info\n"); ++ ++ if ((padapter->bDriverStopped) || (pdata == NULL)) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ while ((check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING))) == true) ++ { ++ msleep(30); ++ cnt++; ++ if (cnt > 100) ++ break; ++ } ++ ++ ++ /* pdata->length = 0;? */ ++ pdata->flags = 0; ++ if (pdata->length>=32) ++ { ++ if (copy_from_user(data, pdata->pointer, 32)) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ } ++ else ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); ++ ++ phead = get_list_head(queue); ++ plist = get_next(phead); ++ ++ while (1) ++ { ++ if (phead == plist) ++ break; ++ ++ ++ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); ++ ++ /* if (hwaddr_aton_i(pdata->pointer, bssid)) */ ++ if (hwaddr_aton_i(data, bssid)) ++ { ++ DBG_871X("Invalid BSSID '%s'.\n", (u8 *)data); ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ return -EINVAL; ++ } ++ ++ ++ if (!memcmp(bssid, pnetwork->network.MacAddress, ETH_ALEN))/* BSSID match, then check if supporting wpa/wpa2 */ ++ { ++ DBG_871X("BSSID:" MAC_FMT "\n", MAC_ARG(bssid)); ++ ++ pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12); ++ if (pbuf && (wpa_ielen>0)) ++ { ++ pdata->flags = 1; ++ break; ++ } ++ ++ pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12); ++ if (pbuf && (wpa_ielen>0)) ++ { ++ pdata->flags = 2; ++ break; ++ } ++ ++ } ++ ++ plist = get_next(plist); ++ ++ } ++ ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); ++ ++ if (pdata->length>=34) ++ { ++ if (copy_to_user((u8 __force __user *)pdata->pointer+32, (u8 *)&pdata->flags, 1)) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ } ++ ++exit: ++ ++ return ret; ++ ++} ++ ++static int rtw_set_pid(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ int *pdata = (int *)wrqu; ++ int selector; ++ ++ if ((padapter->bDriverStopped) || (pdata == NULL)) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ selector = *pdata; ++ if (selector < 3 && selector >= 0) { ++ padapter->pid[selector] = *(pdata+1); ++ DBG_871X("%s set pid[%d]=%d\n", __func__, selector , padapter->pid[selector]); ++ } ++ else ++ DBG_871X("%s selector %d error\n", __func__, selector); ++ ++exit: ++ ++ return ret; ++ ++} ++ ++static int rtw_wps_start(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ u32 u32wps_start = 0; ++ unsigned int uintRet = 0; ++ ++ if ((true == padapter->bDriverStopped) ||(true ==padapter->bSurpriseRemoved) || (NULL == pdata)) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ uintRet = copy_from_user((void*) &u32wps_start, pdata->pointer, 4); ++ if (u32wps_start == 0) ++ { ++ u32wps_start = *extra; ++ } ++ ++ DBG_871X("[%s] wps_start = %d\n", __func__, u32wps_start); ++ ++#ifdef CONFIG_INTEL_WIDI ++ process_intel_widi_wps_status(padapter, u32wps_start); ++#endif /* CONFIG_INTEL_WIDI */ ++ ++exit: ++ ++ return ret; ++ ++} ++ ++static int rtw_p2p_set(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ ++ return ret; ++ ++} ++ ++static int rtw_p2p_get(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ ++ return ret; ++ ++} ++ ++static int rtw_p2p_get2(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret = 0; ++ ++ return ret; ++ ++} ++ ++static int rtw_rereg_nd_name(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ struct rereg_nd_name_data *rereg_priv = &padapter->rereg_nd_name_priv; ++ char new_ifname[IFNAMSIZ]; ++ ++ if (rereg_priv->old_ifname[0] == 0) { ++ char *reg_ifname; ++ reg_ifname = padapter->registrypriv.ifname; ++ ++ strncpy(rereg_priv->old_ifname, reg_ifname, IFNAMSIZ); ++ rereg_priv->old_ifname[IFNAMSIZ-1] = 0; ++ } ++ ++ /* DBG_871X("%s wrqu->data.length:%d\n", __func__, wrqu->data.length); */ ++ if (wrqu->data.length > IFNAMSIZ) ++ return -EFAULT; ++ ++ if (copy_from_user(new_ifname, wrqu->data.pointer, IFNAMSIZ)) { ++ return -EFAULT; ++ } ++ ++ if (0 == strcmp(rereg_priv->old_ifname, new_ifname)) { ++ return ret; ++ } ++ ++ DBG_871X("%s new_ifname:%s\n", __func__, new_ifname); ++ if (0 != (ret = rtw_change_ifname(padapter, new_ifname))) { ++ goto exit; ++ } ++ ++ strncpy(rereg_priv->old_ifname, new_ifname, IFNAMSIZ); ++ rereg_priv->old_ifname[IFNAMSIZ-1] = 0; ++ ++ if (!memcmp(new_ifname, "disable%d", 9)) { ++ ++ DBG_871X("%s disable\n", __func__); ++ /* free network queue for Android's timming issue */ ++ rtw_free_network_queue(padapter, true); ++ ++ /* the interface is being "disabled", we can do deeper IPS */ ++ /* rereg_priv->old_ips_mode = rtw_get_ips_mode_req(&padapter->pwrctrlpriv); */ ++ /* rtw_ips_mode_req(&padapter->pwrctrlpriv, IPS_NORMAL); */ ++ } ++exit: ++ return ret; ++ ++} ++ ++static int rtw_dbg_port(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ u8 major_cmd, minor_cmd; ++ u16 arg; ++ u32 extra_arg, *pdata, val32; ++ struct sta_info *psta; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct wlan_network *cur_network = &(pmlmepriv->cur_network); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ ++ pdata = (u32*)&wrqu->data; ++ ++ val32 = *pdata; ++ arg = (u16)(val32&0x0000ffff); ++ major_cmd = (u8)(val32>>24); ++ minor_cmd = (u8)((val32>>16)&0x00ff); ++ ++ extra_arg = *(pdata+1); ++ ++ switch (major_cmd) ++ { ++ case 0x70:/* read_reg */ ++ switch (minor_cmd) ++ { ++ case 1: ++ DBG_871X("rtw_read8(0x%x) = 0x%02x\n", arg, rtw_read8(padapter, arg)); ++ break; ++ case 2: ++ DBG_871X("rtw_read16(0x%x) = 0x%04x\n", arg, rtw_read16(padapter, arg)); ++ break; ++ case 4: ++ DBG_871X("rtw_read32(0x%x) = 0x%08x\n", arg, rtw_read32(padapter, arg)); ++ break; ++ } ++ break; ++ case 0x71:/* write_reg */ ++ switch (minor_cmd) ++ { ++ case 1: ++ rtw_write8(padapter, arg, extra_arg); ++ DBG_871X("rtw_write8(0x%x) = 0x%02x\n", arg, rtw_read8(padapter, arg)); ++ break; ++ case 2: ++ rtw_write16(padapter, arg, extra_arg); ++ DBG_871X("rtw_write16(0x%x) = 0x%04x\n", arg, rtw_read16(padapter, arg)); ++ break; ++ case 4: ++ rtw_write32(padapter, arg, extra_arg); ++ DBG_871X("rtw_write32(0x%x) = 0x%08x\n", arg, rtw_read32(padapter, arg)); ++ break; ++ } ++ break; ++ case 0x72:/* read_bb */ ++ DBG_871X("read_bbreg(0x%x) = 0x%x\n", arg, rtw_hal_read_bbreg(padapter, arg, 0xffffffff)); ++ break; ++ case 0x73:/* write_bb */ ++ rtw_hal_write_bbreg(padapter, arg, 0xffffffff, extra_arg); ++ DBG_871X("write_bbreg(0x%x) = 0x%x\n", arg, rtw_hal_read_bbreg(padapter, arg, 0xffffffff)); ++ break; ++ case 0x74:/* read_rf */ ++ DBG_871X("read RF_reg path(0x%02x), offset(0x%x), value(0x%08x)\n", minor_cmd, arg, rtw_hal_read_rfreg(padapter, minor_cmd, arg, 0xffffffff)); ++ break; ++ case 0x75:/* write_rf */ ++ rtw_hal_write_rfreg(padapter, minor_cmd, arg, 0xffffffff, extra_arg); ++ DBG_871X("write RF_reg path(0x%02x), offset(0x%x), value(0x%08x)\n", minor_cmd, arg, rtw_hal_read_rfreg(padapter, minor_cmd, arg, 0xffffffff)); ++ break; ++ ++ case 0x76: ++ switch (minor_cmd) ++ { ++ case 0x00: /* normal mode, */ ++ padapter->recvpriv.is_signal_dbg = 0; ++ break; ++ case 0x01: /* dbg mode */ ++ padapter->recvpriv.is_signal_dbg = 1; ++ extra_arg = extra_arg>100?100:extra_arg; ++ padapter->recvpriv.signal_strength_dbg =extra_arg; ++ break; ++ } ++ break; ++ case 0x78: /* IOL test */ ++ break; ++ case 0x79: ++ { ++ /* ++ * dbg 0x79000000 [value], set RESP_TXAGC to + value, value:0~15 ++ * dbg 0x79010000 [value], set RESP_TXAGC to - value, value:0~15 ++ */ ++ u8 value = extra_arg & 0x0f; ++ u8 sign = minor_cmd; ++ u16 write_value = 0; ++ ++ DBG_871X("%s set RESP_TXAGC to %s %u\n", __func__, sign?"minus":"plus", value); ++ ++ if (sign) ++ value = value | 0x10; ++ ++ write_value = value | (value << 5); ++ rtw_write16(padapter, 0x6d9, write_value); ++ } ++ break; ++ case 0x7a: ++ receive_disconnect(padapter, pmlmeinfo->network.MacAddress ++ , WLAN_REASON_EXPIRATION_CHK); ++ break; ++ case 0x7F: ++ switch (minor_cmd) ++ { ++ case 0x0: ++ DBG_871X("fwstate = 0x%x\n", get_fwstate(pmlmepriv)); ++ break; ++ case 0x01: ++ DBG_871X("minor_cmd 0x%x\n", minor_cmd); ++ break; ++ case 0x02: ++ DBG_871X("pmlmeinfo->state = 0x%x\n", pmlmeinfo->state); ++ DBG_871X("DrvBcnEarly =%d\n", pmlmeext->DrvBcnEarly); ++ DBG_871X("DrvBcnTimeOut =%d\n", pmlmeext->DrvBcnTimeOut); ++ break; ++ case 0x03: ++ DBG_871X("qos_option =%d\n", pmlmepriv->qospriv.qos_option); ++ DBG_871X("ht_option =%d\n", pmlmepriv->htpriv.ht_option); ++ break; ++ case 0x04: ++ DBG_871X("cur_ch =%d\n", pmlmeext->cur_channel); ++ DBG_871X("cur_bw =%d\n", pmlmeext->cur_bwmode); ++ DBG_871X("cur_ch_off =%d\n", pmlmeext->cur_ch_offset); ++ ++ DBG_871X("oper_ch =%d\n", rtw_get_oper_ch(padapter)); ++ DBG_871X("oper_bw =%d\n", rtw_get_oper_bw(padapter)); ++ DBG_871X("oper_ch_offet =%d\n", rtw_get_oper_choffset(padapter)); ++ ++ break; ++ case 0x05: ++ psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress); ++ if (psta) ++ { ++ int i; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ ++ DBG_871X("SSID =%s\n", cur_network->network.Ssid.Ssid); ++ DBG_871X("sta's macaddr:" MAC_FMT "\n", MAC_ARG(psta->hwaddr)); ++ DBG_871X("cur_channel =%d, cur_bwmode =%d, cur_ch_offset =%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset); ++ DBG_871X("rtsen =%d, cts2slef =%d\n", psta->rtsen, psta->cts2self); ++ DBG_871X("state = 0x%x, aid =%d, macid =%d, raid =%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); ++ DBG_871X("qos_en =%d, ht_en =%d, init_rate =%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate); ++ DBG_871X("bwmode =%d, ch_offset =%d, sgi_20m =%d, sgi_40m =%d\n", psta->bw_mode, psta->htpriv.ch_offset, psta->htpriv.sgi_20m, psta->htpriv.sgi_40m); ++ DBG_871X("ampdu_enable = %d\n", psta->htpriv.ampdu_enable); ++ DBG_871X("agg_enable_bitmap =%x, candidate_tid_bitmap =%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap); ++ ++ for (i = 0;i<16;i++) ++ { ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ if (preorder_ctrl->enable) ++ { ++ DBG_871X("tid =%d, indicate_seq =%d\n", i, preorder_ctrl->indicate_seq); ++ } ++ } ++ ++ } ++ else ++ { ++ DBG_871X("can't get sta's macaddr, cur_network's macaddr:" MAC_FMT "\n", MAC_ARG(cur_network->network.MacAddress)); ++ } ++ break; ++ case 0x06: ++ { ++ u32 ODMFlag; ++ rtw_hal_get_hwreg(padapter, HW_VAR_DM_FLAG, (u8 *)(&ODMFlag)); ++ DBG_871X("(B)DMFlag = 0x%x, arg = 0x%x\n", ODMFlag, arg); ++ ODMFlag = (u32)(0x0f&arg); ++ DBG_871X("(A)DMFlag = 0x%x\n", ODMFlag); ++ rtw_hal_set_hwreg(padapter, HW_VAR_DM_FLAG, (u8 *)(&ODMFlag)); ++ } ++ break; ++ case 0x07: ++ DBG_871X("bSurpriseRemoved =%d, bDriverStopped =%d\n", ++ padapter->bSurpriseRemoved, padapter->bDriverStopped); ++ break; ++ case 0x08: ++ { ++ DBG_871X("minor_cmd 0x%x\n", minor_cmd); ++ } ++ break; ++ case 0x09: ++ { ++ int i, j; ++ struct list_head *plist, *phead; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ ++ DBG_871X("sta_dz_bitmap = 0x%x, tim_bitmap = 0x%x\n", pstapriv->sta_dz_bitmap, pstapriv->tim_bitmap); ++ ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ ++ for (i = 0; i< NUM_STA; i++) ++ { ++ phead = &(pstapriv->sta_hash[i]); ++ plist = get_next(phead); ++ ++ while (phead != plist) ++ { ++ psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); ++ ++ plist = get_next(plist); ++ ++ if (extra_arg == psta->aid) ++ { ++ DBG_871X("sta's macaddr:" MAC_FMT "\n", MAC_ARG(psta->hwaddr)); ++ DBG_871X("rtsen =%d, cts2slef =%d\n", psta->rtsen, psta->cts2self); ++ DBG_871X("state = 0x%x, aid =%d, macid =%d, raid =%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); ++ DBG_871X("qos_en =%d, ht_en =%d, init_rate =%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate); ++ DBG_871X("bwmode =%d, ch_offset =%d, sgi_20m =%d, sgi_40m =%d\n", psta->bw_mode, psta->htpriv.ch_offset, psta->htpriv.sgi_20m, psta->htpriv.sgi_40m); ++ DBG_871X("ampdu_enable = %d\n", psta->htpriv.ampdu_enable); ++ DBG_871X("agg_enable_bitmap =%x, candidate_tid_bitmap =%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap); ++ DBG_871X("capability = 0x%x\n", psta->capability); ++ DBG_871X("flags = 0x%x\n", psta->flags); ++ DBG_871X("wpa_psk = 0x%x\n", psta->wpa_psk); ++ DBG_871X("wpa2_group_cipher = 0x%x\n", psta->wpa2_group_cipher); ++ DBG_871X("wpa2_pairwise_cipher = 0x%x\n", psta->wpa2_pairwise_cipher); ++ DBG_871X("qos_info = 0x%x\n", psta->qos_info); ++ DBG_871X("dot118021XPrivacy = 0x%x\n", psta->dot118021XPrivacy); ++ ++ ++ ++ for (j = 0;j<16;j++) ++ { ++ preorder_ctrl = &psta->recvreorder_ctrl[j]; ++ if (preorder_ctrl->enable) ++ { ++ DBG_871X("tid =%d, indicate_seq =%d\n", j, preorder_ctrl->indicate_seq); ++ } ++ } ++ ++ } ++ ++ } ++ } ++ ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++ ++ } ++ break; ++ case 0x0a: ++ { ++ int max_mac_id = 0; ++ max_mac_id = rtw_search_max_mac_id(padapter); ++ printk("%s ==> max_mac_id = %d\n", __func__, max_mac_id); ++ } ++ break; ++ case 0x0b: /* Enable = 1, Disable = 0 driver control vrtl_carrier_sense. */ ++ if (arg == 0) { ++ DBG_871X("disable driver ctrl vcs\n"); ++ padapter->driver_vcs_en = 0; ++ } ++ else if (arg == 1) { ++ DBG_871X("enable driver ctrl vcs = %d\n", extra_arg); ++ padapter->driver_vcs_en = 1; ++ ++ if (extra_arg>2) ++ padapter->driver_vcs_type = 1; ++ else ++ padapter->driver_vcs_type = extra_arg; ++ } ++ break; ++ case 0x0c:/* dump rx/tx packet */ ++ { ++ if (arg == 0) { ++ DBG_871X("dump rx packet (%d)\n", extra_arg); ++ /* pHalData->bDumpRxPkt =extra_arg; */ ++ rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DUMP_RXPKT, &(extra_arg)); ++ } ++ else if (arg == 1) { ++ DBG_871X("dump tx packet (%d)\n", extra_arg); ++ rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DUMP_TXPKT, &(extra_arg)); ++ } ++ } ++ break; ++ case 0x0e: ++ { ++ if (arg == 0) { ++ DBG_871X("disable driver ctrl rx_ampdu_factor\n"); ++ padapter->driver_rx_ampdu_factor = 0xFF; ++ } ++ else if (arg == 1) { ++ ++ DBG_871X("enable driver ctrl rx_ampdu_factor = %d\n", extra_arg); ++ ++ if ((extra_arg & 0x03) > 0x03) ++ padapter->driver_rx_ampdu_factor = 0xFF; ++ else ++ padapter->driver_rx_ampdu_factor = extra_arg; ++ } ++ } ++ break; ++ ++ case 0x10:/* driver version display */ ++ dump_drv_version(RTW_DBGDUMP); ++ break; ++ case 0x11:/* dump linked status */ ++ { ++ linked_info_dump(padapter, extra_arg); ++ } ++ break; ++ case 0x12: /* set rx_stbc */ ++ { ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ /* 0: disable, bit(0):enable 2.4g, bit(1):enable 5g, 0x3: enable both 2.4g and 5g */ ++ /* default is set to enable 2.4GHZ for IOT issue with bufflao's AP at 5GHZ */ ++ if (pregpriv && (extra_arg == 0 || extra_arg == 1|| extra_arg == 2 || extra_arg == 3)) ++ { ++ pregpriv->rx_stbc = extra_arg; ++ DBG_871X("set rx_stbc =%d\n", pregpriv->rx_stbc); ++ } ++ else ++ DBG_871X("get rx_stbc =%d\n", pregpriv->rx_stbc); ++ ++ } ++ break; ++ case 0x13: /* set ampdu_enable */ ++ { ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ /* 0: disable, 0x1:enable (but wifi_spec should be 0), 0x2: force enable (don't care wifi_spec) */ ++ if (pregpriv && extra_arg < 3) ++ { ++ pregpriv->ampdu_enable = extra_arg; ++ DBG_871X("set ampdu_enable =%d\n", pregpriv->ampdu_enable); ++ } ++ else ++ DBG_871X("get ampdu_enable =%d\n", pregpriv->ampdu_enable); ++ ++ } ++ break; ++ case 0x14: ++ { ++ DBG_871X("minor_cmd 0x%x\n", minor_cmd); ++ } ++ break; ++ case 0x16: ++ { ++ if (arg == 0xff) { ++ rtw_odm_dbg_comp_msg(RTW_DBGDUMP, padapter); ++ } ++ else { ++ u64 dbg_comp = (u64)extra_arg; ++ rtw_odm_dbg_comp_set(padapter, dbg_comp); ++ } ++ } ++ break; ++#ifdef DBG_FIXED_CHAN ++ case 0x17: ++ { ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ printk("===> Fixed channel to %d\n", extra_arg); ++ pmlmeext->fixed_chan = extra_arg; ++ ++ } ++ break; ++#endif ++ case 0x18: ++ { ++ printk("===> Switch USB Mode %d\n", extra_arg); ++ rtw_hal_set_hwreg(padapter, HW_VAR_USB_MODE, (u8 *)&extra_arg); ++ } ++ break; ++ case 0x19: ++ { ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ /* extra_arg : */ ++ /* BIT0: Enable VHT LDPC Rx, BIT1: Enable VHT LDPC Tx, */ ++ /* BIT4: Enable HT LDPC Rx, BIT5: Enable HT LDPC Tx */ ++ if (arg == 0) { ++ DBG_871X("driver disable LDPC\n"); ++ pregistrypriv->ldpc_cap = 0x00; ++ } ++ else if (arg == 1) { ++ DBG_871X("driver set LDPC cap = 0x%x\n", extra_arg); ++ pregistrypriv->ldpc_cap = (u8)(extra_arg&0x33); ++ } ++ } ++ break; ++ case 0x1a: ++ { ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ /* extra_arg : */ ++ /* BIT0: Enable VHT STBC Rx, BIT1: Enable VHT STBC Tx, */ ++ /* BIT4: Enable HT STBC Rx, BIT5: Enable HT STBC Tx */ ++ if (arg == 0) { ++ DBG_871X("driver disable STBC\n"); ++ pregistrypriv->stbc_cap = 0x00; ++ } ++ else if (arg == 1) { ++ DBG_871X("driver set STBC cap = 0x%x\n", extra_arg); ++ pregistrypriv->stbc_cap = (u8)(extra_arg&0x33); ++ } ++ } ++ break; ++ case 0x1b: ++ { ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ ++ if (arg == 0) { ++ DBG_871X("disable driver ctrl max_rx_rate, reset to default_rate_set\n"); ++ init_mlme_default_rate_set(padapter); ++ pregistrypriv->ht_enable = (u8)rtw_ht_enable; ++ } ++ else if (arg == 1) { ++ ++ int i; ++ u8 max_rx_rate; ++ ++ DBG_871X("enable driver ctrl max_rx_rate = 0x%x\n", extra_arg); ++ ++ max_rx_rate = (u8)extra_arg; ++ ++ if (max_rx_rate < 0xc) /* max_rx_rate < MSC0 -> B or G -> disable HT */ ++ { ++ pregistrypriv->ht_enable = 0; ++ for (i = 0; idatarate[i] > max_rx_rate) ++ pmlmeext->datarate[i] = 0xff; ++ } ++ ++ } ++ else if (max_rx_rate < 0x1c) /* mcs0~mcs15 */ ++ { ++ u32 mcs_bitmap = 0x0; ++ ++ for (i = 0; i<((max_rx_rate+1)-0xc); i++) ++ mcs_bitmap |= BIT(i); ++ ++ set_mcs_rate_by_mask(pmlmeext->default_supported_mcs_set, mcs_bitmap); ++ } ++ } ++ } ++ break; ++ case 0x1c: /* enable/disable driver control AMPDU Density for peer sta's rx */ ++ { ++ if (arg == 0) { ++ DBG_871X("disable driver ctrl ampdu density\n"); ++ padapter->driver_ampdu_spacing = 0xFF; ++ } ++ else if (arg == 1) { ++ ++ DBG_871X("enable driver ctrl ampdu density = %d\n", extra_arg); ++ ++ if ((extra_arg & 0x07) > 0x07) ++ padapter->driver_ampdu_spacing = 0xFF; ++ else ++ padapter->driver_ampdu_spacing = extra_arg; ++ } ++ } ++ break; ++#ifdef CONFIG_BACKGROUND_NOISE_MONITOR ++ case 0x1e: ++ { ++ struct hal_com_data *pHalData = GET_HAL_DATA(padapter); ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++ u8 chan = rtw_get_oper_ch(padapter); ++ DBG_871X("===========================================\n"); ++ ODM_InbandNoise_Monitor(pDM_Odm, true, 0x1e, 100); ++ DBG_871X("channel(%d), noise_a = %d, noise_b = %d , noise_all:%d\n", ++ chan, pDM_Odm->noise_level.noise[ODM_RF_PATH_A], ++ pDM_Odm->noise_level.noise[ODM_RF_PATH_B], ++ pDM_Odm->noise_level.noise_all); ++ DBG_871X("===========================================\n"); ++ ++ } ++ break; ++#endif ++ case 0x23: ++ { ++ DBG_871X("turn %s the bNotifyChannelChange Variable\n", (extra_arg == 1)?"on":"off"); ++ padapter->bNotifyChannelChange = extra_arg; ++ break; ++ } ++ case 0x24: ++ { ++ break; ++ } ++#ifdef CONFIG_GPIO_API ++ case 0x25: /* Get GPIO register */ ++ { ++ /* ++ * dbg 0x7f250000 [gpio_num], Get gpio value, gpio_num:0~7 ++ */ ++ ++ int value; ++ DBG_871X("Read GPIO Value extra_arg = %d\n", extra_arg); ++ value = rtw_get_gpio(dev, extra_arg); ++ DBG_871X("Read GPIO Value = %d\n", value); ++ break; ++ } ++ case 0x26: /* Set GPIO direction */ ++ { ++ ++ /* dbg 0x7f26000x [y], Set gpio direction, ++ * x: gpio_num, 4~7 y: indicate direction, 0~1 ++ */ ++ ++ int value; ++ DBG_871X("Set GPIO Direction! arg = %d , extra_arg =%d\n", arg , extra_arg); ++ value = rtw_config_gpio(dev, arg, extra_arg); ++ DBG_871X("Set GPIO Direction %s\n", (value ==-1)?"Fail!!!":"Success"); ++ break; ++ } ++ case 0x27: /* Set GPIO output direction value */ ++ { ++ /* ++ * dbg 0x7f27000x [y], Set gpio output direction value, ++ * x: gpio_num, 4~7 y: indicate direction, 0~1 ++ */ ++ ++ int value; ++ DBG_871X("Set GPIO Value! arg = %d , extra_arg =%d\n", arg , extra_arg); ++ value = rtw_set_gpio_output_value(dev, arg, extra_arg); ++ DBG_871X("Set GPIO Value %s\n", (value ==-1)?"Fail!!!":"Success"); ++ break; ++ } ++#endif ++ case 0xaa: ++ { ++ if ((extra_arg & 0x7F)> 0x3F) extra_arg = 0xFF; ++ DBG_871X("chang data rate to :0x%02x\n", extra_arg); ++ padapter->fix_rate = extra_arg; ++ } ++ break; ++ case 0xdd:/* registers dump , 0 for mac reg, 1 for bb reg, 2 for rf reg */ ++ { ++ if (extra_arg == 0) { ++ mac_reg_dump(RTW_DBGDUMP, padapter); ++ } ++ else if (extra_arg == 1) { ++ bb_reg_dump(RTW_DBGDUMP, padapter); ++ } ++ else if (extra_arg ==2) { ++ rf_reg_dump(RTW_DBGDUMP, padapter); ++ } ++ } ++ break; ++ ++ case 0xee:/* turn on/off dynamic funcs */ ++ { ++ u32 odm_flag; ++ ++ if (0xf ==extra_arg) { ++ rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DM_FUNC,&odm_flag); ++ DBG_871X(" === DMFlag(0x%08x) ===\n", odm_flag); ++ DBG_871X("extra_arg = 0 - disable all dynamic func\n"); ++ DBG_871X("extra_arg = 1 - disable DIG- BIT(0)\n"); ++ DBG_871X("extra_arg = 2 - disable High power - BIT(1)\n"); ++ DBG_871X("extra_arg = 3 - disable tx power tracking - BIT(2)\n"); ++ DBG_871X("extra_arg = 4 - disable BT coexistence - BIT(3)\n"); ++ DBG_871X("extra_arg = 5 - disable antenna diversity - BIT(4)\n"); ++ DBG_871X("extra_arg = 6 - enable all dynamic func\n"); ++ } ++ else { ++ /*extra_arg = 0 - disable all dynamic func ++ extra_arg = 1 - disable DIG ++ extra_arg = 2 - disable tx power tracking ++ extra_arg = 3 - turn on all dynamic func ++ */ ++ rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DM_FUNC, &(extra_arg)); ++ rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DM_FUNC,&odm_flag); ++ DBG_871X(" === DMFlag(0x%08x) ===\n", odm_flag); ++ } ++ } ++ break; ++ ++ case 0xfd: ++ rtw_write8(padapter, 0xc50, arg); ++ DBG_871X("wr(0xc50) = 0x%x\n", rtw_read8(padapter, 0xc50)); ++ rtw_write8(padapter, 0xc58, arg); ++ DBG_871X("wr(0xc58) = 0x%x\n", rtw_read8(padapter, 0xc58)); ++ break; ++ case 0xfe: ++ DBG_871X("rd(0xc50) = 0x%x\n", rtw_read8(padapter, 0xc50)); ++ DBG_871X("rd(0xc58) = 0x%x\n", rtw_read8(padapter, 0xc58)); ++ break; ++ case 0xff: ++ { ++ DBG_871X("dbg(0x210) = 0x%x\n", rtw_read32(padapter, 0x210)); ++ DBG_871X("dbg(0x608) = 0x%x\n", rtw_read32(padapter, 0x608)); ++ DBG_871X("dbg(0x280) = 0x%x\n", rtw_read32(padapter, 0x280)); ++ DBG_871X("dbg(0x284) = 0x%x\n", rtw_read32(padapter, 0x284)); ++ DBG_871X("dbg(0x288) = 0x%x\n", rtw_read32(padapter, 0x288)); ++ ++ DBG_871X("dbg(0x664) = 0x%x\n", rtw_read32(padapter, 0x664)); ++ ++ ++ DBG_871X("\n"); ++ ++ DBG_871X("dbg(0x430) = 0x%x\n", rtw_read32(padapter, 0x430)); ++ DBG_871X("dbg(0x438) = 0x%x\n", rtw_read32(padapter, 0x438)); ++ ++ DBG_871X("dbg(0x440) = 0x%x\n", rtw_read32(padapter, 0x440)); ++ ++ DBG_871X("dbg(0x458) = 0x%x\n", rtw_read32(padapter, 0x458)); ++ ++ DBG_871X("dbg(0x484) = 0x%x\n", rtw_read32(padapter, 0x484)); ++ DBG_871X("dbg(0x488) = 0x%x\n", rtw_read32(padapter, 0x488)); ++ ++ DBG_871X("dbg(0x444) = 0x%x\n", rtw_read32(padapter, 0x444)); ++ DBG_871X("dbg(0x448) = 0x%x\n", rtw_read32(padapter, 0x448)); ++ DBG_871X("dbg(0x44c) = 0x%x\n", rtw_read32(padapter, 0x44c)); ++ DBG_871X("dbg(0x450) = 0x%x\n", rtw_read32(padapter, 0x450)); ++ } ++ break; ++ } ++ break; ++ default: ++ DBG_871X("error dbg cmd!\n"); ++ break; ++ } ++ ++ ++ return ret; ++ ++} ++ ++static int wpa_set_param(struct net_device *dev, u8 name, u32 value) ++{ ++ uint ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ switch (name) { ++ case IEEE_PARAM_WPA_ENABLED: ++ ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; /* 802.1x */ ++ ++ /* ret = ieee80211_wpa_enable(ieee, value); */ ++ ++ switch ((value)&0xff) ++ { ++ case 1 : /* WPA */ ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK; /* WPA_PSK */ ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; ++ break; ++ case 2: /* WPA2 */ ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK; /* WPA2_PSK */ ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; ++ break; ++ } ++ ++ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("wpa_set_param:padapter->securitypriv.ndisauthtype =%d\n", padapter->securitypriv.ndisauthtype)); ++ ++ 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. ++ */ ++ break; ++ ++ } ++ case IEEE_PARAM_PRIVACY_INVOKED: ++ ++ /* ieee->privacy_invoked =value; */ ++ ++ break; ++ ++ case IEEE_PARAM_AUTH_ALGS: ++ ++ ret = wpa_set_auth_algs(dev, value); ++ ++ break; ++ ++ case IEEE_PARAM_IEEE_802_1X: ++ ++ /* ieee->ieee802_1x =value; */ ++ ++ break; ++ ++ case IEEE_PARAM_WPAX_SELECT: ++ ++ /* added for WPA2 mixed mode */ ++ /* DBG_871X(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: ++ ++ ++ ++ ret = -EOPNOTSUPP; ++ ++ ++ break; ++ ++ } ++ ++ return ret; ++ ++} ++ ++static int wpa_mlme(struct net_device *dev, u32 command, u32 reason) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ switch (command) ++ { ++ case IEEE_MLME_STA_DEAUTH: ++ ++ if (!rtw_set_802_11_disassociate(padapter)) ++ ret = -1; ++ ++ break; ++ ++ case IEEE_MLME_STA_DISASSOC: ++ ++ if (!rtw_set_802_11_disassociate(padapter)) ++ ret = -1; ++ ++ break; ++ ++ default: ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ return ret; ++ ++} ++ ++static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p) ++{ ++ struct ieee_param *param; ++ uint ret = 0; ++ ++ /* down(&ieee->wx_sem); */ ++ ++ if (p->length < sizeof(struct ieee_param) || !p->pointer) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ param = (struct ieee_param *)rtw_malloc(p->length); ++ if (param == NULL) ++ { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ if (copy_from_user(param, p->pointer, p->length)) ++ { ++ kfree((u8 *)param); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ switch (param->cmd) { ++ ++ case IEEE_CMD_SET_WPA_PARAM: ++ ret = wpa_set_param(dev, param->u.wpa_param.name, param->u.wpa_param.value); ++ break; ++ ++ case IEEE_CMD_SET_WPA_IE: ++ /* ret = wpa_set_wpa_ie(dev, param, p->length); */ ++ ret = rtw_set_wpa_ie((struct adapter *)rtw_netdev_priv(dev), (char*)param->u.wpa_ie.data, (u16)param->u.wpa_ie.len); ++ break; ++ ++ case IEEE_CMD_SET_ENCRYPTION: ++ ret = wpa_set_encryption(dev, param, p->length); ++ break; ++ ++ case IEEE_CMD_MLME: ++ ret = wpa_mlme(dev, param->u.mlme.command, param->u.mlme.reason_code); ++ break; ++ ++ default: ++ DBG_871X("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((u8 *)param); ++ ++out: ++ ++ /* up(&ieee->wx_sem); */ ++ ++ return ret; ++ ++} ++ ++static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len) ++{ ++ int ret = 0; ++ u32 wep_key_idx, wep_key_len, wep_total_len; ++ struct ndis_802_11_wep *pwep = NULL; ++ struct sta_info *psta = NULL, *pbcmc_sta = NULL; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv* psecuritypriv =&(padapter->securitypriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ DBG_871X("%s\n", __func__); ++ ++ param->u.crypt.err = 0; ++ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; ++ ++ /* sizeof(struct ieee_param) = 64 bytes; */ ++ /* if (param_len != (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) */ ++ if (param_len != sizeof(struct ieee_param) + param->u.crypt.key_len) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ 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) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ } ++ else ++ { ++ psta = rtw_get_stainfo(pstapriv, param->sta_addr); ++ if (!psta) ++ { ++ /* ret = -EINVAL; */ ++ DBG_871X("rtw_set_encryption(), sta has already been removed or never been added\n"); ++ goto exit; ++ } ++ } ++ ++ if (strcmp(param->u.crypt.alg, "none") == 0 && (psta == NULL)) ++ { ++ /* todo:clear default encryption keys */ ++ ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; ++ psecuritypriv->ndisencryptstatus = Ndis802_11EncryptionDisabled; ++ psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ ++ DBG_871X("clear default encryption keys, keyid =%d\n", param->u.crypt.idx); ++ ++ goto exit; ++ } ++ ++ ++ if (strcmp(param->u.crypt.alg, "WEP") == 0 && (psta == NULL)) ++ { ++ DBG_871X("r871x_set_encryption, crypt.alg = WEP\n"); ++ ++ wep_key_idx = param->u.crypt.idx; ++ wep_key_len = param->u.crypt.key_len; ++ ++ DBG_871X("r871x_set_encryption, wep_key_idx =%d, len =%d\n", wep_key_idx, wep_key_len); ++ ++ if ((wep_key_idx >= WEP_KEYS) || (wep_key_len<= 0)) ++ { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ ++ if (wep_key_len > 0) ++ { ++ wep_key_len = wep_key_len <= 5 ? 5 : 13; ++ wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial); ++ pwep =(struct ndis_802_11_wep *)rtw_malloc(wep_total_len); ++ if (pwep == NULL) { ++ DBG_871X(" r871x_set_encryption: pwep allocate fail !!!\n"); ++ goto exit; ++ } ++ ++ memset(pwep, 0, wep_total_len); ++ ++ pwep->KeyLength = wep_key_len; ++ pwep->Length = wep_total_len; ++ ++ } ++ ++ pwep->KeyIndex = wep_key_idx; ++ ++ memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength); ++ ++ if (param->u.crypt.set_tx) ++ { ++ DBG_871X("wep, set_tx = 1\n"); ++ ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; ++ psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; ++ psecuritypriv->dot118021XGrpPrivacy = _WEP40_; ++ ++ if (pwep->KeyLength == 13) ++ { ++ psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; ++ psecuritypriv->dot118021XGrpPrivacy = _WEP104_; ++ } ++ ++ ++ psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx; ++ ++ memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength); ++ ++ psecuritypriv->dot11DefKeylen[wep_key_idx]=pwep->KeyLength; ++ ++ rtw_ap_set_wep_key(padapter, pwep->KeyMaterial, pwep->KeyLength, wep_key_idx, 1); ++ } ++ else ++ { ++ DBG_871X("wep, set_tx = 0\n"); ++ ++ /* don't update "psecuritypriv->dot11PrivacyAlgrthm" and */ ++ /* psecuritypriv->dot11PrivacyKeyIndex =keyid", but can rtw_set_key to cam */ ++ ++ memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength); ++ ++ psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->KeyLength; ++ ++ rtw_ap_set_wep_key(padapter, pwep->KeyMaterial, pwep->KeyLength, wep_key_idx, 0); ++ } ++ ++ goto exit; ++ ++ } ++ ++ ++ if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) /* group key */ ++ { ++ if (param->u.crypt.set_tx == 1) ++ { ++ if (strcmp(param->u.crypt.alg, "WEP") == 0) ++ { ++ DBG_871X("%s, set group_key, WEP\n", __func__); ++ ++ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _WEP40_; ++ if (param->u.crypt.key_len == 13) ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _WEP104_; ++ } ++ ++ } ++ else if (strcmp(param->u.crypt.alg, "TKIP") == 0) ++ { ++ DBG_871X("%s, set group_key, TKIP\n", __func__); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _TKIP_; ++ ++ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ ++ /* set mic key */ ++ memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8); ++ memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8); ++ ++ psecuritypriv->busetkipkey = true; ++ ++ } ++ else if (strcmp(param->u.crypt.alg, "CCMP") == 0) ++ { ++ DBG_871X("%s, set group_key, CCMP\n", __func__); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _AES_; ++ ++ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ } ++ else ++ { ++ DBG_871X("%s, set group_key, none\n", __func__); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ } ++ ++ psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx; ++ ++ psecuritypriv->binstallGrpkey = true; ++ ++ psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;/* */ ++ ++ rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx); ++ ++ pbcmc_sta =rtw_get_bcmc_stainfo(padapter); ++ if (pbcmc_sta) ++ { ++ pbcmc_sta->ieee8021x_blocked = false; ++ pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;/* rx will use bmc_sta's dot118021XPrivacy */ ++ } ++ ++ } ++ ++ goto exit; ++ ++ } ++ ++ if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && psta) /* psk/802_1x */ ++ { ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ { ++ if (param->u.crypt.set_tx == 1) ++ { ++ memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ if (strcmp(param->u.crypt.alg, "WEP") == 0) ++ { ++ DBG_871X("%s, set pairwise key, WEP\n", __func__); ++ ++ psta->dot118021XPrivacy = _WEP40_; ++ if (param->u.crypt.key_len == 13) ++ { ++ psta->dot118021XPrivacy = _WEP104_; ++ } ++ } ++ else if (strcmp(param->u.crypt.alg, "TKIP") == 0) ++ { ++ DBG_871X("%s, set pairwise key, TKIP\n", __func__); ++ ++ psta->dot118021XPrivacy = _TKIP_; ++ ++ /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ ++ /* set mic key */ ++ memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8); ++ memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8); ++ ++ psecuritypriv->busetkipkey = true; ++ ++ } ++ else if (strcmp(param->u.crypt.alg, "CCMP") == 0) ++ { ++ ++ DBG_871X("%s, set pairwise key, CCMP\n", __func__); ++ ++ psta->dot118021XPrivacy = _AES_; ++ } ++ else ++ { ++ DBG_871X("%s, set pairwise key, none\n", __func__); ++ ++ psta->dot118021XPrivacy = _NO_PRIVACY_; ++ } ++ ++ rtw_ap_set_pairwise_key(padapter, psta); ++ ++ psta->ieee8021x_blocked = false; ++ ++ } ++ else/* group key??? */ ++ { ++ if (strcmp(param->u.crypt.alg, "WEP") == 0) ++ { ++ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ psecuritypriv->dot118021XGrpPrivacy = _WEP40_; ++ if (param->u.crypt.key_len == 13) ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _WEP104_; ++ } ++ } ++ else if (strcmp(param->u.crypt.alg, "TKIP") == 0) ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _TKIP_; ++ ++ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ ++ /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ ++ /* set mic key */ ++ memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8); ++ memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8); ++ ++ psecuritypriv->busetkipkey = true; ++ ++ } ++ else if (strcmp(param->u.crypt.alg, "CCMP") == 0) ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _AES_; ++ ++ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len)); ++ } ++ else ++ { ++ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ } ++ ++ psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx; ++ ++ psecuritypriv->binstallGrpkey = true; ++ ++ psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;/* */ ++ ++ rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx); ++ ++ pbcmc_sta =rtw_get_bcmc_stainfo(padapter); ++ if (pbcmc_sta) ++ { ++ pbcmc_sta->ieee8021x_blocked = false; ++ pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;/* rx will use bmc_sta's dot118021XPrivacy */ ++ } ++ ++ } ++ ++ } ++ ++ } ++ ++exit: ++ ++ if (pwep) ++ { ++ kfree((u8 *)pwep); ++ } ++ ++ return ret; ++ ++} ++ ++static int rtw_set_beacon(struct net_device *dev, struct ieee_param *param, int len) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ unsigned char *pbuf = param->u.bcn_ie.buf; ++ ++ ++ DBG_871X("%s, len =%d\n", __func__, len); ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) ++ return -EINVAL; ++ ++ memcpy(&pstapriv->max_num_sta, param->u.bcn_ie.reserved, 2); ++ ++ if ((pstapriv->max_num_sta>NUM_STA) || (pstapriv->max_num_sta<= 0)) ++ pstapriv->max_num_sta = NUM_STA; ++ ++ ++ if (rtw_check_beacon_data(padapter, pbuf, (len-12-2)) == _SUCCESS)/* 12 = param header, 2:no packed */ ++ ret = 0; ++ else ++ ret = -EINVAL; ++ ++ ++ return ret; ++ ++} ++ ++static int rtw_hostapd_sta_flush(struct net_device *dev) ++{ ++ /* _irqL irqL; */ ++ /* struct list_head *phead, *plist; */ ++ int ret = 0; ++ /* struct sta_info *psta = NULL; */ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ /* struct sta_priv *pstapriv = &padapter->stapriv; */ ++ ++ DBG_871X("%s\n", __func__); ++ ++ flush_all_cam_entry(padapter); /* clear CAM */ ++ ++ ret = rtw_sta_flush(padapter); ++ ++ return ret; ++ ++} ++ ++static int rtw_add_sta(struct net_device *dev, struct ieee_param *param) ++{ ++ int ret = 0; ++ struct sta_info *psta = NULL; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ DBG_871X("rtw_add_sta(aid =%d) =" MAC_FMT "\n", param->u.add_sta.aid, MAC_ARG(param->sta_addr)); ++ ++ if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) ++ { ++ 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) ++ { ++ return -EINVAL; ++ } ++ ++/* ++ psta = rtw_get_stainfo(pstapriv, param->sta_addr); ++ if (psta) ++ { ++ DBG_871X("rtw_add_sta(), free has been added psta =%p\n", psta); ++ spin_lock_bh(&(pstapriv->sta_hash_lock)); ++ rtw_free_stainfo(padapter, psta); ++ spin_unlock_bh(&(pstapriv->sta_hash_lock)); ++ ++ psta = NULL; ++ } ++*/ ++ /* psta = rtw_alloc_stainfo(pstapriv, param->sta_addr); */ ++ psta = rtw_get_stainfo(pstapriv, param->sta_addr); ++ if (psta) ++ { ++ int flags = param->u.add_sta.flags; ++ ++ /* DBG_871X("rtw_add_sta(), init sta's variables, psta =%p\n", psta); */ ++ ++ psta->aid = param->u.add_sta.aid;/* aid = 1~2007 */ ++ ++ memcpy(psta->bssrateset, param->u.add_sta.tx_supp_rates, 16); ++ ++ ++ /* check wmm cap. */ ++ if (WLAN_STA_WME&flags) ++ psta->qos_option = 1; ++ else ++ psta->qos_option = 0; ++ ++ if (pmlmepriv->qospriv.qos_option == 0) ++ psta->qos_option = 0; ++ ++ /* chec 802.11n ht cap. */ ++ if (WLAN_STA_HT&flags) ++ { ++ psta->htpriv.ht_option = true; ++ psta->qos_option = 1; ++ memcpy((void*)&psta->htpriv.ht_cap, (void*)¶m->u.add_sta.ht_cap, sizeof(struct rtw_ieee80211_ht_cap)); ++ } ++ else ++ { ++ psta->htpriv.ht_option = false; ++ } ++ ++ if (pmlmepriv->htpriv.ht_option == false) ++ psta->htpriv.ht_option = false; ++ ++ update_sta_info_apmode(padapter, psta); ++ ++ ++ } ++ else ++ { ++ ret = -ENOMEM; ++ } ++ ++ return ret; ++ ++} ++ ++static int rtw_del_sta(struct net_device *dev, struct ieee_param *param) ++{ ++ int ret = 0; ++ struct sta_info *psta = NULL; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ DBG_871X("rtw_del_sta =" MAC_FMT "\n", MAC_ARG(param->sta_addr)); ++ ++ if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) ++ { ++ 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) ++ { ++ return -EINVAL; ++ } ++ ++ psta = rtw_get_stainfo(pstapriv, param->sta_addr); ++ if (psta) ++ { ++ u8 updated =false; ++ ++ /* DBG_871X("free psta =%p, aid =%d\n", psta, psta->aid); */ ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ if (list_empty(&psta->asoc_list) ==false) ++ { ++ list_del_init(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING); ++ ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ associated_clients_update(padapter, updated); ++ ++ psta = NULL; ++ ++ } ++ else ++ { ++ DBG_871X("rtw_del_sta(), sta has already been removed or never been added\n"); ++ ++ /* ret = -1; */ ++ } ++ ++ ++ return ret; ++ ++} ++ ++static int rtw_ioctl_get_sta_data(struct net_device *dev, struct ieee_param *param, int len) ++{ ++ int ret = 0; ++ struct sta_info *psta = NULL; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct ieee_param_ex *param_ex = (struct ieee_param_ex *)param; ++ struct sta_data *psta_data = (struct sta_data *)param_ex->data; ++ ++ DBG_871X("rtw_ioctl_get_sta_info, sta_addr: " MAC_FMT "\n", MAC_ARG(param_ex->sta_addr)); ++ ++ if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) ++ { ++ return -EINVAL; ++ } ++ ++ if (param_ex->sta_addr[0] == 0xff && param_ex->sta_addr[1] == 0xff && ++ param_ex->sta_addr[2] == 0xff && param_ex->sta_addr[3] == 0xff && ++ param_ex->sta_addr[4] == 0xff && param_ex->sta_addr[5] == 0xff) ++ { ++ return -EINVAL; ++ } ++ ++ psta = rtw_get_stainfo(pstapriv, param_ex->sta_addr); ++ if (psta) ++ { ++ psta_data->aid = (u16)psta->aid; ++ psta_data->capability = psta->capability; ++ psta_data->flags = psta->flags; ++ ++/* ++ nonerp_set : BIT(0) ++ no_short_slot_time_set : BIT(1) ++ no_short_preamble_set : BIT(2) ++ no_ht_gf_set : BIT(3) ++ no_ht_set : BIT(4) ++ ht_20mhz_set : BIT(5) ++*/ ++ ++ psta_data->sta_set =((psta->nonerp_set) | ++ (psta->no_short_slot_time_set <<1) | ++ (psta->no_short_preamble_set <<2) | ++ (psta->no_ht_gf_set <<3) | ++ (psta->no_ht_set <<4) | ++ (psta->ht_20mhz_set <<5)); ++ ++ psta_data->tx_supp_rates_len = psta->bssratelen; ++ memcpy(psta_data->tx_supp_rates, psta->bssrateset, psta->bssratelen); ++ memcpy(&psta_data->ht_cap, &psta->htpriv.ht_cap, sizeof(struct rtw_ieee80211_ht_cap)); ++ psta_data->rx_pkts = psta->sta_stats.rx_data_pkts; ++ psta_data->rx_bytes = psta->sta_stats.rx_bytes; ++ psta_data->rx_drops = psta->sta_stats.rx_drops; ++ ++ psta_data->tx_pkts = psta->sta_stats.tx_pkts; ++ psta_data->tx_bytes = psta->sta_stats.tx_bytes; ++ psta_data->tx_drops = psta->sta_stats.tx_drops; ++ ++ ++ } ++ else ++ { ++ ret = -1; ++ } ++ ++ return ret; ++ ++} ++ ++static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param) ++{ ++ int ret = 0; ++ struct sta_info *psta = NULL; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ DBG_871X("rtw_get_sta_wpaie, sta_addr: " MAC_FMT "\n", MAC_ARG(param->sta_addr)); ++ ++ if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) ++ { ++ 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) ++ { ++ return -EINVAL; ++ } ++ ++ psta = rtw_get_stainfo(pstapriv, param->sta_addr); ++ if (psta) ++ { ++ if ((psta->wpa_ie[0] == WLAN_EID_RSN) || (psta->wpa_ie[0] == WLAN_EID_GENERIC)) ++ { ++ int wpa_ie_len; ++ int copy_len; ++ ++ wpa_ie_len = psta->wpa_ie[1]; ++ ++ copy_len = ((wpa_ie_len+2) > sizeof(psta->wpa_ie)) ? (sizeof(psta->wpa_ie)):(wpa_ie_len+2); ++ ++ param->u.wpa_ie.len = copy_len; ++ ++ memcpy(param->u.wpa_ie.reserved, psta->wpa_ie, copy_len); ++ } ++ else ++ { ++ /* ret = -1; */ ++ DBG_871X("sta's wpa_ie is NONE\n"); ++ } ++ } ++ else ++ { ++ ret = -1; ++ } ++ ++ return ret; ++ ++} ++ ++static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param, int len) ++{ ++ int ret = 0; ++ unsigned char wps_oui[4]={0x0, 0x50, 0xf2, 0x04}; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); ++ int ie_len; ++ ++ DBG_871X("%s, len =%d\n", __func__, len); ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) ++ return -EINVAL; ++ ++ ie_len = len-12-2;/* 12 = param header, 2:no packed */ ++ ++ ++ if (pmlmepriv->wps_beacon_ie) ++ { ++ kfree(pmlmepriv->wps_beacon_ie); ++ pmlmepriv->wps_beacon_ie = NULL; ++ } ++ ++ if (ie_len>0) ++ { ++ pmlmepriv->wps_beacon_ie = rtw_malloc(ie_len); ++ pmlmepriv->wps_beacon_ie_len = ie_len; ++ if (pmlmepriv->wps_beacon_ie == NULL) { ++ DBG_871X("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__); ++ return -EINVAL; ++ } ++ ++ memcpy(pmlmepriv->wps_beacon_ie, param->u.bcn_ie.buf, ie_len); ++ ++ update_beacon(padapter, _VENDOR_SPECIFIC_IE_, wps_oui, true); ++ ++ pmlmeext->bstart_bss = true; ++ ++ } ++ ++ ++ return ret; ++ ++} ++ ++static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *param, int len) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ int ie_len; ++ ++ DBG_871X("%s, len =%d\n", __func__, len); ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) ++ return -EINVAL; ++ ++ ie_len = len-12-2;/* 12 = param header, 2:no packed */ ++ ++ ++ if (pmlmepriv->wps_probe_resp_ie) ++ { ++ kfree(pmlmepriv->wps_probe_resp_ie); ++ pmlmepriv->wps_probe_resp_ie = NULL; ++ } ++ ++ if (ie_len>0) ++ { ++ pmlmepriv->wps_probe_resp_ie = rtw_malloc(ie_len); ++ pmlmepriv->wps_probe_resp_ie_len = ie_len; ++ if (pmlmepriv->wps_probe_resp_ie == NULL) { ++ DBG_871X("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__); ++ return -EINVAL; ++ } ++ memcpy(pmlmepriv->wps_probe_resp_ie, param->u.bcn_ie.buf, ie_len); ++ } ++ ++ ++ return ret; ++ ++} ++ ++static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *param, int len) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ int ie_len; ++ ++ DBG_871X("%s, len =%d\n", __func__, len); ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) ++ return -EINVAL; ++ ++ ie_len = len-12-2;/* 12 = param header, 2:no packed */ ++ ++ ++ if (pmlmepriv->wps_assoc_resp_ie) ++ { ++ kfree(pmlmepriv->wps_assoc_resp_ie); ++ pmlmepriv->wps_assoc_resp_ie = NULL; ++ } ++ ++ if (ie_len>0) ++ { ++ pmlmepriv->wps_assoc_resp_ie = rtw_malloc(ie_len); ++ pmlmepriv->wps_assoc_resp_ie_len = ie_len; ++ if (pmlmepriv->wps_assoc_resp_ie == NULL) { ++ DBG_871X("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__); ++ return -EINVAL; ++ } ++ ++ memcpy(pmlmepriv->wps_assoc_resp_ie, param->u.bcn_ie.buf, ie_len); ++ } ++ ++ ++ return ret; ++ ++} ++ ++static int rtw_set_hidden_ssid(struct net_device *dev, struct ieee_param *param, int len) ++{ ++ int ret = 0; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *mlmepriv = &(adapter->mlmepriv); ++ struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv); ++ struct mlme_ext_info *mlmeinfo = &(mlmeext->mlmext_info); ++ int ie_len; ++ u8 *ssid_ie; ++ char ssid[NDIS_802_11_LENGTH_SSID + 1]; ++ sint ssid_len; ++ u8 ignore_broadcast_ssid; ++ ++ if (check_fwstate(mlmepriv, WIFI_AP_STATE) != true) ++ return -EPERM; ++ ++ if (param->u.bcn_ie.reserved[0] != 0xea) ++ return -EINVAL; ++ ++ mlmeinfo->hidden_ssid_mode = ignore_broadcast_ssid = param->u.bcn_ie.reserved[1]; ++ ++ ie_len = len-12-2;/* 12 = param header, 2:no packed */ ++ ssid_ie = rtw_get_ie(param->u.bcn_ie.buf, WLAN_EID_SSID, &ssid_len, ie_len); ++ ++ if (ssid_ie && ssid_len > 0 && ssid_len <= NDIS_802_11_LENGTH_SSID) { ++ struct wlan_bssid_ex *pbss_network = &mlmepriv->cur_network.network; ++ struct wlan_bssid_ex *pbss_network_ext = &mlmeinfo->network; ++ ++ memcpy(ssid, ssid_ie+2, ssid_len); ++ ssid[ssid_len] = 0x0; ++ ++ if (0) ++ DBG_871X(FUNC_ADPT_FMT" ssid:(%s,%d), from ie:(%s,%d), (%s,%d)\n", FUNC_ADPT_ARG(adapter), ++ ssid, ssid_len, ++ pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength, ++ pbss_network_ext->Ssid.Ssid, pbss_network_ext->Ssid.SsidLength); ++ ++ memcpy(pbss_network->Ssid.Ssid, (void *)ssid, ssid_len); ++ pbss_network->Ssid.SsidLength = ssid_len; ++ memcpy(pbss_network_ext->Ssid.Ssid, (void *)ssid, ssid_len); ++ pbss_network_ext->Ssid.SsidLength = ssid_len; ++ ++ if (0) ++ DBG_871X(FUNC_ADPT_FMT" after ssid:(%s,%d), (%s,%d)\n", FUNC_ADPT_ARG(adapter), ++ pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength, ++ pbss_network_ext->Ssid.Ssid, pbss_network_ext->Ssid.SsidLength); ++ } ++ ++ DBG_871X(FUNC_ADPT_FMT" ignore_broadcast_ssid:%d, %s,%d\n", FUNC_ADPT_ARG(adapter), ++ ignore_broadcast_ssid, ssid, ssid_len); ++ ++ return ret; ++} ++ ++static int rtw_ioctl_acl_remove_sta(struct net_device *dev, struct ieee_param *param, int len) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) ++ 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) ++ { ++ return -EINVAL; ++ } ++ ++ ret = rtw_acl_remove_sta(padapter, param->sta_addr); ++ ++ return ret; ++ ++} ++ ++static int rtw_ioctl_acl_add_sta(struct net_device *dev, struct ieee_param *param, int len) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) ++ 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) ++ { ++ return -EINVAL; ++ } ++ ++ ret = rtw_acl_add_sta(padapter, param->sta_addr); ++ ++ return ret; ++ ++} ++ ++static int rtw_ioctl_set_macaddr_acl(struct net_device *dev, struct ieee_param *param, int len) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) ++ return -EINVAL; ++ ++ rtw_set_macaddr_acl(padapter, param->u.mlme.command); ++ ++ return ret; ++} ++ ++static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p) ++{ ++ struct ieee_param *param; ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ /* DBG_871X("%s\n", __func__); */ ++ ++ /* ++ * this function is expect to call in master mode, which allows no power saving ++ * so, we just check hw_init_completed ++ */ ++ ++ if (padapter->hw_init_completed ==false) { ++ ret = -EPERM; ++ goto out; ++ } ++ ++ ++ /* if (p->length < sizeof(struct ieee_param) || !p->pointer) { */ ++ if (!p->pointer) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ param = (struct ieee_param *)rtw_malloc(p->length); ++ if (param == NULL) ++ { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ if (copy_from_user(param, p->pointer, p->length)) ++ { ++ kfree((u8 *)param); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ /* DBG_871X("%s, cmd =%d\n", __func__, param->cmd); */ ++ ++ switch (param->cmd) ++ { ++ case RTL871X_HOSTAPD_FLUSH: ++ ++ ret = rtw_hostapd_sta_flush(dev); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_ADD_STA: ++ ++ ret = rtw_add_sta(dev, param); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_REMOVE_STA: ++ ++ ret = rtw_del_sta(dev, param); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_SET_BEACON: ++ ++ ret = rtw_set_beacon(dev, param, p->length); ++ ++ break; ++ ++ case RTL871X_SET_ENCRYPTION: ++ ++ ret = rtw_set_encryption(dev, param, p->length); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_GET_WPAIE_STA: ++ ++ ret = rtw_get_sta_wpaie(dev, param); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_SET_WPS_BEACON: ++ ++ ret = rtw_set_wps_beacon(dev, param, p->length); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_SET_WPS_PROBE_RESP: ++ ++ ret = rtw_set_wps_probe_resp(dev, param, p->length); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP: ++ ++ ret = rtw_set_wps_assoc_resp(dev, param, p->length); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_SET_HIDDEN_SSID: ++ ++ ret = rtw_set_hidden_ssid(dev, param, p->length); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_GET_INFO_STA: ++ ++ ret = rtw_ioctl_get_sta_data(dev, param, p->length); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_SET_MACADDR_ACL: ++ ++ ret = rtw_ioctl_set_macaddr_acl(dev, param, p->length); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_ACL_ADD_STA: ++ ++ ret = rtw_ioctl_acl_add_sta(dev, param, p->length); ++ ++ break; ++ ++ case RTL871X_HOSTAPD_ACL_REMOVE_STA: ++ ++ ret = rtw_ioctl_acl_remove_sta(dev, param, p->length); ++ ++ break; ++ ++ default: ++ DBG_871X("Unknown hostapd request: %d\n", param->cmd); ++ ret = -EOPNOTSUPP; ++ break; ++ ++ } ++ ++ if (ret == 0 && copy_to_user(p->pointer, param, p->length)) ++ ret = -EFAULT; ++ ++ ++ kfree((u8 *)param); ++ ++out: ++ ++ return ret; ++ ++} ++ ++static int rtw_wx_set_priv(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *awrq, ++ char *extra) ++{ ++ ++#ifdef CONFIG_DEBUG_RTW_WX_SET_PRIV ++ char *ext_dbg; ++#endif ++ ++ int ret = 0; ++ int len = 0; ++ char *ext; ++ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct iw_point *dwrq = (struct iw_point*)awrq; ++ ++ /* RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_notice_, ("+rtw_wx_set_priv\n")); */ ++ if (dwrq->length == 0) ++ return -EFAULT; ++ ++ len = dwrq->length; ++ if (!(ext = vmalloc(len))) ++ return -ENOMEM; ++ ++ if (copy_from_user(ext, dwrq->pointer, len)) { ++ vfree(ext); ++ return -EFAULT; ++ } ++ ++ ++ /* RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_notice_, */ ++ /* ("rtw_wx_set_priv: %s req =%s\n", */ ++ /* dev->name, ext)); */ ++ ++ #ifdef CONFIG_DEBUG_RTW_WX_SET_PRIV ++ if (!(ext_dbg = vmalloc(len))) ++ { ++ vfree(ext, len); ++ return -ENOMEM; ++ } ++ ++ memcpy(ext_dbg, ext, len); ++ #endif ++ ++ /* added for wps2.0 @20110524 */ ++ if (dwrq->flags == 0x8766 && len > 8) ++ { ++ u32 cp_sz; ++ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); ++ u8 *probereq_wpsie = ext; ++ int probereq_wpsie_len = len; ++ u8 wps_oui[4]={0x0, 0x50, 0xf2, 0x04}; ++ ++ if ((_VENDOR_SPECIFIC_IE_ == probereq_wpsie[0]) && ++ (!memcmp(&probereq_wpsie[2], wps_oui, 4))) ++ { ++ cp_sz = probereq_wpsie_len>MAX_WPS_IE_LEN ? MAX_WPS_IE_LEN:probereq_wpsie_len; ++ ++ if (pmlmepriv->wps_probe_req_ie) ++ { ++ pmlmepriv->wps_probe_req_ie_len = 0; ++ kfree(pmlmepriv->wps_probe_req_ie); ++ pmlmepriv->wps_probe_req_ie = NULL; ++ } ++ ++ pmlmepriv->wps_probe_req_ie = rtw_malloc(cp_sz); ++ if (pmlmepriv->wps_probe_req_ie == NULL) { ++ printk("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__); ++ ret = -EINVAL; ++ goto FREE_EXT; ++ ++ } ++ ++ memcpy(pmlmepriv->wps_probe_req_ie, probereq_wpsie, cp_sz); ++ pmlmepriv->wps_probe_req_ie_len = cp_sz; ++ ++ } ++ ++ goto FREE_EXT; ++ ++ } ++ ++ if (len >= WEXT_CSCAN_HEADER_SIZE ++ && !memcmp(ext, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE) ++ ) { ++ ret = rtw_wx_set_scan(dev, info, awrq, ext); ++ goto FREE_EXT; ++ } ++ ++FREE_EXT: ++ ++ vfree(ext); ++ #ifdef CONFIG_DEBUG_RTW_WX_SET_PRIV ++ vfree(ext_dbg); ++ #endif ++ ++ /* DBG_871X("rtw_wx_set_priv: (SIOCSIWPRIV) %s ret =%d\n", */ ++ /* dev->name, ret); */ ++ ++ return ret; ++ ++} ++ ++static int rtw_pm_set(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ unsigned mode = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ DBG_871X("[%s] extra = %s\n", __func__, extra); ++ ++ if (!memcmp(extra, "lps =", 4)) ++ { ++ sscanf(extra+4, "%u", &mode); ++ ret = rtw_pm_set_lps(padapter, mode); ++ } ++ else if (!memcmp(extra, "ips =", 4)) ++ { ++ sscanf(extra+4, "%u", &mode); ++ ret = rtw_pm_set_ips(padapter, mode); ++ } ++ else { ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int rtw_mp_efuse_get(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wdata, char *extra) ++{ ++ int err = 0; ++ return err; ++} ++ ++static int rtw_mp_efuse_set(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wdata, char *extra) ++{ ++ int err = 0; ++ return err; ++} ++ ++static int rtw_tdls(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ return ret; ++} ++ ++ ++static int rtw_tdls_get(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ return ret; ++} ++ ++ ++ ++ ++ ++#ifdef CONFIG_INTEL_WIDI ++static int rtw_widi_set(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ process_intel_widi_cmd(padapter, extra); ++ ++ return ret; ++} ++ ++static int rtw_widi_set_probe_request(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ u8 *pbuf = NULL; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ pbuf = rtw_malloc(sizeof(l2_msg_t)); ++ if (pbuf) ++ { ++ if (copy_from_user(pbuf, wrqu->data.pointer, wrqu->data.length)) ++ ret = -EFAULT; ++ /* memcpy(pbuf, wrqu->data.pointer, wrqu->data.length); */ ++ ++ if (wrqu->data.flags == 0) ++ intel_widi_wk_cmd(padapter, INTEL_WIDI_ISSUE_PROB_WK, pbuf, sizeof(l2_msg_t)); ++ else if (wrqu->data.flags == 1) ++ rtw_set_wfd_rds_sink_info(padapter, (l2_msg_t *)pbuf); ++ } ++ return ret; ++} ++#endif /* CONFIG_INTEL_WIDI */ ++ ++static int rtw_test( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ u32 len; ++ u8 *pbuf, *pch; ++ char *ptmp; ++ u8 *delim = ","; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ ++ DBG_871X("+%s\n", __func__); ++ len = wrqu->data.length; ++ ++ pbuf = (u8 *)rtw_zmalloc(len); ++ if (pbuf == NULL) { ++ DBG_871X("%s: no memory!\n", __func__); ++ return -ENOMEM; ++ } ++ ++ if (copy_from_user(pbuf, wrqu->data.pointer, len)) { ++ kfree(pbuf); ++ DBG_871X("%s: copy from user fail!\n", __func__); ++ return -EFAULT; ++ } ++ DBG_871X("%s: string =\"%s\"\n", __func__, pbuf); ++ ++ ptmp = (char*)pbuf; ++ pch = strsep(&ptmp, delim); ++ if ((pch == NULL) || (strlen(pch) == 0)) { ++ kfree(pbuf); ++ DBG_871X("%s: parameter error(level 1)!\n", __func__); ++ return -EFAULT; ++ } ++ ++ if (strcmp(pch, "bton") == 0) ++ { ++ rtw_btcoex_SetManualControl(padapter, false); ++ } ++ ++ if (strcmp(pch, "btoff") == 0) ++ { ++ rtw_btcoex_SetManualControl(padapter, true); ++ } ++ ++ if (strcmp(pch, "h2c") == 0) ++ { ++ u8 param[8]; ++ u8 count = 0; ++ u32 tmp; ++ u8 i; ++ u32 pos; ++ s32 ret; ++ ++ ++ do { ++ pch = strsep(&ptmp, delim); ++ if ((pch == NULL) || (strlen(pch) == 0)) ++ break; ++ ++ sscanf(pch, "%x", &tmp); ++ param[count++] = (u8)tmp; ++ } while (count < 8); ++ ++ if (count == 0) { ++ kfree(pbuf); ++ DBG_871X("%s: parameter error(level 2)!\n", __func__); ++ return -EFAULT; ++ } ++ ++ ret = rtw_hal_fill_h2c_cmd(padapter, param[0], count-1, ¶m[1]); ++ ++ pos = sprintf(extra, "H2C ID = 0x%02x content =", param[0]); ++ for (i = 1; idata.length = strlen(extra) + 1; ++ } ++ ++ kfree(pbuf); ++ return 0; ++} ++ ++static iw_handler rtw_handlers[] = ++{ ++ NULL, /* SIOCSIWCOMMIT */ ++ rtw_wx_get_name, /* SIOCGIWNAME */ ++ dummy, /* SIOCSIWNWID */ ++ dummy, /* SIOCGIWNWID */ ++ rtw_wx_set_freq, /* SIOCSIWFREQ */ ++ rtw_wx_get_freq, /* SIOCGIWFREQ */ ++ rtw_wx_set_mode, /* SIOCSIWMODE */ ++ rtw_wx_get_mode, /* SIOCGIWMODE */ ++ dummy, /* SIOCSIWSENS */ ++ rtw_wx_get_sens, /* SIOCGIWSENS */ ++ NULL, /* SIOCSIWRANGE */ ++ rtw_wx_get_range, /* SIOCGIWRANGE */ ++ rtw_wx_set_priv, /* SIOCSIWPRIV */ ++ NULL, /* SIOCGIWPRIV */ ++ NULL, /* SIOCSIWSTATS */ ++ NULL, /* SIOCGIWSTATS */ ++ dummy, /* SIOCSIWSPY */ ++ dummy, /* SIOCGIWSPY */ ++ NULL, /* SIOCGIWTHRSPY */ ++ NULL, /* SIOCWIWTHRSPY */ ++ rtw_wx_set_wap, /* SIOCSIWAP */ ++ rtw_wx_get_wap, /* SIOCGIWAP */ ++ rtw_wx_set_mlme, /* request MLME operation; uses struct iw_mlme */ ++ dummy, /* SIOCGIWAPLIST -- depricated */ ++ rtw_wx_set_scan, /* SIOCSIWSCAN */ ++ rtw_wx_get_scan, /* SIOCGIWSCAN */ ++ rtw_wx_set_essid, /* SIOCSIWESSID */ ++ rtw_wx_get_essid, /* SIOCGIWESSID */ ++ dummy, /* SIOCSIWNICKN */ ++ rtw_wx_get_nick, /* SIOCGIWNICKN */ ++ NULL, /* -- hole -- */ ++ NULL, /* -- hole -- */ ++ rtw_wx_set_rate, /* SIOCSIWRATE */ ++ rtw_wx_get_rate, /* SIOCGIWRATE */ ++ rtw_wx_set_rts, /* SIOCSIWRTS */ ++ rtw_wx_get_rts, /* SIOCGIWRTS */ ++ rtw_wx_set_frag, /* SIOCSIWFRAG */ ++ rtw_wx_get_frag, /* SIOCGIWFRAG */ ++ dummy, /* SIOCSIWTXPOW */ ++ dummy, /* SIOCGIWTXPOW */ ++ dummy, /* SIOCSIWRETRY */ ++ rtw_wx_get_retry, /* SIOCGIWRETRY */ ++ rtw_wx_set_enc, /* SIOCSIWENCODE */ ++ rtw_wx_get_enc, /* SIOCGIWENCODE */ ++ dummy, /* SIOCSIWPOWER */ ++ rtw_wx_get_power, /* SIOCGIWPOWER */ ++ NULL, /*---hole---*/ ++ NULL, /*---hole---*/ ++ rtw_wx_set_gen_ie, /* SIOCSIWGENIE */ ++ NULL, /* SIOCGWGENIE */ ++ rtw_wx_set_auth, /* SIOCSIWAUTH */ ++ NULL, /* SIOCGIWAUTH */ ++ rtw_wx_set_enc_ext, /* SIOCSIWENCODEEXT */ ++ NULL, /* SIOCGIWENCODEEXT */ ++ rtw_wx_set_pmkid, /* SIOCSIWPMKSA */ ++ NULL, /*---hole---*/ ++}; ++ ++static const struct iw_priv_args rtw_private_args[] = { ++ { ++ SIOCIWFIRSTPRIV + 0x0, ++ IW_PRIV_TYPE_CHAR | 0x7FF, 0, "write" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x1, ++ IW_PRIV_TYPE_CHAR | 0x7FF, ++ IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "read" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x2, 0, 0, "driver_ext" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x3, 0, 0, "mp_ioctl" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x4, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "apinfo" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x5, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "setpid" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x6, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_start" ++ }, ++/* for PLATFORM_MT53XX */ ++ { ++ SIOCIWFIRSTPRIV + 0x7, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "get_sensitivity" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x8, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_prob_req_ie" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x9, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_assoc_req_ie" ++ }, ++ ++/* for RTK_DMP_PLATFORM */ ++ { ++ SIOCIWFIRSTPRIV + 0xA, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "channel_plan" ++ }, ++ ++ { ++ SIOCIWFIRSTPRIV + 0xB, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "dbg" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0xC, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "rfw" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0xD, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "rfr" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x10, ++ IW_PRIV_TYPE_CHAR | 1024, 0, "p2p_set" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x11, ++ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK , "p2p_get" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x12, 0, 0, "NULL" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x13, ++ IW_PRIV_TYPE_CHAR | 64, IW_PRIV_TYPE_CHAR | 64 , "p2p_get2" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x14, ++ IW_PRIV_TYPE_CHAR | 64, 0, "tdls" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x15, ++ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024 , "tdls_get" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x16, ++ IW_PRIV_TYPE_CHAR | 64, 0, "pm_set" ++ }, ++ ++ {SIOCIWFIRSTPRIV + 0x18, IW_PRIV_TYPE_CHAR | IFNAMSIZ , 0 , "rereg_nd_name"}, ++ {SIOCIWFIRSTPRIV + 0x1A, IW_PRIV_TYPE_CHAR | 1024, 0, "efuse_set"}, ++ {SIOCIWFIRSTPRIV + 0x1B, IW_PRIV_TYPE_CHAR | 128, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_get"}, ++ { ++ SIOCIWFIRSTPRIV + 0x1D, ++ IW_PRIV_TYPE_CHAR | 40, IW_PRIV_TYPE_CHAR | 0x7FF, "test" ++ }, ++ ++#ifdef CONFIG_INTEL_WIDI ++ { ++ SIOCIWFIRSTPRIV + 0x1E, ++ IW_PRIV_TYPE_CHAR | 1024, 0, "widi_set" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x1F, ++ IW_PRIV_TYPE_CHAR | 128, 0, "widi_prob_req" ++ }, ++#endif /* CONFIG_INTEL_WIDI */ ++ ++#ifdef CONFIG_WOWLAN ++ { MP_WOW_ENABLE , IW_PRIV_TYPE_CHAR | 1024, 0, "wow_mode" }, /* set */ ++#endif ++#ifdef CONFIG_AP_WOWLAN ++ { MP_AP_WOW_ENABLE , IW_PRIV_TYPE_CHAR | 1024, 0, "ap_wow_mode" }, /* set */ ++#endif ++}; ++ ++static iw_handler rtw_private_handler[] = ++{ ++ rtw_wx_write32, /* 0x00 */ ++ rtw_wx_read32, /* 0x01 */ ++ rtw_drvext_hdl, /* 0x02 */ ++ rtw_mp_ioctl_hdl, /* 0x03 */ ++ ++/* for MM DTV platform */ ++ rtw_get_ap_info, /* 0x04 */ ++ ++ rtw_set_pid, /* 0x05 */ ++ rtw_wps_start, /* 0x06 */ ++ ++/* for PLATFORM_MT53XX */ ++ rtw_wx_get_sensitivity, /* 0x07 */ ++ rtw_wx_set_mtk_wps_probe_ie, /* 0x08 */ ++ rtw_wx_set_mtk_wps_ie, /* 0x09 */ ++ ++/* for RTK_DMP_PLATFORM */ ++/* Set Channel depend on the country code */ ++ rtw_wx_set_channel_plan, /* 0x0A */ ++ ++ rtw_dbg_port, /* 0x0B */ ++ rtw_wx_write_rf, /* 0x0C */ ++ rtw_wx_read_rf, /* 0x0D */ ++ rtw_wx_priv_null, /* 0x0E */ ++ rtw_wx_priv_null, /* 0x0F */ ++ rtw_p2p_set, /* 0x10 */ ++ rtw_p2p_get, /* 0x11 */ ++ NULL, /* 0x12 */ ++ rtw_p2p_get2, /* 0x13 */ ++ ++ rtw_tdls, /* 0x14 */ ++ rtw_tdls_get, /* 0x15 */ ++ ++ rtw_pm_set, /* 0x16 */ ++ rtw_wx_priv_null, /* 0x17 */ ++ rtw_rereg_nd_name, /* 0x18 */ ++ rtw_wx_priv_null, /* 0x19 */ ++ rtw_mp_efuse_set, /* 0x1A */ ++ rtw_mp_efuse_get, /* 0x1B */ ++ NULL, /* 0x1C is reserved for hostapd */ ++ rtw_test, /* 0x1D */ ++#ifdef CONFIG_INTEL_WIDI ++ rtw_widi_set, /* 0x1E */ ++ rtw_widi_set_probe_request, /* 0x1F */ ++#endif /* CONFIG_INTEL_WIDI */ ++}; ++ ++static struct iw_statistics *rtw_get_wireless_stats(struct net_device *dev) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct iw_statistics *piwstats =&padapter->iwstats; ++ int tmp_level = 0; ++ int tmp_qual = 0; ++ int tmp_noise = 0; ++ ++ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) != true) ++ { ++ piwstats->qual.qual = 0; ++ piwstats->qual.level = 0; ++ piwstats->qual.noise = 0; ++ /* DBG_871X("No link level:%d, qual:%d, noise:%d\n", tmp_level, tmp_qual, tmp_noise); */ ++ } ++ else { ++ #ifdef CONFIG_SIGNAL_DISPLAY_DBM ++ tmp_level = translate_percentage_to_dbm(padapter->recvpriv.signal_strength); ++ #else ++ #ifdef CONFIG_SKIP_SIGNAL_SCALE_MAPPING ++ { ++ /* Do signal scale mapping when using percentage as the unit of signal strength, since the scale mapping is skipped in odm */ ++ ++ struct hal_com_data *pHal = GET_HAL_DATA(padapter); ++ ++ tmp_level = (u8)odm_SignalScaleMapping(&pHal->odmpriv, padapter->recvpriv.signal_strength); ++ } ++ #else ++ tmp_level = padapter->recvpriv.signal_strength; ++ #endif ++ #endif ++ ++ tmp_qual = padapter->recvpriv.signal_qual; ++#if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) ++ if (rtw_linked_check(padapter)) { ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct noise_info info; ++ info.bPauseDIG = true; ++ info.IGIValue = 0x1e; ++ info.max_time = 100;/* ms */ ++ info.chan = pmlmeext->cur_channel ;/* rtw_get_oper_ch(padapter); */ ++ rtw_ps_deny(padapter, PS_DENY_IOCTL); ++ LeaveAllPowerSaveModeDirect(padapter); ++ ++ rtw_hal_set_odm_var(padapter, HAL_ODM_NOISE_MONITOR,&info, false); ++ /* ODM_InbandNoise_Monitor(podmpriv, true, 0x20, 100); */ ++ rtw_ps_deny_cancel(padapter, PS_DENY_IOCTL); ++ rtw_hal_get_odm_var(padapter, HAL_ODM_NOISE_MONITOR,&(info.chan), &(padapter->recvpriv.noise)); ++ DBG_871X("chan:%d, noise_level:%d\n", info.chan, padapter->recvpriv.noise); ++ } ++#endif ++ tmp_noise = padapter->recvpriv.noise; ++ DBG_871X("level:%d, qual:%d, noise:%d, rssi (%d)\n", tmp_level, tmp_qual, tmp_noise, padapter->recvpriv.rssi); ++ ++ piwstats->qual.level = tmp_level; ++ piwstats->qual.qual = tmp_qual; ++ piwstats->qual.noise = tmp_noise; ++ } ++ piwstats->qual.updated = IW_QUAL_ALL_UPDATED ;/* IW_QUAL_DBM; */ ++ ++ #ifdef CONFIG_SIGNAL_DISPLAY_DBM ++ piwstats->qual.updated = piwstats->qual.updated | IW_QUAL_DBM; ++ #endif ++ ++ return &padapter->iwstats; ++} ++ ++struct iw_handler_def rtw_handlers_def = ++{ ++ .standard = rtw_handlers, ++ .num_standard = sizeof(rtw_handlers) / sizeof(iw_handler), ++#if defined(CONFIG_WEXT_PRIV) ++ .private = rtw_private_handler, ++ .private_args = (struct iw_priv_args *)rtw_private_args, ++ .num_private = sizeof(rtw_private_handler) / sizeof(iw_handler), ++ .num_private_args = sizeof(rtw_private_args) / sizeof(struct iw_priv_args), ++#endif ++ .get_wireless_stats = rtw_get_wireless_stats, ++}; ++ ++/* copy from net/wireless/wext.c start */ ++/* ---------------------------------------------------------------- */ ++/* ++ * Calculate size of private arguments ++ */ ++static const char iw_priv_type_size[] = { ++ 0, /* IW_PRIV_TYPE_NONE */ ++ 1, /* IW_PRIV_TYPE_BYTE */ ++ 1, /* IW_PRIV_TYPE_CHAR */ ++ 0, /* Not defined */ ++ sizeof(__u32), /* IW_PRIV_TYPE_INT */ ++ sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */ ++ sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */ ++ 0, /* Not defined */ ++}; ++ ++static int get_priv_size(__u16 args) ++{ ++ int num = args & IW_PRIV_SIZE_MASK; ++ int type = (args & IW_PRIV_TYPE_MASK) >> 12; ++ ++ return num * iw_priv_type_size[type]; ++} ++/* copy from net/wireless/wext.c end */ ++ ++static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_data) ++{ ++ int err = 0; ++ u8 *input = NULL; ++ u32 input_len = 0; ++ const char delim[] = " "; ++ u8 *output = NULL; ++ u32 output_len = 0; ++ u32 count = 0; ++ u8 *buffer = NULL; ++ u32 buffer_len = 0; ++ char *ptr = NULL; ++ u8 cmdname[17] = {0}; /* IFNAMSIZ+1 */ ++ u32 cmdlen; ++ s32 len; ++ u8 *extra = NULL; ++ u32 extra_size = 0; ++ ++ s32 k; ++ const iw_handler *priv; /* Private ioctl */ ++ const struct iw_priv_args *priv_args; /* Private ioctl description */ ++ u32 num_priv; /* Number of ioctl */ ++ u32 num_priv_args; /* Number of descriptions */ ++ iw_handler handler; ++ int temp; ++ int subcmd = 0; /* sub-ioctl index */ ++ int offset = 0; /* Space for sub-ioctl index */ ++ ++ union iwreq_data wdata; ++ ++ ++ memcpy(&wdata, wrq_data, sizeof(wdata)); ++ ++ input_len = 2048; ++ input = rtw_zmalloc(input_len); ++ if (NULL == input) ++ return -ENOMEM; ++ if (copy_from_user(input, wdata.data.pointer, input_len)) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ptr = input; ++ len = strlen(input); ++ ++ sscanf(ptr, "%16s", cmdname); ++ cmdlen = strlen(cmdname); ++ DBG_8192C("%s: cmd =%s\n", __func__, cmdname); ++ ++ /* skip command string */ ++ if (cmdlen > 0) ++ cmdlen += 1; /* skip one space */ ++ ptr += cmdlen; ++ len -= cmdlen; ++ DBG_8192C("%s: parameters =%s\n", __func__, ptr); ++ ++ priv = rtw_private_handler; ++ priv_args = rtw_private_args; ++ num_priv = sizeof(rtw_private_handler) / sizeof(iw_handler); ++ num_priv_args = sizeof(rtw_private_args) / sizeof(struct iw_priv_args); ++ ++ if (num_priv_args == 0) { ++ err = -EOPNOTSUPP; ++ goto exit; ++ } ++ ++ /* Search the correct ioctl */ ++ k = -1; ++ while ((++k < num_priv_args) && strcmp(priv_args[k].name, cmdname)); ++ ++ /* If not found... */ ++ if (k == num_priv_args) { ++ err = -EOPNOTSUPP; ++ goto exit; ++ } ++ ++ /* Watch out for sub-ioctls ! */ ++ if (priv_args[k].cmd < SIOCDEVPRIVATE) ++ { ++ int j = -1; ++ ++ /* Find the matching *real* ioctl */ ++ while ((++j < num_priv_args) && ((priv_args[j].name[0] != '\0') || ++ (priv_args[j].set_args != priv_args[k].set_args) || ++ (priv_args[j].get_args != priv_args[k].get_args))); ++ ++ /* If not found... */ ++ if (j == num_priv_args) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ /* Save sub-ioctl number */ ++ subcmd = priv_args[k].cmd; ++ /* Reserve one int (simplify alignment issues) */ ++ offset = sizeof(__u32); ++ /* Use real ioctl definition from now on */ ++ k = j; ++ } ++ ++ buffer = rtw_zmalloc(4096); ++ if (NULL == buffer) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ /* If we have to set some data */ ++ if ((priv_args[k].set_args & IW_PRIV_TYPE_MASK) && ++ (priv_args[k].set_args & IW_PRIV_SIZE_MASK)) ++ { ++ u8 *str; ++ ++ switch (priv_args[k].set_args & IW_PRIV_TYPE_MASK) ++ { ++ case IW_PRIV_TYPE_BYTE: ++ /* Fetch args */ ++ count = 0; ++ do { ++ str = strsep(&ptr, delim); ++ if (NULL == str) break; ++ sscanf(str, "%i", &temp); ++ buffer[count++] = (u8)temp; ++ } while (1); ++ buffer_len = count; ++ ++ /* Number of args to fetch */ ++ wdata.data.length = count; ++ if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK)) ++ wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK; ++ ++ break; ++ ++ case IW_PRIV_TYPE_INT: ++ /* Fetch args */ ++ count = 0; ++ do { ++ str = strsep(&ptr, delim); ++ if (NULL == str) break; ++ sscanf(str, "%i", &temp); ++ ((s32*)buffer)[count++] = (s32)temp; ++ } while (1); ++ buffer_len = count * sizeof(s32); ++ ++ /* Number of args to fetch */ ++ wdata.data.length = count; ++ if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK)) ++ wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK; ++ ++ break; ++ ++ case IW_PRIV_TYPE_CHAR: ++ if (len > 0) ++ { ++ /* Size of the string to fetch */ ++ wdata.data.length = len; ++ if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK)) ++ wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK; ++ ++ /* Fetch string */ ++ memcpy(buffer, ptr, wdata.data.length); ++ } ++ else ++ { ++ wdata.data.length = 1; ++ buffer[0] = '\0'; ++ } ++ buffer_len = wdata.data.length; ++ break; ++ ++ default: ++ DBG_8192C("%s: Not yet implemented...\n", __func__); ++ err = -1; ++ goto exit; ++ } ++ ++ if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) && ++ (wdata.data.length != (priv_args[k].set_args & IW_PRIV_SIZE_MASK))) ++ { ++ DBG_8192C("%s: The command %s needs exactly %d argument(s)...\n", ++ __func__, cmdname, priv_args[k].set_args & IW_PRIV_SIZE_MASK); ++ err = -EINVAL; ++ goto exit; ++ } ++ } /* if args to set */ ++ else ++ { ++ wdata.data.length = 0L; ++ } ++ ++ /* Those two tests are important. They define how the driver ++ * will have to handle the data */ ++ if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) && ++ ((get_priv_size(priv_args[k].set_args) + offset) <= IFNAMSIZ)) ++ { ++ /* First case : all SET args fit within wrq */ ++ if (offset) ++ wdata.mode = subcmd; ++ memcpy(wdata.name + offset, buffer, IFNAMSIZ - offset); ++ } ++ else ++ { ++ if ((priv_args[k].set_args == 0) && ++ (priv_args[k].get_args & IW_PRIV_SIZE_FIXED) && ++ (get_priv_size(priv_args[k].get_args) <= IFNAMSIZ)) ++ { ++ /* Second case : no SET args, GET args fit within wrq */ ++ if (offset) ++ wdata.mode = subcmd; ++ } ++ else ++ { ++ /* Third case : args won't fit in wrq, or variable number of args */ ++ if (copy_to_user(wdata.data.pointer, buffer, buffer_len)) { ++ err = -EFAULT; ++ goto exit; ++ } ++ wdata.data.flags = subcmd; ++ } ++ } ++ ++ kfree(input); ++ input = NULL; ++ ++ extra_size = 0; ++ if (IW_IS_SET(priv_args[k].cmd)) ++ { ++ /* Size of set arguments */ ++ extra_size = get_priv_size(priv_args[k].set_args); ++ ++ /* Does it fits in iwr ? */ ++ if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) && ++ ((extra_size + offset) <= IFNAMSIZ)) ++ extra_size = 0; ++ } else { ++ /* Size of get arguments */ ++ extra_size = get_priv_size(priv_args[k].get_args); ++ ++ /* Does it fits in iwr ? */ ++ if ((priv_args[k].get_args & IW_PRIV_SIZE_FIXED) && ++ (extra_size <= IFNAMSIZ)) ++ extra_size = 0; ++ } ++ ++ if (extra_size == 0) { ++ extra = (u8 *)&wdata; ++ kfree(buffer); ++ buffer = NULL; ++ } else ++ extra = buffer; ++ ++ handler = priv[priv_args[k].cmd - SIOCIWFIRSTPRIV]; ++ err = handler(dev, NULL, &wdata, extra); ++ ++ /* If we have to get some data */ ++ if ((priv_args[k].get_args & IW_PRIV_TYPE_MASK) && ++ (priv_args[k].get_args & IW_PRIV_SIZE_MASK)) ++ { ++ int j; ++ int n = 0; /* number of args */ ++ u8 str[20] = {0}; ++ ++ /* Check where is the returned data */ ++ if ((priv_args[k].get_args & IW_PRIV_SIZE_FIXED) && ++ (get_priv_size(priv_args[k].get_args) <= IFNAMSIZ)) ++ n = priv_args[k].get_args & IW_PRIV_SIZE_MASK; ++ else ++ n = wdata.data.length; ++ ++ output = rtw_zmalloc(4096); ++ if (NULL == output) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ switch (priv_args[k].get_args & IW_PRIV_TYPE_MASK) ++ { ++ case IW_PRIV_TYPE_BYTE: ++ /* Display args */ ++ for (j = 0; j < n; j++) ++ { ++ sprintf(str, "%d ", extra[j]); ++ len = strlen(str); ++ output_len = strlen(output); ++ if ((output_len + len + 1) > 4096) { ++ err = -E2BIG; ++ goto exit; ++ } ++ memcpy(output+output_len, str, len); ++ } ++ break; ++ ++ case IW_PRIV_TYPE_INT: ++ /* Display args */ ++ for (j = 0; j < n; j++) ++ { ++ sprintf(str, "%d ", ((__s32*)extra)[j]); ++ len = strlen(str); ++ output_len = strlen(output); ++ if ((output_len + len + 1) > 4096) { ++ err = -E2BIG; ++ goto exit; ++ } ++ memcpy(output+output_len, str, len); ++ } ++ break; ++ ++ case IW_PRIV_TYPE_CHAR: ++ /* Display args */ ++ memcpy(output, extra, n); ++ break; ++ ++ default: ++ DBG_8192C("%s: Not yet implemented...\n", __func__); ++ err = -1; ++ goto exit; ++ } ++ ++ output_len = strlen(output) + 1; ++ wrq_data->data.length = output_len; ++ if (copy_to_user(wrq_data->data.pointer, output, output_len)) { ++ err = -EFAULT; ++ goto exit; ++ } ++ } /* if args to set */ ++ else ++ { ++ wrq_data->data.length = 0; ++ } ++ ++exit: ++ if (input) ++ kfree(input); ++ if (buffer) ++ kfree(buffer); ++ if (output) ++ kfree(output); ++ ++ return err; ++} ++ ++int rtw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ++{ ++ struct iwreq *wrq = (struct iwreq *)rq; ++ int ret = 0; ++ ++ switch (cmd) ++ { ++ case RTL_IOCTL_WPA_SUPPLICANT: ++ ret = wpa_supplicant_ioctl(dev, &wrq->u.data); ++ break; ++ case RTL_IOCTL_HOSTAPD: ++ ret = rtw_hostapd_ioctl(dev, &wrq->u.data); ++ break; ++ case SIOCDEVPRIVATE: ++ ret = rtw_ioctl_wext_private(dev, &wrq->u); ++ break; ++ default: ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ return ret; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/os_dep/mlme_linux.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/mlme_linux.c +--- linux-4.3/3rdparty/rtl8723bs/os_dep/mlme_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/mlme_linux.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,206 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++ ++#define _MLME_OSDEP_C_ ++ ++#include ++#include ++ ++static void _dynamic_check_timer_handlder (void *FunctionContext) ++{ ++ struct adapter *adapter = (struct adapter *)FunctionContext; ++ ++ rtw_dynamic_check_timer_handlder(adapter); ++ ++ _set_timer(&adapter->mlmepriv.dynamic_chk_timer, 2000); ++} ++ ++static void _rtw_set_scan_deny_timer_hdl(void *FunctionContext) ++{ ++ struct adapter *adapter = (struct adapter *)FunctionContext; ++ rtw_set_scan_deny_timer_hdl(adapter); ++} ++ ++void rtw_init_mlme_timer(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ _init_timer(&(pmlmepriv->assoc_timer), padapter->pnetdev, _rtw_join_timeout_handler, padapter); ++ /* _init_timer(&(pmlmepriv->sitesurveyctrl.sitesurvey_ctrl_timer), padapter->pnetdev, sitesurvey_ctrl_handler, padapter); */ ++ _init_timer(&(pmlmepriv->scan_to_timer), padapter->pnetdev, rtw_scan_timeout_handler, padapter); ++ ++ _init_timer(&(pmlmepriv->dynamic_chk_timer), padapter->pnetdev, _dynamic_check_timer_handlder, padapter); ++ ++ _init_timer(&(pmlmepriv->set_scan_deny_timer), padapter->pnetdev, _rtw_set_scan_deny_timer_hdl, padapter); ++} ++ ++void rtw_os_indicate_connect(struct adapter *adapter) ++{ ++ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); ++ ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ==true) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ==true)) ++ { ++ rtw_cfg80211_ibss_indicate_connect(adapter); ++ } ++ else ++ rtw_cfg80211_indicate_connect(adapter); ++ ++ rtw_indicate_wx_assoc_event(adapter); ++ netif_carrier_on(adapter->pnetdev); ++ ++ if (adapter->pid[2] != 0) ++ rtw_signal_process(adapter->pid[2], SIGALRM); ++} ++ ++void rtw_os_indicate_scan_done(struct adapter *padapter, bool aborted) ++{ ++ rtw_cfg80211_indicate_scan_done(padapter, aborted); ++ indicate_wx_scan_complete_event(padapter); ++} ++ ++static RT_PMKID_LIST backupPMKIDList[ NUM_PMKID_CACHE ]; ++void rtw_reset_securitypriv(struct adapter *adapter) ++{ ++ u8 backupPMKIDIndex = 0; ++ u8 backupTKIPCountermeasure = 0x00; ++ u32 backupTKIPcountermeasure_time = 0; ++ /* add for CONFIG_IEEE80211W, none 11w also can use */ ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ ++ spin_lock_bh(&adapter->security_key_mutex); ++ ++ if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)/* 802.1x */ ++ { ++ /* Added by Albert 2009/02/18 */ ++ /* We have to backup the PMK information for WiFi PMK Caching test item. */ ++ /* */ ++ /* Backup the btkip_countermeasure information. */ ++ /* When the countermeasure is trigger, the driver have to disconnect with AP for 60 seconds. */ ++ ++ memset(&backupPMKIDList[ 0 ], 0x00, sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE); ++ ++ memcpy(&backupPMKIDList[ 0 ], &adapter->securitypriv.PMKIDList[ 0 ], sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE); ++ backupPMKIDIndex = adapter->securitypriv.PMKIDIndex; ++ backupTKIPCountermeasure = adapter->securitypriv.btkip_countermeasure; ++ backupTKIPcountermeasure_time = adapter->securitypriv.btkip_countermeasure_time; ++ ++ /* reset RX BIP packet number */ ++ pmlmeext->mgnt_80211w_IPN_rx = 0; ++ ++ memset((unsigned char *)&adapter->securitypriv, 0, sizeof (struct security_priv)); ++ ++ /* Added by Albert 2009/02/18 */ ++ /* Restore the PMK information to securitypriv structure for the following connection. */ ++ memcpy(&adapter->securitypriv.PMKIDList[ 0 ], &backupPMKIDList[ 0 ], sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE); ++ adapter->securitypriv.PMKIDIndex = backupPMKIDIndex; ++ adapter->securitypriv.btkip_countermeasure = backupTKIPCountermeasure; ++ adapter->securitypriv.btkip_countermeasure_time = backupTKIPcountermeasure_time; ++ ++ adapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; ++ adapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled; ++ ++ } ++ else /* reset values in securitypriv */ ++ { ++ /* if (adapter->mlmepriv.fw_state & WIFI_STATION_STATE) */ ++ /* */ ++ struct security_priv *psec_priv =&adapter->securitypriv; ++ ++ psec_priv->dot11AuthAlgrthm =dot11AuthAlgrthm_Open; /* open system */ ++ psec_priv->dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ psec_priv->dot11PrivacyKeyIndex = 0; ++ ++ psec_priv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ psec_priv->dot118021XGrpKeyid = 1; ++ ++ psec_priv->ndisauthtype = Ndis802_11AuthModeOpen; ++ psec_priv->ndisencryptstatus = Ndis802_11WEPDisabled; ++ /* */ ++ } ++ /* add for CONFIG_IEEE80211W, none 11w also can use */ ++ spin_unlock_bh(&adapter->security_key_mutex); ++} ++ ++void rtw_os_indicate_disconnect(struct adapter *adapter) ++{ ++ /* RT_PMKID_LIST backupPMKIDList[ NUM_PMKID_CACHE ]; */ ++ ++ netif_carrier_off(adapter->pnetdev); /* Do it first for tx broadcast pkt after disconnection issue! */ ++ ++ rtw_cfg80211_indicate_disconnect(adapter); ++ ++ rtw_indicate_wx_disassoc_event(adapter); ++ ++ /* modify for CONFIG_IEEE80211W, none 11w also can use the same command */ ++ rtw_reset_securitypriv_cmd(adapter); ++} ++ ++void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie) ++{ ++ uint len; ++ u8 *buff,*p, i; ++ union iwreq_data wrqu; ++ ++ RT_TRACE(_module_mlme_osdep_c_, _drv_info_, ("+rtw_report_sec_ie, authmode =%d\n", authmode)); ++ ++ buff = NULL; ++ if (authmode == _WPA_IE_ID_) ++ { ++ RT_TRACE(_module_mlme_osdep_c_, _drv_info_, ("rtw_report_sec_ie, authmode =%d\n", authmode)); ++ ++ buff = rtw_zmalloc(IW_CUSTOM_MAX); ++ if (NULL == buff) { ++ DBG_871X(FUNC_ADPT_FMT ": alloc memory FAIL!!\n", ++ FUNC_ADPT_ARG(adapter)); ++ return; ++ } ++ p = buff; ++ ++ p+=sprintf(p,"ASSOCINFO(ReqIEs ="); ++ ++ len = sec_ie[1]+2; ++ len = (len < IW_CUSTOM_MAX) ? len:IW_CUSTOM_MAX; ++ ++ for (i = 0;iaddba_retry_timer, padapter->pnetdev, addba_timer_hdl, psta); ++} ++ ++void init_mlme_ext_timer(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ _init_timer(&pmlmeext->survey_timer, padapter->pnetdev, survey_timer_hdl, padapter); ++ _init_timer(&pmlmeext->link_timer, padapter->pnetdev, link_timer_hdl, padapter); ++ _init_timer(&pmlmeext->sa_query_timer, padapter->pnetdev, sa_query_timer_hdl, padapter); ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/os_dep/osdep_service.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/osdep_service.c +--- linux-4.3/3rdparty/rtl8723bs/os_dep/osdep_service.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/osdep_service.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,481 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++ ++#define _OSDEP_SERVICE_C_ ++ ++#include ++#include ++ ++/* ++* Translate the OS dependent @param error_code to OS independent RTW_STATUS_CODE ++* @return: one of RTW_STATUS_CODE ++*/ ++inline int RTW_STATUS_CODE(int error_code) ++{ ++ if (error_code >= 0) ++ return _SUCCESS; ++ return _FAIL; ++} ++ ++u8 *_rtw_malloc(u32 sz) ++{ ++ u8 *pbuf = NULL; ++ ++ pbuf = kmalloc(sz, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); ++ ++ return pbuf; ++} ++ ++u8 *_rtw_zmalloc(u32 sz) ++{ ++ u8 *pbuf = _rtw_malloc(sz); ++ ++ if (pbuf != NULL) { ++ memset(pbuf, 0, sz); ++ } ++ ++ return pbuf; ++} ++ ++inline struct sk_buff *_rtw_skb_alloc(u32 sz) ++{ ++ return __dev_alloc_skb(sz, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); ++} ++ ++inline struct sk_buff *_rtw_skb_copy(const struct sk_buff *skb) ++{ ++ return skb_copy(skb, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); ++} ++ ++inline struct sk_buff *_rtw_skb_clone(struct sk_buff *skb) ++{ ++ return skb_clone(skb, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); ++} ++ ++inline int _rtw_netif_rx(_nic_hdl ndev, struct sk_buff *skb) ++{ ++ skb->dev = ndev; ++ return netif_rx(skb); ++} ++ ++void rtw_init_timer(_timer *ptimer, void *padapter, void *pfunc) ++{ ++ struct adapter *adapter = (struct adapter *)padapter; ++ ++ _init_timer(ptimer, adapter->pnetdev, pfunc, adapter); ++} ++ ++void _rtw_init_queue(struct __queue *pqueue) ++{ ++ INIT_LIST_HEAD(&(pqueue->queue)); ++ ++ spin_lock_init(&(pqueue->lock)); ++} ++ ++/* ++* Open a file with the specific @param path, @param flag, @param mode ++* @param fpp the pointer of struct file pointer to get struct file pointer while file opening is success ++* @param path the path of the file to open ++* @param flag file operation flags, please refer to linux document ++* @param mode please refer to linux document ++* @return Linux specific error code ++*/ ++static int openFile(struct file **fpp, char *path, int flag, int mode) ++{ ++ struct file *fp; ++ ++ fp =filp_open(path, flag, mode); ++ if (IS_ERR(fp)) { ++ *fpp = NULL; ++ return PTR_ERR(fp); ++ } ++ else { ++ *fpp =fp; ++ return 0; ++ } ++} ++ ++/* ++* Close the file with the specific @param fp ++* @param fp the pointer of struct file to close ++* @return always 0 ++*/ ++static int closeFile(struct file *fp) ++{ ++ filp_close(fp, NULL); ++ return 0; ++} ++ ++static int readFile(struct file *fp, char *buf, int len) ++{ ++ int rlen = 0, sum = 0; ++ ++ if (!fp->f_op || !fp->f_op->read) ++ return -EPERM; ++ ++ while (sumf_op->read(fp, (char __force __user *)buf+sum, len-sum, &fp->f_pos); ++ if (rlen>0) ++ sum+=rlen; ++ else if (0 != rlen) ++ return rlen; ++ else ++ break; ++ } ++ ++ return sum; ++ ++} ++ ++/* ++* Test if the specifi @param path is a file and readable ++* @param path the path of the file to test ++* @return Linux specific error code ++*/ ++static int isFileReadable(char *path) ++{ ++ struct file *fp; ++ int ret = 0; ++ mm_segment_t oldfs; ++ char buf; ++ ++ fp =filp_open(path, O_RDONLY, 0); ++ if (IS_ERR(fp)) { ++ ret = PTR_ERR(fp); ++ } ++ else { ++ oldfs = get_fs(); set_fs(get_ds()); ++ ++ if (1!=readFile(fp, &buf, 1)) ++ ret = PTR_ERR(fp); ++ ++ set_fs(oldfs); ++ filp_close(fp, NULL); ++ } ++ return ret; ++} ++ ++/* ++* Open the file with @param path and retrive the file content into memory starting from @param buf for @param sz at most ++* @param path the path of the file to open and read ++* @param buf the starting address of the buffer to store file content ++* @param sz how many bytes to read at most ++* @return the byte we've read, or Linux specific error code ++*/ ++static int retriveFromFile(char *path, u8 *buf, u32 sz) ++{ ++ int ret =-1; ++ mm_segment_t oldfs; ++ struct file *fp; ++ ++ if (path && buf) { ++ if (0 == (ret =openFile(&fp, path, O_RDONLY, 0))) { ++ DBG_871X("%s openFile path:%s fp =%p\n", __func__, path , fp); ++ ++ oldfs = get_fs(); set_fs(get_ds()); ++ ret =readFile(fp, buf, sz); ++ set_fs(oldfs); ++ closeFile(fp); ++ ++ DBG_871X("%s readFile, ret:%d\n", __func__, ret); ++ ++ } else { ++ DBG_871X("%s openFile path:%s Fail, ret:%d\n", __func__, path, ret); ++ } ++ } else { ++ DBG_871X("%s NULL pointer\n", __func__); ++ ret = -EINVAL; ++ } ++ return ret; ++} ++ ++/* ++* Test if the specifi @param path is a file and readable ++* @param path the path of the file to test ++* @return true or false ++*/ ++int rtw_is_file_readable(char *path) ++{ ++ if (isFileReadable(path) == 0) ++ return true; ++ else ++ return false; ++} ++ ++/* ++* Open the file with @param path and retrive the file content into memory starting from @param buf for @param sz at most ++* @param path the path of the file to open and read ++* @param buf the starting address of the buffer to store file content ++* @param sz how many bytes to read at most ++* @return the byte we've read ++*/ ++int rtw_retrive_from_file(char *path, u8 *buf, u32 sz) ++{ ++ int ret =retriveFromFile(path, buf, sz); ++ return ret>= 0?ret:0; ++} ++ ++struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv, void *old_priv) ++{ ++ struct net_device *pnetdev; ++ struct rtw_netdev_priv_indicator *pnpi; ++ ++ pnetdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4); ++ if (!pnetdev) ++ goto RETURN; ++ ++ pnpi = netdev_priv(pnetdev); ++ pnpi->priv =old_priv; ++ pnpi->sizeof_priv =sizeof_priv; ++ ++RETURN: ++ return pnetdev; ++} ++ ++struct net_device *rtw_alloc_etherdev(int sizeof_priv) ++{ ++ struct net_device *pnetdev; ++ struct rtw_netdev_priv_indicator *pnpi; ++ ++ pnetdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4); ++ if (!pnetdev) ++ goto RETURN; ++ ++ pnpi = netdev_priv(pnetdev); ++ ++ pnpi->priv = vzalloc(sizeof_priv); ++ if (!pnpi->priv) { ++ free_netdev(pnetdev); ++ pnetdev = NULL; ++ goto RETURN; ++ } ++ ++ pnpi->sizeof_priv =sizeof_priv; ++RETURN: ++ return pnetdev; ++} ++ ++void rtw_free_netdev(struct net_device * netdev) ++{ ++ struct rtw_netdev_priv_indicator *pnpi; ++ ++ if (!netdev) ++ goto RETURN; ++ ++ pnpi = netdev_priv(netdev); ++ ++ if (!pnpi->priv) ++ goto RETURN; ++ ++ vfree(pnpi->priv); ++ free_netdev(netdev); ++ ++RETURN: ++ return; ++} ++ ++int rtw_change_ifname(struct adapter *padapter, const char *ifname) ++{ ++ struct net_device *pnetdev; ++ struct net_device *cur_pnetdev; ++ struct rereg_nd_name_data *rereg_priv; ++ int ret; ++ ++ if (!padapter) ++ goto error; ++ ++ cur_pnetdev = padapter->pnetdev; ++ rereg_priv = &padapter->rereg_nd_name_priv; ++ ++ /* free the old_pnetdev */ ++ if (rereg_priv->old_pnetdev) { ++ free_netdev(rereg_priv->old_pnetdev); ++ rereg_priv->old_pnetdev = NULL; ++ } ++ ++ if (!rtnl_is_locked()) ++ unregister_netdev(cur_pnetdev); ++ else ++ unregister_netdevice(cur_pnetdev); ++ ++ rereg_priv->old_pnetdev =cur_pnetdev; ++ ++ pnetdev = rtw_init_netdev(padapter); ++ if (!pnetdev) { ++ ret = -1; ++ goto error; ++ } ++ ++ SET_NETDEV_DEV(pnetdev, dvobj_to_dev(adapter_to_dvobj(padapter))); ++ ++ rtw_init_netdev_name(pnetdev, ifname); ++ ++ memcpy(pnetdev->dev_addr, padapter->eeprompriv.mac_addr, ETH_ALEN); ++ ++ if (!rtnl_is_locked()) ++ ret = register_netdev(pnetdev); ++ else ++ ret = register_netdevice(pnetdev); ++ ++ if (ret != 0) { ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("register_netdev() failed\n")); ++ goto error; ++ } ++ ++ return 0; ++ ++error: ++ ++ return -1; ++ ++} ++ ++u64 rtw_modular64(u64 x, u64 y) ++{ ++ return do_div(x, y); ++} ++ ++void rtw_buf_free(u8 **buf, u32 *buf_len) ++{ ++ u32 ori_len; ++ ++ if (!buf || !buf_len) ++ return; ++ ++ ori_len = *buf_len; ++ ++ if (*buf) { ++ *buf_len = 0; ++ kfree(*buf); ++ *buf = NULL; ++ } ++} ++ ++void rtw_buf_update(u8 **buf, u32 *buf_len, u8 *src, u32 src_len) ++{ ++ u32 ori_len = 0, dup_len = 0; ++ u8 *ori = NULL; ++ u8 *dup = NULL; ++ ++ if (!buf || !buf_len) ++ return; ++ ++ if (!src || !src_len) ++ goto keep_ori; ++ ++ /* duplicate src */ ++ dup = rtw_malloc(src_len); ++ if (dup) { ++ dup_len = src_len; ++ memcpy(dup, src, dup_len); ++ } ++ ++keep_ori: ++ ori = *buf; ++ ori_len = *buf_len; ++ ++ /* replace buf with dup */ ++ *buf_len = 0; ++ *buf = dup; ++ *buf_len = dup_len; ++ ++ /* free ori */ ++ if (ori && ori_len > 0) ++ kfree(ori); ++} ++ ++ ++/** ++ * rtw_cbuf_full - test if cbuf is full ++ * @cbuf: pointer of struct rtw_cbuf ++ * ++ * Returns: true if cbuf is full ++ */ ++inline bool rtw_cbuf_full(struct rtw_cbuf *cbuf) ++{ ++ return (cbuf->write == cbuf->read-1)? true : false; ++} ++ ++/** ++ * rtw_cbuf_empty - test if cbuf is empty ++ * @cbuf: pointer of struct rtw_cbuf ++ * ++ * Returns: true if cbuf is empty ++ */ ++inline bool rtw_cbuf_empty(struct rtw_cbuf *cbuf) ++{ ++ return (cbuf->write == cbuf->read)? true : false; ++} ++ ++/** ++ * rtw_cbuf_push - push a pointer into cbuf ++ * @cbuf: pointer of struct rtw_cbuf ++ * @buf: pointer to push in ++ * ++ * Lock free operation, be careful of the use scheme ++ * Returns: true push success ++ */ ++bool rtw_cbuf_push(struct rtw_cbuf *cbuf, void *buf) ++{ ++ if (rtw_cbuf_full(cbuf)) ++ return _FAIL; ++ ++ DBG_871X("%s on %u\n", __func__, cbuf->write); ++ cbuf->bufs[cbuf->write] = buf; ++ cbuf->write = (cbuf->write+1)%cbuf->size; ++ ++ return _SUCCESS; ++} ++ ++/** ++ * rtw_cbuf_pop - pop a pointer from cbuf ++ * @cbuf: pointer of struct rtw_cbuf ++ * ++ * Lock free operation, be careful of the use scheme ++ * Returns: pointer popped out ++ */ ++void *rtw_cbuf_pop(struct rtw_cbuf *cbuf) ++{ ++ void *buf; ++ if (rtw_cbuf_empty(cbuf)) ++ return NULL; ++ ++ DBG_871X("%s on %u\n", __func__, cbuf->read); ++ buf = cbuf->bufs[cbuf->read]; ++ cbuf->read = (cbuf->read+1)%cbuf->size; ++ ++ return buf; ++} ++ ++/** ++ * rtw_cbuf_alloc - allocte a rtw_cbuf with given size and do initialization ++ * @size: size of pointer ++ * ++ * Returns: pointer of srtuct rtw_cbuf, NULL for allocation failure ++ */ ++struct rtw_cbuf *rtw_cbuf_alloc(u32 size) ++{ ++ struct rtw_cbuf *cbuf; ++ ++ cbuf = (struct rtw_cbuf *)rtw_malloc(sizeof(*cbuf) + sizeof(void*)*size); ++ ++ if (cbuf) { ++ cbuf->write = cbuf->read = 0; ++ cbuf->size = size; ++ } ++ ++ return cbuf; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/os_dep/os_intfs.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/os_intfs.c +--- linux-4.3/3rdparty/rtl8723bs/os_dep/os_intfs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/os_intfs.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,1916 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _OS_INTFS_C_ ++ ++#include ++#include ++#include ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Realtek Wireless Lan Driver"); ++MODULE_AUTHOR("Realtek Semiconductor Corp."); ++MODULE_VERSION(DRIVERVERSION); ++ ++/* module param defaults */ ++static int rtw_chip_version = 0x00; ++static int rtw_rfintfs = HWPI; ++static int rtw_lbkmode = 0;/* RTL8712_AIR_TRX; */ ++ ++ ++static int rtw_network_mode = Ndis802_11IBSS;/* Ndis802_11Infrastructure;infra, ad-hoc, auto */ ++/* struct ndis_802_11_ssid ssid; */ ++static int rtw_channel = 1;/* ad-hoc support requirement */ ++static int rtw_wireless_mode = WIRELESS_MODE_MAX; ++static int rtw_vrtl_carrier_sense = AUTO_VCS; ++static int rtw_vcs_type = RTS_CTS;/* */ ++static int rtw_rts_thresh = 2347;/* */ ++static int rtw_frag_thresh = 2346;/* */ ++static int rtw_preamble = PREAMBLE_LONG;/* long, short, auto */ ++static int rtw_scan_mode = 1;/* active, passive */ ++static int rtw_adhoc_tx_pwr = 1; ++static int rtw_soft_ap = 0; ++/* int smart_ps = 1; */ ++static int rtw_power_mgnt = 1; ++static int rtw_ips_mode = IPS_NORMAL; ++module_param(rtw_ips_mode, int, 0644); ++MODULE_PARM_DESC(rtw_ips_mode,"The default IPS mode"); ++ ++static int rtw_smart_ps = 2; ++ ++static int rtw_check_fw_ps = 1; ++ ++static int rtw_usb_rxagg_mode = 2;/* USB_RX_AGG_DMA = 1, USB_RX_AGG_USB =2 */ ++module_param(rtw_usb_rxagg_mode, int, 0644); ++ ++static int rtw_radio_enable = 1; ++static int rtw_long_retry_lmt = 7; ++static int rtw_short_retry_lmt = 7; ++static int rtw_busy_thresh = 40; ++/* int qos_enable = 0; */ ++static int rtw_ack_policy = NORMAL_ACK; ++ ++static int rtw_software_encrypt = 0; ++static int rtw_software_decrypt = 0; ++ ++static int rtw_acm_method = 0;/* 0:By SW 1:By HW. */ ++ ++static int rtw_wmm_enable = 1;/* default is set to enable the wmm. */ ++static int rtw_uapsd_enable = 0; ++static int rtw_uapsd_max_sp = NO_LIMIT; ++static int rtw_uapsd_acbk_en = 0; ++static int rtw_uapsd_acbe_en = 0; ++static int rtw_uapsd_acvi_en = 0; ++static int rtw_uapsd_acvo_en = 0; ++ ++int rtw_ht_enable = 1; ++/* 0: 20 MHz, 1: 40 MHz, 2: 80 MHz, 3: 160MHz, 4: 80+80MHz */ ++/* 2.4G use bit 0 ~ 3, 5G use bit 4 ~ 7 */ ++/* 0x21 means enable 2.4G 40MHz & 5G 80MHz */ ++static int rtw_bw_mode = 0x21; ++static int rtw_ampdu_enable = 1;/* for enable tx_ampdu ,0: disable, 0x1:enable (but wifi_spec should be 0), 0x2: force enable (don't care wifi_spec) */ ++static int rtw_rx_stbc = 1;/* 0: disable, 1:enable 2.4g */ ++static int rtw_ampdu_amsdu = 0;/* 0: disabled, 1:enabled, 2:auto . There is an IOT issu with DLINK DIR-629 when the flag turn on */ ++/* Short GI support Bit Map */ ++/* BIT0 - 20MHz, 0: non-support, 1: support */ ++/* BIT1 - 40MHz, 0: non-support, 1: support */ ++/* BIT2 - 80MHz, 0: non-support, 1: support */ ++/* BIT3 - 160MHz, 0: non-support, 1: support */ ++static int rtw_short_gi = 0xf; ++/* BIT0: Enable VHT LDPC Rx, BIT1: Enable VHT LDPC Tx, BIT4: Enable HT LDPC Rx, BIT5: Enable HT LDPC Tx */ ++static int rtw_ldpc_cap = 0x33; ++/* BIT0: Enable VHT STBC Rx, BIT1: Enable VHT STBC Tx, BIT4: Enable HT STBC Rx, BIT5: Enable HT STBC Tx */ ++static int rtw_stbc_cap = 0x13; ++/* BIT0: Enable VHT Beamformer, BIT1: Enable VHT Beamformee, BIT4: Enable HT Beamformer, BIT5: Enable HT Beamformee */ ++static int rtw_beamform_cap = 0x2; ++ ++static int rtw_lowrate_two_xmit = 1;/* Use 2 path Tx to transmit MCS0~7 and legacy mode */ ++ ++/* int rf_config = RF_1T2R; 1T2R */ ++static int rtw_rf_config = RF_MAX_TYPE; /* auto */ ++static int rtw_low_power = 0; ++static int rtw_wifi_spec = 0; ++static int rtw_channel_plan = RT_CHANNEL_DOMAIN_MAX; ++ ++static int rtw_btcoex_enable = 1; ++module_param(rtw_btcoex_enable, int, 0644); ++MODULE_PARM_DESC(rtw_btcoex_enable, "Enable BT co-existence mechanism"); ++static int rtw_bt_iso = 2;/* 0:Low, 1:High, 2:From Efuse */ ++static int rtw_bt_sco = 3;/* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter, 4.Busy, 5.OtherBusy */ ++static int rtw_bt_ampdu = 1 ;/* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */ ++static int rtw_ant_num = -1; /* <0: undefined, >0: Antenna number */ ++module_param(rtw_ant_num, int, 0644); ++MODULE_PARM_DESC(rtw_ant_num, "Antenna number setting"); ++ ++static int rtw_AcceptAddbaReq = true;/* 0:Reject AP's Add BA req, 1:Accept AP's Add BA req. */ ++ ++static int rtw_antdiv_cfg = 1; /* 0:OFF , 1:ON, 2:decide by Efuse config */ ++static int rtw_antdiv_type = 0 ; /* 0:decide by efuse 1: for 88EE, 1Tx and 1RxCG are diversity.(2 Ant with SPDT), 2: for 88EE, 1Tx and 2Rx are diversity.(2 Ant, Tx and RxCG are both on aux port, RxCS is on main port), 3: for 88EE, 1Tx and 1RxCG are fixed.(1Ant, Tx and RxCG are both on aux port) */ ++ ++ ++static int rtw_enusbss = 0;/* 0:disable, 1:enable */ ++ ++static int rtw_hwpdn_mode =2;/* 0:disable, 1:enable, 2: by EFUSE config */ ++ ++#ifdef CONFIG_HW_PWRP_DETECTION ++static int rtw_hwpwrp_detect = 1; ++#else ++static int rtw_hwpwrp_detect = 0; /* HW power ping detect 0:disable , 1:enable */ ++#endif ++ ++static int rtw_hw_wps_pbc = 0; ++ ++int rtw_mc2u_disable = 0; ++ ++static int rtw_80211d = 0; ++ ++#ifdef CONFIG_QOS_OPTIMIZATION ++static int rtw_qos_opt_enable = 1;/* 0: disable, 1:enable */ ++#else ++static int rtw_qos_opt_enable = 0;/* 0: disable, 1:enable */ ++#endif ++module_param(rtw_qos_opt_enable, int, 0644); ++ ++static char* ifname = "wlan%d"; ++module_param(ifname, charp, 0644); ++MODULE_PARM_DESC(ifname, "The default name to allocate for first interface"); ++ ++char* rtw_initmac = NULL; /* temp mac address if users want to use instead of the mac address in Efuse */ ++ ++module_param(rtw_initmac, charp, 0644); ++module_param(rtw_channel_plan, int, 0644); ++module_param(rtw_chip_version, int, 0644); ++module_param(rtw_rfintfs, int, 0644); ++module_param(rtw_lbkmode, int, 0644); ++module_param(rtw_network_mode, int, 0644); ++module_param(rtw_channel, int, 0644); ++module_param(rtw_wmm_enable, int, 0644); ++module_param(rtw_vrtl_carrier_sense, int, 0644); ++module_param(rtw_vcs_type, int, 0644); ++module_param(rtw_busy_thresh, int, 0644); ++ ++module_param(rtw_ht_enable, int, 0644); ++module_param(rtw_bw_mode, int, 0644); ++module_param(rtw_ampdu_enable, int, 0644); ++module_param(rtw_rx_stbc, int, 0644); ++module_param(rtw_ampdu_amsdu, int, 0644); ++ ++module_param(rtw_lowrate_two_xmit, int, 0644); ++ ++module_param(rtw_rf_config, int, 0644); ++module_param(rtw_power_mgnt, int, 0644); ++module_param(rtw_smart_ps, int, 0644); ++module_param(rtw_low_power, int, 0644); ++module_param(rtw_wifi_spec, int, 0644); ++ ++module_param(rtw_antdiv_cfg, int, 0644); ++module_param(rtw_antdiv_type, int, 0644); ++ ++module_param(rtw_enusbss, int, 0644); ++module_param(rtw_hwpdn_mode, int, 0644); ++module_param(rtw_hwpwrp_detect, int, 0644); ++ ++module_param(rtw_hw_wps_pbc, int, 0644); ++ ++static uint rtw_max_roaming_times =2; ++module_param(rtw_max_roaming_times, uint, 0644); ++MODULE_PARM_DESC(rtw_max_roaming_times,"The max roaming times to try"); ++ ++module_param(rtw_mc2u_disable, int, 0644); ++ ++module_param(rtw_80211d, int, 0644); ++MODULE_PARM_DESC(rtw_80211d, "Enable 802.11d mechanism"); ++ ++static uint rtw_notch_filter = 0; ++module_param(rtw_notch_filter, uint, 0644); ++MODULE_PARM_DESC(rtw_notch_filter, "0:Disable, 1:Enable, 2:Enable only for P2P"); ++ ++#define CONFIG_RTW_HIQ_FILTER 1 ++ ++static uint rtw_hiq_filter = CONFIG_RTW_HIQ_FILTER; ++module_param(rtw_hiq_filter, uint, 0644); ++MODULE_PARM_DESC(rtw_hiq_filter, "0:allow all, 1:allow special, 2:deny all"); ++ ++static int rtw_tx_pwr_lmt_enable = 0; ++static int rtw_tx_pwr_by_rate = 0; ++ ++module_param(rtw_tx_pwr_lmt_enable, int, 0644); ++MODULE_PARM_DESC(rtw_tx_pwr_lmt_enable,"0:Disable, 1:Enable, 2: Depend on efuse"); ++ ++module_param(rtw_tx_pwr_by_rate, int, 0644); ++MODULE_PARM_DESC(rtw_tx_pwr_by_rate,"0:Disable, 1:Enable, 2: Depend on efuse"); ++ ++#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE ++char *rtw_phy_file_path = ""; ++module_param(rtw_phy_file_path, charp, 0644); ++MODULE_PARM_DESC(rtw_phy_file_path, "The path of phy parameter"); ++/* PHY FILE Bit Map */ ++/* BIT0 - MAC, 0: non-support, 1: support */ ++/* BIT1 - BB, 0: non-support, 1: support */ ++/* BIT2 - BB_PG, 0: non-support, 1: support */ ++/* BIT3 - BB_MP, 0: non-support, 1: support */ ++/* BIT4 - RF, 0: non-support, 1: support */ ++/* BIT5 - RF_TXPWR_TRACK, 0: non-support, 1: support */ ++/* BIT6 - RF_TXPWR_LMT, 0: non-support, 1: support */ ++static int rtw_load_phy_file = (BIT2|BIT6); ++module_param(rtw_load_phy_file, int, 0644); ++MODULE_PARM_DESC(rtw_load_phy_file,"PHY File Bit Map"); ++static int rtw_decrypt_phy_file = 0; ++module_param(rtw_decrypt_phy_file, int, 0644); ++MODULE_PARM_DESC(rtw_decrypt_phy_file,"Enable Decrypt PHY File"); ++#endif ++ ++int _netdev_open(struct net_device *pnetdev); ++int netdev_open (struct net_device *pnetdev); ++static int netdev_close (struct net_device *pnetdev); ++ ++static uint loadparam(struct adapter *padapter, _nic_hdl pnetdev) ++{ ++ uint status = _SUCCESS; ++ struct registry_priv *registry_par = &padapter->registrypriv; ++ ++ registry_par->chip_version = (u8)rtw_chip_version; ++ registry_par->rfintfs = (u8)rtw_rfintfs; ++ registry_par->lbkmode = (u8)rtw_lbkmode; ++ /* registry_par->hci = (u8)hci; */ ++ registry_par->network_mode = (u8)rtw_network_mode; ++ ++ memcpy(registry_par->ssid.Ssid, "ANY", 3); ++ registry_par->ssid.SsidLength = 3; ++ ++ registry_par->channel = (u8)rtw_channel; ++ registry_par->wireless_mode = (u8)rtw_wireless_mode; ++ ++ if (registry_par->channel > 14) ++ registry_par->channel = 1; ++ ++ registry_par->vrtl_carrier_sense = (u8)rtw_vrtl_carrier_sense ; ++ registry_par->vcs_type = (u8)rtw_vcs_type; ++ registry_par->rts_thresh =(u16)rtw_rts_thresh; ++ registry_par->frag_thresh =(u16)rtw_frag_thresh; ++ registry_par->preamble = (u8)rtw_preamble; ++ registry_par->scan_mode = (u8)rtw_scan_mode; ++ registry_par->adhoc_tx_pwr = (u8)rtw_adhoc_tx_pwr; ++ registry_par->soft_ap = (u8)rtw_soft_ap; ++ registry_par->smart_ps = (u8)rtw_smart_ps; ++ registry_par->check_fw_ps = (u8)rtw_check_fw_ps; ++ registry_par->power_mgnt = (u8)rtw_power_mgnt; ++ registry_par->ips_mode = (u8)rtw_ips_mode; ++ registry_par->radio_enable = (u8)rtw_radio_enable; ++ registry_par->long_retry_lmt = (u8)rtw_long_retry_lmt; ++ registry_par->short_retry_lmt = (u8)rtw_short_retry_lmt; ++ registry_par->busy_thresh = (u16)rtw_busy_thresh; ++ /* registry_par->qos_enable = (u8)rtw_qos_enable; */ ++ registry_par->ack_policy = (u8)rtw_ack_policy; ++ registry_par->software_encrypt = (u8)rtw_software_encrypt; ++ registry_par->software_decrypt = (u8)rtw_software_decrypt; ++ ++ registry_par->acm_method = (u8)rtw_acm_method; ++ registry_par->usb_rxagg_mode = (u8)rtw_usb_rxagg_mode; ++ ++ /* UAPSD */ ++ registry_par->wmm_enable = (u8)rtw_wmm_enable; ++ registry_par->uapsd_enable = (u8)rtw_uapsd_enable; ++ registry_par->uapsd_max_sp = (u8)rtw_uapsd_max_sp; ++ registry_par->uapsd_acbk_en = (u8)rtw_uapsd_acbk_en; ++ registry_par->uapsd_acbe_en = (u8)rtw_uapsd_acbe_en; ++ registry_par->uapsd_acvi_en = (u8)rtw_uapsd_acvi_en; ++ registry_par->uapsd_acvo_en = (u8)rtw_uapsd_acvo_en; ++ ++ registry_par->ht_enable = (u8)rtw_ht_enable; ++ registry_par->bw_mode = (u8)rtw_bw_mode; ++ registry_par->ampdu_enable = (u8)rtw_ampdu_enable; ++ registry_par->rx_stbc = (u8)rtw_rx_stbc; ++ registry_par->ampdu_amsdu = (u8)rtw_ampdu_amsdu; ++ registry_par->short_gi = (u8)rtw_short_gi; ++ registry_par->ldpc_cap = (u8)rtw_ldpc_cap; ++ registry_par->stbc_cap = (u8)rtw_stbc_cap; ++ registry_par->beamform_cap = (u8)rtw_beamform_cap; ++ ++ registry_par->lowrate_two_xmit = (u8)rtw_lowrate_two_xmit; ++ registry_par->rf_config = (u8)rtw_rf_config; ++ registry_par->low_power = (u8)rtw_low_power; ++ ++ ++ registry_par->wifi_spec = (u8)rtw_wifi_spec; ++ ++ registry_par->channel_plan = (u8)rtw_channel_plan; ++ ++ registry_par->btcoex = (u8)rtw_btcoex_enable; ++ registry_par->bt_iso = (u8)rtw_bt_iso; ++ registry_par->bt_sco = (u8)rtw_bt_sco; ++ registry_par->bt_ampdu = (u8)rtw_bt_ampdu; ++ registry_par->ant_num = (s8)rtw_ant_num; ++ ++ registry_par->bAcceptAddbaReq = (u8)rtw_AcceptAddbaReq; ++ ++ registry_par->antdiv_cfg = (u8)rtw_antdiv_cfg; ++ registry_par->antdiv_type = (u8)rtw_antdiv_type; ++ ++ registry_par->hw_wps_pbc = (u8)rtw_hw_wps_pbc; ++ ++ registry_par->max_roaming_times = (u8)rtw_max_roaming_times; ++#ifdef CONFIG_INTEL_WIDI ++ registry_par->max_roaming_times = (u8)rtw_max_roaming_times + 2; ++#endif /* CONFIG_INTEL_WIDI */ ++ ++ registry_par->enable80211d = (u8)rtw_80211d; ++ ++ snprintf(registry_par->ifname, 16, "%s", ifname); ++ ++ registry_par->notch_filter = (u8)rtw_notch_filter; ++ ++ registry_par->RegEnableTxPowerLimit = (u8)rtw_tx_pwr_lmt_enable; ++ registry_par->RegEnableTxPowerByRate = (u8)rtw_tx_pwr_by_rate; ++ ++ registry_par->RegPowerBase = 14; ++ registry_par->TxBBSwing_2G = 0xFF; ++ registry_par->TxBBSwing_5G = 0xFF; ++ registry_par->bEn_RFE = 1; ++ registry_par->RFE_Type = 64; ++ ++#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE ++ registry_par->load_phy_file = (u8)rtw_load_phy_file; ++ registry_par->RegDecryptCustomFile = (u8)rtw_decrypt_phy_file; ++#endif ++ registry_par->qos_opt_enable = (u8)rtw_qos_opt_enable; ++ ++ registry_par->hiq_filter = (u8)rtw_hiq_filter; ++ return status; ++} ++ ++static int rtw_net_set_mac_address(struct net_device *pnetdev, void *p) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev); ++ struct sockaddr *addr = p; ++ ++ if (padapter->bup == false) ++ { ++ /* DBG_871X("r8711_net_set_mac_address(), MAC =%x:%x:%x:%x:%x:%x\n", addr->sa_data[0], addr->sa_data[1], addr->sa_data[2], addr->sa_data[3], */ ++ /* addr->sa_data[4], addr->sa_data[5]); */ ++ memcpy(padapter->eeprompriv.mac_addr, addr->sa_data, ETH_ALEN); ++ /* memcpy(pnetdev->dev_addr, addr->sa_data, ETH_ALEN); */ ++ /* padapter->bset_hwaddr = true; */ ++ } ++ ++ return 0; ++} ++ ++static struct net_device_stats *rtw_net_get_stats(struct net_device *pnetdev) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev); ++ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); ++ struct recv_priv *precvpriv = &(padapter->recvpriv); ++ ++ padapter->stats.tx_packets = pxmitpriv->tx_pkts;/* pxmitpriv->tx_pkts++; */ ++ padapter->stats.rx_packets = precvpriv->rx_pkts;/* precvpriv->rx_pkts++; */ ++ padapter->stats.tx_dropped = pxmitpriv->tx_drop; ++ padapter->stats.rx_dropped = precvpriv->rx_drop; ++ padapter->stats.tx_bytes = pxmitpriv->tx_bytes; ++ padapter->stats.rx_bytes = precvpriv->rx_bytes; ++ ++ return &padapter->stats; ++} ++ ++/* ++ * AC to queue mapping ++ * ++ * AC_VO -> queue 0 ++ * AC_VI -> queue 1 ++ * AC_BE -> queue 2 ++ * AC_BK -> queue 3 ++ */ ++static const u16 rtw_1d_to_queue[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; ++ ++/* Given a data frame determine the 802.1p/1d tag to use. */ ++static unsigned int rtw_classify8021d(struct sk_buff *skb) ++{ ++ unsigned int dscp; ++ ++ /* skb->priority values from 256->263 are magic values to ++ * directly indicate a specific 802.1d priority. This is used ++ * to allow 802.1d priority to be passed directly in from VLAN ++ * tags, etc. ++ */ ++ if (skb->priority >= 256 && skb->priority <= 263) ++ return skb->priority - 256; ++ ++ switch (skb->protocol) { ++ case htons(ETH_P_IP): ++ dscp = ip_hdr(skb)->tos & 0xfc; ++ break; ++ default: ++ return 0; ++ } ++ ++ return dscp >> 5; ++} ++ ++ ++static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb ++ , void *accel_priv ++ , select_queue_fallback_t fallback ++) ++{ ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ skb->priority = rtw_classify8021d(skb); ++ ++ if (pmlmepriv->acm_mask != 0) ++ { ++ skb->priority = qos_acm(pmlmepriv->acm_mask, skb->priority); ++ } ++ ++ return rtw_1d_to_queue[skb->priority]; ++} ++ ++u16 rtw_recv_select_queue(struct sk_buff *skb) ++{ ++ struct iphdr *piphdr; ++ unsigned int dscp; ++ __be16 eth_type; ++ u32 priority; ++ u8 *pdata = skb->data; ++ ++ memcpy(ð_type, pdata+(ETH_ALEN<<1), 2); ++ ++ switch (be16_to_cpu(eth_type)) { ++ case ETH_P_IP: ++ ++ piphdr = (struct iphdr *)(pdata+ETH_HLEN); ++ ++ dscp = piphdr->tos & 0xfc; ++ ++ priority = dscp >> 5; ++ ++ break; ++ default: ++ priority = 0; ++ } ++ ++ return rtw_1d_to_queue[priority]; ++ ++} ++ ++static int rtw_ndev_notifier_call(struct notifier_block * nb, unsigned long state, void *ptr) ++{ ++ struct net_device *dev = netdev_notifier_info_to_dev(ptr); ++ ++ if (dev->netdev_ops->ndo_do_ioctl != rtw_ioctl) ++ return NOTIFY_DONE; ++ ++ DBG_871X_LEVEL(_drv_info_, FUNC_NDEV_FMT" state:%lu\n", FUNC_NDEV_ARG(dev), state); ++ ++ switch (state) { ++ case NETDEV_CHANGENAME: ++ rtw_adapter_proc_replace(dev); ++ break; ++ } ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block rtw_ndev_notifier = { ++ .notifier_call = rtw_ndev_notifier_call, ++}; ++ ++int rtw_ndev_notifier_register(void) ++{ ++ return register_netdevice_notifier(&rtw_ndev_notifier); ++} ++ ++void rtw_ndev_notifier_unregister(void) ++{ ++ unregister_netdevice_notifier(&rtw_ndev_notifier); ++} ++ ++ ++static int rtw_ndev_init(struct net_device *dev) ++{ ++ struct adapter *adapter = rtw_netdev_priv(dev); ++ ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter)); ++ strncpy(adapter->old_ifname, dev->name, IFNAMSIZ); ++ rtw_adapter_proc_init(dev); ++ ++ return 0; ++} ++ ++static void rtw_ndev_uninit(struct net_device *dev) ++{ ++ struct adapter *adapter = rtw_netdev_priv(dev); ++ ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter)); ++ rtw_adapter_proc_deinit(dev); ++} ++ ++static const struct net_device_ops rtw_netdev_ops = { ++ .ndo_init = rtw_ndev_init, ++ .ndo_uninit = rtw_ndev_uninit, ++ .ndo_open = netdev_open, ++ .ndo_stop = netdev_close, ++ .ndo_start_xmit = rtw_xmit_entry, ++ .ndo_select_queue = rtw_select_queue, ++ .ndo_set_mac_address = rtw_net_set_mac_address, ++ .ndo_get_stats = rtw_net_get_stats, ++ .ndo_do_ioctl = rtw_ioctl, ++}; ++ ++int rtw_init_netdev_name(struct net_device *pnetdev, const char *ifname) ++{ ++ if (dev_alloc_name(pnetdev, ifname) < 0) ++ RT_TRACE(_module_os_intfs_c_, _drv_err_, ("dev_alloc_name, fail!\n")); ++ ++ netif_carrier_off(pnetdev); ++ /* rtw_netif_stop_queue(pnetdev); */ ++ ++ return 0; ++} ++ ++struct net_device *rtw_init_netdev(struct adapter *old_padapter) ++{ ++ struct adapter *padapter; ++ struct net_device *pnetdev; ++ ++ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+init_net_dev\n")); ++ ++ if (old_padapter != NULL) ++ pnetdev = rtw_alloc_etherdev_with_old_priv(sizeof(struct adapter), (void *)old_padapter); ++ else ++ pnetdev = rtw_alloc_etherdev(sizeof(struct adapter)); ++ ++ if (!pnetdev) ++ return NULL; ++ ++ padapter = rtw_netdev_priv(pnetdev); ++ padapter->pnetdev = pnetdev; ++ ++ /* pnetdev->init = NULL; */ ++ ++ DBG_871X("register rtw_netdev_ops to netdev_ops\n"); ++ pnetdev->netdev_ops = &rtw_netdev_ops; ++ ++ /* pnetdev->tx_timeout = NULL; */ ++ pnetdev->watchdog_timeo = HZ*3; /* 3 second timeout */ ++ pnetdev->wireless_handlers = (struct iw_handler_def *)&rtw_handlers_def; ++ ++ /* step 2. */ ++ loadparam(padapter, pnetdev); ++ ++ return pnetdev; ++} ++ ++void rtw_unregister_netdevs(struct dvobj_priv *dvobj) ++{ ++ struct adapter *padapter = NULL; ++ struct net_device *pnetdev = NULL; ++ ++ padapter = dvobj->padapters; ++ ++ if (padapter == NULL) ++ return; ++ ++ pnetdev = padapter->pnetdev; ++ ++ if ((padapter->DriverState != DRIVER_DISAPPEAR) && pnetdev) ++ unregister_netdev(pnetdev); /* will call netdev_close() */ ++ rtw_wdev_unregister(padapter->rtw_wdev); ++} ++ ++u32 rtw_start_drv_threads(struct adapter *padapter) ++{ ++ u32 _status = _SUCCESS; ++ ++ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_start_drv_threads\n")); ++ padapter->xmitThread = kthread_run(rtw_xmit_thread, padapter, "RTW_XMIT_THREAD"); ++ if (IS_ERR(padapter->xmitThread)) ++ _status = _FAIL; ++ ++ padapter->cmdThread = kthread_run(rtw_cmd_thread, padapter, "RTW_CMD_THREAD"); ++ if (IS_ERR(padapter->cmdThread)) ++ _status = _FAIL; ++ else ++ down(&padapter->cmdpriv.terminate_cmdthread_sema); /* wait for cmd_thread to run */ ++ ++ rtw_hal_start_thread(padapter); ++ return _status; ++} ++ ++void rtw_stop_drv_threads (struct adapter *padapter) ++{ ++ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_stop_drv_threads\n")); ++ ++ rtw_stop_cmd_thread(padapter); ++ ++ /* Below is to termindate tx_thread... */ ++ up(&padapter->xmitpriv.xmit_sema); ++ down(&padapter->xmitpriv.terminate_xmitthread_sema); ++ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("\n drv_halt: rtw_xmit_thread can be terminated !\n")); ++ ++ rtw_hal_stop_thread(padapter); ++} ++ ++static u8 rtw_init_default_value(struct adapter *padapter) ++{ ++ u8 ret = _SUCCESS; ++ struct registry_priv* pregistrypriv = &padapter->registrypriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ /* xmit_priv */ ++ pxmitpriv->vcs_setting = pregistrypriv->vrtl_carrier_sense; ++ pxmitpriv->vcs = pregistrypriv->vcs_type; ++ pxmitpriv->vcs_type = pregistrypriv->vcs_type; ++ /* pxmitpriv->rts_thresh = pregistrypriv->rts_thresh; */ ++ pxmitpriv->frag_len = pregistrypriv->frag_thresh; ++ ++ /* recv_priv */ ++ ++ /* mlme_priv */ ++ pmlmepriv->scan_mode = SCAN_ACTIVE; ++ ++ /* qos_priv */ ++ /* pmlmepriv->qospriv.qos_option = pregistrypriv->wmm_enable; */ ++ ++ /* ht_priv */ ++ pmlmepriv->htpriv.ampdu_enable = false;/* set to disabled */ ++ ++ /* security_priv */ ++ /* rtw_get_encrypt_decrypt_from_registrypriv(padapter); */ ++ psecuritypriv->binstallGrpkey = _FAIL; ++#ifdef CONFIG_GTK_OL ++ psecuritypriv->binstallKCK_KEK = _FAIL; ++#endif /* CONFIG_GTK_OL */ ++ psecuritypriv->sw_encrypt =pregistrypriv->software_encrypt; ++ psecuritypriv->sw_decrypt =pregistrypriv->software_decrypt; ++ ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */ ++ psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ ++ psecuritypriv->dot11PrivacyKeyIndex = 0; ++ ++ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ psecuritypriv->dot118021XGrpKeyid = 1; ++ ++ psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen; ++ psecuritypriv->ndisencryptstatus = Ndis802_11WEPDisabled; ++ ++ /* registry_priv */ ++ rtw_init_registrypriv_dev_network(padapter); ++ rtw_update_registrypriv_dev_network(padapter); ++ ++ /* hal_priv */ ++ rtw_hal_def_value_init(padapter); ++ ++ /* misc. */ ++ RTW_ENABLE_FUNC(padapter, DF_RX_BIT); ++ RTW_ENABLE_FUNC(padapter, DF_TX_BIT); ++ padapter->bLinkInfoDump = 0; ++ padapter->bNotifyChannelChange = 0; ++ ++ /* for debug purpose */ ++ padapter->fix_rate = 0xFF; ++ padapter->driver_ampdu_spacing = 0xFF; ++ padapter->driver_rx_ampdu_factor = 0xFF; ++ ++ return ret; ++} ++ ++struct dvobj_priv *devobj_init(void) ++{ ++ struct dvobj_priv *pdvobj = NULL; ++ ++ if ((pdvobj = (struct dvobj_priv*)rtw_zmalloc(sizeof(*pdvobj))) == NULL) ++ return NULL; ++ ++ mutex_init(&pdvobj->hw_init_mutex); ++ mutex_init(&pdvobj->h2c_fwcmd_mutex); ++ mutex_init(&pdvobj->setch_mutex); ++ mutex_init(&pdvobj->setbw_mutex); ++ ++ spin_lock_init(&pdvobj->lock); ++ ++ pdvobj->macid[1] = true; /* macid = 1 for bc/mc stainfo */ ++ ++ pdvobj->processing_dev_remove = false; ++ ++ atomic_set(&pdvobj->disable_func, 0); ++ ++ spin_lock_init(&pdvobj->cam_ctl.lock); ++ ++ return pdvobj; ++} ++ ++void devobj_deinit(struct dvobj_priv *pdvobj) ++{ ++ if (!pdvobj) ++ return; ++ ++ mutex_destroy(&pdvobj->hw_init_mutex); ++ mutex_destroy(&pdvobj->h2c_fwcmd_mutex); ++ mutex_destroy(&pdvobj->setch_mutex); ++ mutex_destroy(&pdvobj->setbw_mutex); ++ ++ kfree((u8 *)pdvobj); ++} ++ ++u8 rtw_reset_drv_sw(struct adapter *padapter) ++{ ++ u8 ret8 = _SUCCESS; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); ++ ++ /* hal_priv */ ++ if (is_primary_adapter(padapter)) ++ rtw_hal_def_value_init(padapter); ++ ++ RTW_ENABLE_FUNC(padapter, DF_RX_BIT); ++ RTW_ENABLE_FUNC(padapter, DF_TX_BIT); ++ padapter->bLinkInfoDump = 0; ++ ++ padapter->xmitpriv.tx_pkts = 0; ++ padapter->recvpriv.rx_pkts = 0; ++ ++ pmlmepriv->LinkDetectInfo.bBusyTraffic = false; ++ ++ /* pmlmepriv->LinkDetectInfo.TrafficBusyState = false; */ ++ pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 0; ++ pmlmepriv->LinkDetectInfo.LowPowerTransitionCount = 0; ++ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY |_FW_UNDER_LINKING); ++ ++ pwrctrlpriv->pwr_state_check_cnts = 0; ++ ++ /* mlmeextpriv */ ++ padapter->mlmeextpriv.sitesurvey_res.state = SCAN_DISABLE; ++ ++ rtw_set_signal_stat_timer(&padapter->recvpriv); ++ ++ return ret8; ++} ++ ++ ++u8 rtw_init_drv_sw(struct adapter *padapter) ++{ ++ u8 ret8 = _SUCCESS; ++ ++ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_init_drv_sw\n")); ++ ++ ret8 = rtw_init_default_value(padapter); ++ ++ rtw_init_hal_com_default_value(padapter); ++ ++ if ((rtw_init_cmd_priv(&padapter->cmdpriv)) == _FAIL) { ++ RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init cmd_priv\n")); ++ ret8 = _FAIL; ++ goto exit; ++ } ++ ++ padapter->cmdpriv.padapter =padapter; ++ ++ if ((rtw_init_evt_priv(&padapter->evtpriv)) == _FAIL) { ++ RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init evt_priv\n")); ++ ret8 = _FAIL; ++ goto exit; ++ } ++ ++ ++ if (rtw_init_mlme_priv(padapter) == _FAIL) { ++ RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init mlme_priv\n")); ++ ret8 = _FAIL; ++ goto exit; ++ } ++ ++ if (init_mlme_ext_priv(padapter) == _FAIL) { ++ RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init mlme_ext_priv\n")); ++ ret8 = _FAIL; ++ goto exit; ++ } ++ ++ if (_rtw_init_xmit_priv(&padapter->xmitpriv, padapter) == _FAIL) { ++ DBG_871X("Can't _rtw_init_xmit_priv\n"); ++ ret8 = _FAIL; ++ goto exit; ++ } ++ ++ if (_rtw_init_recv_priv(&padapter->recvpriv, padapter) == _FAIL) { ++ DBG_871X("Can't _rtw_init_recv_priv\n"); ++ ret8 = _FAIL; ++ goto exit; ++ } ++ /* add for CONFIG_IEEE80211W, none 11w also can use */ ++ spin_lock_init(&padapter->security_key_mutex); ++ ++ /* We don't need to memset padapter->XXX to zero, because adapter is allocated by vzalloc(). */ ++ /* memset((unsigned char *)&padapter->securitypriv, 0, sizeof (struct security_priv)); */ ++ ++ if (_rtw_init_sta_priv(&padapter->stapriv) == _FAIL) { ++ DBG_871X("Can't _rtw_init_sta_priv\n"); ++ ret8 = _FAIL; ++ goto exit; ++ } ++ ++ padapter->stapriv.padapter = padapter; ++ padapter->setband = GHZ24_50; ++ padapter->fix_rate = 0xFF; ++ rtw_init_bcmc_stainfo(padapter); ++ ++ rtw_init_pwrctrl_priv(padapter); ++ ++ rtw_hal_dm_init(padapter); ++ ++#ifdef CONFIG_INTEL_WIDI ++ if (rtw_init_intel_widi(padapter) == _FAIL) { ++ DBG_871X("Can't rtw_init_intel_widi\n"); ++ ret8 = _FAIL; ++ goto exit; ++ } ++#endif /* CONFIG_INTEL_WIDI */ ++ ++exit: ++ ++ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-rtw_init_drv_sw\n")); ++ ++ return ret8; ++} ++ ++void rtw_cancel_all_timer(struct adapter *padapter) ++{ ++ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_cancel_all_timer\n")); ++ ++ del_timer_sync(&padapter->mlmepriv.assoc_timer); ++ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("rtw_cancel_all_timer:cancel association timer complete!\n")); ++ ++ del_timer_sync(&padapter->mlmepriv.scan_to_timer); ++ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("rtw_cancel_all_timer:cancel scan_to_timer!\n")); ++ ++ del_timer_sync(&padapter->mlmepriv.dynamic_chk_timer); ++ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("rtw_cancel_all_timer:cancel dynamic_chk_timer!\n")); ++ ++ del_timer_sync(&(adapter_to_pwrctl(padapter)->pwr_state_check_timer)); ++ ++ del_timer_sync(&padapter->mlmepriv.set_scan_deny_timer); ++ rtw_clear_scan_deny(padapter); ++ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("rtw_cancel_all_timer:cancel set_scan_deny_timer!\n")); ++ ++ del_timer_sync(&padapter->recvpriv.signal_stat_timer); ++ ++ /* cancel dm timer */ ++ rtw_hal_dm_deinit(padapter); ++} ++ ++u8 rtw_free_drv_sw(struct adapter *padapter) ++{ ++ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("==>rtw_free_drv_sw")); ++ ++#ifdef CONFIG_INTEL_WIDI ++ rtw_free_intel_widi(padapter); ++#endif /* CONFIG_INTEL_WIDI */ ++ ++ free_mlme_ext_priv(&padapter->mlmeextpriv); ++ ++ rtw_free_cmd_priv(&padapter->cmdpriv); ++ ++ rtw_free_evt_priv(&padapter->evtpriv); ++ ++ rtw_free_mlme_priv(&padapter->mlmepriv); ++ ++ /* free_io_queue(padapter); */ ++ ++ _rtw_free_xmit_priv(&padapter->xmitpriv); ++ ++ _rtw_free_sta_priv(&padapter->stapriv); /* will free bcmc_stainfo here */ ++ ++ _rtw_free_recv_priv(&padapter->recvpriv); ++ ++ rtw_free_pwrctrl_priv(padapter); ++ ++ /* kfree((void *)padapter); */ ++ ++ rtw_hal_free_data(padapter); ++ ++ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("<==rtw_free_drv_sw\n")); ++ ++ /* free the old_pnetdev */ ++ if (padapter->rereg_nd_name_priv.old_pnetdev) { ++ free_netdev(padapter->rereg_nd_name_priv.old_pnetdev); ++ padapter->rereg_nd_name_priv.old_pnetdev = NULL; ++ } ++ ++ /* clear pbuddystruct adapter to avoid access wrong pointer. */ ++ if (padapter->pbuddy_adapter != NULL) ++ padapter->pbuddy_adapter->pbuddy_adapter = NULL; ++ ++ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-rtw_free_drv_sw\n")); ++ ++ return _SUCCESS; ++} ++ ++static int _rtw_drv_register_netdev(struct adapter *padapter, char *name) ++{ ++ int ret = _SUCCESS; ++ struct net_device *pnetdev = padapter->pnetdev; ++ ++ /* alloc netdev name */ ++ rtw_init_netdev_name(pnetdev, name); ++ ++ memcpy(pnetdev->dev_addr, padapter->eeprompriv.mac_addr, ETH_ALEN); ++ ++ /* Tell the network stack we exist */ ++ if (register_netdev(pnetdev) != 0) { ++ DBG_871X(FUNC_NDEV_FMT "Failed!\n", FUNC_NDEV_ARG(pnetdev)); ++ ret = _FAIL; ++ goto error_register_netdev; ++ } ++ ++ DBG_871X("%s, MAC Address (if%d) = " MAC_FMT "\n", __func__, (padapter->iface_id+1), MAC_ARG(pnetdev->dev_addr)); ++ ++ return ret; ++ ++error_register_netdev: ++ ++ rtw_free_drv_sw(padapter); ++ ++ rtw_free_netdev(pnetdev); ++ ++ return ret; ++} ++ ++int rtw_drv_register_netdev(struct adapter *if1) ++{ ++ struct dvobj_priv *dvobj = if1->dvobj; ++ struct adapter *padapter = dvobj->padapters; ++ char *name = if1->registrypriv.ifname; ++ ++ return _rtw_drv_register_netdev(padapter, name); ++} ++ ++int _netdev_open(struct net_device *pnetdev) ++{ ++ uint status; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev); ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); ++ ++ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+871x_drv - dev_open\n")); ++ DBG_871X("+871x_drv - drv_open, bup =%d\n", padapter->bup); ++ ++ padapter->netif_up = true; ++ ++ if (pwrctrlpriv->ps_flag == true) { ++ padapter->net_closed = false; ++ goto netdev_open_normal_process; ++ } ++ ++ if (padapter->bup == false) { ++ padapter->bDriverStopped = false; ++ padapter->bSurpriseRemoved = false; ++ padapter->bCardDisableWOHSM = false; ++ ++ status = rtw_hal_init(padapter); ++ if (status == _FAIL) { ++ RT_TRACE(_module_os_intfs_c_, _drv_err_, ("rtl871x_hal_init(): Can't init h/w!\n")); ++ goto netdev_open_error; ++ } ++ ++ DBG_871X("MAC Address = "MAC_FMT"\n", MAC_ARG(pnetdev->dev_addr)); ++ ++ status =rtw_start_drv_threads(padapter); ++ if (status == _FAIL) { ++ DBG_871X("Initialize driver software resource Failed!\n"); ++ goto netdev_open_error; ++ } ++ ++ if (padapter->intf_start) ++ padapter->intf_start(padapter); ++ ++ rtw_cfg80211_init_wiphy(padapter); ++ ++ padapter->bup = true; ++ pwrctrlpriv->bips_processing = false; ++ } ++ padapter->net_closed = false; ++ ++ _set_timer(&padapter->mlmepriv.dynamic_chk_timer, 2000); ++ ++ if (!rtw_netif_queue_stopped(pnetdev)) ++ rtw_netif_start_queue(pnetdev); ++ else ++ rtw_netif_wake_queue(pnetdev); ++ ++netdev_open_normal_process: ++ ++ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-871x_drv - dev_open\n")); ++ DBG_871X("-871x_drv - drv_open, bup =%d\n", padapter->bup); ++ ++ return 0; ++ ++netdev_open_error: ++ ++ padapter->bup = false; ++ ++ netif_carrier_off(pnetdev); ++ rtw_netif_stop_queue(pnetdev); ++ ++ RT_TRACE(_module_os_intfs_c_, _drv_err_, ("-871x_drv - dev_open, fail!\n")); ++ DBG_871X("-871x_drv - drv_open fail, bup =%d\n", padapter->bup); ++ ++ return (-1); ++ ++} ++ ++int netdev_open(struct net_device *pnetdev) ++{ ++ int ret; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev); ++ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); ++ ++ if (pwrctrlpriv->bInSuspend == true) ++ { ++ DBG_871X("+871x_drv - drv_open, bInSuspend =%d\n", pwrctrlpriv->bInSuspend); ++ return 0; ++ } ++ ++ if (mutex_lock_interruptible(&(adapter_to_dvobj(padapter)->hw_init_mutex))) ++ return -1; ++ ++ ret = _netdev_open(pnetdev); ++ mutex_unlock(&(adapter_to_dvobj(padapter)->hw_init_mutex)); ++ ++ return ret; ++} ++ ++static int ips_netdrv_open(struct adapter *padapter) ++{ ++ int status = _SUCCESS; ++ /* struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); */ ++ ++ padapter->net_closed = false; ++ ++ DBG_871X("===> %s.........\n", __func__); ++ ++ ++ padapter->bDriverStopped = false; ++ padapter->bCardDisableWOHSM = false; ++ /* padapter->bup = true; */ ++ ++ status = rtw_hal_init(padapter); ++ if (status == _FAIL) ++ { ++ RT_TRACE(_module_os_intfs_c_, _drv_err_, ("ips_netdrv_open(): Can't init h/w!\n")); ++ goto netdev_open_error; ++ } ++ ++ if (padapter->intf_start) ++ { ++ padapter->intf_start(padapter); ++ } ++ ++ _set_timer(&padapter->mlmepriv.dynamic_chk_timer, 2000); ++ ++ return _SUCCESS; ++ ++netdev_open_error: ++ /* padapter->bup = false; */ ++ DBG_871X("-ips_netdrv_open - drv_open failure, bup =%d\n", padapter->bup); ++ ++ return _FAIL; ++} ++ ++ ++int rtw_ips_pwr_up(struct adapter *padapter) ++{ ++ int result; ++ DBG_871X("===> rtw_ips_pwr_up..............\n"); ++ ++ result = ips_netdrv_open(padapter); ++ ++ DBG_871X("<=== rtw_ips_pwr_up..............\n"); ++ return result; ++ ++} ++ ++void rtw_ips_pwr_down(struct adapter *padapter) ++{ ++ DBG_871X("===> rtw_ips_pwr_down...................\n"); ++ ++ padapter->bCardDisableWOHSM = true; ++ padapter->net_closed = true; ++ ++ rtw_ips_dev_unload(padapter); ++ padapter->bCardDisableWOHSM = false; ++ DBG_871X("<=== rtw_ips_pwr_down.....................\n"); ++} ++ ++void rtw_ips_dev_unload(struct adapter *padapter) ++{ ++ DBG_871X("====> %s...\n", __func__); ++ ++ ++ if (padapter->bSurpriseRemoved == false) ++ { ++ rtw_hal_deinit(padapter); ++ } ++ ++} ++ ++ ++static int pm_netdev_open(struct net_device *pnetdev, u8 bnormal) ++{ ++ int status = -1; ++ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev); ++ ++ if (true == bnormal) ++ { ++ if (mutex_lock_interruptible(&(adapter_to_dvobj(padapter)->hw_init_mutex)) == 0) { ++ status = _netdev_open(pnetdev); ++ mutex_unlock(&(adapter_to_dvobj(padapter)->hw_init_mutex)); ++ } ++ } ++ else ++ status = (_SUCCESS == ips_netdrv_open(padapter))?(0):(-1); ++ ++ return status; ++} ++ ++static int netdev_close(struct net_device *pnetdev) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev); ++ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); ++ ++ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+871x_drv - drv_close\n")); ++ ++ if (pwrctl->bInternalAutoSuspend == true) ++ { ++ /* rtw_pwr_wakeup(padapter); */ ++ if (pwrctl->rf_pwrstate == rf_off) ++ pwrctl->ps_flag = true; ++ } ++ padapter->net_closed = true; ++ padapter->netif_up = false; ++ ++/*if (!padapter->hw_init_completed) ++ { ++ DBG_871X("(1)871x_drv - drv_close, bup =%d, hw_init_completed =%d\n", padapter->bup, padapter->hw_init_completed); ++ ++ padapter->bDriverStopped = true; ++ ++ rtw_dev_unload(padapter); ++ } ++ else*/ ++ if (pwrctl->rf_pwrstate == rf_on) { ++ DBG_871X("(2)871x_drv - drv_close, bup =%d, hw_init_completed =%d\n", padapter->bup, padapter->hw_init_completed); ++ ++ /* s1. */ ++ if (pnetdev) ++ { ++ if (!rtw_netif_queue_stopped(pnetdev)) ++ rtw_netif_stop_queue(pnetdev); ++ } ++ ++ /* s2. */ ++ LeaveAllPowerSaveMode(padapter); ++ rtw_disassoc_cmd(padapter, 500, false); ++ /* s2-2. indicate disconnect to os */ ++ rtw_indicate_disconnect(padapter); ++ /* s2-3. */ ++ rtw_free_assoc_resources(padapter, 1); ++ /* s2-4. */ ++ rtw_free_network_queue(padapter, true); ++ } ++ ++ rtw_scan_abort(padapter); ++ adapter_wdev_data(padapter)->bandroid_scan = false; ++ ++ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-871x_drv - drv_close\n")); ++ DBG_871X("-871x_drv - drv_close, bup =%d\n", padapter->bup); ++ ++ return 0; ++ ++} ++ ++void rtw_ndev_destructor(struct net_device *ndev) ++{ ++ DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); ++ ++ if (ndev->ieee80211_ptr) ++ kfree((u8 *)ndev->ieee80211_ptr); ++ ++ free_netdev(ndev); ++} ++ ++void rtw_dev_unload(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); ++ struct dvobj_priv *pobjpriv = padapter->dvobj; ++ struct debug_priv *pdbgpriv = &pobjpriv->drv_dbg; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 cnt = 0; ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+%s\n", __func__)); ++ ++ if (padapter->bup == true) ++ { ++ DBG_871X("===> %s\n", __func__); ++ ++ padapter->bDriverStopped = true; ++ if (padapter->xmitpriv.ack_tx) ++ rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_DRV_STOP); ++ ++ if (padapter->intf_stop) ++ padapter->intf_stop(padapter); ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("@ rtw_dev_unload: stop intf complete!\n")); ++ ++ if (!pwrctl->bInternalAutoSuspend) ++ rtw_stop_drv_threads(padapter); ++ ++ while (atomic_read(&(pcmdpriv->cmdthd_running)) == true) { ++ if (cnt > 5) { ++ DBG_871X("stop cmdthd timeout\n"); ++ break; ++ } else { ++ cnt ++; ++ DBG_871X("cmdthd is running(%d)\n", cnt); ++ msleep(10); ++ } ++ } ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("@ %s: stop thread complete!\n", __func__)); ++ ++ /* check the status of IPS */ ++ if (rtw_hal_check_ips_status(padapter) == true || pwrctl->rf_pwrstate == rf_off) { /* check HW status and SW state */ ++ DBG_871X_LEVEL(_drv_always_, "%s: driver in IPS-FWLPS\n", __func__); ++ pdbgpriv->dbg_dev_unload_inIPS_cnt++; ++ LeaveAllPowerSaveMode(padapter); ++ } else { ++ DBG_871X_LEVEL(_drv_always_, "%s: driver not in IPS\n", __func__); ++ } ++ ++ if (padapter->bSurpriseRemoved == false) ++ { ++ rtw_btcoex_IpsNotify(padapter, pwrctl->ips_mode_req); ++#ifdef CONFIG_WOWLAN ++ if (pwrctl->bSupportRemoteWakeup == true && ++ pwrctl->wowlan_mode ==true) { ++ DBG_871X_LEVEL(_drv_always_, "%s bSupportRemoteWakeup ==true do not run rtw_hal_deinit()\n", __func__); ++ } ++ else ++#endif ++ { ++ /* amy modify 20120221 for power seq is different between driver open and ips */ ++ rtw_hal_deinit(padapter); ++ } ++ padapter->bSurpriseRemoved = true; ++ } ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("@ %s: deinit hal complelt!\n", __func__)); ++ ++ padapter->bup = false; ++ ++ DBG_871X("<=== %s\n", __func__); ++ } ++ else { ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("%s: bup ==false\n", __func__)); ++ DBG_871X("%s: bup ==false\n", __func__); ++ } ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("-%s\n", __func__)); ++} ++ ++static int rtw_suspend_free_assoc_resource(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ DBG_871X("==> "FUNC_ADPT_FMT" entry....\n", FUNC_ADPT_ARG(padapter)); ++ ++ if (rtw_chk_roam_flags(padapter, RTW_ROAM_ON_RESUME)) { ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) ++ && check_fwstate(pmlmepriv, _FW_LINKED)) ++ { ++ DBG_871X("%s %s(" MAC_FMT "), length:%d assoc_ssid.length:%d\n", __func__, ++ pmlmepriv->cur_network.network.Ssid.Ssid, ++ MAC_ARG(pmlmepriv->cur_network.network.MacAddress), ++ pmlmepriv->cur_network.network.Ssid.SsidLength, ++ pmlmepriv->assoc_ssid.SsidLength); ++ rtw_set_to_roam(padapter, 1); ++ } ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED)) ++ { ++ rtw_disassoc_cmd(padapter, 0, false); ++ /* s2-2. indicate disconnect to os */ ++ rtw_indicate_disconnect(padapter); ++ } ++ else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ { ++ rtw_sta_flush(padapter); ++ } ++ ++ /* s2-3. */ ++ rtw_free_assoc_resources(padapter, 1); ++ ++ /* s2-4. */ ++ rtw_free_network_queue(padapter, true); ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) ++ rtw_indicate_scan_done(padapter, 1); ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) ++ { ++ DBG_871X_LEVEL(_drv_always_, "%s: fw_under_linking\n", __func__); ++ rtw_indicate_disconnect(padapter); ++ } ++ ++ DBG_871X("<== "FUNC_ADPT_FMT" exit....\n", FUNC_ADPT_ARG(padapter)); ++ return _SUCCESS; ++} ++ ++#ifdef CONFIG_WOWLAN ++int rtw_suspend_wow(struct adapter *padapter) ++{ ++ u8 ch, bw, offset; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct net_device *pnetdev = padapter->pnetdev; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct wowlan_ioctl_param poidparam; ++ int ret = _SUCCESS; ++ ++ DBG_871X("==> "FUNC_ADPT_FMT" entry....\n", FUNC_ADPT_ARG(padapter)); ++ ++ ++ DBG_871X("wowlan_mode: %d\n", pwrpriv->wowlan_mode); ++ DBG_871X("wowlan_pno_enable: %d\n", pwrpriv->wowlan_pno_enable); ++ ++ if (pwrpriv->wowlan_mode == true) { ++ if (pnetdev) ++ rtw_netif_stop_queue(pnetdev); ++ /* 1. stop thread */ ++ padapter->bDriverStopped = true; /* for stop thread */ ++ rtw_stop_drv_threads(padapter); ++ padapter->bDriverStopped = false; /* for 32k command */ ++ ++ /* 2. disable interrupt */ ++ if (padapter->intf_stop) { ++ padapter->intf_stop(padapter); ++ } ++ ++ /* 2.1 clean interupt */ ++ if (padapter->HalFunc.clear_interrupt) ++ padapter->HalFunc.clear_interrupt(padapter); ++ ++ /* 2.2 free irq */ ++ /* sdio_free_irq(adapter_to_dvobj(padapter)); */ ++ if (padapter->intf_free_irq) ++ padapter->intf_free_irq(adapter_to_dvobj(padapter)); ++ ++ poidparam.subcode = WOWLAN_ENABLE; ++ padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_WOWLAN, (u8 *)&poidparam); ++ if (rtw_chk_roam_flags(padapter, RTW_ROAM_ON_RESUME)) { ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) ++ && check_fwstate(pmlmepriv, _FW_LINKED)) ++ { ++ DBG_871X("%s %s(" MAC_FMT "), length:%d assoc_ssid.length:%d\n", __func__, ++ pmlmepriv->cur_network.network.Ssid.Ssid, ++ MAC_ARG(pmlmepriv->cur_network.network.MacAddress), ++ pmlmepriv->cur_network.network.Ssid.SsidLength, ++ pmlmepriv->assoc_ssid.SsidLength); ++ ++ rtw_set_to_roam(padapter, 0); ++ } ++ } ++ ++ DBG_871X_LEVEL(_drv_always_, "%s: wowmode suspending\n", __func__); ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) ++ { ++ DBG_871X_LEVEL(_drv_always_, "%s: fw_under_survey\n", __func__); ++ rtw_indicate_scan_done(padapter, 1); ++ clr_fwstate(pmlmepriv, _FW_UNDER_SURVEY); ++ } ++ ++ if (rtw_get_ch_setting_union(padapter, &ch, &bw, &offset) != 0) { ++ DBG_871X(FUNC_ADPT_FMT" back to linked/linking union - ch:%u, bw:%u, offset:%u\n", ++ FUNC_ADPT_ARG(padapter), ch, bw, offset); ++ set_channel_bwmode(padapter, ch, offset, bw); ++ } ++ ++ if (pwrpriv->wowlan_pno_enable) ++ DBG_871X_LEVEL(_drv_always_, "%s: pno: %d\n", __func__, pwrpriv->wowlan_pno_enable); ++ else ++ rtw_set_ps_mode(padapter, PS_MODE_DTIM, 0, 0, "WOWLAN"); ++ ++ } ++ else ++ { ++ DBG_871X_LEVEL(_drv_always_, "%s: ### ERROR ### wowlan_mode =%d\n", __func__, pwrpriv->wowlan_mode); ++ } ++ DBG_871X("<== "FUNC_ADPT_FMT" exit....\n", FUNC_ADPT_ARG(padapter)); ++ return ret; ++} ++#endif /* ifdef CONFIG_WOWLAN */ ++ ++#ifdef CONFIG_AP_WOWLAN ++int rtw_suspend_ap_wow(struct adapter *padapter) ++{ ++ u8 ch, bw, offset; ++ struct net_device *pnetdev = padapter->pnetdev; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct wowlan_ioctl_param poidparam; ++ int ret = _SUCCESS; ++ ++ DBG_871X("==> "FUNC_ADPT_FMT" entry....\n", FUNC_ADPT_ARG(padapter)); ++ ++ pwrpriv->wowlan_ap_mode = true; ++ ++ DBG_871X("wowlan_ap_mode: %d\n", pwrpriv->wowlan_ap_mode); ++ ++ if (pnetdev) ++ rtw_netif_stop_queue(pnetdev); ++ /* 1. stop thread */ ++ padapter->bDriverStopped = true; /* for stop thread */ ++ rtw_stop_drv_threads(padapter); ++ padapter->bDriverStopped = false; /* for 32k command */ ++ ++ /* 2. disable interrupt */ ++ rtw_hal_disable_interrupt(padapter); /* It need wait for leaving 32K. */ ++ ++ /* 2.1 clean interupt */ ++ if (padapter->HalFunc.clear_interrupt) ++ padapter->HalFunc.clear_interrupt(padapter); ++ ++ /* 2.2 free irq */ ++ /* sdio_free_irq(adapter_to_dvobj(padapter)); */ ++ if (padapter->intf_free_irq) ++ padapter->intf_free_irq(adapter_to_dvobj(padapter)); ++ ++ poidparam.subcode = WOWLAN_AP_ENABLE; ++ padapter->HalFunc.SetHwRegHandler(padapter, ++ HW_VAR_AP_WOWLAN, (u8 *)&poidparam); ++ ++ DBG_871X_LEVEL(_drv_always_, "%s: wowmode suspending\n", __func__); ++ ++ if (rtw_get_ch_setting_union(padapter, &ch, &bw, &offset) != 0) { ++ DBG_871X(FUNC_ADPT_FMT" back to linked/linking union - ch:%u, bw:%u, offset:%u\n", ++ FUNC_ADPT_ARG(padapter), ch, bw, offset); ++ set_channel_bwmode(padapter, ch, offset, bw); ++ } ++ ++ rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, 0, "AP-WOWLAN"); ++ ++ DBG_871X("<== "FUNC_ADPT_FMT" exit....\n", FUNC_ADPT_ARG(padapter)); ++ return ret; ++} ++#endif /* ifdef CONFIG_AP_WOWLAN */ ++ ++ ++static int rtw_suspend_normal(struct adapter *padapter) ++{ ++ struct net_device *pnetdev = padapter->pnetdev; ++ int ret = _SUCCESS; ++ ++ DBG_871X("==> "FUNC_ADPT_FMT" entry....\n", FUNC_ADPT_ARG(padapter)); ++ if (pnetdev) { ++ netif_carrier_off(pnetdev); ++ rtw_netif_stop_queue(pnetdev); ++ } ++ ++ rtw_suspend_free_assoc_resource(padapter); ++ ++ if ((rtw_hal_check_ips_status(padapter) == true) ++ || (adapter_to_pwrctl(padapter)->rf_pwrstate == rf_off)) ++ { ++ DBG_871X_LEVEL(_drv_always_, "%s: ### ERROR #### driver in IPS ####ERROR###!!!\n", __func__); ++ ++ } ++ ++ rtw_dev_unload(padapter); ++ ++ /* sdio_deinit(adapter_to_dvobj(padapter)); */ ++ if (padapter->intf_deinit) ++ padapter->intf_deinit(adapter_to_dvobj(padapter)); ++ ++ DBG_871X("<== "FUNC_ADPT_FMT" exit....\n", FUNC_ADPT_ARG(padapter)); ++ return ret; ++} ++ ++int rtw_suspend_common(struct adapter *padapter) ++{ ++ struct dvobj_priv *psdpriv = padapter->dvobj; ++ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(psdpriv); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ int ret = 0; ++ unsigned long start_time = jiffies; ++ ++ DBG_871X_LEVEL(_drv_always_, " suspend start\n"); ++ DBG_871X("==> %s (%s:%d)\n", __func__, current->comm, current->pid); ++ pdbgpriv->dbg_suspend_cnt++; ++ ++ pwrpriv->bInSuspend = true; ++ ++ while (pwrpriv->bips_processing == true) ++ msleep(1); ++ ++ if ((!padapter->bup) || (padapter->bDriverStopped)||(padapter->bSurpriseRemoved)) ++ { ++ DBG_871X("%s bup =%d bDriverStopped =%d bSurpriseRemoved = %d\n", __func__ ++ , padapter->bup, padapter->bDriverStopped, padapter->bSurpriseRemoved); ++ pdbgpriv->dbg_suspend_error_cnt++; ++ goto exit; ++ } ++ rtw_ps_deny(padapter, PS_DENY_SUSPEND); ++ ++ rtw_cancel_all_timer(padapter); ++ ++ LeaveAllPowerSaveModeDirect(padapter); ++ ++ rtw_stop_cmd_thread(padapter); ++ ++ /* wait for the latest FW to remove this condition. */ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { ++ rtw_btcoex_SuspendNotify(padapter, 0); ++ DBG_871X("WIFI_AP_STATE\n"); ++ } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { ++ rtw_btcoex_SuspendNotify(padapter, 1); ++ DBG_871X("STATION\n"); ++ } ++ ++ rtw_ps_deny_cancel(padapter, PS_DENY_SUSPEND); ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { ++ #ifdef CONFIG_WOWLAN ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ pwrpriv->wowlan_mode = true; ++ } else if (pwrpriv->wowlan_pno_enable == true) { ++ pwrpriv->wowlan_mode |= pwrpriv->wowlan_pno_enable; ++ } ++ ++ if (pwrpriv->wowlan_mode == true) ++ rtw_suspend_wow(padapter); ++ else ++ rtw_suspend_normal(padapter); ++ ++ #else /* CONFIG_WOWLAN */ ++ rtw_suspend_normal(padapter); ++ #endif /* CONFIG_WOWLAN */ ++ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { ++ #ifdef CONFIG_AP_WOWLAN ++ rtw_suspend_ap_wow(padapter); ++ #else ++ rtw_suspend_normal(padapter); ++ #endif /* CONFIG_AP_WOWLAN */ ++ } else { ++ rtw_suspend_normal(padapter); ++ } ++ ++ DBG_871X_LEVEL(_drv_always_, "rtw suspend success in %d ms\n", ++ jiffies_to_msecs(jiffies - start_time)); ++ ++exit: ++ DBG_871X("<=== %s return %d.............. in %dms\n", __func__ ++ , ret, jiffies_to_msecs(jiffies - start_time)); ++ ++ return ret; ++} ++ ++#ifdef CONFIG_WOWLAN ++int rtw_resume_process_wow(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); ++ struct net_device *pnetdev = padapter->pnetdev; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct dvobj_priv *psdpriv = padapter->dvobj; ++ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; ++ struct wowlan_ioctl_param poidparam; ++ struct sta_info *psta = NULL; ++ int ret = _SUCCESS; ++ ++ DBG_871X("==> "FUNC_ADPT_FMT" entry....\n", FUNC_ADPT_ARG(padapter)); ++ ++ if (padapter) { ++ pnetdev = padapter->pnetdev; ++ pwrpriv = adapter_to_pwrctl(padapter); ++ } else { ++ pdbgpriv->dbg_resume_error_cnt++; ++ ret = -1; ++ goto exit; ++ } ++ ++ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) { ++ DBG_871X("%s pdapter %p bDriverStopped %d bSurpriseRemoved %d\n", ++ __func__, padapter, padapter->bDriverStopped, ++ padapter->bSurpriseRemoved); ++ goto exit; ++ } ++ ++#ifdef CONFIG_PNO_SUPPORT ++ pwrpriv->pno_in_resume = true; ++#endif ++ ++ if (pwrpriv->wowlan_mode == true) { ++ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, "WOWLAN"); ++ ++ pwrpriv->bFwCurrentInPSMode = false; ++ ++ if (padapter->intf_stop) { ++ padapter->intf_stop(padapter); ++ } ++ ++ if (padapter->HalFunc.clear_interrupt) ++ padapter->HalFunc.clear_interrupt(padapter); ++ ++ /* if (sdio_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS) { */ ++ if ((padapter->intf_alloc_irq) && (padapter->intf_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS)) { ++ ret = -1; ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: sdio_alloc_irq Failed!!\n", __func__)); ++ goto exit; ++ } ++ ++ /* Disable WOW, set H2C command */ ++ poidparam.subcode =WOWLAN_DISABLE; ++ padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_WOWLAN, (u8 *)&poidparam); ++ ++ psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(&padapter->mlmepriv)); ++ if (psta) { ++ set_sta_rate(padapter, psta); ++ } ++ ++ ++ padapter->bDriverStopped = false; ++ DBG_871X("%s: wowmode resuming, DriverStopped:%d\n", __func__, padapter->bDriverStopped); ++ rtw_start_drv_threads(padapter); ++ ++ if (padapter->intf_start) { ++ padapter->intf_start(padapter); ++ } ++ ++ /* start netif queue */ ++ if (pnetdev) { ++ if (!rtw_netif_queue_stopped(pnetdev)) ++ rtw_netif_start_queue(pnetdev); ++ else ++ rtw_netif_wake_queue(pnetdev); ++ } ++ } ++ else { ++ ++ DBG_871X_LEVEL(_drv_always_, "%s: ### ERROR ### wowlan_mode =%d\n", __func__, pwrpriv->wowlan_mode); ++ } ++ ++ if (padapter->pid[1]!= 0) { ++ DBG_871X("pid[1]:%d\n", padapter->pid[1]); ++ rtw_signal_process(padapter->pid[1], SIGUSR2); ++ } ++ ++ if (rtw_chk_roam_flags(padapter, RTW_ROAM_ON_RESUME)) { ++ if (pwrpriv->wowlan_wake_reason == FWDecisionDisconnect || ++ pwrpriv->wowlan_wake_reason == Rx_DisAssoc || ++ pwrpriv->wowlan_wake_reason == Rx_DeAuth) { ++ ++ DBG_871X("%s: disconnect reason: %02x\n", __func__, ++ pwrpriv->wowlan_wake_reason); ++ rtw_indicate_disconnect(padapter); ++ ++ rtw_sta_media_status_rpt(padapter, ++ rtw_get_stainfo(&padapter->stapriv, ++ get_bssid(&padapter->mlmepriv)), 0); ++ ++ rtw_free_assoc_resources(padapter, 1); ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ ++ } else { ++ DBG_871X("%s: do roaming\n", __func__); ++ rtw_roaming(padapter, NULL); ++ } ++ } ++ ++ if (pwrpriv->wowlan_mode == true) { ++ pwrpriv->bips_processing = false; ++ _set_timer(&padapter->mlmepriv.dynamic_chk_timer, 2000); ++ } else { ++ DBG_871X_LEVEL(_drv_always_, "do not reset timer\n"); ++ } ++ ++ pwrpriv->wowlan_mode =false; ++ ++ /* clean driver side wake up reason. */ ++ pwrpriv->wowlan_wake_reason = 0; ++exit: ++ DBG_871X("<== "FUNC_ADPT_FMT" exit....\n", FUNC_ADPT_ARG(padapter)); ++ return ret; ++} ++#endif /* ifdef CONFIG_WOWLAN */ ++ ++#ifdef CONFIG_AP_WOWLAN ++int rtw_resume_process_ap_wow(struct adapter *padapter) ++{ ++ struct net_device *pnetdev = padapter->pnetdev; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct dvobj_priv *psdpriv = padapter->dvobj; ++ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; ++ struct wowlan_ioctl_param poidparam; ++ int ret = _SUCCESS; ++ ++ DBG_871X("==> "FUNC_ADPT_FMT" entry....\n", FUNC_ADPT_ARG(padapter)); ++ ++ if (padapter) { ++ pnetdev = padapter->pnetdev; ++ pwrpriv = adapter_to_pwrctl(padapter); ++ } else { ++ pdbgpriv->dbg_resume_error_cnt++; ++ ret = -1; ++ goto exit; ++ } ++ ++ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, "AP-WOWLAN"); ++ ++ pwrpriv->bFwCurrentInPSMode = false; ++ ++ rtw_hal_disable_interrupt(padapter); ++ ++ if (padapter->HalFunc.clear_interrupt) ++ padapter->HalFunc.clear_interrupt(padapter); ++ ++ /* if (sdio_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS) { */ ++ if ((padapter->intf_alloc_irq) && (padapter->intf_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS)) { ++ ret = -1; ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: sdio_alloc_irq Failed!!\n", __func__)); ++ goto exit; ++ } ++ ++ /* Disable WOW, set H2C command */ ++ poidparam.subcode = WOWLAN_AP_DISABLE; ++ padapter->HalFunc.SetHwRegHandler(padapter, ++ HW_VAR_AP_WOWLAN, (u8 *)&poidparam); ++ pwrpriv->wowlan_ap_mode = false; ++ ++ padapter->bDriverStopped = false; ++ DBG_871X("%s: wowmode resuming, DriverStopped:%d\n", __func__, padapter->bDriverStopped); ++ rtw_start_drv_threads(padapter); ++ ++ if (padapter->intf_start) { ++ padapter->intf_start(padapter); ++ } ++ ++ /* start netif queue */ ++ if (pnetdev) { ++ if (!rtw_netif_queue_stopped(pnetdev)) ++ rtw_netif_start_queue(pnetdev); ++ else ++ rtw_netif_wake_queue(pnetdev); ++ } ++ ++ if (padapter->pid[1]!= 0) { ++ DBG_871X("pid[1]:%d\n", padapter->pid[1]); ++ rtw_signal_process(padapter->pid[1], SIGUSR2); ++ } ++ ++ pwrpriv->bips_processing = false; ++ _set_timer(&padapter->mlmepriv.dynamic_chk_timer, 2000); ++ ++ /* clean driver side wake up reason. */ ++ pwrpriv->wowlan_wake_reason = 0; ++exit: ++ DBG_871X("<== "FUNC_ADPT_FMT" exit....\n", FUNC_ADPT_ARG(padapter)); ++ return ret; ++} ++#endif /* ifdef CONFIG_APWOWLAN */ ++ ++static int rtw_resume_process_normal(struct adapter *padapter) ++{ ++ struct net_device *pnetdev; ++ struct pwrctrl_priv *pwrpriv; ++ struct mlme_priv *pmlmepriv; ++ struct dvobj_priv *psdpriv; ++ struct debug_priv *pdbgpriv; ++ ++ int ret = _SUCCESS; ++ ++ if (!padapter) { ++ ret = -1; ++ goto exit; ++ } ++ ++ pnetdev = padapter->pnetdev; ++ pwrpriv = adapter_to_pwrctl(padapter); ++ pmlmepriv = &padapter->mlmepriv; ++ psdpriv = padapter->dvobj; ++ pdbgpriv = &psdpriv->drv_dbg; ++ ++ DBG_871X("==> "FUNC_ADPT_FMT" entry....\n", FUNC_ADPT_ARG(padapter)); ++ /* interface init */ ++ /* if (sdio_init(adapter_to_dvobj(padapter)) != _SUCCESS) */ ++ if ((padapter->intf_init) && (padapter->intf_init(adapter_to_dvobj(padapter)) != _SUCCESS)) ++ { ++ ret = -1; ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: initialize SDIO Failed!!\n", __func__)); ++ goto exit; ++ } ++ rtw_hal_disable_interrupt(padapter); ++ /* if (sdio_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS) */ ++ if ((padapter->intf_alloc_irq) && (padapter->intf_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS)) ++ { ++ ret = -1; ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: sdio_alloc_irq Failed!!\n", __func__)); ++ goto exit; ++ } ++ ++ rtw_reset_drv_sw(padapter); ++ pwrpriv->bkeepfwalive = false; ++ ++ DBG_871X("bkeepfwalive(%x)\n", pwrpriv->bkeepfwalive); ++ if (pm_netdev_open(pnetdev, true) != 0) { ++ ret = -1; ++ pdbgpriv->dbg_resume_error_cnt++; ++ goto exit; ++ } ++ ++ netif_device_attach(pnetdev); ++ netif_carrier_on(pnetdev); ++ ++ if (padapter->pid[1]!= 0) { ++ DBG_871X("pid[1]:%d\n", padapter->pid[1]); ++ rtw_signal_process(padapter->pid[1], SIGUSR2); ++ } ++ ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { ++ DBG_871X(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_STATION_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv)); ++ ++ if (rtw_chk_roam_flags(padapter, RTW_ROAM_ON_RESUME)) ++ rtw_roaming(padapter, NULL); ++ ++ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ DBG_871X(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_AP_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv)); ++ rtw_ap_restore_network(padapter); ++ } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { ++ DBG_871X(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_ADHOC_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv)); ++ } else { ++ DBG_871X(FUNC_ADPT_FMT" fwstate:0x%08x - ???\n", FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv)); ++ } ++ ++ DBG_871X("<== "FUNC_ADPT_FMT" exit....\n", FUNC_ADPT_ARG(padapter)); ++ ++exit: ++ return ret; ++} ++ ++int rtw_resume_common(struct adapter *padapter) ++{ ++ int ret = 0; ++ unsigned long start_time = jiffies; ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ DBG_871X_LEVEL(_drv_always_, "resume start\n"); ++ DBG_871X("==> %s (%s:%d)\n", __func__, current->comm, current->pid); ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { ++ #ifdef CONFIG_WOWLAN ++ if (pwrpriv->wowlan_mode == true) ++ rtw_resume_process_wow(padapter); ++ else ++ rtw_resume_process_normal(padapter); ++ #else ++ rtw_resume_process_normal(padapter); ++ #endif ++ ++ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { ++ #ifdef CONFIG_AP_WOWLAN ++ rtw_resume_process_ap_wow(padapter); ++ #else ++ rtw_resume_process_normal(padapter); ++ #endif /* CONFIG_AP_WOWLAN */ ++ } else { ++ rtw_resume_process_normal(padapter); ++ } ++ ++ rtw_btcoex_SuspendNotify(padapter, 0); ++ ++ if (pwrpriv) { ++ pwrpriv->bInSuspend = false; ++ #ifdef CONFIG_PNO_SUPPORT ++ pwrpriv->pno_in_resume = false; ++ #endif ++ } ++ DBG_871X_LEVEL(_drv_always_, "%s:%d in %d ms\n", __func__ , ret, ++ jiffies_to_msecs(jiffies - start_time)); ++ ++ return ret; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/os_dep/recv_linux.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/recv_linux.c +--- linux-4.3/3rdparty/rtl8723bs/os_dep/recv_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/recv_linux.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,366 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2011 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _RECV_OSDEP_C_ ++ ++#include ++#include ++#include ++ ++void rtw_os_free_recvframe(union recv_frame *precvframe) ++{ ++ if (precvframe->u.hdr.pkt) ++ { ++ dev_kfree_skb_any(precvframe->u.hdr.pkt);/* free skb by driver */ ++ ++ precvframe->u.hdr.pkt = NULL; ++ } ++} ++ ++/* alloc os related resource in union recv_frame */ ++int rtw_os_recv_resource_alloc(struct adapter *padapter, union recv_frame *precvframe) ++{ ++ int res = _SUCCESS; ++ ++ precvframe->u.hdr.pkt_newalloc = precvframe->u.hdr.pkt = NULL; ++ ++ return res; ++} ++ ++/* free os related resource in union recv_frame */ ++void rtw_os_recv_resource_free(struct recv_priv *precvpriv) ++{ ++ sint i; ++ union recv_frame *precvframe; ++ precvframe = (union recv_frame*) precvpriv->precv_frame_buf; ++ ++ for (i = 0; i < NR_RECVFRAME; i++) ++ { ++ if (precvframe->u.hdr.pkt) ++ { ++ dev_kfree_skb_any(precvframe->u.hdr.pkt);/* free skb by driver */ ++ precvframe->u.hdr.pkt = NULL; ++ } ++ precvframe++; ++ } ++} ++ ++/* free os related resource in struct recv_buf */ ++int rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf) ++{ ++ int ret = _SUCCESS; ++ ++ if (precvbuf->pskb) ++ { ++ dev_kfree_skb_any(precvbuf->pskb); ++ } ++ return ret; ++ ++} ++ ++_pkt *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata) ++{ ++ u16 eth_type; ++ u8 *data_ptr; ++ _pkt *sub_skb; ++ struct rx_pkt_attrib *pattrib; ++ ++ pattrib = &prframe->u.hdr.attrib; ++ ++ sub_skb = rtw_skb_alloc(nSubframe_Length + 12); ++ if (sub_skb) ++ { ++ skb_reserve(sub_skb, 12); ++ data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length); ++ memcpy(data_ptr, (pdata + ETH_HLEN), nSubframe_Length); ++ } ++ else ++ { ++ sub_skb = rtw_skb_clone(prframe->u.hdr.pkt); ++ if (sub_skb) ++ { ++ sub_skb->data = pdata + ETH_HLEN; ++ sub_skb->len = nSubframe_Length; ++ skb_set_tail_pointer(sub_skb, nSubframe_Length); ++ } ++ else ++ { ++ DBG_871X("%s(): rtw_skb_clone() Fail!!!\n", __func__); ++ return NULL; ++ } ++ } ++ ++ eth_type = RTW_GET_BE16(&sub_skb->data[6]); ++ ++ if (sub_skb->len >= 8 && ++ ((!memcmp(sub_skb->data, rtw_rfc1042_header, SNAP_SIZE) && ++ eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || ++ !memcmp(sub_skb->data, rtw_bridge_tunnel_header, SNAP_SIZE))) { ++ /* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */ ++ skb_pull(sub_skb, SNAP_SIZE); ++ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN); ++ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN); ++ } else { ++ __be16 len; ++ /* Leave Ethernet header part of hdr and full payload */ ++ len = htons(sub_skb->len); ++ memcpy(skb_push(sub_skb, 2), &len, 2); ++ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN); ++ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN); ++ } ++ ++ return sub_skb; ++} ++ ++void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt_attrib *pattrib) ++{ ++ struct mlme_priv*pmlmepriv = &padapter->mlmepriv; ++ int ret; ++ ++ /* Indicat the packets to upper layer */ ++ if (pkt) { ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ++ { ++ _pkt *pskb2 = NULL; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ int bmcast = IS_MCAST(pattrib->dst); ++ ++ /* DBG_871X("bmcast =%d\n", bmcast); */ ++ ++ if (memcmp(pattrib->dst, myid(&padapter->eeprompriv), ETH_ALEN)) ++ { ++ /* DBG_871X("not ap psta =%p, addr =%pM\n", psta, pattrib->dst); */ ++ ++ if (bmcast) ++ { ++ psta = rtw_get_bcmc_stainfo(padapter); ++ pskb2 = rtw_skb_clone(pkt); ++ } else { ++ psta = rtw_get_stainfo(pstapriv, pattrib->dst); ++ } ++ ++ if (psta) ++ { ++ struct net_device *pnetdev = (struct net_device*)padapter->pnetdev; ++ ++ /* DBG_871X("directly forwarding to the rtw_xmit_entry\n"); */ ++ ++ /* skb->ip_summed = CHECKSUM_NONE; */ ++ pkt->dev = pnetdev; ++ skb_set_queue_mapping(pkt, rtw_recv_select_queue(pkt)); ++ ++ _rtw_xmit_entry(pkt, pnetdev); ++ ++ if (bmcast && (pskb2 != NULL)) { ++ pkt = pskb2; ++ DBG_COUNTER(padapter->rx_logs.os_indicate_ap_mcast); ++ } else { ++ DBG_COUNTER(padapter->rx_logs.os_indicate_ap_forward); ++ return; ++ } ++ } ++ } ++ else/* to APself */ ++ { ++ /* DBG_871X("to APSelf\n"); */ ++ DBG_COUNTER(padapter->rx_logs.os_indicate_ap_self); ++ } ++ } ++ ++ pkt->protocol = eth_type_trans(pkt, padapter->pnetdev); ++ pkt->dev = padapter->pnetdev; ++ ++#ifdef CONFIG_TCP_CSUM_OFFLOAD_RX ++ if ((pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1)) { ++ pkt->ip_summed = CHECKSUM_UNNECESSARY; ++ } else { ++ pkt->ip_summed = CHECKSUM_NONE; ++ } ++#else /* !CONFIG_TCP_CSUM_OFFLOAD_RX */ ++ pkt->ip_summed = CHECKSUM_NONE; ++#endif /* CONFIG_TCP_CSUM_OFFLOAD_RX */ ++ ++ ret = rtw_netif_rx(padapter->pnetdev, pkt); ++ if (ret == NET_RX_SUCCESS) ++ DBG_COUNTER(padapter->rx_logs.os_netif_ok); ++ else ++ DBG_COUNTER(padapter->rx_logs.os_netif_err); ++ } ++} ++ ++void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup) ++{ ++ enum nl80211_key_type key_type = 0; ++ union iwreq_data wrqu; ++ struct iw_michaelmicfailure ev; ++ struct mlme_priv* pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ unsigned long cur_time = 0; ++ ++ if (psecuritypriv->last_mic_err_time == 0) ++ { ++ psecuritypriv->last_mic_err_time = jiffies; ++ } ++ else ++ { ++ cur_time = jiffies; ++ ++ if (cur_time - psecuritypriv->last_mic_err_time < 60*HZ) ++ { ++ psecuritypriv->btkip_countermeasure = true; ++ psecuritypriv->last_mic_err_time = 0; ++ psecuritypriv->btkip_countermeasure_time = cur_time; ++ } ++ else ++ { ++ psecuritypriv->last_mic_err_time = jiffies; ++ } ++ } ++ ++ if (bgroup) ++ { ++ key_type |= NL80211_KEYTYPE_GROUP; ++ } ++ else ++ { ++ key_type |= NL80211_KEYTYPE_PAIRWISE; ++ } ++ ++ cfg80211_michael_mic_failure(padapter->pnetdev, (u8 *)&pmlmepriv->assoc_bssid[ 0 ], key_type, -1, ++ NULL, GFP_ATOMIC); ++ ++ memset(&ev, 0x00, sizeof(ev)); ++ if (bgroup) ++ { ++ ev.flags |= IW_MICFAILURE_GROUP; ++ } ++ else ++ { ++ ev.flags |= IW_MICFAILURE_PAIRWISE; ++ } ++ ++ ev.src_addr.sa_family = ARPHRD_ETHER; ++ memcpy(ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); ++ ++ memset(&wrqu, 0x00, sizeof(wrqu)); ++ wrqu.data.length = sizeof(ev); ++} ++ ++#ifdef CONFIG_AUTO_AP_MODE ++static void rtw_os_ksocket_send(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ _pkt *skb = precv_frame->u.hdr.pkt; ++ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; ++ struct sta_info *psta = precv_frame->u.hdr.psta; ++ ++ DBG_871X("eth rx: got eth_type = 0x%x\n", pattrib->eth_type); ++ ++ if (psta && psta->isrc && psta->pid>0) ++ { ++ u16 rx_pid; ++ ++ rx_pid = *(u16*)(skb->data+ETH_HLEN); ++ ++ DBG_871X("eth rx(pid = 0x%x): sta("MAC_FMT") pid = 0x%x\n", ++ rx_pid, MAC_ARG(psta->hwaddr), psta->pid); ++ ++ if (rx_pid == psta->pid) ++ { ++ int i; ++ u16 len = *(u16*)(skb->data+ETH_HLEN+2); ++ /* u16 ctrl_type = *(u16*)(skb->data+ETH_HLEN+4); */ ++ ++ /* DBG_871X("eth, RC: len = 0x%x, ctrl_type = 0x%x\n", len, ctrl_type); */ ++ DBG_871X("eth, RC: len = 0x%x\n", len); ++ ++ for (i = 0;idata+ETH_HLEN+4+i)); ++ /* DBG_871X("0x%x\n", *(skb->data+ETH_HLEN+6+i)); */ ++ ++ DBG_871X("eth, RC-end\n"); ++ } ++ ++ } ++ ++} ++#endif /* CONFIG_AUTO_AP_MODE */ ++ ++int rtw_recv_indicatepkt(struct adapter *padapter, union recv_frame *precv_frame) ++{ ++ struct recv_priv *precvpriv; ++ struct __queue *pfree_recv_queue; ++ _pkt *skb; ++ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; ++ ++ DBG_COUNTER(padapter->rx_logs.os_indicate); ++ ++ precvpriv = &(padapter->recvpriv); ++ pfree_recv_queue = &(precvpriv->free_recv_queue); ++ ++ skb = precv_frame->u.hdr.pkt; ++ if (skb == NULL) ++ { ++ RT_TRACE(_module_recv_osdep_c_, _drv_err_, ("rtw_recv_indicatepkt():skb == NULL something wrong!!!!\n")); ++ goto _recv_indicatepkt_drop; ++ } ++ ++ RT_TRACE(_module_recv_osdep_c_, _drv_info_, ("rtw_recv_indicatepkt():skb != NULL !!!\n")); ++ RT_TRACE(_module_recv_osdep_c_, _drv_info_, ("rtw_recv_indicatepkt():precv_frame->u.hdr.rx_head =%p precv_frame->hdr.rx_data =%p\n", precv_frame->u.hdr.rx_head, precv_frame->u.hdr.rx_data)); ++ RT_TRACE(_module_recv_osdep_c_, _drv_info_, ("precv_frame->hdr.rx_tail =%p precv_frame->u.hdr.rx_end =%p precv_frame->hdr.len =%d\n", precv_frame->u.hdr.rx_tail, precv_frame->u.hdr.rx_end, precv_frame->u.hdr.len)); ++ ++ skb->data = precv_frame->u.hdr.rx_data; ++ ++ skb_set_tail_pointer(skb, precv_frame->u.hdr.len); ++ ++ skb->len = precv_frame->u.hdr.len; ++ ++ RT_TRACE(_module_recv_osdep_c_, _drv_info_, ("\n skb->head =%p skb->data =%p skb->tail =%p skb->end =%p skb->len =%d\n", skb->head, skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), skb->len)); ++ ++#ifdef CONFIG_AUTO_AP_MODE ++ if (0x8899 == pattrib->eth_type) ++ { ++ rtw_os_ksocket_send(padapter, precv_frame); ++ ++ /* goto _recv_indicatepkt_drop; */ ++ } ++#endif /* CONFIG_AUTO_AP_MODE */ ++ ++ rtw_os_recv_indicate_pkt(padapter, skb, pattrib); ++ ++ precv_frame->u.hdr.pkt = NULL; /* pointers to NULL before rtw_free_recvframe() */ ++ ++ rtw_free_recvframe(precv_frame, pfree_recv_queue); ++ ++ RT_TRACE(_module_recv_osdep_c_, _drv_info_, ("\n rtw_recv_indicatepkt :after rtw_os_recv_indicate_pkt!!!!\n")); ++ ++ return _SUCCESS; ++ ++_recv_indicatepkt_drop: ++ ++ /* enqueue back to free_recv_queue */ ++ if (precv_frame) ++ rtw_free_recvframe(precv_frame, pfree_recv_queue); ++ ++ DBG_COUNTER(padapter->rx_logs.os_indicate_err); ++ return _FAIL; ++} ++ ++void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl) ++{ ++ struct adapter *padapter = preorder_ctrl->padapter; ++ ++ _init_timer(&(preorder_ctrl->reordering_ctrl_timer), padapter->pnetdev, rtw_reordering_ctrl_timeout_handler, preorder_ctrl); ++ ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/os_dep/rtw_proc.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/rtw_proc.c +--- linux-4.3/3rdparty/rtl8723bs/os_dep/rtw_proc.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/rtw_proc.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,786 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2013 Realtek 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. ++ * ++ ******************************************************************************/ ++ ++#include ++#include ++#include "rtw_proc.h" ++ ++#ifdef CONFIG_PROC_DEBUG ++ ++static struct proc_dir_entry *rtw_proc = NULL; ++ ++#define RTW_PROC_NAME "rtl8723bs" ++ ++#define get_proc_net init_net.proc_net ++ ++inline struct proc_dir_entry *rtw_proc_create_dir(const char *name, struct proc_dir_entry *parent, void *data) ++{ ++ struct proc_dir_entry *entry; ++ ++ entry = proc_mkdir_data(name, S_IRUGO|S_IXUGO, parent, data); ++ ++ return entry; ++} ++ ++inline struct proc_dir_entry *rtw_proc_create_entry(const char *name, struct proc_dir_entry *parent, ++ const struct file_operations *fops, void *data) ++{ ++ struct proc_dir_entry *entry; ++ ++ entry = proc_create_data(name, S_IFREG|S_IRUGO, parent, fops, data); ++ ++ return entry; ++} ++ ++static int proc_get_dummy(struct seq_file *m, void *v) ++{ ++ return 0; ++} ++ ++static int proc_get_drv_version(struct seq_file *m, void *v) ++{ ++ dump_drv_version(m); ++ return 0; ++} ++ ++static int proc_get_log_level(struct seq_file *m, void *v) ++{ ++ dump_log_level(m); ++ return 0; ++} ++ ++static ssize_t proc_set_log_level(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ char tmp[32]; ++ int log_level; ++ ++ if (count < 1) ++ return -EINVAL; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ sscanf(tmp, "%d ", &log_level); ++ if (log_level >= _drv_always_ && log_level <= _drv_debug_) ++ { ++ GlobalDebugLevel = log_level; ++ printk("%d\n", GlobalDebugLevel); ++ } ++ } else { ++ return -EFAULT; ++ } ++ ++ return count; ++} ++ ++/* ++* rtw_drv_proc: ++* init/deinit when register/unregister driver ++*/ ++static const struct rtw_proc_hdl drv_proc_hdls [] = { ++ {"ver_info", proc_get_drv_version, NULL}, ++ {"log_level", proc_get_log_level, proc_set_log_level}, ++}; ++ ++static const int drv_proc_hdls_num = sizeof(drv_proc_hdls) / sizeof(struct rtw_proc_hdl); ++ ++static int rtw_drv_proc_open(struct inode *inode, struct file *file) ++{ ++ /* struct net_device *dev = proc_get_parent_data(inode); */ ++ ssize_t index = (ssize_t)PDE_DATA(inode); ++ const struct rtw_proc_hdl *hdl = drv_proc_hdls+index; ++ return single_open(file, hdl->show, NULL); ++} ++ ++static ssize_t rtw_drv_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) ++{ ++ ssize_t index = (ssize_t)PDE_DATA(file_inode(file)); ++ const struct rtw_proc_hdl *hdl = drv_proc_hdls+index; ++ ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *, void *) = hdl->write; ++ ++ if (write) ++ return write(file, buffer, count, pos, NULL); ++ ++ return -EROFS; ++} ++ ++static const struct file_operations rtw_drv_proc_fops = { ++ .owner = THIS_MODULE, ++ .open = rtw_drv_proc_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .write = rtw_drv_proc_write, ++}; ++ ++int rtw_drv_proc_init(void) ++{ ++ int ret = _FAIL; ++ ssize_t i; ++ struct proc_dir_entry *entry = NULL; ++ ++ if (rtw_proc != NULL) { ++ rtw_warn_on(1); ++ goto exit; ++ } ++ ++ rtw_proc = rtw_proc_create_dir(RTW_PROC_NAME, get_proc_net, NULL); ++ ++ if (rtw_proc == NULL) { ++ rtw_warn_on(1); ++ goto exit; ++ } ++ ++ for (i = 0;iprivate; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ sd_f0_reg_dump(m, adapter); ++ ++ return 0; ++} ++ ++static int proc_get_mac_reg_dump(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ mac_reg_dump(m, adapter); ++ ++ return 0; ++} ++ ++static int proc_get_bb_reg_dump(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ bb_reg_dump(m, adapter); ++ ++ return 0; ++} ++ ++static int proc_get_rf_reg_dump(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ rf_reg_dump(m, adapter); ++ ++ return 0; ++} ++static int proc_get_linked_info_dump(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ if (padapter) ++ DBG_871X_SEL_NL(m, "linked_info_dump :%s\n", (padapter->bLinkInfoDump)?"enable":"disable"); ++ ++ return 0; ++} ++ ++static ssize_t proc_set_linked_info_dump(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ char tmp[2]; ++ int mode = 0; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ if (padapter) ++ { ++ /* padapter->bLinkInfoDump = mode; */ ++ /* DBG_871X("linked_info_dump =%s\n", (padapter->bLinkInfoDump)?"enable":"disable"); */ ++ linked_info_dump(padapter, mode); ++ } ++ ++ } ++ ++ return count; ++ ++} ++ ++static int proc_get_rx_info(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct dvobj_priv *psdpriv = padapter->dvobj; ++ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; ++ ++ /* Counts of packets whose seq_num is less than preorder_ctrl->indicate_seq, Ex delay, retransmission, redundant packets and so on */ ++ DBG_871X_SEL_NL(m,"Counts of Packets Whose Seq_Num Less Than Reorder Control Seq_Num: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_ampdu_drop_count); ++ /* How many times the Rx Reorder Timer is triggered. */ ++ DBG_871X_SEL_NL(m,"Rx Reorder Time-out Trigger Counts: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_ampdu_forced_indicate_count); ++ /* Total counts of packets loss */ ++ DBG_871X_SEL_NL(m,"Rx Packet Loss Counts: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_ampdu_loss_count); ++ DBG_871X_SEL_NL(m,"Duplicate Management Frame Drop Count: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_dup_mgt_frame_drop_count); ++ DBG_871X_SEL_NL(m,"AMPDU BA window shift Count: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_ampdu_window_shift_cnt); ++ return 0; ++} ++ ++ ++static ssize_t proc_reset_rx_info(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct dvobj_priv *psdpriv = padapter->dvobj; ++ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; ++ char cmd[32]; ++ if (buffer && !copy_from_user(cmd, buffer, sizeof(cmd))) { ++ if ('0' == cmd[0]) { ++ pdbgpriv->dbg_rx_ampdu_drop_count = 0; ++ pdbgpriv->dbg_rx_ampdu_forced_indicate_count = 0; ++ pdbgpriv->dbg_rx_ampdu_loss_count = 0; ++ pdbgpriv->dbg_rx_dup_mgt_frame_drop_count = 0; ++ pdbgpriv->dbg_rx_ampdu_window_shift_cnt = 0; ++ } ++ } ++ ++ return count; ++} ++ ++static int proc_get_cam(struct seq_file *m, void *v) ++{ ++ return 0; ++} ++ ++static ssize_t proc_set_cam(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *adapter; ++ ++ char tmp[32]; ++ char cmd[4]; ++ u8 id; ++ ++ adapter = (struct adapter *)rtw_netdev_priv(dev); ++ if (!adapter) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ /* c : clear specific cam entry */ ++ /* wfc : write specific cam entry from cam cache */ ++ ++ int num = sscanf(tmp, "%4s %hhu", cmd, &id); ++ ++ if (num < 2) ++ return count; ++ ++ if (strcmp("c", cmd) == 0) { ++ _clear_cam_entry(adapter, id); ++ adapter->securitypriv.hw_decrypted = false; /* temporarily set this for TX path to use SW enc */ ++ } else if (strcmp("wfc", cmd) == 0) { ++ write_cam_from_cache(adapter, id); ++ } ++ } ++ ++ return count; ++} ++ ++static int proc_get_cam_cache(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); ++ u8 i; ++ ++ DBG_871X_SEL_NL(m, "cam bitmap:0x%016llx\n", dvobj->cam_ctl.bitmap); ++ ++ DBG_871X_SEL_NL(m, "%-2s %-6s %-17s %-32s %-3s %-7s" ++ /* %-2s %-2s %-4s %-5s" */ ++ "\n" ++ , "id", "ctrl", "addr", "key", "kid", "type" ++ /* "MK", "GK", "MFB", "valid" */ ++ ); ++ ++ for (i = 0;i<32;i++) { ++ if (dvobj->cam_cache[i].ctrl != 0) ++ DBG_871X_SEL_NL(m, "%2u 0x%04x "MAC_FMT" "KEY_FMT" %3u %-7s" ++ /* %2u %2u 0x%02x %5u" */ ++ "\n", i ++ , dvobj->cam_cache[i].ctrl ++ , MAC_ARG(dvobj->cam_cache[i].mac) ++ , KEY_ARG(dvobj->cam_cache[i].key) ++ , (dvobj->cam_cache[i].ctrl)&0x03 ++ , security_type_str(((dvobj->cam_cache[i].ctrl)>>2)&0x07) ++ /* ((dvobj->cam_cache[i].ctrl)>>5)&0x01 */ ++ /* ((dvobj->cam_cache[i].ctrl)>>6)&0x01 */ ++ /* ((dvobj->cam_cache[i].ctrl)>>8)&0x7f */ ++ /* ((dvobj->cam_cache[i].ctrl)>>15)&0x01 */ ++ ); ++ } ++ ++ return 0; ++} ++ ++/* ++* rtw_adapter_proc: ++* init/deinit when register/unregister net_device ++*/ ++static const struct rtw_proc_hdl adapter_proc_hdls [] = { ++ {"write_reg", proc_get_dummy, proc_set_write_reg}, ++ {"read_reg", proc_get_read_reg, proc_set_read_reg}, ++ {"fwstate", proc_get_fwstate, NULL}, ++ {"sec_info", proc_get_sec_info, NULL}, ++ {"mlmext_state", proc_get_mlmext_state, NULL}, ++ {"qos_option", proc_get_qos_option, NULL}, ++ {"ht_option", proc_get_ht_option, NULL}, ++ {"rf_info", proc_get_rf_info, NULL}, ++ {"survey_info", proc_get_survey_info, NULL}, ++ {"ap_info", proc_get_ap_info, NULL}, ++ {"adapter_state", proc_get_adapter_state, NULL}, ++ {"trx_info", proc_get_trx_info, NULL}, ++ {"rate_ctl", proc_get_rate_ctl, proc_set_rate_ctl}, ++ {"cam", proc_get_cam, proc_set_cam}, ++ {"cam_cache", proc_get_cam_cache, NULL}, ++ {"suspend_info", proc_get_suspend_resume_info, NULL}, ++ {"rx_info", proc_get_rx_info, proc_reset_rx_info}, ++ ++ {"roam_flags", proc_get_roam_flags, proc_set_roam_flags}, ++ {"roam_param", proc_get_roam_param, proc_set_roam_param}, ++ {"roam_tgt_addr", proc_get_dummy, proc_set_roam_tgt_addr}, ++ ++ {"sd_f0_reg_dump", proc_get_sd_f0_reg_dump, NULL}, ++ ++ {"fwdl_test_case", proc_get_dummy, proc_set_fwdl_test_case}, ++ {"wait_hiq_empty", proc_get_dummy, proc_set_wait_hiq_empty}, ++ ++ {"mac_reg_dump", proc_get_mac_reg_dump, NULL}, ++ {"bb_reg_dump", proc_get_bb_reg_dump, NULL}, ++ {"rf_reg_dump", proc_get_rf_reg_dump, NULL}, ++ ++ {"all_sta_info", proc_get_all_sta_info, NULL}, ++ ++ {"rx_signal", proc_get_rx_signal, proc_set_rx_signal}, ++ {"hw_info", proc_get_hw_status, NULL}, ++ ++ {"ht_enable", proc_get_ht_enable, proc_set_ht_enable}, ++ {"bw_mode", proc_get_bw_mode, proc_set_bw_mode}, ++ {"ampdu_enable", proc_get_ampdu_enable, proc_set_ampdu_enable}, ++ {"rx_stbc", proc_get_rx_stbc, proc_set_rx_stbc}, ++ {"rx_ampdu", proc_get_rx_ampdu, proc_set_rx_ampdu}, ++ ++ {"en_fwps", proc_get_en_fwps, proc_set_en_fwps}, ++ ++ /* path_rssi", proc_get_two_path_rssi, NULL}, */ ++ {"rssi_disp", proc_get_rssi_disp, proc_set_rssi_disp}, ++ ++ {"btcoex_dbg", proc_get_btcoex_dbg, proc_set_btcoex_dbg}, ++ {"btcoex", proc_get_btcoex_info, NULL}, ++ ++ {"linked_info_dump", proc_get_linked_info_dump, proc_set_linked_info_dump}, ++#ifdef CONFIG_DBG_COUNTER ++ {"rx_logs", proc_get_rx_logs, NULL}, ++ {"tx_logs", proc_get_tx_logs, NULL}, ++ {"int_logs", proc_get_int_logs, NULL}, ++#endif ++}; ++ ++static const int adapter_proc_hdls_num = sizeof(adapter_proc_hdls) / sizeof(struct rtw_proc_hdl); ++ ++static int rtw_adapter_proc_open(struct inode *inode, struct file *file) ++{ ++ ssize_t index = (ssize_t)PDE_DATA(inode); ++ const struct rtw_proc_hdl *hdl = adapter_proc_hdls+index; ++ ++ return single_open(file, hdl->show, proc_get_parent_data(inode)); ++} ++ ++static ssize_t rtw_adapter_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) ++{ ++ ssize_t index = (ssize_t)PDE_DATA(file_inode(file)); ++ const struct rtw_proc_hdl *hdl = adapter_proc_hdls+index; ++ ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *, void *) = hdl->write; ++ ++ if (write) ++ return write(file, buffer, count, pos, ((struct seq_file *)file->private_data)->private); ++ ++ return -EROFS; ++} ++ ++static const struct file_operations rtw_adapter_proc_fops = { ++ .owner = THIS_MODULE, ++ .open = rtw_adapter_proc_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .write = rtw_adapter_proc_write, ++}; ++ ++int proc_get_odm_dbg_comp(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ rtw_odm_dbg_comp_msg(m, adapter); ++ ++ return 0; ++} ++ ++ssize_t proc_set_odm_dbg_comp(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ char tmp[32]; ++ ++ u64 dbg_comp; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%llx", &dbg_comp); ++ ++ if (num != 1) ++ return count; ++ ++ rtw_odm_dbg_comp_set(adapter, dbg_comp); ++ } ++ ++ return count; ++} ++ ++int proc_get_odm_dbg_level(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ rtw_odm_dbg_level_msg(m, adapter); ++ ++ return 0; ++} ++ ++ssize_t proc_set_odm_dbg_level(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ char tmp[32]; ++ ++ u32 dbg_level; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%u", &dbg_level); ++ ++ if (num != 1) ++ return count; ++ ++ rtw_odm_dbg_level_set(adapter, dbg_level); ++ } ++ ++ return count; ++} ++ ++static int proc_get_odm_ability(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ rtw_odm_ability_msg(m, adapter); ++ ++ return 0; ++} ++ ++static ssize_t proc_set_odm_ability(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev); ++ char tmp[32]; ++ ++ u32 ability; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%x", &ability); ++ ++ if (num != 1) ++ return count; ++ ++ rtw_odm_ability_set(adapter, ability); ++ } ++ ++ return count; ++} ++ ++int proc_get_odm_adaptivity(struct seq_file *m, void *v) ++{ ++ struct net_device *dev = m->private; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ rtw_odm_adaptivity_parm_msg(m, padapter); ++ ++ return 0; ++} ++ ++ssize_t proc_set_odm_adaptivity(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ char tmp[32]; ++ u32 TH_L2H_ini; ++ s8 TH_EDCCA_HL_diff; ++ u32 IGI_Base; ++ int ForceEDCCA; ++ u8 AdapEn_RSSI; ++ u8 IGI_LowerBound; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ ++ int num = sscanf(tmp, "%x %hhd %x %d %hhu %hhu", ++ &TH_L2H_ini, &TH_EDCCA_HL_diff, &IGI_Base, &ForceEDCCA, &AdapEn_RSSI, &IGI_LowerBound); ++ ++ if (num != 6) ++ return count; ++ ++ rtw_odm_adaptivity_parm_set(padapter, (s8)TH_L2H_ini, TH_EDCCA_HL_diff, (s8)IGI_Base, (bool)ForceEDCCA, AdapEn_RSSI, IGI_LowerBound); ++ } ++ ++ return count; ++} ++ ++/* ++* rtw_odm_proc: ++* init/deinit when register/unregister net_device, along with rtw_adapter_proc ++*/ ++static const struct rtw_proc_hdl odm_proc_hdls [] = { ++ {"dbg_comp", proc_get_odm_dbg_comp, proc_set_odm_dbg_comp}, ++ {"dbg_level", proc_get_odm_dbg_level, proc_set_odm_dbg_level}, ++ {"ability", proc_get_odm_ability, proc_set_odm_ability}, ++ {"adaptivity", proc_get_odm_adaptivity, proc_set_odm_adaptivity}, ++}; ++ ++static const int odm_proc_hdls_num = sizeof(odm_proc_hdls) / sizeof(struct rtw_proc_hdl); ++ ++static int rtw_odm_proc_open(struct inode *inode, struct file *file) ++{ ++ ssize_t index = (ssize_t)PDE_DATA(inode); ++ const struct rtw_proc_hdl *hdl = odm_proc_hdls+index; ++ ++ return single_open(file, hdl->show, proc_get_parent_data(inode)); ++} ++ ++static ssize_t rtw_odm_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) ++{ ++ ssize_t index = (ssize_t)PDE_DATA(file_inode(file)); ++ const struct rtw_proc_hdl *hdl = odm_proc_hdls+index; ++ ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *, void *) = hdl->write; ++ ++ if (write) ++ return write(file, buffer, count, pos, ((struct seq_file *)file->private_data)->private); ++ ++ return -EROFS; ++} ++ ++static const struct file_operations rtw_odm_proc_fops = { ++ .owner = THIS_MODULE, ++ .open = rtw_odm_proc_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .write = rtw_odm_proc_write, ++}; ++ ++static struct proc_dir_entry *rtw_odm_proc_init(struct net_device *dev) ++{ ++ struct proc_dir_entry *dir_odm = NULL; ++ struct proc_dir_entry *entry = NULL; ++ struct adapter *adapter = rtw_netdev_priv(dev); ++ ssize_t i; ++ ++ if (adapter->dir_dev == NULL) { ++ rtw_warn_on(1); ++ goto exit; ++ } ++ ++ if (adapter->dir_odm != NULL) { ++ rtw_warn_on(1); ++ goto exit; ++ } ++ ++ dir_odm = rtw_proc_create_dir("odm", adapter->dir_dev, dev); ++ if (dir_odm == NULL) { ++ rtw_warn_on(1); ++ goto exit; ++ } ++ ++ adapter->dir_odm = dir_odm; ++ ++ for (i = 0;idir_odm; ++ ++ if (dir_odm == NULL) { ++ rtw_warn_on(1); ++ return; ++ } ++ ++ for (i = 0;idir_dev); ++ ++ adapter->dir_odm = NULL; ++} ++ ++struct proc_dir_entry *rtw_adapter_proc_init(struct net_device *dev) ++{ ++ struct proc_dir_entry *drv_proc = rtw_proc; ++ struct proc_dir_entry *dir_dev = NULL; ++ struct proc_dir_entry *entry = NULL; ++ struct adapter *adapter = rtw_netdev_priv(dev); ++ ssize_t i; ++ ++ if (drv_proc == NULL) { ++ rtw_warn_on(1); ++ goto exit; ++ } ++ ++ if (adapter->dir_dev != NULL) { ++ rtw_warn_on(1); ++ goto exit; ++ } ++ ++ dir_dev = rtw_proc_create_dir(dev->name, drv_proc, dev); ++ if (dir_dev == NULL) { ++ rtw_warn_on(1); ++ goto exit; ++ } ++ ++ adapter->dir_dev = dir_dev; ++ ++ for (i = 0;idir_dev; ++ ++ if (dir_dev == NULL) { ++ rtw_warn_on(1); ++ return; ++ } ++ ++ for (i = 0;iname, drv_proc); ++ ++ adapter->dir_dev = NULL; ++} ++ ++void rtw_adapter_proc_replace(struct net_device *dev) ++{ ++ struct proc_dir_entry *drv_proc = rtw_proc; ++ struct proc_dir_entry *dir_dev = NULL; ++ struct adapter *adapter = rtw_netdev_priv(dev); ++ int i; ++ ++ dir_dev = adapter->dir_dev; ++ ++ if (dir_dev == NULL) { ++ rtw_warn_on(1); ++ return; ++ } ++ ++ for (i = 0;iold_ifname, drv_proc); ++ ++ adapter->dir_dev = NULL; ++ ++ rtw_adapter_proc_init(dev); ++ ++} ++ ++#endif /* CONFIG_PROC_DEBUG */ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/os_dep/rtw_proc.h linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/rtw_proc.h +--- linux-4.3/3rdparty/rtl8723bs/os_dep/rtw_proc.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/rtw_proc.h 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,45 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2013 Realtek 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. ++ * ++ ******************************************************************************/ ++#ifndef __RTW_PROC_H__ ++#define __RTW_PROC_H__ ++ ++#include ++#include ++ ++struct rtw_proc_hdl { ++ char *name; ++ int (*show)(struct seq_file *, void *); ++ ssize_t (*write)(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); ++}; ++ ++#ifdef CONFIG_PROC_DEBUG ++ ++int rtw_drv_proc_init(void); ++void rtw_drv_proc_deinit(void); ++struct proc_dir_entry *rtw_adapter_proc_init(struct net_device *dev); ++void rtw_adapter_proc_deinit(struct net_device *dev); ++void rtw_adapter_proc_replace(struct net_device *dev); ++ ++#else //!CONFIG_PROC_DEBUG ++ ++int rtw_drv_proc_init(void) {return 0;} ++void rtw_drv_proc_deinit(void) {} ++struct proc_dir_entry *rtw_adapter_proc_init(struct net_device *dev){return NULL;} ++void rtw_adapter_proc_deinit(struct net_device *dev){} ++void rtw_adapter_proc_replace(struct net_device *dev){} ++ ++#endif //!CONFIG_PROC_DEBUG ++ ++#endif //__RTW_PROC_H__ +diff -Nurp linux-4.3/3rdparty/rtl8723bs/os_dep/sdio_intf.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/sdio_intf.c +--- linux-4.3/3rdparty/rtl8723bs/os_dep/sdio_intf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/sdio_intf.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,725 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _HCI_INTF_C_ ++ ++#include ++#include ++#include ++ ++#ifndef dev_to_sdio_func ++#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev) ++#endif ++ ++static const struct sdio_device_id sdio_ids[] = ++{ ++// { SDIO_DEVICE(0x024c, 0xB723), }, ++// { SDIO_DEVICE(0x024c, 0x0523), }, ++// { SDIO_DEVICE(0x024c, 0x0623), }, ++ { SDIO_DEVICE_CLASS(SDIO_CLASS_WLAN) }, ++ { /* end: all zeroes */ }, ++}; ++ ++MODULE_DEVICE_TABLE(sdio, sdio_ids); ++ ++static int rtw_drv_init(struct sdio_func *func, const struct sdio_device_id *id); ++static void rtw_dev_remove(struct sdio_func *func); ++static int rtw_sdio_resume(struct device *dev); ++static int rtw_sdio_suspend(struct device *dev); ++ ++static const struct dev_pm_ops rtw_sdio_pm_ops = { ++ .suspend = rtw_sdio_suspend, ++ .resume = rtw_sdio_resume, ++}; ++ ++struct sdio_drv_priv { ++ struct sdio_driver r871xs_drv; ++ int drv_registered; ++}; ++ ++static struct sdio_drv_priv sdio_drvpriv = { ++ .r871xs_drv.probe = rtw_drv_init, ++ .r871xs_drv.remove = rtw_dev_remove, ++ .r871xs_drv.name = "rtl8723bs", ++ .r871xs_drv.id_table = sdio_ids, ++ .r871xs_drv.drv = { ++ .pm = &rtw_sdio_pm_ops, ++ } ++}; ++ ++static void sd_sync_int_hdl(struct sdio_func *func) ++{ ++ struct dvobj_priv *psdpriv; ++ ++ ++ psdpriv = sdio_get_drvdata(func); ++ ++ if (!psdpriv->if1) { ++ DBG_871X("%s if1 == NULL\n", __func__); ++ return; ++ } ++ ++ rtw_sdio_set_irq_thd(psdpriv, current); ++ sd_int_hdl(psdpriv->if1); ++ rtw_sdio_set_irq_thd(psdpriv, NULL); ++} ++ ++static int sdio_alloc_irq(struct dvobj_priv *dvobj) ++{ ++ PSDIO_DATA psdio_data; ++ struct sdio_func *func; ++ int err; ++ ++ psdio_data = &dvobj->intf_data; ++ func = psdio_data->func; ++ ++ sdio_claim_host(func); ++ ++ err = sdio_claim_irq(func, &sd_sync_int_hdl); ++ if (err) ++ { ++ dvobj->drv_dbg.dbg_sdio_alloc_irq_error_cnt++; ++ printk(KERN_CRIT "%s: sdio_claim_irq FAIL(%d)!\n", __func__, err); ++ } ++ else ++ { ++ dvobj->drv_dbg.dbg_sdio_alloc_irq_cnt++; ++ dvobj->irq_alloc = 1; ++ } ++ ++ sdio_release_host(func); ++ ++ return err?_FAIL:_SUCCESS; ++} ++ ++static void sdio_free_irq(struct dvobj_priv *dvobj) ++{ ++ PSDIO_DATA psdio_data; ++ struct sdio_func *func; ++ int err; ++ ++ if (dvobj->irq_alloc) { ++ psdio_data = &dvobj->intf_data; ++ func = psdio_data->func; ++ ++ if (func) { ++ sdio_claim_host(func); ++ err = sdio_release_irq(func); ++ if (err) ++ { ++ dvobj->drv_dbg.dbg_sdio_free_irq_error_cnt++; ++ DBG_871X_LEVEL(_drv_err_,"%s: sdio_release_irq FAIL(%d)!\n", __func__, err); ++ } ++ else ++ dvobj->drv_dbg.dbg_sdio_free_irq_cnt++; ++ sdio_release_host(func); ++ } ++ dvobj->irq_alloc = 0; ++ } ++} ++ ++#ifdef CONFIG_GPIO_WAKEUP ++extern unsigned int oob_irq; ++static irqreturn_t gpio_hostwakeup_irq_thread(int irq, void *data) ++{ ++ struct adapter *padapter = (struct adapter *)data; ++ DBG_871X_LEVEL(_drv_always_, "gpio_hostwakeup_irq_thread\n"); ++ /* Disable interrupt before calling handler */ ++ /* disable_irq_nosync(oob_irq); */ ++ rtw_lock_suspend_timeout(HZ/2); ++ return IRQ_HANDLED; ++} ++ ++static u8 gpio_hostwakeup_alloc_irq(struct adapter *padapter) ++{ ++ int err; ++ if (oob_irq == 0) { ++ DBG_871X("oob_irq ZERO!\n"); ++ return _FAIL; ++ } ++ /* dont set it IRQF_TRIGGER_LOW, or wowlan */ ++ /* power is high after suspend */ ++ /* and failing can prevent can not sleep issue if */ ++ /* wifi gpio12 pin is not linked with CPU */ ++ err = request_threaded_irq(oob_irq, gpio_hostwakeup_irq_thread, NULL, ++ /* IRQF_TRIGGER_LOW | IRQF_ONESHOT, */ ++ IRQF_TRIGGER_FALLING, ++ "rtw_wifi_gpio_wakeup", padapter); ++ if (err < 0) { ++ DBG_871X("Oops: can't allocate gpio irq %d err:%d\n", oob_irq, err); ++ return false; ++ } else { ++ DBG_871X("allocate gpio irq %d ok\n", oob_irq); ++ } ++ ++ enable_irq_wake(oob_irq); ++ return _SUCCESS; ++} ++ ++static void gpio_hostwakeup_free_irq(struct adapter *padapter) ++{ ++ if (oob_irq == 0) ++ return; ++ ++ disable_irq_wake(oob_irq); ++ free_irq(oob_irq, padapter); ++} ++#endif ++ ++static u32 sdio_init(struct dvobj_priv *dvobj) ++{ ++ PSDIO_DATA psdio_data; ++ struct sdio_func *func; ++ int err; ++ ++ psdio_data = &dvobj->intf_data; ++ func = psdio_data->func; ++ ++ /* 3 1. init SDIO bus */ ++ sdio_claim_host(func); ++ ++ err = sdio_enable_func(func); ++ if (err) { ++ dvobj->drv_dbg.dbg_sdio_init_error_cnt++; ++ DBG_8192C(KERN_CRIT "%s: sdio_enable_func FAIL(%d)!\n", __func__, err); ++ goto release; ++ } ++ ++ err = sdio_set_block_size(func, 512); ++ if (err) { ++ dvobj->drv_dbg.dbg_sdio_init_error_cnt++; ++ DBG_8192C(KERN_CRIT "%s: sdio_set_block_size FAIL(%d)!\n", __func__, err); ++ goto release; ++ } ++ psdio_data->block_transfer_len = 512; ++ psdio_data->tx_block_mode = 1; ++ psdio_data->rx_block_mode = 1; ++ ++release: ++ sdio_release_host(func); ++ ++ if (err) ++ return _FAIL; ++ return _SUCCESS; ++} ++ ++static void sdio_deinit(struct dvobj_priv *dvobj) ++{ ++ struct sdio_func *func; ++ int err; ++ ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+sdio_deinit\n")); ++ ++ func = dvobj->intf_data.func; ++ ++ if (func) { ++ sdio_claim_host(func); ++ err = sdio_disable_func(func); ++ if (err) ++ { ++ dvobj->drv_dbg.dbg_sdio_deinit_error_cnt++; ++ DBG_8192C(KERN_ERR "%s: sdio_disable_func(%d)\n", __func__, err); ++ } ++ ++ if (dvobj->irq_alloc) { ++ err = sdio_release_irq(func); ++ if (err) ++ { ++ dvobj->drv_dbg.dbg_sdio_free_irq_error_cnt++; ++ DBG_8192C(KERN_ERR "%s: sdio_release_irq(%d)\n", __func__, err); ++ } ++ else ++ dvobj->drv_dbg.dbg_sdio_free_irq_cnt++; ++ } ++ ++ sdio_release_host(func); ++ } ++} ++static struct dvobj_priv *sdio_dvobj_init(struct sdio_func *func) ++{ ++ int status = _FAIL; ++ struct dvobj_priv *dvobj = NULL; ++ PSDIO_DATA psdio; ++ ++ if ((dvobj = devobj_init()) == NULL) { ++ goto exit; ++ } ++ ++ sdio_set_drvdata(func, dvobj); ++ ++ psdio = &dvobj->intf_data; ++ psdio->func = func; ++ ++ if (sdio_init(dvobj) != _SUCCESS) { ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: initialize SDIO Failed!\n", __func__)); ++ goto free_dvobj; ++ } ++ rtw_reset_continual_io_error(dvobj); ++ status = _SUCCESS; ++ ++free_dvobj: ++ if (status != _SUCCESS && dvobj) { ++ sdio_set_drvdata(func, NULL); ++ ++ devobj_deinit(dvobj); ++ ++ dvobj = NULL; ++ } ++exit: ++ return dvobj; ++} ++ ++static void sdio_dvobj_deinit(struct sdio_func *func) ++{ ++ struct dvobj_priv *dvobj = sdio_get_drvdata(func); ++ ++ sdio_set_drvdata(func, NULL); ++ if (dvobj) { ++ sdio_deinit(dvobj); ++ devobj_deinit(dvobj); ++ } ++ return; ++} ++ ++void rtw_set_hal_ops(struct adapter *padapter) ++{ ++ /* alloc memory for HAL DATA */ ++ rtw_hal_data_init(padapter); ++ ++ rtl8723bs_set_hal_ops(padapter); ++} ++ ++static void sd_intf_start(struct adapter *padapter) ++{ ++ if (padapter == NULL) { ++ DBG_8192C(KERN_ERR "%s: padapter is NULL!\n", __func__); ++ return; ++ } ++ ++ /* hal dep */ ++ rtw_hal_enable_interrupt(padapter); ++} ++ ++static void sd_intf_stop(struct adapter *padapter) ++{ ++ if (padapter == NULL) { ++ DBG_8192C(KERN_ERR "%s: padapter is NULL!\n", __func__); ++ return; ++ } ++ ++ /* hal dep */ ++ rtw_hal_disable_interrupt(padapter); ++} ++ ++ ++static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct sdio_device_id *pdid) ++{ ++ int status = _FAIL; ++ struct net_device *pnetdev; ++ struct adapter *padapter = NULL; ++ ++ if ((padapter = (struct adapter *)vzalloc(sizeof(*padapter))) == NULL) { ++ goto exit; ++ } ++ ++ padapter->dvobj = dvobj; ++ dvobj->if1 = padapter; ++ ++ padapter->bDriverStopped =true; ++ ++ dvobj->padapters = padapter; ++ padapter->iface_id = 0; ++ ++ /* 3 1. init network device data */ ++ pnetdev = rtw_init_netdev(padapter); ++ if (!pnetdev) ++ goto free_adapter; ++ ++ SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj)); ++ ++ padapter = rtw_netdev_priv(pnetdev); ++ ++ rtw_wdev_alloc(padapter, dvobj_to_dev(dvobj)); ++ ++ /* 3 3. init driver special setting, interface, OS and hardware relative */ ++ ++ /* 4 3.1 set hardware operation functions */ ++ rtw_set_hal_ops(padapter); ++ ++ ++ /* 3 5. initialize Chip version */ ++ padapter->intf_start = &sd_intf_start; ++ padapter->intf_stop = &sd_intf_stop; ++ ++ padapter->intf_init = &sdio_init; ++ padapter->intf_deinit = &sdio_deinit; ++ padapter->intf_alloc_irq = &sdio_alloc_irq; ++ padapter->intf_free_irq = &sdio_free_irq; ++ ++ if (rtw_init_io_priv(padapter, sdio_set_intf_ops) == _FAIL) ++ { ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ++ ("rtw_drv_init: Can't init io_priv\n")); ++ goto free_hal_data; ++ } ++ ++ rtw_hal_read_chip_version(padapter); ++ ++ rtw_hal_chip_configure(padapter); ++ ++ rtw_btcoex_Initialize(padapter); ++ ++ /* 3 6. read efuse/eeprom data */ ++ rtw_hal_read_chip_info(padapter); ++ ++ /* 3 7. init driver common data */ ++ if (rtw_init_drv_sw(padapter) == _FAIL) { ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ++ ("rtw_drv_init: Initialize driver software resource Failed!\n")); ++ goto free_hal_data; ++ } ++ ++ /* 3 8. get WLan MAC address */ ++ /* set mac addr */ ++ rtw_macaddr_cfg(padapter->eeprompriv.mac_addr); ++ ++ rtw_hal_disable_interrupt(padapter); ++ ++ DBG_871X("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n" ++ , padapter->bDriverStopped ++ , padapter->bSurpriseRemoved ++ , padapter->bup ++ , padapter->hw_init_completed ++ ); ++ ++ status = _SUCCESS; ++ ++free_hal_data: ++ if (status != _SUCCESS && padapter->HalData) ++ kfree(padapter->HalData); ++ ++ if (status != _SUCCESS) { ++ rtw_wdev_unregister(padapter->rtw_wdev); ++ rtw_wdev_free(padapter->rtw_wdev); ++ } ++ ++free_adapter: ++ if (status != _SUCCESS) { ++ if (pnetdev) ++ rtw_free_netdev(pnetdev); ++ else ++ vfree((u8 *)padapter); ++ padapter = NULL; ++ } ++exit: ++ return padapter; ++} ++ ++static void rtw_sdio_if1_deinit(struct adapter *if1) ++{ ++ struct net_device *pnetdev = if1->pnetdev; ++ struct mlme_priv *pmlmepriv = &if1->mlmepriv; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) ++ rtw_disassoc_cmd(if1, 0, false); ++ ++ free_mlme_ap_info(if1); ++ ++#ifdef CONFIG_GPIO_WAKEUP ++ gpio_hostwakeup_free_irq(if1); ++#endif ++ ++ rtw_cancel_all_timer(if1); ++ ++#ifdef CONFIG_WOWLAN ++ adapter_to_pwrctl(if1)->wowlan_mode =false; ++ DBG_871X_LEVEL(_drv_always_, "%s wowlan_mode:%d\n", __func__, adapter_to_pwrctl(if1)->wowlan_mode); ++#endif /* CONFIG_WOWLAN */ ++ ++ rtw_dev_unload(if1); ++ DBG_871X("+r871xu_dev_remove, hw_init_completed =%d\n", if1->hw_init_completed); ++ ++ if (if1->rtw_wdev) { ++ rtw_wdev_free(if1->rtw_wdev); ++ } ++ ++ rtw_free_drv_sw(if1); ++ ++ if (pnetdev) ++ rtw_free_netdev(pnetdev); ++} ++ ++/* ++ * drv_init() - a device potentially for us ++ * ++ * notes: drv_init() is called when the bus driver has located a card for us to support. ++ * We accept the new device by returning 0. ++ */ ++static int rtw_drv_init( ++ struct sdio_func *func, ++ const struct sdio_device_id *id) ++{ ++ int status = _FAIL; ++ struct adapter *if1 = NULL, *if2 = NULL; ++ struct dvobj_priv *dvobj; ++ ++ switch (func->vendor) { ++ case 0x024c: ++ switch (func->device) { ++ case 0x0523: ++ case 0x0623: ++ case 0xb723: ++ break; ++ default: ++ pr_info("RTL8723BS: Found unrecognized vendor 0x%x, device 0x%x\n", ++ func->vendor, func->device); ++ goto exit; ++ } ++ break; ++ default: ++ pr_info("RTL8723BS: Found unrecognized vendor 0x%x, device 0x%x\n", ++ func->vendor, func->device); ++ goto exit; ++ } ++ if ((dvobj = sdio_dvobj_init(func)) == NULL) { ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("initialize device object priv Failed!\n")); ++ goto exit; ++ } ++ ++ if ((if1 = rtw_sdio_if1_init(dvobj, id)) == NULL) { ++ DBG_871X("rtw_init_primarystruct adapter Failed!\n"); ++ goto free_dvobj; ++ } ++ ++ /* dev_alloc_name && register_netdev */ ++ if ((status = rtw_drv_register_netdev(if1)) != _SUCCESS) { ++ goto free_if2; ++ } ++ ++ if (sdio_alloc_irq(dvobj) != _SUCCESS) ++ goto free_if2; ++ ++#ifdef CONFIG_GPIO_WAKEUP ++ gpio_hostwakeup_alloc_irq(if1); ++#endif ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-871x_drv - drv_init, success!\n")); ++ ++ rtw_ndev_notifier_register(); ++ status = _SUCCESS; ++ ++free_if2: ++ if (status != _SUCCESS && if2) { ++ } ++ if (status != _SUCCESS && if1) { ++ rtw_sdio_if1_deinit(if1); ++ } ++free_dvobj: ++ if (status != _SUCCESS) ++ sdio_dvobj_deinit(func); ++exit: ++ return status == _SUCCESS?0:-ENODEV; ++} ++ ++static void rtw_dev_remove(struct sdio_func *func) ++{ ++ struct dvobj_priv *dvobj = sdio_get_drvdata(func); ++ struct adapter *padapter = dvobj->if1; ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+rtw_dev_remove\n")); ++ ++ dvobj->processing_dev_remove = true; ++ ++ rtw_unregister_netdevs(dvobj); ++ ++ if (padapter->bSurpriseRemoved == false) { ++ int err; ++ ++ /* test surprise remove */ ++ sdio_claim_host(func); ++ sdio_readb(func, 0, &err); ++ sdio_release_host(func); ++ if (err == -ENOMEDIUM) { ++ padapter->bSurpriseRemoved = true; ++ DBG_871X(KERN_NOTICE "%s: device had been removed!\n", __func__); ++ } ++ } ++ ++ rtw_ps_deny(padapter, PS_DENY_DRV_REMOVE); ++ ++ rtw_pm_set_ips(padapter, IPS_NONE); ++ rtw_pm_set_lps(padapter, PS_MODE_ACTIVE); ++ ++ LeaveAllPowerSaveMode(padapter); ++ ++ rtw_btcoex_HaltNotify(padapter); ++ ++ rtw_sdio_if1_deinit(padapter); ++ ++ sdio_dvobj_deinit(func); ++ ++ RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("-rtw_dev_remove\n")); ++} ++ ++extern int pm_netdev_open(struct net_device *pnetdev, u8 bnormal); ++extern int pm_netdev_close(struct net_device *pnetdev, u8 bnormal); ++ ++static int rtw_sdio_suspend(struct device *dev) ++{ ++ struct sdio_func *func =dev_to_sdio_func(dev); ++ struct dvobj_priv *psdpriv = sdio_get_drvdata(func); ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(psdpriv); ++ struct adapter *padapter = psdpriv->if1; ++ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; ++ int ret = 0; ++ ++ if (padapter->bDriverStopped == true) ++ { ++ DBG_871X("%s bDriverStopped = %d\n", __func__, padapter->bDriverStopped); ++ goto exit; ++ } ++ ++ if (pwrpriv->bInSuspend == true) ++ { ++ DBG_871X("%s bInSuspend = %d\n", __func__, pwrpriv->bInSuspend); ++ pdbgpriv->dbg_suspend_error_cnt++; ++ goto exit; ++ } ++ ++ ret = rtw_suspend_common(padapter); ++ ++exit: ++#ifdef CONFIG_RTW_SDIO_PM_KEEP_POWER ++ /* Android 4.0 don't support WIFI close power */ ++ /* or power down or clock will close after wifi resume, */ ++ /* this is sprd's bug in Android 4.0, but sprd don't */ ++ /* want to fix it. */ ++ /* we have test power under 8723as, power consumption is ok */ ++ if (func) { ++ mmc_pm_flag_t pm_flag = 0; ++ pm_flag = sdio_get_host_pm_caps(func); ++ DBG_871X("cmd: %s: suspend: PM flag = 0x%x\n", sdio_func_id(func), pm_flag); ++ if (!(pm_flag & MMC_PM_KEEP_POWER)) { ++ DBG_871X("%s: cannot remain alive while host is suspended\n", sdio_func_id(func)); ++ pdbgpriv->dbg_suspend_error_cnt++; ++ return -ENOSYS; ++ } else { ++ DBG_871X("cmd: suspend with MMC_PM_KEEP_POWER\n"); ++ sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); ++ } ++ } ++#endif ++ return ret; ++} ++static int rtw_resume_process(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); ++ struct dvobj_priv *psdpriv = padapter->dvobj; ++ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; ++ ++ if (pwrpriv->bInSuspend == false) ++ { ++ pdbgpriv->dbg_resume_error_cnt++; ++ DBG_871X("%s bInSuspend = %d\n", __func__, pwrpriv->bInSuspend); ++ return -1; ++ } ++ ++ return rtw_resume_common(padapter); ++} ++ ++static int rtw_sdio_resume(struct device *dev) ++{ ++ struct sdio_func *func =dev_to_sdio_func(dev); ++ struct dvobj_priv *psdpriv = sdio_get_drvdata(func); ++ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(psdpriv); ++ struct adapter *padapter = psdpriv->if1; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ int ret = 0; ++ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; ++ ++ DBG_871X("==> %s (%s:%d)\n", __func__, current->comm, current->pid); ++ ++ pdbgpriv->dbg_resume_cnt++; ++ ++ if (pwrpriv->bInternalAutoSuspend) ++ { ++ ret = rtw_resume_process(padapter); ++ } ++ else ++ { ++ if (pwrpriv->wowlan_mode || pwrpriv->wowlan_ap_mode) ++ { ++ ret = rtw_resume_process(padapter); ++ } ++ else ++ { ++ ret = rtw_resume_process(padapter); ++ } ++ } ++ pmlmeext->last_scan_time = jiffies; ++ DBG_871X("<======== %s return %d\n", __func__, ret); ++ return ret; ++ ++} ++ ++static int __init rtw_drv_entry(void) ++{ ++ int ret = 0; ++ ++ DBG_871X_LEVEL(_drv_always_, "module init start\n"); ++ dump_drv_version(RTW_DBGDUMP); ++#ifdef BTCOEXVERSION ++ DBG_871X_LEVEL(_drv_always_, "rtl8723bs BT-Coex version = %s\n", BTCOEXVERSION); ++#endif /* BTCOEXVERSION */ ++ ++ sdio_drvpriv.drv_registered = true; ++ rtw_drv_proc_init(); ++ ++ ret = sdio_register_driver(&sdio_drvpriv.r871xs_drv); ++ if (ret != 0) ++ { ++ sdio_drvpriv.drv_registered = false; ++ rtw_drv_proc_deinit(); ++ rtw_ndev_notifier_unregister(); ++ DBG_871X("%s: register driver failed!!(%d)\n", __func__, ret); ++ goto exit; ++ } ++ ++ goto exit; ++ ++exit: ++ DBG_871X_LEVEL(_drv_always_, "module init ret =%d\n", ret); ++ return ret; ++} ++ ++static void __exit rtw_drv_halt(void) ++{ ++ DBG_871X_LEVEL(_drv_always_, "module exit start\n"); ++ ++ sdio_drvpriv.drv_registered = false; ++ ++ sdio_unregister_driver(&sdio_drvpriv.r871xs_drv); ++ ++ rtw_drv_proc_deinit(); ++ rtw_ndev_notifier_unregister(); ++ ++ DBG_871X_LEVEL(_drv_always_, "module exit success\n"); ++ ++ rtw_mstat_dump(RTW_DBGDUMP); ++} ++ ++ ++module_init(rtw_drv_entry); ++module_exit(rtw_drv_halt); +diff -Nurp linux-4.3/3rdparty/rtl8723bs/os_dep/sdio_ops_linux.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/sdio_ops_linux.c +--- linux-4.3/3rdparty/rtl8723bs/os_dep/sdio_ops_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/sdio_ops_linux.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,599 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ *******************************************************************************/ ++#define _SDIO_OPS_LINUX_C_ ++ ++#include ++#include ++ ++static bool rtw_sdio_claim_host_needed(struct sdio_func *func) ++{ ++ struct dvobj_priv *dvobj = sdio_get_drvdata(func); ++ PSDIO_DATA sdio_data = &dvobj->intf_data; ++ ++ if (sdio_data->sys_sdio_irq_thd && sdio_data->sys_sdio_irq_thd == current) ++ return false; ++ return true; ++} ++ ++inline void rtw_sdio_set_irq_thd(struct dvobj_priv *dvobj, void *thd_hdl) ++{ ++ PSDIO_DATA sdio_data = &dvobj->intf_data; ++ ++ sdio_data->sys_sdio_irq_thd = thd_hdl; ++} ++ ++u8 sd_f0_read8(struct intf_hdl *pintfhdl, u32 addr, s32 *err) ++{ ++ struct adapter *padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ u8 v = 0; ++ struct sdio_func *func; ++ bool claim_needed; ++ ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if (padapter->bSurpriseRemoved) { ++ /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ ++ return v; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ v = sdio_f0_readb(func, addr, err); ++ if (claim_needed) ++ sdio_release_host(func); ++ if (err && *err) ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x\n", __func__, *err, addr); ++ return v; ++} ++ ++/* ++ * Return: ++ *0 Success ++ *others Fail ++ */ ++s32 _sd_cmd52_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata) ++{ ++ struct adapter *padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ int err = 0, i; ++ struct sdio_func *func; ++ ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if (padapter->bSurpriseRemoved) { ++ /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ ++ return err; ++ } ++ ++ func = psdio->func; ++ ++ for (i = 0; i < cnt; i++) { ++ pdata[i] = sdio_readb(func, addr+i, &err); ++ if (err) { ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x\n", __func__, err, addr+i); ++ break; ++ } ++ } ++ return err; ++} ++ ++/* ++ * Return: ++ *0 Success ++ *others Fail ++ */ ++s32 sd_cmd52_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata) ++{ ++ struct adapter *padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ int err = 0; ++ struct sdio_func *func; ++ bool claim_needed; ++ ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if (padapter->bSurpriseRemoved) { ++ /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ ++ return err; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ err = _sd_cmd52_read(pintfhdl, addr, cnt, pdata); ++ if (claim_needed) ++ sdio_release_host(func); ++ return err; ++} ++ ++/* ++ * Return: ++ *0 Success ++ *others Fail ++ */ ++s32 _sd_cmd52_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata) ++{ ++ struct adapter *padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ int err = 0, i; ++ struct sdio_func *func; ++ ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if (padapter->bSurpriseRemoved) { ++ /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ ++ return err; ++ } ++ ++ func = psdio->func; ++ ++ for (i = 0; i < cnt; i++) { ++ sdio_writeb(func, pdata[i], addr+i, &err); ++ if (err) { ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x val = 0x%02x\n", __func__, err, addr+i, pdata[i]); ++ break; ++ } ++ } ++ return err; ++} ++ ++/* ++ * Return: ++ *0 Success ++ *others Fail ++ */ ++s32 sd_cmd52_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata) ++{ ++ struct adapter *padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ int err = 0; ++ struct sdio_func *func; ++ bool claim_needed; ++ ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if (padapter->bSurpriseRemoved) { ++ /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ ++ return err; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ err = _sd_cmd52_write(pintfhdl, addr, cnt, pdata); ++ if (claim_needed) ++ sdio_release_host(func); ++ return err; ++} ++ ++u8 sd_read8(struct intf_hdl *pintfhdl, u32 addr, s32 *err) ++{ ++ struct adapter *padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ u8 v = 0; ++ struct sdio_func *func; ++ bool claim_needed; ++ ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if (padapter->bSurpriseRemoved) { ++ /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ ++ return v; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ v = sdio_readb(func, addr, err); ++ if (claim_needed) ++ sdio_release_host(func); ++ if (err && *err) ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x\n", __func__, *err, addr); ++ return v; ++} ++ ++u32 sd_read32(struct intf_hdl *pintfhdl, u32 addr, s32 *err) ++{ ++ struct adapter *padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ u32 v = 0; ++ struct sdio_func *func; ++ bool claim_needed; ++ ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if (padapter->bSurpriseRemoved) { ++ /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ ++ return v; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ v = sdio_readl(func, addr, err); ++ if (claim_needed) ++ sdio_release_host(func); ++ ++ if (err && *err) ++ { ++ int i; ++ ++ DBG_871X(KERN_ERR "%s: (%d) addr = 0x%05x, val = 0x%x\n", __func__, *err, addr, v); ++ ++ *err = 0; ++ for (i = 0; ibSurpriseRemoved = true; ++ } ++ ++ if (rtw_inc_and_chk_continual_io_error(psdiodev) == true) { ++ padapter->bSurpriseRemoved = true; ++ break; ++ } ++ } ++ } ++ ++ if (i ==SD_IO_TRY_CNT) ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x, val = 0x%x, try_cnt =%d\n", __func__, *err, addr, v, i); ++ else ++ DBG_871X(KERN_ERR "%s: (%d) addr = 0x%05x, val = 0x%x, try_cnt =%d\n", __func__, *err, addr, v, i); ++ ++ } ++ return v; ++} ++ ++void sd_write8(struct intf_hdl *pintfhdl, u32 addr, u8 v, s32 *err) ++{ ++ struct adapter *padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ struct sdio_func *func; ++ bool claim_needed; ++ ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if (padapter->bSurpriseRemoved) { ++ /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ ++ return ; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ sdio_writeb(func, v, addr, err); ++ if (claim_needed) ++ sdio_release_host(func); ++ if (err && *err) ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x val = 0x%02x\n", __func__, *err, addr, v); ++} ++ ++void sd_write32(struct intf_hdl *pintfhdl, u32 addr, u32 v, s32 *err) ++{ ++ struct adapter *padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ struct sdio_func *func; ++ bool claim_needed; ++ ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if (padapter->bSurpriseRemoved) { ++ /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ ++ return ; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ sdio_writel(func, v, addr, err); ++ if (claim_needed) ++ sdio_release_host(func); ++ ++ if (err && *err) ++ { ++ int i; ++ ++ DBG_871X(KERN_ERR "%s: (%d) addr = 0x%05x val = 0x%08x\n", __func__, *err, addr, v); ++ ++ *err = 0; ++ for (i = 0; ibSurpriseRemoved = true; ++ } ++ ++ if (rtw_inc_and_chk_continual_io_error(psdiodev) == true) { ++ padapter->bSurpriseRemoved = true; ++ break; ++ } ++ } ++ } ++ ++ if (i ==SD_IO_TRY_CNT) ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x val = 0x%08x, try_cnt =%d\n", __func__, *err, addr, v, i); ++ else ++ DBG_871X(KERN_ERR "%s: (%d) addr = 0x%05x val = 0x%08x, try_cnt =%d\n", __func__, *err, addr, v, i); ++ } ++} ++ ++/* ++ * Use CMD53 to read data from SDIO device. ++ * This function MUST be called after sdio_claim_host() or ++ * in SDIO ISR(host had been claimed). ++ * ++ * Parameters: ++ *psdio pointer of SDIO_DATA ++ *addr address to read ++ *cnt amount to read ++ *pdata pointer to put data, this should be a "DMA:able scratch buffer"! ++ * ++ * Return: ++ *0 Success ++ *others Fail ++ */ ++s32 _sd_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) ++{ ++ struct adapter *padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ int err = -EPERM; ++ struct sdio_func *func; ++ ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if (padapter->bSurpriseRemoved) { ++ /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ ++ return err; ++ } ++ ++ func = psdio->func; ++ ++ if (unlikely((cnt == 1) || (cnt ==2))) ++ { ++ int i; ++ u8 *pbuf = (u8 *)pdata; ++ ++ for (i = 0; i < cnt; i++) ++ { ++ *(pbuf+i) = sdio_readb(func, addr+i, &err); ++ ++ if (err) { ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x\n", __func__, err, addr); ++ break; ++ } ++ } ++ return err; ++ } ++ ++ err = sdio_memcpy_fromio(func, pdata, addr, cnt); ++ if (err) { ++ DBG_871X(KERN_ERR "%s: FAIL(%d)! ADDR =%#x Size =%d\n", __func__, err, addr, cnt); ++ } ++ return err; ++} ++ ++/* ++ * Use CMD53 to read data from SDIO device. ++ * ++ * Parameters: ++ *psdio pointer of SDIO_DATA ++ *addr address to read ++ *cnt amount to read ++ *pdata pointer to put data, this should be a "DMA:able scratch buffer"! ++ * ++ * Return: ++ *0 Success ++ *others Fail ++ */ ++s32 sd_read(struct intf_hdl * pintfhdl, u32 addr, u32 cnt, void *pdata) ++{ ++ struct adapter *padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ struct sdio_func *func; ++ bool claim_needed; ++ s32 err = -EPERM; ++ ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if (padapter->bSurpriseRemoved) { ++ /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ ++ return err; ++ } ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ err = _sd_read(pintfhdl, addr, cnt, pdata); ++ if (claim_needed) ++ sdio_release_host(func); ++ return err; ++} ++ ++/* ++ * Use CMD53 to write data to SDIO device. ++ * This function MUST be called after sdio_claim_host() or ++ * in SDIO ISR(host had been claimed). ++ * ++ * Parameters: ++ *psdio pointer of SDIO_DATA ++ *addr address to write ++ *cnt amount to write ++ *pdata data pointer, this should be a "DMA:able scratch buffer"! ++ * ++ * Return: ++ *0 Success ++ *others Fail ++ */ ++s32 _sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) ++{ ++ struct adapter *padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ ++ struct sdio_func *func; ++ u32 size; ++ s32 err =-EPERM; ++ ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if (padapter->bSurpriseRemoved) { ++ /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ ++ return err; ++ } ++ ++ func = psdio->func; ++/* size = sdio_align_size(func, cnt); */ ++ ++ if (unlikely((cnt == 1) || (cnt ==2))) ++ { ++ int i; ++ u8 *pbuf = (u8 *)pdata; ++ ++ for (i = 0; i < cnt; i++) ++ { ++ sdio_writeb(func, *(pbuf+i), addr+i, &err); ++ if (err) { ++ DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x val = 0x%02x\n", __func__, err, addr, *(pbuf+i)); ++ break; ++ } ++ } ++ ++ return err; ++ } ++ ++ size = cnt; ++ err = sdio_memcpy_toio(func, addr, pdata, size); ++ if (err) { ++ DBG_871X(KERN_ERR "%s: FAIL(%d)! ADDR =%#x Size =%d(%d)\n", __func__, err, addr, cnt, size); ++ } ++ return err; ++} ++ ++/* ++ * Use CMD53 to write data to SDIO device. ++ * ++ * Parameters: ++ * psdio pointer of SDIO_DATA ++ * addr address to write ++ * cnt amount to write ++ * pdata data pointer, this should be a "DMA:able scratch buffer"! ++ * ++ * Return: ++ * 0 Success ++ * others Fail ++ */ ++s32 sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) ++{ ++ struct adapter *padapter; ++ struct dvobj_priv *psdiodev; ++ PSDIO_DATA psdio; ++ struct sdio_func *func; ++ bool claim_needed; ++ s32 err =-EPERM; ++ ++ padapter = pintfhdl->padapter; ++ psdiodev = pintfhdl->pintf_dev; ++ psdio = &psdiodev->intf_data; ++ ++ if (padapter->bSurpriseRemoved) { ++ /* DBG_871X(" %s (padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n", __func__); */ ++ return err; ++ } ++ ++ func = psdio->func; ++ claim_needed = rtw_sdio_claim_host_needed(func); ++ ++ if (claim_needed) ++ sdio_claim_host(func); ++ err = _sd_write(pintfhdl, addr, cnt, pdata); ++ if (claim_needed) ++ sdio_release_host(func); ++ return err; ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/os_dep/wifi_regd.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/wifi_regd.c +--- linux-4.3/3rdparty/rtl8723bs/os_dep/wifi_regd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/wifi_regd.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,218 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2009-2010 Realtek Corporation. ++ * ++ *****************************************************************************/ ++ ++#include ++#include ++ ++#include ++ ++/* ++ * REG_RULE(freq start, freq end, bandwidth, max gain, eirp, reg_flags) ++ */ ++ ++/* ++ *Only these channels all allow active ++ *scan on all world regulatory domains ++ */ ++ ++/* 2G chan 01 - chan 11 */ ++#define RTW_2GHZ_CH01_11 \ ++ REG_RULE(2412-10, 2462+10, 40, 0, 20, 0) ++ ++/* ++ *We enable active scan on these a case ++ *by case basis by regulatory domain ++ */ ++ ++/* 2G chan 12 - chan 13, PASSIV SCAN */ ++#define RTW_2GHZ_CH12_13 \ ++ REG_RULE(2467-10, 2472+10, 40, 0, 20, \ ++ NL80211_RRF_PASSIVE_SCAN) ++ ++/* 2G chan 14, PASSIVS SCAN, NO OFDM (B only) */ ++#define RTW_2GHZ_CH14 \ ++ REG_RULE(2484-10, 2484+10, 40, 0, 20, \ ++ NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM) ++ ++static const struct ieee80211_regdomain rtw_regdom_rd = { ++ .n_reg_rules = 3, ++ .alpha2 = "99", ++ .reg_rules = { ++ RTW_2GHZ_CH01_11, ++ RTW_2GHZ_CH12_13, ++ } ++}; ++ ++static const struct ieee80211_regdomain rtw_regdom_11 = { ++ .n_reg_rules = 1, ++ .alpha2 = "99", ++ .reg_rules = { ++ RTW_2GHZ_CH01_11, ++ } ++}; ++ ++static const struct ieee80211_regdomain rtw_regdom_12_13 = { ++ .n_reg_rules = 2, ++ .alpha2 = "99", ++ .reg_rules = { ++ RTW_2GHZ_CH01_11, ++ RTW_2GHZ_CH12_13, ++ } ++}; ++ ++static const struct ieee80211_regdomain rtw_regdom_no_midband = { ++ .n_reg_rules = 3, ++ .alpha2 = "99", ++ .reg_rules = { ++ RTW_2GHZ_CH01_11, ++ } ++}; ++ ++static const struct ieee80211_regdomain rtw_regdom_60_64 = { ++ .n_reg_rules = 3, ++ .alpha2 = "99", ++ .reg_rules = { ++ RTW_2GHZ_CH01_11, ++ RTW_2GHZ_CH12_13, ++ } ++}; ++ ++static const struct ieee80211_regdomain rtw_regdom_14_60_64 = { ++ .n_reg_rules = 4, ++ .alpha2 = "99", ++ .reg_rules = { ++ RTW_2GHZ_CH01_11, ++ RTW_2GHZ_CH12_13, ++ RTW_2GHZ_CH14, ++ } ++}; ++ ++static const struct ieee80211_regdomain rtw_regdom_14 = { ++ .n_reg_rules = 3, ++ .alpha2 = "99", ++ .reg_rules = { ++ RTW_2GHZ_CH01_11, ++ RTW_2GHZ_CH12_13, ++ RTW_2GHZ_CH14, ++ } ++}; ++ ++static int rtw_ieee80211_channel_to_frequency(int chan, int band) ++{ ++ /* see 802.11 17.3.8.3.2 and Annex J ++ * there are overlapping channel numbers in 5GHz and 2GHz bands */ ++ ++ /* IEEE80211_BAND_2GHZ */ ++ if (chan == 14) ++ return 2484; ++ else if (chan < 14) ++ return 2407 + chan * 5; ++ else ++ return 0; /* not supported */ ++} ++ ++static void _rtw_reg_apply_flags(struct wiphy *wiphy) ++{ ++ struct adapter *padapter = wiphy_to_adapter(wiphy); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ RT_CHANNEL_INFO *channel_set = pmlmeext->channel_set; ++ u8 max_chan_nums = pmlmeext->max_chan_nums; ++ ++ struct ieee80211_supported_band *sband; ++ struct ieee80211_channel *ch; ++ unsigned int i, j; ++ u16 channel; ++ u32 freq; ++ ++ /* all channels disable */ ++ for (i = 0; i < IEEE80211_NUM_BANDS; i++) { ++ sband = wiphy->bands[i]; ++ ++ if (sband) { ++ for (j = 0; j < sband->n_channels; j++) { ++ ch = &sband->channels[j]; ++ ++ if (ch) ++ ch->flags = IEEE80211_CHAN_DISABLED; ++ } ++ } ++ } ++ ++ /* channels apply by channel plans. */ ++ for (i = 0; i < max_chan_nums; i++) { ++ channel = channel_set[i].ChannelNum; ++ freq = ++ rtw_ieee80211_channel_to_frequency(channel, ++ IEEE80211_BAND_2GHZ); ++ ++ ch = ieee80211_get_channel(wiphy, freq); ++ if (ch) { ++ if (channel_set[i].ScanType == SCAN_PASSIVE) { ++ ch->flags = IEEE80211_CHAN_NO_IR; ++ } ++ else { ++ ch->flags = 0; ++ } ++ } ++ } ++} ++ ++static int _rtw_reg_notifier_apply(struct wiphy *wiphy, ++ struct regulatory_request *request, ++ struct rtw_regulatory *reg) ++{ ++ /* Hard code flags */ ++ _rtw_reg_apply_flags(wiphy); ++ return 0; ++} ++ ++static const struct ieee80211_regdomain *_rtw_regdomain_select(struct ++ rtw_regulatory ++ *reg) ++{ ++ return &rtw_regdom_rd; ++} ++ ++static void _rtw_regd_init_wiphy(struct rtw_regulatory *reg, ++ struct wiphy *wiphy, ++ void (*reg_notifier) (struct wiphy * wiphy, ++ struct regulatory_request * ++ request)) ++{ ++ const struct ieee80211_regdomain *regd; ++ ++ wiphy->reg_notifier = reg_notifier; ++ ++ wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; ++ wiphy->regulatory_flags &= ~REGULATORY_STRICT_REG; ++ wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS; ++ ++ regd = _rtw_regdomain_select(reg); ++ wiphy_apply_custom_regulatory(wiphy, regd); ++ ++ /* Hard code flags */ ++ _rtw_reg_apply_flags(wiphy); ++} ++ ++int rtw_regd_init(struct adapter *padapter, ++ void (*reg_notifier) (struct wiphy * wiphy, ++ struct regulatory_request *request)) ++{ ++ /* struct registry_priv *registrypriv = &padapter->registrypriv; */ ++ struct wiphy *wiphy = padapter->rtw_wdev->wiphy; ++ _rtw_regd_init_wiphy(NULL, wiphy, reg_notifier); ++ ++ return 0; ++} ++ ++void rtw_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) ++{ ++ struct rtw_regulatory *reg = NULL; ++ ++ DBG_8192C("%s\n", __func__); ++ ++ _rtw_reg_notifier_apply(wiphy, request, reg); ++} +diff -Nurp linux-4.3/3rdparty/rtl8723bs/os_dep/xmit_linux.c linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/xmit_linux.c +--- linux-4.3/3rdparty/rtl8723bs/os_dep/xmit_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.3-rtl8723bs/3rdparty/rtl8723bs/os_dep/xmit_linux.c 2015-11-21 19:42:45.000000000 +0200 +@@ -0,0 +1,298 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2012 Realtek 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. ++ * ++ ******************************************************************************/ ++#define _XMIT_OSDEP_C_ ++ ++#include ++#include ++ ++ ++uint rtw_remainder_len(struct pkt_file *pfile) ++{ ++ return (pfile->buf_len - ((SIZE_PTR)(pfile->cur_addr) - (SIZE_PTR)(pfile->buf_start))); ++} ++ ++void _rtw_open_pktfile (_pkt *pktptr, struct pkt_file *pfile) ++{ ++ pfile->pkt = pktptr; ++ pfile->cur_addr = pfile->buf_start = pktptr->data; ++ pfile->pkt_len = pfile->buf_len = pktptr->len; ++ ++ pfile->cur_buffer = pfile->buf_start ; ++} ++ ++uint _rtw_pktfile_read (struct pkt_file *pfile, u8 *rmem, uint rlen) ++{ ++ uint len = 0; ++ ++ len = rtw_remainder_len(pfile); ++ len = (rlen > len)? len: rlen; ++ ++ if (rmem) ++ skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, rmem, len); ++ ++ pfile->cur_addr += len; ++ pfile->pkt_len -= len; ++ return len; ++} ++ ++sint rtw_endofpktfile(struct pkt_file *pfile) ++{ ++ if (pfile->pkt_len == 0) ++ return true; ++ return false; ++} ++ ++void rtw_set_tx_chksum_offload(_pkt *pkt, struct pkt_attrib *pattrib) ++{ ++ ++} ++ ++int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz, u8 flag) ++{ ++ if (alloc_sz > 0) { ++ pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz); ++ if (pxmitbuf->pallocated_buf == NULL) ++ { ++ return _FAIL; ++ } ++ ++ pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ); ++ } ++ ++ return _SUCCESS; ++} ++ ++void rtw_os_xmit_resource_free(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 free_sz, u8 flag) ++{ ++ if (free_sz > 0) { ++ if (pxmitbuf->pallocated_buf) ++ kfree(pxmitbuf->pallocated_buf); ++ } ++} ++ ++#define WMM_XMIT_THRESHOLD (NR_XMITFRAME*2/5) ++ ++void rtw_os_pkt_complete(struct adapter *padapter, _pkt *pkt) ++{ ++ u16 queue; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ queue = skb_get_queue_mapping(pkt); ++ if (padapter->registrypriv.wifi_spec) { ++ if (__netif_subqueue_stopped(padapter->pnetdev, queue) && ++ (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD)) ++ { ++ netif_wake_subqueue(padapter->pnetdev, queue); ++ } ++ } else { ++ if (__netif_subqueue_stopped(padapter->pnetdev, queue)) ++ netif_wake_subqueue(padapter->pnetdev, queue); ++ } ++ ++ dev_kfree_skb_any(pkt); ++} ++ ++void rtw_os_xmit_complete(struct adapter *padapter, struct xmit_frame *pxframe) ++{ ++ if (pxframe->pkt) ++ rtw_os_pkt_complete(padapter, pxframe->pkt); ++ ++ pxframe->pkt = NULL; ++} ++ ++void rtw_os_xmit_schedule(struct adapter *padapter) ++{ ++ struct adapter *pri_adapter = padapter; ++ ++ if (!padapter) ++ return; ++ ++ if (!list_empty(&padapter->xmitpriv.pending_xmitbuf_queue.queue)) ++ up(&pri_adapter->xmitpriv.xmit_sema); ++} ++ ++static void rtw_check_xmit_resource(struct adapter *padapter, _pkt *pkt) ++{ ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ u16 queue; ++ ++ queue = skb_get_queue_mapping(pkt); ++ if (padapter->registrypriv.wifi_spec) { ++ /* No free space for Tx, tx_worker is too slow */ ++ if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD) { ++ /* DBG_871X("%s(): stop netif_subqueue[%d]\n", __func__, queue); */ ++ netif_stop_subqueue(padapter->pnetdev, queue); ++ } ++ } else { ++ if (pxmitpriv->free_xmitframe_cnt<=4) { ++ if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue))) ++ netif_stop_subqueue(padapter->pnetdev, queue); ++ } ++ } ++} ++ ++static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb) ++{ ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct list_head *phead, *plist; ++ struct sk_buff *newskb; ++ struct sta_info *psta = NULL; ++ u8 chk_alive_num = 0; ++ char chk_alive_list[NUM_STA]; ++ u8 bc_addr[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ u8 null_addr[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ++ ++ int i; ++ s32 res; ++ ++ DBG_COUNTER(padapter->tx_logs.os_tx_m2u); ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ phead = &pstapriv->asoc_list; ++ plist = get_next(phead); ++ ++ /* free sta asoc_queue */ ++ while (phead != plist) { ++ int stainfo_offset; ++ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); ++ plist = get_next(plist); ++ ++ stainfo_offset = rtw_stainfo_offset(pstapriv, psta); ++ if (stainfo_offset_valid(stainfo_offset)) { ++ chk_alive_list[chk_alive_num++] = stainfo_offset; ++ } ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ for (i = 0; i < chk_alive_num; i++) { ++ psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]); ++ if (!(psta->state &_FW_LINKED)) ++ { ++ DBG_COUNTER(padapter->tx_logs.os_tx_m2u_ignore_fw_linked); ++ continue; ++ } ++ ++ /* avoid come from STA1 and send back STA1 */ ++ if (!memcmp(psta->hwaddr, &skb->data[6], 6) ++ || !memcmp(psta->hwaddr, null_addr, 6) ++ || !memcmp(psta->hwaddr, bc_addr, 6) ++ ) ++ { ++ DBG_COUNTER(padapter->tx_logs.os_tx_m2u_ignore_self); ++ continue; ++ } ++ ++ DBG_COUNTER(padapter->tx_logs.os_tx_m2u_entry); ++ ++ newskb = rtw_skb_copy(skb); ++ ++ if (newskb) { ++ memcpy(newskb->data, psta->hwaddr, 6); ++ res = rtw_xmit(padapter, &newskb); ++ if (res < 0) { ++ DBG_COUNTER(padapter->tx_logs.os_tx_m2u_entry_err_xmit); ++ DBG_871X("%s()-%d: rtw_xmit() return error!\n", __func__, __LINE__); ++ pxmitpriv->tx_drop++; ++ dev_kfree_skb_any(newskb); ++ } ++ } else { ++ DBG_COUNTER(padapter->tx_logs.os_tx_m2u_entry_err_skb); ++ DBG_871X("%s-%d: rtw_skb_copy() failed!\n", __func__, __LINE__); ++ pxmitpriv->tx_drop++; ++ /* dev_kfree_skb_any(skb); */ ++ return false; /* Caller shall tx this multicast frame via normal way. */ ++ } ++ } ++ ++ dev_kfree_skb_any(skb); ++ return true; ++} ++ ++int _rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev); ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ s32 res = 0; ++ ++ DBG_COUNTER(padapter->tx_logs.os_tx); ++ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n")); ++ ++ if (rtw_if_up(padapter) == false) { ++ DBG_COUNTER(padapter->tx_logs.os_tx_err_up); ++ RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit_entry: rtw_if_up fail\n")); ++ #ifdef DBG_TX_DROP_FRAME ++ DBG_871X("DBG_TX_DROP_FRAME %s if_up fail\n", __func__); ++ #endif ++ goto drop_packet; ++ } ++ ++ rtw_check_xmit_resource(padapter, pkt); ++ ++ if (!rtw_mc2u_disable ++ && check_fwstate(pmlmepriv, WIFI_AP_STATE) == true ++ && (IP_MCAST_MAC(pkt->data) ++ || ICMPV6_MCAST_MAC(pkt->data) ++ #ifdef CONFIG_TX_BCAST2UNI ++ || is_broadcast_mac_addr(pkt->data) ++ #endif ++ ) ++ && (padapter->registrypriv.wifi_spec == 0) ++ ) ++ { ++ if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME/4)) { ++ res = rtw_mlcst2unicst(padapter, pkt); ++ if (res == true) { ++ goto exit; ++ } ++ } else { ++ /* DBG_871X("Stop M2U(%d, %d)! ", pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmitbuf_cnt); */ ++ /* DBG_871X("!m2u); */ ++ DBG_COUNTER(padapter->tx_logs.os_tx_m2u_stop); ++ } ++ } ++ ++ res = rtw_xmit(padapter, &pkt); ++ if (res < 0) { ++ #ifdef DBG_TX_DROP_FRAME ++ DBG_871X("DBG_TX_DROP_FRAME %s rtw_xmit fail\n", __func__); ++ #endif ++ goto drop_packet; ++ } ++ ++ RT_TRACE(_module_xmit_osdep_c_, _drv_info_, ("rtw_xmit_entry: tx_pkts =%d\n", (u32)pxmitpriv->tx_pkts)); ++ goto exit; ++ ++drop_packet: ++ pxmitpriv->tx_drop++; ++ dev_kfree_skb_any(pkt); ++ RT_TRACE(_module_xmit_osdep_c_, _drv_notice_, ("rtw_xmit_entry: drop, tx_drop =%d\n", (u32)pxmitpriv->tx_drop)); ++ ++exit: ++ return 0; ++} ++ ++int rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev) ++{ ++ int ret = 0; ++ ++ if (pkt) { ++ rtw_mstat_update(MSTAT_TYPE_SKB, MSTAT_ALLOC_SUCCESS, pkt->truesize); ++ ret = _rtw_xmit_entry(pkt, pnetdev); ++ } ++ ++ return ret; ++} diff --git a/kernel/tools/perf/files/patches/mageia/3rd-viahss-0.92.patch b/kernel/tools/perf/files/patches/mageia/3rd-viahss-0.92.patch new file mode 100644 index 0000000000..bc9a567817 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-viahss-0.92.patch @@ -0,0 +1,189 @@ + 3rdparty/viahss/Kconfig | 14 +++++++ + 3rdparty/viahss/Makefile | 3 + + 3rdparty/viahss/README.html | 68 ++++++++++++++++++++++++++++++++++++ + 3rdparty/viahss/viahss.c | 83 ++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 168 insertions(+) +diff -Nurp linux-2.6.37/3rdparty/viahss/Kconfig linux-2.6.37.3rdparty/3rdparty/viahss/Kconfig +--- linux-2.6.37/3rdparty/viahss/Kconfig 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/viahss/Kconfig 2003-12-01 01:53:51.000000000 +0200 +@@ -0,0 +1,14 @@ ++config VIAHSS ++ tristate "VIA High Speed Serial" ++ depends on SERIAL_CORE && m ++ ---help--- ++ VIA High Speed Serial is a little kernel module (1 KB) which enables ++ high speed serial port modes of VIA VT82C686A or VT82C686B ++ southbridge-equipped motherboards. With this module, you can use the ++ serial port at 230400 bit/s so that you can get the full 128000 bit/s ++ from ISDN-TA. The module has been tested with both 686A and 686B ++ chipsets. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called viahss. ++ +diff -Nurp linux-2.6.37/3rdparty/viahss/Makefile linux-2.6.37.3rdparty/3rdparty/viahss/Makefile +--- linux-2.6.37/3rdparty/viahss/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/viahss/Makefile 2003-12-01 01:43:23.000000000 +0200 +@@ -0,0 +1,3 @@ ++ ++obj-$(CONFIG_VIAHSS) += viahss.o ++ +diff -Nurp linux-2.6.37/3rdparty/viahss/README.html linux-2.6.37.3rdparty/3rdparty/viahss/README.html +--- linux-2.6.37/3rdparty/viahss/README.html 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/viahss/README.html 2003-12-01 01:58:23.000000000 +0200 +@@ -0,0 +1,68 @@ ++ ++ ++ ++ ++ High speed serial port for VIA VT82C686 chipsets for linux ++ ++ ++

Setting the serial port speed over 115,200bps

++
++If you have motherboard which has VIA VT82C686A or VT82C686B chipset ++you can set serial ports in high speed mode with this kernel module. ++I use module with external ISDN-TA and haven't had any problems ++so far but I cannot guarantee that you won't have buffer overflows if ++you use full 230K or 460K speed all the time (FIFO's are still 16550A size). ++ISDN with two channels maxes out at 128 Kb which means that it doesn't ++really stress serial ports at 230400. Unlike SHSMOD-patches you don't have ++to patch serial driver and module takes only 1KB of memory when it's ++loaded which should leave enough room for other programs. It should ++be also possible to make this work from userspace but accessing ++pci devices is so much easier from kernel. ++ ++

How to use module

++Get the package ++and compile it using included makefiles. ++

For 2.4

++If you have kernel in some other location than /usr/src/linux edit Makefile ++before compiling. You can also install module with "make install". After ++you have loaded module in kernel (use modprobe or insmod) you can set serial ++ports to use high speed modes with setserial.
++

For 2.5/2.6

++Copy Makefile-2.6 on top of Makefile and do make. After loading module set ++serial speed with setserial. (NOTE: This gives a warning on depracated ++method). ++ ++
++# setserial /dev/ttyS0 spd_cust divisor 0x8002 ++

++which sets COM1: speed to 230400. With 0x8001 you should get 460800 ++but I haven't tested it. If you want to use COM2: use ttyS1 instead of ttyS0. ++ ++After this you should set program which you are using to use 38400 bps ++speed which is now actually 230K or 460K. For more information check ++setserial man page (spd_cust). ++ ++You can use serial port work as normal if you do
++
++# setserial /dev/ttyS0 spd_normal

++After this you can also remove viahss module with rmmod if you need to. Module doesn't intefere with normal serial port usage so you can leave ++it loaded if you don't need that extra 1KB which module uses. ++

Download

++viahss-0.92.tar.gz ++ ++

Acknowledgments

++ ++Thanks to Kimmo Rintala for help with divisor settings.
++I also like to thank Jeff Garzik for help with VIA datasheets.
++Port to 2.5/2.6 by Kingsly John with the help of LWN ++ ++

Version History

++0.90 First release
++0.91 Fixed Makefile
++0.92 Fixed for 2.5/2.6
++ ++

Contact

++ ++You can reach me by email: jrauti@iki.fi ++ ++ +diff -Nurp linux-2.6.37/3rdparty/viahss/viahss.c linux-2.6.37.3rdparty/3rdparty/viahss/viahss.c +--- linux-2.6.37/3rdparty/viahss/viahss.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/viahss/viahss.c 2003-07-17 09:49:59.000000000 +0300 +@@ -0,0 +1,83 @@ ++/* ++ * VIA VT 82c686[AB] high speed serial port enabler ++ * Version 0.92 ++ * Copyright (c) 2000-2001 Juhani Rautiainen ++ * ++ * 0.92: ++ * Ported to 2.5/2.6 by Kingsly John ++ * - Corrected locking (no more cli() and sti()) ++ * - New makefile ++ * ++ * Can be freely distributed and used under the terms of the GNU GPL. ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++ ++const unsigned short confindex=0x3F0,confdata=0x3F1; ++const unsigned char spcidx=0xEE; ++ ++spinlock_t driver_lock = SPIN_LOCK_UNLOCKED; ++ ++static int __init viahss_init(void) ++{ ++ struct pci_dev *pcidev = NULL; ++ unsigned char confval,val; ++ pcidev = pci_find_device (PCI_VENDOR_ID_VIA,PCI_DEVICE_ID_VIA_82C686,NULL); ++ if (pcidev) { ++ spin_lock_irq(&driver_lock); ++ /* start config */ ++ pci_read_config_byte(pcidev,0x85,&confval); ++ confval |= 0x2; ++ pci_write_config_byte (pcidev, 0x85,confval); ++ /* activate high speed bits */ ++ outb(spcidx,confindex); /* set index */ ++ val = (unsigned char) inb(confdata); ++ val |= 0xC0; /* both ports on high speed*/ ++ outb (spcidx,confindex); ++ outb (val,confdata); ++ /*stop config*/ ++ confval &= ~0x2; ++ pci_write_config_byte(pcidev, 0x85, confval); ++ spin_unlock_irq(&driver_lock); ++ printk (KERN_INFO "VIA VT82C686[AB] serial port high speed enabled\n"); ++ } ++ else { ++ printk (KERN_INFO "Couldn't locate VIA chipset\n"); ++ return -ENODEV; ++ } ++ return 0; ++} ++ ++static void __exit viahss_exit(void) ++{ ++ struct pci_dev *pcidev = NULL; ++ unsigned char confval,val; ++ pcidev = pci_find_device (PCI_VENDOR_ID_VIA,PCI_DEVICE_ID_VIA_82C686,NULL); ++ if (pcidev) { ++ spin_lock_irq(&driver_lock); ++ /* start config */ ++ pci_read_config_byte(pcidev,0x85,&confval); ++ confval |= 0x2; ++ pci_write_config_byte (pcidev, 0x85,confval); ++ /* activate high speed bits */ ++ outb(spcidx,confindex); /* set index */ ++ val = (unsigned char) inb(confdata); ++ val &= ~0xC0; /* both ports off high speed*/ ++ outb (spcidx,confindex); ++ outb (val,confdata); ++ /*stop config*/ ++ confval &= ~0x2; ++ pci_write_config_byte(pcidev, 0x85, confval); ++ spin_unlock_irq(&driver_lock); ++ printk (KERN_INFO "VIA VT82C686[AB] serial port high speed disabled\n"); ++ } ++} ++ ++module_init(viahss_init); ++module_exit(viahss_exit); ++MODULE_DESCRIPTION("VIA VT82C686[AB] high speed serial port enabler"); ++MODULE_AUTHOR("Juhani Rautiainen "); diff --git a/kernel/tools/perf/files/patches/mageia/3rd-viahss-2.6.35-buildfix.patch b/kernel/tools/perf/files/patches/mageia/3rd-viahss-2.6.35-buildfix.patch new file mode 100644 index 0000000000..5ae42e926d --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-viahss-2.6.35-buildfix.patch @@ -0,0 +1,20 @@ +--- linux-2.6.35-rc6-git-mnb0.1/3rdparty/viahss/viahss.c.orig 2010-07-30 21:17:30.000000000 +0300 ++++ linux-2.6.35-rc6-git-mnb0.1/3rdparty/viahss/viahss.c 2010-07-30 23:10:21.324978822 +0300 +@@ -25,7 +25,7 @@ static int __init viahss_init(void) + { + struct pci_dev *pcidev = NULL; + unsigned char confval,val; +- pcidev = pci_find_device (PCI_VENDOR_ID_VIA,PCI_DEVICE_ID_VIA_82C686,NULL); ++ pcidev = pci_get_device (PCI_VENDOR_ID_VIA,PCI_DEVICE_ID_VIA_82C686,NULL); + if (pcidev) { + spin_lock_irq(&driver_lock); + /* start config */ +@@ -55,7 +55,7 @@ static void __exit viahss_exit(void) + { + struct pci_dev *pcidev = NULL; + unsigned char confval,val; +- pcidev = pci_find_device (PCI_VENDOR_ID_VIA,PCI_DEVICE_ID_VIA_82C686,NULL); ++ pcidev = pci_get_device (PCI_VENDOR_ID_VIA,PCI_DEVICE_ID_VIA_82C686,NULL); + if (pcidev) { + spin_lock_irq(&driver_lock); + /* start config */ diff --git a/kernel/tools/perf/files/patches/mageia/3rd-viahss-3.0-buildfix.patch b/kernel/tools/perf/files/patches/mageia/3rd-viahss-3.0-buildfix.patch new file mode 100644 index 0000000000..7db738810a --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-viahss-3.0-buildfix.patch @@ -0,0 +1,19 @@ + +fix build with 3.0 + +Signed-off-by: Thomas Backlund + + 3rdparty/viahss/viahss.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/3rdparty/viahss/viahss.c.orig 2011-07-15 02:37:27.000000000 +0300 ++++ a/3rdparty/viahss/viahss.c 2011-07-15 13:48:13.204291256 +0300 +@@ -19,7 +19,7 @@ + const unsigned short confindex=0x3F0,confdata=0x3F1; + const unsigned char spcidx=0xEE; + +-spinlock_t driver_lock = SPIN_LOCK_UNLOCKED; ++DEFINE_SPINLOCK(driver_lock); + + static int __init viahss_init(void) + { diff --git a/kernel/tools/perf/files/patches/mageia/3rd-viahss-config.patch b/kernel/tools/perf/files/patches/mageia/3rd-viahss-config.patch new file mode 100644 index 0000000000..0d1bdbd3a0 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-viahss-config.patch @@ -0,0 +1,18 @@ +linux/config.h is gone in 2.6.21 + +--- + 3rdparty/viahss/viahss.c | 1 0 + 1 - 0 ! + 1 files changed, 1 deletion(-) + +Index: linux-2.6.21/3rdparty/viahss/viahss.c +=================================================================== +--- linux-2.6.21.orig/3rdparty/viahss/viahss.c 2003-07-17 08:49:59.000000000 +0200 ++++ linux-2.6.21/3rdparty/viahss/viahss.c 2007-05-14 17:06:56.000000000 +0200 +@@ -12,7 +12,6 @@ + */ + + #include +-#include + #include + #include + #include diff --git a/kernel/tools/perf/files/patches/mageia/3rd-viahss-module-license.patch b/kernel/tools/perf/files/patches/mageia/3rd-viahss-module-license.patch new file mode 100644 index 0000000000..540538f2f8 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rd-viahss-module-license.patch @@ -0,0 +1,7 @@ +--- linux-2.6.25/3rdparty/viahss/viahss.c.orig 2008-06-28 22:50:05.000000000 +0300 ++++ linux-2.6.25/3rdparty/viahss/viahss.c 2008-06-29 14:26:55.000000000 +0300 +@@ -80,3 +80,4 @@ module_init(viahss_init); + module_exit(viahss_exit); + MODULE_DESCRIPTION("VIA VT82C686[AB] high speed serial port enabler"); + MODULE_AUTHOR("Juhani Rautiainen "); ++MODULE_LICENSE("GPL"); diff --git a/kernel/tools/perf/files/patches/mageia/3rdparty.series b/kernel/tools/perf/files/patches/mageia/3rdparty.series new file mode 100644 index 0000000000..17ace736e0 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/3rdparty.series @@ -0,0 +1,3 @@ +# Mageia SVN does not like binaries in /packages tree +# it can still be used for out ov svn builds + diff --git a/kernel/tools/perf/files/patches/mageia/ACPI-video-Add-a-quirk-to-force-acpi-video-backlight.patch b/kernel/tools/perf/files/patches/mageia/ACPI-video-Add-a-quirk-to-force-acpi-video-backlight.patch new file mode 100644 index 0000000000..ff64a1e103 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/ACPI-video-Add-a-quirk-to-force-acpi-video-backlight.patch @@ -0,0 +1,40 @@ +From 61f9738d65094a6b18d22c7beb6bb8c3dc0606b9 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 26 Oct 2015 15:20:46 +0100 +Subject: [PATCH] ACPI / video: Add a quirk to force acpi-video backlight on + Dell XPS L421X + +Just like the Dell XPS 15 (L521X) the Dell XPS 14 (L421X) needs to use +the acpi-video backlight interface rather then the native one for backlight +control to work, add a quirk for this. + +Link: https://bugzilla.redhat.com/show_bug.cgi?id=1272633 +Signed-off-by: Hans de Goede +Signed-off-by: Rafael J. Wysocki +--- + drivers/acpi/video_detect.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c +index 0d3a384..daaf1c4 100644 +--- a/drivers/acpi/video_detect.c ++++ b/drivers/acpi/video_detect.c +@@ -233,6 +233,15 @@ static const struct dmi_system_id video_detect_dmi_table[] = { + }, + }, + { ++ /* https://bugzilla.redhat.com/show_bug.cgi?id=1272633 */ ++ .callback = video_detect_force_video, ++ .ident = "Dell XPS14 L421X", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"), ++ }, ++ }, ++ { + /* https://bugzilla.redhat.com/show_bug.cgi?id=1163574 */ + .callback = video_detect_force_video, + .ident = "Dell XPS15 L521X", +-- +2.3.10 + diff --git a/kernel/tools/perf/files/patches/mageia/Bluetooth-Add-support-of-13d3-3490-AR3012-device.patch b/kernel/tools/perf/files/patches/mageia/Bluetooth-Add-support-of-13d3-3490-AR3012-device.patch new file mode 100644 index 0000000000..851dcecd91 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/Bluetooth-Add-support-of-13d3-3490-AR3012-device.patch @@ -0,0 +1,57 @@ +From 12d868964f7352e8b18e755488f7265a93431de1 Mon Sep 17 00:00:00 2001 +From: Dmitry Tunin +Date: Tue, 12 Jul 2016 01:35:18 +0300 +Subject: [PATCH] Bluetooth: Add support of 13d3:3490 AR3012 device + +T: Bus=01 Lev=01 Prnt=01 Port=07 Cnt=05 Dev#= 5 Spd=12 MxCh= 0 +D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=13d3 ProdID=3490 Rev=00.01 +C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA +I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb + +BugLink: https://bugs.launchpad.net/bugs/1600623 + +Signed-off-by: Dmitry Tunin +Signed-off-by: Marcel Holtmann +Cc: stable@vger.kernel.org +--- + drivers/bluetooth/ath3k.c | 2 ++ + drivers/bluetooth/btusb.c | 1 + + 2 files changed, 3 insertions(+) + +diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c +index 2589468..fadba88 100644 +--- a/drivers/bluetooth/ath3k.c ++++ b/drivers/bluetooth/ath3k.c +@@ -123,6 +123,7 @@ static const struct usb_device_id ath3k_table[] = { + { USB_DEVICE(0x13d3, 0x3472) }, + { USB_DEVICE(0x13d3, 0x3474) }, + { USB_DEVICE(0x13d3, 0x3487) }, ++ { USB_DEVICE(0x13d3, 0x3490) }, + + /* Atheros AR5BBU12 with sflash firmware */ + { USB_DEVICE(0x0489, 0xE02C) }, +@@ -190,6 +191,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = { + { USB_DEVICE(0x13d3, 0x3472), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3487), .driver_info = BTUSB_ATH3012 }, ++ { USB_DEVICE(0x13d3, 0x3490), .driver_info = BTUSB_ATH3012 }, + + /* Atheros AR5BBU22 with sflash firmware */ + { USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 }, +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index f2e8fd7..811f9b9 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -237,6 +237,7 @@ static const struct usb_device_id blacklist_table[] = { + { USB_DEVICE(0x13d3, 0x3472), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3487), .driver_info = BTUSB_ATH3012 }, ++ { USB_DEVICE(0x13d3, 0x3490), .driver_info = BTUSB_ATH3012 }, + + /* Atheros AR5BBU12 with sflash firmware */ + { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, +-- +2.9.2 + diff --git a/kernel/tools/perf/files/patches/mageia/HID-uhid-fix-timeout-when-probe-races-with-IO.patch b/kernel/tools/perf/files/patches/mageia/HID-uhid-fix-timeout-when-probe-races-with-IO.patch new file mode 100644 index 0000000000..c166ab8dc9 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/HID-uhid-fix-timeout-when-probe-races-with-IO.patch @@ -0,0 +1,116 @@ +From 67f8ecc550b5bda03335f845dc869b8501d25fd0 Mon Sep 17 00:00:00 2001 +From: Roderick Colenbrander +Date: Wed, 18 May 2016 13:11:09 -0700 +Subject: [PATCH] HID: uhid: fix timeout when probe races with IO + +Many devices use userspace bluetooth stacks like BlueZ or Bluedroid in combination +with uhid. If any of these stacks is used with a HID device for which the driver +performs a HID request as part .probe (or technically another HID operation), +this results in a deadlock situation. The deadlock results in a 5 second timeout +for I/O operations in HID drivers, so isn't fatal, but none of the I/O operations +have a chance of succeeding. + +The root cause for the problem is that uhid only allows for one request to be +processed at a time per uhid instance and locks out other operations. This means +that if a user space is creating a new HID device through 'UHID_CREATE', which +ultimately triggers '.probe' through the HID layer. Then any HID request e.g. a +read for calibration data would trigger a HID operation on uhid again, but it +won't go out to userspace, because it is still stuck in UHID_CREATE. +In addition bluetooth stacks are typically single threaded, so they wouldn't be +able to handle any requests while waiting on uhid. + +Lucikly the UHID spec is somewhat flexible and allows for fixing the issue, +without breaking user space. The idea which the patch implements as discussed +with David Herrmann is to decouple adding of a hid device (which triggers .probe) +from UHID_CREATE. The work will kick off roughly once UHID_CREATE completed (or +else will wait a tiny bit of time in .probe for a lock). A HID driver has to call +HID to call 'hid_hw_start()' as part of .probe once it is ready for I/O, which +triggers UHID_START to user space. Any HID operations should function now within +.probe and won't deadlock because userspace is stuck on UHID_CREATE. + +We verified this patch on Bluedroid with Android 6.0 and on desktop Linux with +BlueZ stacks. Prior to the patch they had the deadlock issue. + +[jkosina@suse.cz: reword subject] +Signed-off-by: Roderick Colenbrander +Cc: stable@vger.kernel.org +Signed-off-by: Jiri Kosina +--- + drivers/hid/uhid.c | 33 ++++++++++++++++++++++++--------- + 1 file changed, 24 insertions(+), 9 deletions(-) + +diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c +index 16b6f11..99ec3ff 100644 +--- a/drivers/hid/uhid.c ++++ b/drivers/hid/uhid.c +@@ -51,10 +51,26 @@ struct uhid_device { + u32 report_id; + u32 report_type; + struct uhid_event report_buf; ++ struct work_struct worker; + }; + + static struct miscdevice uhid_misc; + ++static void uhid_device_add_worker(struct work_struct *work) ++{ ++ struct uhid_device *uhid = container_of(work, struct uhid_device, worker); ++ int ret; ++ ++ ret = hid_add_device(uhid->hid); ++ if (ret) { ++ hid_err(uhid->hid, "Cannot register HID device: error %d\n", ret); ++ ++ hid_destroy_device(uhid->hid); ++ uhid->hid = NULL; ++ uhid->running = false; ++ } ++} ++ + static void uhid_queue(struct uhid_device *uhid, struct uhid_event *ev) + { + __u8 newhead; +@@ -498,18 +514,14 @@ static int uhid_dev_create2(struct uhid_device *uhid, + uhid->hid = hid; + uhid->running = true; + +- ret = hid_add_device(hid); +- if (ret) { +- hid_err(hid, "Cannot register HID device\n"); +- goto err_hid; +- } ++ /* Adding of a HID device is done through a worker, to allow HID drivers ++ * which use feature requests during .probe to work, without they would ++ * be blocked on devlock, which is held by uhid_char_write. ++ */ ++ schedule_work(&uhid->worker); + + return 0; + +-err_hid: +- hid_destroy_device(hid); +- uhid->hid = NULL; +- uhid->running = false; + err_free: + kfree(uhid->rd_data); + uhid->rd_data = NULL; +@@ -550,6 +562,8 @@ static int uhid_dev_destroy(struct uhid_device *uhid) + uhid->running = false; + wake_up_interruptible(&uhid->report_wait); + ++ cancel_work_sync(&uhid->worker); ++ + hid_destroy_device(uhid->hid); + kfree(uhid->rd_data); + +@@ -612,6 +626,7 @@ static int uhid_char_open(struct inode *inode, struct file *file) + init_waitqueue_head(&uhid->waitq); + init_waitqueue_head(&uhid->report_wait); + uhid->running = false; ++ INIT_WORK(&uhid->worker, uhid_device_add_worker); + + file->private_data = uhid; + nonseekable_open(inode, file); +-- +2.9.2 + diff --git a/kernel/tools/perf/files/patches/mageia/Revert-cpufreq-pcc-Enable-autoload-of-pcc-cpufreq-fo.patch b/kernel/tools/perf/files/patches/mageia/Revert-cpufreq-pcc-Enable-autoload-of-pcc-cpufreq-fo.patch new file mode 100644 index 0000000000..c3fffdfa58 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/Revert-cpufreq-pcc-Enable-autoload-of-pcc-cpufreq-fo.patch @@ -0,0 +1,32 @@ +From 88299efb05387c2c94120fdc9661aab2ec3a1ad8 Mon Sep 17 00:00:00 2001 +From: Thomas Backlund +Date: Fri, 3 Apr 2015 00:10:34 +0259 +Subject: [PATCH] Revert "cpufreq: pcc: Enable autoload of pcc-cpufreq for ACPI + processors" + +This reverts commit 7e7e8fe69820c6fa31395dbbd8e348e3c69cd2a9. +--- + drivers/cpufreq/pcc-cpufreq.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c +index 2a0d589..4d2c8e8 100644 +--- a/drivers/cpufreq/pcc-cpufreq.c ++++ b/drivers/cpufreq/pcc-cpufreq.c +@@ -603,13 +603,6 @@ static void __exit pcc_cpufreq_exit(void) + free_percpu(pcc_cpu_info); + } + +-static const struct acpi_device_id processor_device_ids[] = { +- {ACPI_PROCESSOR_OBJECT_HID, }, +- {ACPI_PROCESSOR_DEVICE_HID, }, +- {}, +-}; +-MODULE_DEVICE_TABLE(acpi, processor_device_ids); +- + MODULE_AUTHOR("Matthew Garrett, Naga Chumbalkar"); + MODULE_VERSION(PCC_VERSION); + MODULE_DESCRIPTION("Processor Clocking Control interface driver"); +-- +2.3.1 + diff --git a/kernel/tools/perf/files/patches/mageia/Revert-cpufreq-pcc-cpufreq-update-default-value-of-c.patch b/kernel/tools/perf/files/patches/mageia/Revert-cpufreq-pcc-cpufreq-update-default-value-of-c.patch new file mode 100644 index 0000000000..fa50aa8f2e --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/Revert-cpufreq-pcc-cpufreq-update-default-value-of-c.patch @@ -0,0 +1,75 @@ +From da7d3abe1c9e5ebac2cf86f97e9e89888a5e2094 Mon Sep 17 00:00:00 2001 +From: Andreas Herrmann +Date: Fri, 22 Jul 2016 17:14:11 +0200 +Subject: [PATCH] Revert "cpufreq: pcc-cpufreq: update default value of + cpuinfo_transition_latency" + +This reverts commit 790d849bf811a8ab5d4cd2cce0f6fda92f6aebf2. + +Using a v4.7-rc7 kernel on a HP ProLiant triggered following messages + + pcc-cpufreq: (v1.10.00) driver loaded with frequency limits: 1200 MHz, 2800 MHz + cpufreq: ondemand governor failed, too long transition latency of HW, fallback to performance governor + +The last line was shown for each CPU in the system. +Testing v4.5 (where commit 790d849b was integrated) triggered +similar messages. Same behaviour on a 2nd HP Proliant system. + +So commit 790d849bf (cpufreq: pcc-cpufreq: update default value of +cpuinfo_transition_latency) causes the system to use performance +governor which, I guess, was not the intention of the patch. + +Enabling debug output in pcc-cpufreq provides following verbose output: + + pcc-cpufreq: (v1.10.00) driver loaded with frequency limits: 1200 MHz, 2800 MHz + pcc_get_offset: for CPU 0: pcc_cpu_data input_offset: 0x44, pcc_cpu_data output_offset: 0x48 + init: policy->max is 2800000, policy->min is 1200000 + get: get_freq for CPU 0 + get: SUCCESS: (virtual) output_offset for cpu 0 is 0xffffc9000d7c0048, contains a value of: 0xff06. Speed is: 168000 MHz + cpufreq: ondemand governor failed, too long transition latency of HW, fallback to performance governor + target: CPU 0 should go to target freq: 2800000 (virtual) input_offset is 0xffffc9000d7c0044 + target: was SUCCESSFUL for cpu 0 + +I am asking to revert 790d849bf to re-enable usage of ondemand +governor with pcc-cpufreq. + +Fixes: 790d849bf (cpufreq: pcc-cpufreq: update default value of cpuinfo_transition_latency) +CC: # 4.5+ +Signed-off-by: Andreas Herrmann +Signed-off-by: Rafael J. Wysocki +--- + Documentation/cpu-freq/pcc-cpufreq.txt | 4 ++-- + drivers/cpufreq/pcc-cpufreq.c | 2 -- + 2 files changed, 2 insertions(+), 4 deletions(-) + +diff --git a/Documentation/cpu-freq/pcc-cpufreq.txt b/Documentation/cpu-freq/pcc-cpufreq.txt +index 0a94224..9e3c3b3 100644 +--- a/Documentation/cpu-freq/pcc-cpufreq.txt ++++ b/Documentation/cpu-freq/pcc-cpufreq.txt +@@ -159,8 +159,8 @@ to be strictly associated with a P-state. + + 2.2 cpuinfo_transition_latency: + ------------------------------- +-The cpuinfo_transition_latency field is CPUFREQ_ETERNAL. The PCC specification +-does not include a field to expose this value currently. ++The cpuinfo_transition_latency field is 0. The PCC specification does ++not include a field to expose this value currently. + + 2.3 cpuinfo_cur_freq: + --------------------- +diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c +index a7ecb9a..3f0ce2a 100644 +--- a/drivers/cpufreq/pcc-cpufreq.c ++++ b/drivers/cpufreq/pcc-cpufreq.c +@@ -555,8 +555,6 @@ static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy) + policy->min = policy->cpuinfo.min_freq = + ioread32(&pcch_hdr->minimum_frequency) * 1000; + +- policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; +- + pr_debug("init: policy->max is %d, policy->min is %d\n", + policy->max, policy->min); + out: +-- +2.9.2 + diff --git a/kernel/tools/perf/files/patches/mageia/Revert-ipmi-Start-the-timer-and-thread-on-internal-m.patch b/kernel/tools/perf/files/patches/mageia/Revert-ipmi-Start-the-timer-and-thread-on-internal-m.patch new file mode 100644 index 0000000000..965e5c74b8 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/Revert-ipmi-Start-the-timer-and-thread-on-internal-m.patch @@ -0,0 +1,197 @@ +From 43034bc4606f1f21186ca6fe27bc0448159d5e00 Mon Sep 17 00:00:00 2001 +From: Thomas Backlund +Date: Thu, 10 Mar 2016 15:44:13 +0200 +Subject: [PATCH] Revert "ipmi: Start the timer and thread on internal msgs" + +This reverts commit 0cfec916e86d881e209de4b4ae9959a6271e6660. + +It's reported on ipmi list that Dell R720xd servers will always panic +on dell ipmi services load + +Reverting this fixes the issue. + +Signed-off-by: Thomas Backlund + +--- + drivers/char/ipmi/ipmi_si_intf.c | 73 ++++++++++++++++------------------------ + 1 file changed, 29 insertions(+), 44 deletions(-) + +diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c +index 4cc72fa..f667be8 100644 +--- a/drivers/char/ipmi/ipmi_si_intf.c ++++ b/drivers/char/ipmi/ipmi_si_intf.c +@@ -412,42 +412,18 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) + return rv; + } + +-static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val) +-{ +- smi_info->last_timeout_jiffies = jiffies; +- mod_timer(&smi_info->si_timer, new_val); +- smi_info->timer_running = true; +-} +- +-/* +- * Start a new message and (re)start the timer and thread. +- */ +-static void start_new_msg(struct smi_info *smi_info, unsigned char *msg, +- unsigned int size) +-{ +- smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES); +- +- if (smi_info->thread) +- wake_up_process(smi_info->thread); +- +- smi_info->handlers->start_transaction(smi_info->si_sm, msg, size); +-} +- +-static void start_check_enables(struct smi_info *smi_info, bool start_timer) ++static void start_check_enables(struct smi_info *smi_info) + { + unsigned char msg[2]; + + msg[0] = (IPMI_NETFN_APP_REQUEST << 2); + msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD; + +- if (start_timer) +- start_new_msg(smi_info, msg, 2); +- else +- smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2); ++ smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2); + smi_info->si_state = SI_CHECKING_ENABLES; + } + +-static void start_clear_flags(struct smi_info *smi_info, bool start_timer) ++static void start_clear_flags(struct smi_info *smi_info) + { + unsigned char msg[3]; + +@@ -456,10 +432,7 @@ static void start_clear_flags(struct smi_info *smi_info, bool start_timer) + msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD; + msg[2] = WDT_PRE_TIMEOUT_INT; + +- if (start_timer) +- start_new_msg(smi_info, msg, 3); +- else +- smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3); ++ smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3); + smi_info->si_state = SI_CLEARING_FLAGS; + } + +@@ -469,8 +442,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info) + smi_info->curr_msg->data[1] = IPMI_GET_MSG_CMD; + smi_info->curr_msg->data_size = 2; + +- start_new_msg(smi_info, smi_info->curr_msg->data, +- smi_info->curr_msg->data_size); ++ smi_info->handlers->start_transaction( ++ smi_info->si_sm, ++ smi_info->curr_msg->data, ++ smi_info->curr_msg->data_size); + smi_info->si_state = SI_GETTING_MESSAGES; + } + +@@ -480,11 +455,20 @@ static void start_getting_events(struct smi_info *smi_info) + smi_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD; + smi_info->curr_msg->data_size = 2; + +- start_new_msg(smi_info, smi_info->curr_msg->data, +- smi_info->curr_msg->data_size); ++ smi_info->handlers->start_transaction( ++ smi_info->si_sm, ++ smi_info->curr_msg->data, ++ smi_info->curr_msg->data_size); + smi_info->si_state = SI_GETTING_EVENTS; + } + ++static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val) ++{ ++ smi_info->last_timeout_jiffies = jiffies; ++ mod_timer(&smi_info->si_timer, new_val); ++ smi_info->timer_running = true; ++} ++ + /* + * When we have a situtaion where we run out of memory and cannot + * allocate messages, we just leave them in the BMC and run the system +@@ -494,11 +478,11 @@ static void start_getting_events(struct smi_info *smi_info) + * Note that we cannot just use disable_irq(), since the interrupt may + * be shared. + */ +-static inline bool disable_si_irq(struct smi_info *smi_info, bool start_timer) ++static inline bool disable_si_irq(struct smi_info *smi_info) + { + if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { + smi_info->interrupt_disabled = true; +- start_check_enables(smi_info, start_timer); ++ start_check_enables(smi_info); + return true; + } + return false; +@@ -508,7 +492,7 @@ static inline bool enable_si_irq(struct smi_info *smi_info) + { + if ((smi_info->irq) && (smi_info->interrupt_disabled)) { + smi_info->interrupt_disabled = false; +- start_check_enables(smi_info, true); ++ start_check_enables(smi_info); + return true; + } + return false; +@@ -526,7 +510,7 @@ static struct ipmi_smi_msg *alloc_msg_handle_irq(struct smi_info *smi_info) + + msg = ipmi_alloc_smi_msg(); + if (!msg) { +- if (!disable_si_irq(smi_info, true)) ++ if (!disable_si_irq(smi_info)) + smi_info->si_state = SI_NORMAL; + } else if (enable_si_irq(smi_info)) { + ipmi_free_smi_msg(msg); +@@ -542,7 +526,7 @@ static void handle_flags(struct smi_info *smi_info) + /* Watchdog pre-timeout */ + smi_inc_stat(smi_info, watchdog_pretimeouts); + +- start_clear_flags(smi_info, true); ++ start_clear_flags(smi_info); + smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT; + if (smi_info->intf) + ipmi_smi_watchdog_pretimeout(smi_info->intf); +@@ -895,7 +879,8 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, + msg[0] = (IPMI_NETFN_APP_REQUEST << 2); + msg[1] = IPMI_GET_MSG_FLAGS_CMD; + +- start_new_msg(smi_info, msg, 2); ++ smi_info->handlers->start_transaction( ++ smi_info->si_sm, msg, 2); + smi_info->si_state = SI_GETTING_FLAGS; + goto restart; + } +@@ -925,7 +910,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, + * disable and messages disabled. + */ + if (smi_info->supports_event_msg_buff || smi_info->irq) { +- start_check_enables(smi_info, true); ++ start_check_enables(smi_info); + } else { + smi_info->curr_msg = alloc_msg_handle_irq(smi_info); + if (!smi_info->curr_msg) +@@ -3635,7 +3620,7 @@ static int try_smi_init(struct smi_info *new_smi) + * Start clearing the flags before we enable interrupts or the + * timer to avoid racing with the timer. + */ +- start_clear_flags(new_smi, false); ++ start_clear_flags(new_smi); + + /* + * IRQ is defined to be set when non-zero. req_events will +@@ -3930,7 +3915,7 @@ static void cleanup_one_si(struct smi_info *to_clean) + poll(to_clean); + schedule_timeout_uninterruptible(1); + } +- disable_si_irq(to_clean, false); ++ disable_si_irq(to_clean); + while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { + poll(to_clean); + schedule_timeout_uninterruptible(1); +-- +2.7.2 + diff --git a/kernel/tools/perf/files/patches/mageia/Revert-x86-mm-mtrr-Remove-kernel-internal-MTRR-inter.patch b/kernel/tools/perf/files/patches/mageia/Revert-x86-mm-mtrr-Remove-kernel-internal-MTRR-inter.patch new file mode 100644 index 0000000000..7ed760cfe5 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/Revert-x86-mm-mtrr-Remove-kernel-internal-MTRR-inter.patch @@ -0,0 +1,70 @@ +From ca45663819accf038291dbe2d67ed66dc48d714c Mon Sep 17 00:00:00 2001 +From: Thomas Backlund +Date: Sun, 29 Nov 2015 14:44:22 +0200 +Subject: [PATCH] Revert "x86/mm/mtrr: Remove kernel internal MTRR interfaces: + unexport mtrr_add() and mtrr_del()" + +This reverts commit 2baa891e42d84159b693eadd44f6fe1486285bdc. + +It currently breaks nvidia304 driver. + +Signed-of-by: Thomas Backlund +--- + Documentation/x86/mtrr.txt | 20 ++++---------------- + arch/x86/kernel/cpu/mtrr/main.c | 2 ++ + 2 files changed, 6 insertions(+), 16 deletions(-) + +diff --git a/Documentation/x86/mtrr.txt b/Documentation/x86/mtrr.txt +index dc3e703..860bc3a 100644 +--- a/Documentation/x86/mtrr.txt ++++ b/Documentation/x86/mtrr.txt +@@ -6,22 +6,10 @@ Luis R. Rodriguez - April 9, 2015 + =============================================================================== + Phasing out MTRR use + +-MTRR use is replaced on modern x86 hardware with PAT. Direct MTRR use by +-drivers on Linux is now completely phased out, device drivers should use +-arch_phys_wc_add() in combination with ioremap_wc() to make MTRR effective on +-non-PAT systems while a no-op but equally effective on PAT enabled systems. +- +-Even if Linux does not use MTRRs directly, some x86 platform firmware may still +-set up MTRRs early before booting the OS. They do this as some platform +-firmware may still have implemented access to MTRRs which would be controlled +-and handled by the platform firmware directly. An example of platform use of +-MTRRs is through the use of SMI handlers, one case could be for fan control, +-the platform code would need uncachable access to some of its fan control +-registers. Such platform access does not need any Operating System MTRR code in +-place other than mtrr_type_lookup() to ensure any OS specific mapping requests +-are aligned with platform MTRR setup. If MTRRs are only set up by the platform +-firmware code though and the OS does not make any specific MTRR mapping +-requests mtrr_type_lookup() should always return MTRR_TYPE_INVALID. ++MTRR use is replaced on modern x86 hardware with PAT. Over time the only type ++of effective MTRR that is expected to be supported will be for write-combining. ++As MTRR use is phased out device drivers should use arch_phys_wc_add() to make ++MTRR effective on non-PAT systems while a no-op on PAT enabled systems. + + For details refer to Documentation/x86/pat.txt. + +diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c +index f891b47..e7ed0d8 100644 +--- a/arch/x86/kernel/cpu/mtrr/main.c ++++ b/arch/x86/kernel/cpu/mtrr/main.c +@@ -448,6 +448,7 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, + return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, + increment); + } ++EXPORT_SYMBOL(mtrr_add); + + /** + * mtrr_del_page - delete a memory type region +@@ -536,6 +537,7 @@ int mtrr_del(int reg, unsigned long base, unsigned long size) + return -EINVAL; + return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT); + } ++EXPORT_SYMBOL(mtrr_del); + + /** + * arch_phys_wc_add - add a WC MTRR and handle errors if PAT is unavailable +-- +2.3.10 + diff --git a/kernel/tools/perf/files/patches/mageia/acpi-CLEVO-M360S-disable_acpi_irq.patch b/kernel/tools/perf/files/patches/mageia/acpi-CLEVO-M360S-disable_acpi_irq.patch new file mode 100644 index 0000000000..1ac3254c52 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/acpi-CLEVO-M360S-disable_acpi_irq.patch @@ -0,0 +1,28 @@ +Subject: CLEVO M360S acpi irq workaround + +Some Hardware vendor use CLEVO M360S Laptop OEM. +This acpi IRQ routing is not correct. we use normal IRQ routing for default. + +Signed-off-by: Go Taniguchi + +--- + arch/x86/kernel/acpi/boot.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -1615,6 +1615,14 @@ static struct dmi_system_id __initdata a + }, + }, + { ++ .callback = disable_acpi_irq, ++ .ident = "CLEVO M360S", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "CLEVO Co."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "M360S"), ++ }, ++ }, ++ { + /* + * Latest BIOS for IBM 600E (1.16) has bad pcinum + * for LPC bridge, which is needed for the PCI diff --git a/kernel/tools/perf/files/patches/mageia/acpi-processor-M720SR-limit-to-C2.patch b/kernel/tools/perf/files/patches/mageia/acpi-processor-M720SR-limit-to-C2.patch new file mode 100644 index 0000000000..a36086281c --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/acpi-processor-M720SR-limit-to-C2.patch @@ -0,0 +1,21 @@ +Limit Clevo M720SR to C2, going to C3 makes the machine freeze. This +needs more investigation, sis chipset/bios problem may be? + +Signed-off-by: Herton Ronaldo Krzesinski + +--- + drivers/acpi/processor_idle.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- linux-2.6.33-rc8-git4-t2/drivers/acpi/processor_idle.c.orig 2010-02-20 12:45:35.000000000 +0200 ++++ linux-2.6.33-rc8-git4-t2/drivers/acpi/processor_idle.c 2010-02-20 12:53:39.679099592 +0200 +@@ -110,6 +110,9 @@ static struct dmi_system_id __cpuinitdat + DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"), + DMI_MATCH(DMI_BIOS_VERSION,"SHE845M0.86C.0013.D.0302131307")}, + (void *)2}, ++ { set_max_cstate, "Clevo M720SR", { ++ DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"), ++ DMI_MATCH(DMI_PRODUCT_NAME,"M720SR")}, (void *)2}, + { set_max_cstate, "Pavilion zv5000", { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME,"Pavilion zv5000 (DS502A#ABA)")}, diff --git a/kernel/tools/perf/files/patches/mageia/ahci-add-new-Intel-device-IDs.patch b/kernel/tools/perf/files/patches/mageia/ahci-add-new-Intel-device-IDs.patch new file mode 100644 index 0000000000..27ba34e719 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/ahci-add-new-Intel-device-IDs.patch @@ -0,0 +1,37 @@ +From 56e74338a535cbcc2f2da08b1ea1a92920194364 Mon Sep 17 00:00:00 2001 +From: Alexandra Yates +Date: Tue, 3 Nov 2015 14:14:18 -0800 +Subject: [PATCH] ahci: add new Intel device IDs + +Adding Intel codename Lewisburg platform device IDs for SATA. + +Signed-off-by: Alexandra Yates +Signed-off-by: Tejun Heo +--- + drivers/ata/ahci.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c +index ff343c4..ff02bb4 100644 +--- a/drivers/ata/ahci.c ++++ b/drivers/ata/ahci.c +@@ -314,6 +314,16 @@ static const struct pci_device_id ahci_pci_tbl[] = { + { PCI_VDEVICE(INTEL, 0x1f37), board_ahci_avn }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f3e), board_ahci_avn }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f3f), board_ahci_avn }, /* Avoton RAID */ ++ { PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/ ++ { PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/ ++ { PCI_VDEVICE(INTEL, 0xa184), board_ahci }, /* Lewisburg RAID*/ ++ { PCI_VDEVICE(INTEL, 0xa204), board_ahci }, /* Lewisburg RAID*/ ++ { PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/ ++ { PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/ ++ { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/ ++ { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* Lewisburg RAID*/ ++ { PCI_VDEVICE(INTEL, 0xa18e), board_ahci }, /* Lewisburg RAID*/ ++ { PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Wellsburg RAID */ + { PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Wellsburg RAID */ + { PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */ +-- +2.3.10 + diff --git a/kernel/tools/perf/files/patches/mageia/arm-0001-ARM-bcm2835-dt-Add-the-ethernet-to-the-device-trees.patch b/kernel/tools/perf/files/patches/mageia/arm-0001-ARM-bcm2835-dt-Add-the-ethernet-to-the-device-trees.patch new file mode 100644 index 0000000000..0c14170730 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/arm-0001-ARM-bcm2835-dt-Add-the-ethernet-to-the-device-trees.patch @@ -0,0 +1,145 @@ +From f7c8d3a509e51f4a555371ded4957b225f1818ad Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Mon, 2 May 2016 09:06:51 +0200 +Subject: [PATCH] ARM: bcm2835: dt: Add the ethernet to the device trees + +The hub and the ethernet in its port 1 are hardwired on the board. + +Compared to the adapters that can be plugged into the USB ports, this +one has no serial EEPROM to store its MAC. Nevertheless, the Raspberry Pi +has the MAC address for this adapter in its ROM, accessible from its +firmware. + +U-Boot can read out the address and set the local-mac-address property of the +node with "ethernet" alias. Let's add the node so that U-Boot can do its +business. + +Model B rev2 and Model B+ entries were verified by me, the hierarchy and +pid/vid pair for the Version 2 was provided by Peter Chen. Original +Model B is a blind shot, though very likely correct. + +Signed-off-by: Lubomir Rintel +Acked-by: Stephen Warren +--- + arch/arm/boot/dts/bcm2835-rpi-b-plus.dts | 1 + + arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts | 1 + + arch/arm/boot/dts/bcm2835-rpi-b.dts | 1 + + arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 1 + + arch/arm/boot/dts/bcm283x-rpi-smsc9512.dtsi | 19 +++++++++++++++++++ + arch/arm/boot/dts/bcm283x-rpi-smsc9514.dtsi | 19 +++++++++++++++++++ + arch/arm/boot/dts/bcm283x.dtsi | 2 ++ + 7 files changed, 44 insertions(+) + create mode 100644 arch/arm/boot/dts/bcm283x-rpi-smsc9512.dtsi + create mode 100644 arch/arm/boot/dts/bcm283x-rpi-smsc9514.dtsi + +diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts +index ef54050..c3e01ce 100644 +--- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts ++++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts +@@ -1,6 +1,7 @@ + /dts-v1/; + #include "bcm2835.dtsi" + #include "bcm2835-rpi.dtsi" ++#include "bcm283x-rpi-smsc9514.dtsi" + + / { + compatible = "raspberrypi,model-b-plus", "brcm,bcm2835"; +diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts +index 86f1f2f..364086a 100644 +--- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts ++++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts +@@ -1,6 +1,7 @@ + /dts-v1/; + #include "bcm2835.dtsi" + #include "bcm2835-rpi.dtsi" ++#include "bcm283x-rpi-smsc9512.dtsi" + + / { + compatible = "raspberrypi,model-b-rev2", "brcm,bcm2835"; +diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts b/arch/arm/boot/dts/bcm2835-rpi-b.dts +index 4859e9d..4420b09 100644 +--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts ++++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts +@@ -1,6 +1,7 @@ + /dts-v1/; + #include "bcm2835.dtsi" + #include "bcm2835-rpi.dtsi" ++#include "bcm283x-rpi-smsc9512.dtsi" + + / { + compatible = "raspberrypi,model-b", "brcm,bcm2835"; +diff --git a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts +index ff94666..b975f29 100644 +--- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts ++++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts +@@ -1,6 +1,7 @@ + /dts-v1/; + #include "bcm2836.dtsi" + #include "bcm2835-rpi.dtsi" ++#include "bcm283x-rpi-smsc9514.dtsi" + + / { + compatible = "raspberrypi,2-model-b", "brcm,bcm2836"; +diff --git a/arch/arm/boot/dts/bcm283x-rpi-smsc9512.dtsi b/arch/arm/boot/dts/bcm283x-rpi-smsc9512.dtsi +new file mode 100644 +index 0000000..12c981e +--- /dev/null ++++ b/arch/arm/boot/dts/bcm283x-rpi-smsc9512.dtsi +@@ -0,0 +1,19 @@ ++/ { ++ aliases { ++ ethernet = ðernet; ++ }; ++}; ++ ++&usb { ++ usb1@1 { ++ compatible = "usb424,9512"; ++ reg = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ ethernet: usbether@1 { ++ compatible = "usb424,ec00"; ++ reg = <1>; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/bcm283x-rpi-smsc9514.dtsi b/arch/arm/boot/dts/bcm283x-rpi-smsc9514.dtsi +new file mode 100644 +index 0000000..3f0a56e +--- /dev/null ++++ b/arch/arm/boot/dts/bcm283x-rpi-smsc9514.dtsi +@@ -0,0 +1,19 @@ ++/ { ++ aliases { ++ ethernet = ðernet; ++ }; ++}; ++ ++&usb { ++ usb1@1 { ++ compatible = "usb424,9514"; ++ reg = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ ethernet: usbether@1 { ++ compatible = "usb424,ec00"; ++ reg = <1>; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi +index 8aaf193..04504b7 100644 +--- a/arch/arm/boot/dts/bcm283x.dtsi ++++ b/arch/arm/boot/dts/bcm283x.dtsi +@@ -287,6 +287,8 @@ + compatible = "brcm,bcm2835-usb"; + reg = <0x7e980000 0x10000>; + interrupts = <1 9>; ++ #address-cells = <1>; ++ #size-cells = <0>; + }; + + v3d: v3d@7ec00000 { diff --git a/kernel/tools/perf/files/patches/mageia/ata-prefer-ata-drivers-over-ide-drivers-when-both-are-built.patch b/kernel/tools/perf/files/patches/mageia/ata-prefer-ata-drivers-over-ide-drivers-when-both-are-built.patch new file mode 100644 index 0000000000..8ba0f02965 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/ata-prefer-ata-drivers-over-ide-drivers-when-both-are-built.patch @@ -0,0 +1,34 @@ +>From 9f04e51293b130474504216a477bb2a73cbf59e1 Mon Sep 17 00:00:00 2001 +From: Anssi Hannula +Date: Thu, 22 Mar 2012 22:29:11 +0200 +Subject: [PATCH] ata: prefer ata drivers over ide drivers when both are built + +Currently the old IDE drivers are preferred over ATA drivers when both +are built, since ide/ is listed first in drivers/Makefile and therefore +the IDE drivers end up before ATA drivers in modules.order which is used +by depmod/modprobe for module ordering. + +Change it so that ATA drivers are preferred over IDE driver by moving +the ide/ entry under ata/ in drivers/Makefile. + +Signed-off-by: Anssi Hannula +--- + drivers/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/Makefile b/drivers/Makefile +index 932e8bf..e8df3d0 100644 +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -69,10 +69,10 @@ obj-$(CONFIG_LIBNVDIMM) += nvdimm/ + obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/ + obj-$(CONFIG_NUBUS) += nubus/ + obj-y += macintosh/ +-obj-$(CONFIG_IDE) += ide/ + obj-$(CONFIG_SCSI) += scsi/ + obj-y += nvme/ + obj-$(CONFIG_ATA) += ata/ ++obj-$(CONFIG_IDE) += ide/ + obj-$(CONFIG_TARGET_CORE) += target/ + obj-$(CONFIG_MTD) += mtd/ + obj-$(CONFIG_SPI) += spi/ diff --git a/kernel/tools/perf/files/patches/mageia/base-cacheinfo-silence-DT-warnings.patch b/kernel/tools/perf/files/patches/mageia/base-cacheinfo-silence-DT-warnings.patch new file mode 100644 index 0000000000..241453ab9e --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/base-cacheinfo-silence-DT-warnings.patch @@ -0,0 +1,49 @@ + +Devicetree is enabled on 32bit kernels for OLPC support, +but this causes error messages: + +'Failed to find cpu0 device node' that breaks bootsplash. + +https://bugs.mageia.org/show_bug.cgi?id=16655#c39 +https://bugs.mageia.org/show_bug.cgi?id=17010 + +So hide them behind debug for cleaner boot. + +Signed-off-by: Thomas Backlund + + +--- linux/drivers/base/cacheinfo.c.orig ++++ linux/drivers/base/cacheinfo.c +@@ -53,12 +53,12 @@ + return 0; + + if (!cpu_dev) { +- pr_err("No cpu device for CPU %d\n", cpu); ++ pr_debug("No cpu device for CPU %d\n", cpu); + return -ENODEV; + } + np = cpu_dev->of_node; + if (!np) { +- pr_err("Failed to find cpu%d device node\n", cpu); ++ pr_debug("Failed to find cpu%d device node\n", cpu); + return -ENOENT; + } + +@@ -203,7 +203,7 @@ + */ + ret = cache_shared_cpu_map_setup(cpu); + if (ret) { +- pr_warn("Unable to detect cache hierarchy from DT for CPU %d\n", ++ pr_debug("Unable to detect cache hierarchy from DT for CPU %d\n", + cpu); + goto free_ci; + } +@@ -540,7 +540,7 @@ + rc = cache_add_dev(cpu); + if (rc) { + free_cache_attributes(cpu); +- pr_err("error populating cacheinfo..cpu%d\n", cpu); ++ pr_debug("error populating cacheinfo..cpu%d\n", cpu); + goto out; + } + } diff --git a/kernel/tools/perf/files/patches/mageia/block-Make-CFQ-default-to-IOPS-mode-on-SSDs.patch b/kernel/tools/perf/files/patches/mageia/block-Make-CFQ-default-to-IOPS-mode-on-SSDs.patch new file mode 100644 index 0000000000..b26bf71443 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/block-Make-CFQ-default-to-IOPS-mode-on-SSDs.patch @@ -0,0 +1,58 @@ +From 41c0126b3f22ef36b97b3c38b8f29569848a5ce2 Mon Sep 17 00:00:00 2001 +From: Tahsin Erdogan +Date: Tue, 19 May 2015 13:55:21 -0700 +Subject: block: Make CFQ default to IOPS mode on SSDs + +CFQ idling causes reduced IOPS throughput on non-rotational disks. +Since disk head seeking is not applicable to SSDs, it doesn't really +help performance by anticipating future near-by IO requests. + +By turning off idling (and switching to IOPS mode), we allow other +processes to dispatch IO requests down to the driver and so increase IO +throughput. + +Following FIO benchmark results were taken on a cloud SSD offering with +idling on and off: + +Idling iops avg-lat(ms) stddev bw +------------------------------------------------------ + On 7054 90.107 38.697 28217KB/s + Off 29255 21.836 11.730 117022KB/s + +fio --name=temp --size=100G --time_based --ioengine=libaio \ + --randrepeat=0 --direct=1 --invalidate=1 --verify=0 \ + --verify_fatal=0 --rw=randread --blocksize=4k --group_reporting=1 \ + --filename=/dev/sdb --runtime=10 --iodepth=64 --numjobs=10 + +And the following is from a local SSD run: + +Idling iops avg-lat(ms) stddev bw +------------------------------------------------------ + On 19320 33.043 14.068 77281KB/s + Off 21626 29.465 12.662 86507KB/s + +fio --name=temp --size=5G --time_based --ioengine=libaio \ + --randrepeat=0 --direct=1 --invalidate=1 --verify=0 \ + --verify_fatal=0 --rw=randread --blocksize=4k --group_reporting=1 \ + --filename=/fio_data --runtime=10 --iodepth=64 --numjobs=10 + +Reviewed-by: Nauman Rafique +Signed-off-by: Tahsin Erdogan +Signed-off-by: Jens Axboe + +diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c +index 5da8e6e..402be01 100644 +--- a/block/cfq-iosched.c ++++ b/block/cfq-iosched.c +@@ -4460,7 +4460,7 @@ static int cfq_init_queue(struct request_queue *q, struct elevator_type *e) + cfqd->cfq_slice[1] = cfq_slice_sync; + cfqd->cfq_target_latency = cfq_target_latency; + cfqd->cfq_slice_async_rq = cfq_slice_async_rq; +- cfqd->cfq_slice_idle = cfq_slice_idle; ++ cfqd->cfq_slice_idle = blk_queue_nonrot(q) ? 0 : cfq_slice_idle; + cfqd->cfq_group_idle = cfq_group_idle; + cfqd->cfq_latency = 1; + cfqd->hw_tag = -1; +-- +cgit v0.10.2 + diff --git a/kernel/tools/perf/files/patches/mageia/block-floppy-disable-pnp-modalias.patch b/kernel/tools/perf/files/patches/mageia/block-floppy-disable-pnp-modalias.patch new file mode 100644 index 0000000000..c994472a96 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/block-floppy-disable-pnp-modalias.patch @@ -0,0 +1,21 @@ + +Disable floppy autoloading as it makes systems without real hw, +but that has the pnp headers hang. + +See https://bugs.mageia.org/show_bug.cgi?id=4696 + +Signed-off-by: Thomas Backlund + +diff -Nurp linux-3.3.3-rc1/drivers/block/floppy.c.orig linux-3.3.3-rc1/drivers/block/floppy.c +--- linux-3.3.3-rc1/drivers/block/floppy.c.orig 2012-03-19 01:15:34.000000000 +0200 ++++ linux-3.3.3-rc1/drivers/block/floppy.c 2012-04-22 02:58:10.238498303 +0300 +@@ -4621,8 +4621,7 @@ static const struct pnp_device_id floppy + {"PNP0700", 0}, + {} + }; +- +-MODULE_DEVICE_TABLE(pnp, floppy_pnpids); ++/* MODULE_DEVICE_TABLE(pnp, floppy_pnpids); */ + + #else + diff --git a/kernel/tools/perf/files/patches/mageia/char-agp-intel-new-Q57-id.patch b/kernel/tools/perf/files/patches/mageia/char-agp-intel-new-Q57-id.patch new file mode 100644 index 0000000000..7093e9c01e --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/char-agp-intel-new-Q57-id.patch @@ -0,0 +1,35 @@ + +agp/intel: add new host bridge id for Q57 system + +Add new Host Bridge ID found on a Q57 based system from Positivo. I +don't know what abbreviation id for this would be best, may be Q_HB +instead of UNKNOWN currently used would be better. + +Signed-off-by: Herton Ronaldo Krzesinski + +[ rebased for 3.8-rc3 /tmb ] +Signed-off-by: Thomas Backlund + +Removed the parts of the patch that are already applied in the kernel by +the commit 67384fe3fd450536342330f684ea1f7dcaef8130: + "char/agp: add another Ironlake host bridge" + +Rediffed for kernel 3.10.24. + +Signed-off-by: Eugene A. Shatokhin + + drivers/char/agp/intel-gtt.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff -Nurp linux-3.8-rc3/drivers/char/agp/intel-gtt.c linux-3.8-rc3.q57/drivers/char/agp/intel-gtt.c +--- linux-3.8-rc3/drivers/char/agp/intel-gtt.c 2013-01-10 08:17:09.690594184 +0200 ++++ linux-3.8-rc3.q57/drivers/char/agp/intel-gtt.c 2013-01-10 08:38:56.649888839 +0200 +@@ -1303,6 +1303,8 @@ static const struct intel_gtt_driver_des + &g4x_gtt_driver }, + { PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, + "HD Graphics", &ironlake_gtt_driver }, ++ { PCI_DEVICE_ID_INTEL_IRONLAKE_D2_HB, ++ "HD Graphics", &ironlake_gtt_driver }, + { PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, + "HD Graphics", &ironlake_gtt_driver }, + { 0, NULL, NULL } diff --git a/kernel/tools/perf/files/patches/mageia/dm-raid-aliases.patch b/kernel/tools/perf/files/patches/mageia/dm-raid-aliases.patch new file mode 100644 index 0000000000..febdb720eb --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/dm-raid-aliases.patch @@ -0,0 +1,20 @@ + +This patch adds module aliases for matching the old dm-raid45 patch +by heinzm@redhat.com carried by kernel-tmb series in order to make +sure there is an upgrade path. + +Signed-off-by: Thomas Backlund + + drivers/md/dm-raid.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- linux-2.6.38.2-mga2/drivers/md/dm-raid.c.orig 2011-03-15 03:20:32.000000000 +0200 ++++ linux-2.6.38.2-mga2/drivers/md/dm-raid.c 2011-04-02 21:52:21.331302590 +0300 +@@ -693,5 +693,7 @@ MODULE_DESCRIPTION(DM_NAME " raid4/5/6 t + MODULE_ALIAS("dm-raid4"); + MODULE_ALIAS("dm-raid5"); + MODULE_ALIAS("dm-raid6"); ++MODULE_ALIAS("dm-raid45"); ++MODULE_ALIAS("dm-raid4-5"); + MODULE_AUTHOR("Neil Brown "); + MODULE_LICENSE("GPL"); diff --git a/kernel/tools/perf/files/patches/mageia/firewire-ieee1394-module-aliases.patch b/kernel/tools/perf/files/patches/mageia/firewire-ieee1394-module-aliases.patch new file mode 100644 index 0000000000..34c4d489d8 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/firewire-ieee1394-module-aliases.patch @@ -0,0 +1,29 @@ + +This patch adds missing module aliases for the old ieee1394 stack +to make it easier for endusers. + +Note: firewire-sbp2 and firewire-ohci already contains the needed aliases. + +Signed-off-by: Thomas Backlund + +diff -Nurp linux-2.6.38.4/drivers/firewire/core-transaction.c linux-2.6.38.4.fw/drivers/firewire/core-transaction.c +--- linux-2.6.38.4/drivers/firewire/core-transaction.c 2011-03-15 03:20:32.000000000 +0200 ++++ linux-2.6.38.4.fw/drivers/firewire/core-transaction.c 2011-04-22 16:22:28.461386738 +0300 +@@ -1174,6 +1174,9 @@ static struct fw_address_handler registe + MODULE_AUTHOR("Kristian Hoegsberg "); + MODULE_DESCRIPTION("Core IEEE1394 transaction logic"); + MODULE_LICENSE("GPL"); ++MODULE_ALIAS("ieee1394"); ++MODULE_ALIAS("raw1394"); ++MODULE_ALIAS("video1394"); + + static const u32 vendor_textual_descriptor[] = { + /* textual descriptor leaf () */ +diff -Nurp linux-2.6.38.4/drivers/firewire/net.c linux-2.6.38.4.fw/drivers/firewire/net.c +--- linux-2.6.38.4/drivers/firewire/net.c 2011-03-15 03:20:32.000000000 +0200 ++++ linux-2.6.38.4.fw/drivers/firewire/net.c 2011-04-22 16:20:34.008883920 +0300 +@@ -1719,3 +1719,4 @@ MODULE_AUTHOR("Jay Fenlason mnt->mnt_flags & MNT_NOEXEC) || + (path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC); + } ++EXPORT_SYMBOL_GPL(path_noexec); + + #ifdef CONFIG_USELIB + /* +diff -Nurp linux-4.7-rc6-aufs/fs/fcntl.c linux-4.7-rc6-aufs-mod/fs/fcntl.c +--- linux-4.7-rc6-aufs/fs/fcntl.c 2016-07-04 19:02:29.260286196 +0300 ++++ linux-4.7-rc6-aufs-mod/fs/fcntl.c 2016-07-04 19:03:53.654714970 +0300 +@@ -82,6 +82,7 @@ int setfl(int fd, struct file * filp, un + out: + return error; + } ++EXPORT_SYMBOL_GPL(setfl); + + static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, + int force) +diff -Nurp linux-4.7-rc6-aufs/fs/file_table.c linux-4.7-rc6-aufs-mod/fs/file_table.c +--- linux-4.7-rc6-aufs/fs/file_table.c 2016-05-16 01:43:13.000000000 +0300 ++++ linux-4.7-rc6-aufs-mod/fs/file_table.c 2016-07-04 19:03:53.654714970 +0300 +@@ -147,6 +147,7 @@ over: + } + return ERR_PTR(-ENFILE); + } ++EXPORT_SYMBOL_GPL(get_empty_filp); + + /** + * alloc_file - allocate and initialize a 'struct file' +@@ -258,6 +259,7 @@ void flush_delayed_fput(void) + { + delayed_fput(NULL); + } ++EXPORT_SYMBOL_GPL(flush_delayed_fput); + + static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput); + +@@ -300,6 +302,7 @@ void __fput_sync(struct file *file) + } + + EXPORT_SYMBOL(fput); ++EXPORT_SYMBOL_GPL(__fput_sync); + + void put_filp(struct file *file) + { +@@ -308,6 +311,7 @@ void put_filp(struct file *file) + file_free(file); + } + } ++EXPORT_SYMBOL_GPL(put_filp); + + void __init files_init(void) + { +diff -Nurp linux-4.7-rc6-aufs/fs/inode.c linux-4.7-rc6-aufs-mod/fs/inode.c +--- linux-4.7-rc6-aufs/fs/inode.c 2016-07-04 19:02:29.261286202 +0300 ++++ linux-4.7-rc6-aufs-mod/fs/inode.c 2016-07-04 20:51:39.805168596 +0300 +@@ -1600,6 +1600,7 @@ int update_time(struct inode *inode, str + + return update_time(inode, time, flags); + } ++EXPORT_SYMBOL_GPL(update_time); + + /** + * touch_atime - update the access time +diff -Nurp linux-4.7-rc6-aufs/fs/namespace.c linux-4.7-rc6-aufs-mod/fs/namespace.c +--- linux-4.7-rc6-aufs/fs/namespace.c 2016-07-04 17:58:15.729773645 +0300 ++++ linux-4.7-rc6-aufs-mod/fs/namespace.c 2016-07-04 19:03:53.654714970 +0300 +@@ -463,6 +463,7 @@ void __mnt_drop_write(struct vfsmount *m + mnt_dec_writers(real_mount(mnt)); + preempt_enable(); + } ++EXPORT_SYMBOL_GPL(__mnt_drop_write); + + /** + * mnt_drop_write - give up write access to a mount +@@ -1812,6 +1813,7 @@ int iterate_mounts(int (*f)(struct vfsmo + } + return 0; + } ++EXPORT_SYMBOL_GPL(iterate_mounts); + + static void cleanup_group_ids(struct mount *mnt, struct mount *end) + { +diff -Nurp linux-4.7-rc6-aufs/fs/notify/group.c linux-4.7-rc6-aufs-mod/fs/notify/group.c +--- linux-4.7-rc6-aufs/fs/notify/group.c 2016-07-04 17:58:15.742773641 +0300 ++++ linux-4.7-rc6-aufs-mod/fs/notify/group.c 2016-07-04 19:03:53.655714975 +0300 +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + #include "fsnotify.h" +@@ -81,6 +82,7 @@ void fsnotify_get_group(struct fsnotify_ + { + atomic_inc(&group->refcnt); + } ++EXPORT_SYMBOL_GPL(fsnotify_get_group); + + /* + * Drop a reference to a group. Free it if it's through. +@@ -90,6 +92,7 @@ void fsnotify_put_group(struct fsnotify_ + if (atomic_dec_and_test(&group->refcnt)) + fsnotify_final_destroy_group(group); + } ++EXPORT_SYMBOL_GPL(fsnotify_put_group); + + /* + * Create a new fsnotify_group and hold a reference for the group returned. +@@ -118,6 +121,7 @@ struct fsnotify_group *fsnotify_alloc_gr + + return group; + } ++EXPORT_SYMBOL_GPL(fsnotify_alloc_group); + + int fsnotify_fasync(int fd, struct file *file, int on) + { +diff -Nurp linux-4.7-rc6-aufs/fs/notify/mark.c linux-4.7-rc6-aufs-mod/fs/notify/mark.c +--- linux-4.7-rc6-aufs/fs/notify/mark.c 2016-07-04 17:58:15.742773641 +0300 ++++ linux-4.7-rc6-aufs-mod/fs/notify/mark.c 2016-07-04 19:03:53.655714975 +0300 +@@ -113,6 +113,7 @@ void fsnotify_put_mark(struct fsnotify_m + mark->free_mark(mark); + } + } ++EXPORT_SYMBOL_GPL(fsnotify_put_mark); + + /* Calculate mask of events for a list of marks */ + u32 fsnotify_recalc_mask(struct hlist_head *head) +@@ -230,6 +231,7 @@ void fsnotify_destroy_mark(struct fsnoti + mutex_unlock(&group->mark_mutex); + fsnotify_free_mark(mark); + } ++EXPORT_SYMBOL_GPL(fsnotify_destroy_mark); + + void fsnotify_destroy_marks(struct hlist_head *head, spinlock_t *lock) + { +@@ -415,6 +417,7 @@ err: + + return ret; + } ++EXPORT_SYMBOL_GPL(fsnotify_add_mark); + + int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, + struct inode *inode, struct vfsmount *mnt, int allow_dups) +@@ -521,6 +524,7 @@ void fsnotify_duplicate_mark(struct fsno + new->mask = old->mask; + new->free_mark = old->free_mark; + } ++EXPORT_SYMBOL_GPL(fsnotify_init_mark); + + /* + * Nothing fancy, just initialize lists and locks and counters. +diff -Nurp linux-4.7-rc6-aufs/fs/open.c linux-4.7-rc6-aufs-mod/fs/open.c +--- linux-4.7-rc6-aufs/fs/open.c 2016-07-04 17:58:15.746773640 +0300 ++++ linux-4.7-rc6-aufs-mod/fs/open.c 2016-07-04 19:03:53.655714975 +0300 +@@ -64,6 +64,7 @@ int do_truncate(struct dentry *dentry, l + inode_unlock(dentry->d_inode); + return ret; + } ++EXPORT_SYMBOL_GPL(do_truncate); + + long vfs_truncate(const struct path *path, loff_t length) + { +@@ -678,6 +679,7 @@ int open_check_o_direct(struct file *f) + } + return 0; + } ++EXPORT_SYMBOL_GPL(open_check_o_direct); + + static int do_dentry_open(struct file *f, + struct inode *inode, +diff -Nurp linux-4.7-rc6-aufs/fs/read_write.c linux-4.7-rc6-aufs-mod/fs/read_write.c +--- linux-4.7-rc6-aufs/fs/read_write.c 2016-07-04 19:02:29.262286207 +0300 ++++ linux-4.7-rc6-aufs-mod/fs/read_write.c 2016-07-04 19:03:53.655714975 +0300 +@@ -525,6 +525,7 @@ vfs_readf_t vfs_readf(struct file *file) + return new_sync_read; + return ERR_PTR(-ENOSYS); + } ++EXPORT_SYMBOL_GPL(vfs_readf); + + vfs_writef_t vfs_writef(struct file *file) + { +@@ -536,6 +537,7 @@ vfs_writef_t vfs_writef(struct file *fil + return new_sync_write; + return ERR_PTR(-ENOSYS); + } ++EXPORT_SYMBOL_GPL(vfs_writef); + + ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos) + { +diff -Nurp linux-4.7-rc6-aufs/fs/splice.c linux-4.7-rc6-aufs-mod/fs/splice.c +--- linux-4.7-rc6-aufs/fs/splice.c 2016-07-04 19:02:29.262286207 +0300 ++++ linux-4.7-rc6-aufs-mod/fs/splice.c 2016-07-04 19:03:53.656714979 +0300 +@@ -1124,6 +1124,7 @@ long do_splice_from(struct pipe_inode_in + + return splice_write(pipe, out, ppos, len, flags); + } ++EXPORT_SYMBOL_GPL(do_splice_from); + + /* + * Attempt to initiate a splice from a file to a pipe. +@@ -1153,6 +1154,7 @@ long do_splice_to(struct file *in, loff_ + + return splice_read(in, ppos, pipe, len, flags); + } ++EXPORT_SYMBOL_GPL(do_splice_to); + + /** + * splice_direct_to_actor - splices data directly between two non-pipes +diff -Nurp linux-4.7-rc6-aufs/fs/xattr.c linux-4.7-rc6-aufs-mod/fs/xattr.c +--- linux-4.7-rc6-aufs/fs/xattr.c 2016-07-04 17:58:15.754773638 +0300 ++++ linux-4.7-rc6-aufs-mod/fs/xattr.c 2016-07-04 19:03:53.656714979 +0300 +@@ -207,6 +207,7 @@ vfs_getxattr_alloc(struct dentry *dentry + *xattr_value = value; + return error; + } ++EXPORT_SYMBOL_GPL(vfs_getxattr_alloc); + + ssize_t + vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) +diff -Nurp linux-4.7-rc6-aufs/kernel/task_work.c linux-4.7-rc6-aufs-mod/kernel/task_work.c +--- linux-4.7-rc6-aufs/kernel/task_work.c 2016-05-16 01:43:13.000000000 +0300 ++++ linux-4.7-rc6-aufs-mod/kernel/task_work.c 2016-07-04 19:03:53.656714979 +0300 +@@ -118,3 +118,4 @@ void task_work_run(void) + } while (work); + } + } ++EXPORT_SYMBOL_GPL(task_work_run); +diff -Nurp linux-4.7-rc6-aufs/security/commoncap.c linux-4.7-rc6-aufs-mod/security/commoncap.c +--- linux-4.7-rc6-aufs/security/commoncap.c 2016-07-04 17:58:15.945773585 +0300 ++++ linux-4.7-rc6-aufs-mod/security/commoncap.c 2016-07-04 19:03:53.656714979 +0300 +@@ -1058,12 +1058,14 @@ int cap_mmap_addr(unsigned long addr) + } + return ret; + } ++EXPORT_SYMBOL_GPL(cap_mmap_addr); + + int cap_mmap_file(struct file *file, unsigned long reqprot, + unsigned long prot, unsigned long flags) + { + return 0; + } ++EXPORT_SYMBOL_GPL(cap_mmap_file); + + #ifdef CONFIG_SECURITY + +diff -Nurp linux-4.7-rc6-aufs/security/device_cgroup.c linux-4.7-rc6-aufs-mod/security/device_cgroup.c +--- linux-4.7-rc6-aufs/security/device_cgroup.c 2016-05-16 01:43:13.000000000 +0300 ++++ linux-4.7-rc6-aufs-mod/security/device_cgroup.c 2016-07-04 19:03:53.656714979 +0300 +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -849,6 +850,7 @@ int __devcgroup_inode_permission(struct + return __devcgroup_check_permission(type, imajor(inode), iminor(inode), + access); + } ++EXPORT_SYMBOL_GPL(__devcgroup_inode_permission); + + int devcgroup_inode_mknod(int mode, dev_t dev) + { +diff -Nurp linux-4.7-rc6-aufs/security/security.c linux-4.7-rc6-aufs-mod/security/security.c +--- linux-4.7-rc6-aufs/security/security.c 2016-07-04 17:58:15.948773584 +0300 ++++ linux-4.7-rc6-aufs-mod/security/security.c 2016-07-04 19:03:53.657714984 +0300 +@@ -434,6 +434,7 @@ int security_path_rmdir(const struct pat + return 0; + return call_int_hook(path_rmdir, 0, dir, dentry); + } ++EXPORT_SYMBOL_GPL(security_path_rmdir); + + int security_path_unlink(const struct path *dir, struct dentry *dentry) + { +@@ -450,6 +451,7 @@ int security_path_symlink(const struct p + return 0; + return call_int_hook(path_symlink, 0, dir, dentry, old_name); + } ++EXPORT_SYMBOL_GPL(security_path_symlink); + + int security_path_link(struct dentry *old_dentry, const struct path *new_dir, + struct dentry *new_dentry) +@@ -458,6 +460,7 @@ int security_path_link(struct dentry *ol + return 0; + return call_int_hook(path_link, 0, old_dentry, new_dir, new_dentry); + } ++EXPORT_SYMBOL_GPL(security_path_link); + + int security_path_rename(const struct path *old_dir, struct dentry *old_dentry, + const struct path *new_dir, struct dentry *new_dentry, +@@ -485,6 +488,7 @@ int security_path_truncate(const struct + return 0; + return call_int_hook(path_truncate, 0, path); + } ++EXPORT_SYMBOL_GPL(security_path_truncate); + + int security_path_chmod(const struct path *path, umode_t mode) + { +@@ -492,6 +496,7 @@ int security_path_chmod(const struct pat + return 0; + return call_int_hook(path_chmod, 0, path, mode); + } ++EXPORT_SYMBOL_GPL(security_path_chmod); + + int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid) + { +@@ -499,6 +504,7 @@ int security_path_chown(const struct pat + return 0; + return call_int_hook(path_chown, 0, path, uid, gid); + } ++EXPORT_SYMBOL_GPL(security_path_chown); + + int security_path_chroot(const struct path *path) + { +@@ -584,6 +590,7 @@ int security_inode_readlink(struct dentr + return 0; + return call_int_hook(inode_readlink, 0, dentry); + } ++EXPORT_SYMBOL_GPL(security_inode_readlink); + + int security_inode_follow_link(struct dentry *dentry, struct inode *inode, + bool rcu) +@@ -599,6 +606,7 @@ int security_inode_permission(struct ino + return 0; + return call_int_hook(inode_permission, 0, inode, mask); + } ++EXPORT_SYMBOL_GPL(security_inode_permission); + + int security_inode_setattr(struct dentry *dentry, struct iattr *attr) + { +@@ -737,6 +745,7 @@ int security_file_permission(struct file + + return fsnotify_perm(file, mask); + } ++EXPORT_SYMBOL_GPL(security_file_permission); + + int security_file_alloc(struct file *file) + { +@@ -796,6 +805,7 @@ int security_mmap_file(struct file *file + return ret; + return ima_file_mmap(file, prot); + } ++EXPORT_SYMBOL_GPL(security_mmap_file); + + int security_mmap_addr(unsigned long addr) + { diff --git a/kernel/tools/perf/files/patches/mageia/fs-aufs-4.7-ver-fix.patch b/kernel/tools/perf/files/patches/mageia/fs-aufs-4.7-ver-fix.patch new file mode 100644 index 0000000000..7ffd27e41f --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/fs-aufs-4.7-ver-fix.patch @@ -0,0 +1,16 @@ + +Mark as 4.7 so we can rebuild aufs tools with matching 4.7 check + +Signed-off-by: Thomas Backlund + +--- linux/include/uapi/linux/aufs_type.h.orig ++++ linux/include/uapi/linux/aufs_type.h +@@ -26,7 +26,7 @@ + + #include + +-#define AUFS_VERSION "4.x-rcN" ++#define AUFS_VERSION "4.7" + + /* todo? move this to linux-2.6.19/include/magic.h */ + #define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') diff --git a/kernel/tools/perf/files/patches/mageia/fs-aufs-4.7.patch b/kernel/tools/perf/files/patches/mageia/fs-aufs-4.7.patch new file mode 100644 index 0000000000..d2d09b831b --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/fs-aufs-4.7.patch @@ -0,0 +1,34482 @@ + + Documentation/ABI/testing/debugfs-aufs | 50 + + Documentation/ABI/testing/sysfs-aufs | 31 + + Documentation/filesystems/aufs/README | 392 +++++ + Documentation/filesystems/aufs/design/01intro.txt | 157 ++ + Documentation/filesystems/aufs/design/02struct.txt | 245 +++ + .../filesystems/aufs/design/03atomic_open.txt | 72 + + Documentation/filesystems/aufs/design/03lookup.txt | 100 ++ + Documentation/filesystems/aufs/design/04branch.txt | 61 + + .../filesystems/aufs/design/05wbr_policy.txt | 51 + + Documentation/filesystems/aufs/design/06fhsm.txt | 105 ++ + Documentation/filesystems/aufs/design/06mmap.txt | 59 + + Documentation/filesystems/aufs/design/06xattr.txt | 81 + + Documentation/filesystems/aufs/design/07export.txt | 45 + + Documentation/filesystems/aufs/design/08shwh.txt | 39 + + Documentation/filesystems/aufs/design/10dynop.txt | 34 + + MAINTAINERS | 13 + + drivers/block/loop.c | 18 + + fs/Kconfig | 1 + + fs/Makefile | 1 + + fs/aufs/Kconfig | 185 ++ + fs/aufs/Makefile | 36 + + fs/aufs/aufs.h | 46 + + fs/aufs/branch.c | 1393 +++++++++++++++ + fs/aufs/branch.h | 296 ++++ + fs/aufs/cpup.c | 1370 +++++++++++++++ + fs/aufs/cpup.h | 81 + + fs/aufs/dbgaufs.c | 419 +++++ + fs/aufs/dbgaufs.h | 35 + + fs/aufs/dcsub.c | 211 +++ + fs/aufs/dcsub.h | 123 ++ + fs/aufs/debug.c | 428 +++++ + fs/aufs/debug.h | 212 +++ + fs/aufs/dentry.c | 1115 ++++++++++++ + fs/aufs/dentry.h | 239 +++ + fs/aufs/dinfo.c | 539 ++++++ + fs/aufs/dir.c | 743 ++++++++ + fs/aufs/dir.h | 118 ++ + fs/aufs/dynop.c | 356 ++++ + fs/aufs/dynop.h | 61 + + fs/aufs/export.c | 824 +++++++++ + fs/aufs/f_op.c | 757 ++++++++ + fs/aufs/fhsm.c | 412 +++++ + fs/aufs/file.c | 830 +++++++++ + fs/aufs/file.h | 278 +++ + fs/aufs/finfo.c | 136 ++ + fs/aufs/fstype.h | 387 ++++ + fs/aufs/hfsnotify.c | 274 +++ + fs/aufs/hfsplus.c | 43 + + fs/aufs/hnotify.c | 697 ++++++++ + fs/aufs/i_op.c | 1401 +++++++++++++++ + fs/aufs/i_op_add.c | 911 ++++++++++ + fs/aufs/i_op_del.c | 498 ++++++ + fs/aufs/i_op_ren.c | 1002 +++++++++++ + fs/aufs/iinfo.c | 271 +++ + fs/aufs/inode.c | 504 ++++++ + fs/aufs/inode.h | 681 ++++++++ + fs/aufs/ioctl.c | 206 +++ + fs/aufs/loop.c | 133 ++ + fs/aufs/loop.h | 39 + + fs/aufs/magic.mk | 30 + + fs/aufs/module.c | 209 +++ + fs/aufs/module.h | 76 + + fs/aufs/mvdown.c | 691 ++++++++ + fs/aufs/opts.c | 1846 ++++++++++++++++++++ + fs/aufs/opts.h | 198 +++ + fs/aufs/plink.c | 489 ++++++ + fs/aufs/poll.c | 39 + + fs/aufs/posix_acl.c | 85 + + fs/aufs/procfs.c | 156 ++ + fs/aufs/rdu.c | 368 ++++ + fs/aufs/rwsem.h | 185 ++ + fs/aufs/sbinfo.c | 340 ++++ + fs/aufs/spl.h | 98 ++ + fs/aufs/super.c | 1026 +++++++++++ + fs/aufs/super.h | 625 +++++++ + fs/aufs/sysaufs.c | 91 + + fs/aufs/sysaufs.h | 88 + + fs/aufs/sysfs.c | 340 ++++ + fs/aufs/sysrq.c | 144 ++ + fs/aufs/vdir.c | 876 ++++++++++ + fs/aufs/vfsub.c | 871 +++++++++ + fs/aufs/vfsub.h | 297 ++++ + fs/aufs/wbr_policy.c | 752 ++++++++ + fs/aufs/whout.c | 1047 +++++++++++ + fs/aufs/whout.h | 72 + + fs/aufs/wkq.c | 205 +++ + fs/aufs/wkq.h | 82 + + fs/aufs/xattr.c | 332 ++++ + fs/aufs/xino.c | 1304 ++++++++++++++ + fs/dcache.c | 2 +- + fs/fcntl.c | 4 +- + fs/inode.c | 2 +- + fs/proc/base.c | 2 +- + fs/proc/nommu.c | 5 +- + fs/proc/task_mmu.c | 7 +- + fs/proc/task_nommu.c | 5 +- + fs/read_write.c | 22 + + fs/splice.c | 10 +- + include/linux/file.h | 1 + + include/linux/fs.h | 9 + + include/linux/mm.h | 22 + + include/linux/mm_types.h | 2 + + include/linux/splice.h | 6 + + include/uapi/linux/Kbuild | 1 + + include/uapi/linux/aufs_type.h | 406 +++++ + kernel/fork.c | 2 +- + mm/Makefile | 2 +- + mm/filemap.c | 2 +- + mm/memory.c | 2 +- + mm/mmap.c | 33 +- + mm/nommu.c | 10 +- + mm/prfile.c | 86 + + 112 files changed, 33420 insertions(+), 30 deletions(-) + +diff --git a/Documentation/ABI/testing/debugfs-aufs b/Documentation/ABI/testing/debugfs-aufs +new file mode 100644 +index 0000000..99642d1 +--- /dev/null ++++ b/Documentation/ABI/testing/debugfs-aufs +@@ -0,0 +1,50 @@ ++What: /debug/aufs/si_/ ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ Under /debug/aufs, a directory named si_ is created ++ per aufs mount, where is a unique id generated ++ internally. ++ ++What: /debug/aufs/si_/plink ++Date: Apr 2013 ++Contact: J. R. Okajima ++Description: ++ It has three lines and shows the information about the ++ pseudo-link. The first line is a single number ++ representing a number of buckets. The second line is a ++ number of pseudo-links per buckets (separated by a ++ blank). The last line is a single number representing a ++ total number of psedo-links. ++ When the aufs mount option 'noplink' is specified, it ++ will show "1\n0\n0\n". ++ ++What: /debug/aufs/si_/xib ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the consumed blocks by xib (External Inode Number ++ Bitmap), its block size and file size. ++ When the aufs mount option 'noxino' is specified, it ++ will be empty. About XINO files, see the aufs manual. ++ ++What: /debug/aufs/si_/xino0, xino1 ... xinoN ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the consumed blocks by xino (External Inode Number ++ Translation Table), its link count, block size and file ++ size. ++ When the aufs mount option 'noxino' is specified, it ++ will be empty. About XINO files, see the aufs manual. ++ ++What: /debug/aufs/si_/xigen ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the consumed blocks by xigen (External Inode ++ Generation Table), its block size and file size. ++ If CONFIG_AUFS_EXPORT is disabled, this entry will not ++ be created. ++ When the aufs mount option 'noxino' is specified, it ++ will be empty. About XINO files, see the aufs manual. +diff --git a/Documentation/ABI/testing/sysfs-aufs b/Documentation/ABI/testing/sysfs-aufs +new file mode 100644 +index 0000000..82f9518 +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-aufs +@@ -0,0 +1,31 @@ ++What: /sys/fs/aufs/si_/ ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ Under /sys/fs/aufs, a directory named si_ is created ++ per aufs mount, where is a unique id generated ++ internally. ++ ++What: /sys/fs/aufs/si_/br0, br1 ... brN ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the abolute path of a member directory (which ++ is called branch) in aufs, and its permission. ++ ++What: /sys/fs/aufs/si_/brid0, brid1 ... bridN ++Date: July 2013 ++Contact: J. R. Okajima ++Description: ++ It shows the id of a member directory (which is called ++ branch) in aufs. ++ ++What: /sys/fs/aufs/si_/xi_path ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the abolute path of XINO (External Inode Number ++ Bitmap, Translation Table and Generation Table) file ++ even if it is the default path. ++ When the aufs mount option 'noxino' is specified, it ++ will be empty. About XINO files, see the aufs manual. +diff --git a/Documentation/filesystems/aufs/README b/Documentation/filesystems/aufs/README +new file mode 100644 +index 0000000..36df674 +--- /dev/null ++++ b/Documentation/filesystems/aufs/README +@@ -0,0 +1,392 @@ ++ ++Aufs4 -- advanced multi layered unification filesystem version 4.x ++http://aufs.sf.net ++Junjiro R. Okajima ++ ++ ++0. Introduction ++---------------------------------------- ++In the early days, aufs was entirely re-designed and re-implemented ++Unionfs Version 1.x series. Adding many original ideas, approaches, ++improvements and implementations, it becomes totally different from ++Unionfs while keeping the basic features. ++Recently, Unionfs Version 2.x series begin taking some of the same ++approaches to aufs1's. ++Unionfs is being developed by Professor Erez Zadok at Stony Brook ++University and his team. ++ ++Aufs4 supports linux-4.0 and later, and for linux-3.x series try aufs3. ++If you want older kernel version support, try aufs2-2.6.git or ++aufs2-standalone.git repository, aufs1 from CVS on SourceForge. ++ ++Note: it becomes clear that "Aufs was rejected. Let's give it up." ++ According to Christoph Hellwig, linux rejects all union-type ++ filesystems but UnionMount. ++ ++ ++PS. Al Viro seems have a plan to merge aufs as well as overlayfs and ++ UnionMount, and he pointed out an issue around a directory mutex ++ lock and aufs addressed it. But it is still unsure whether aufs will ++ be merged (or any other union solution). ++ ++ ++ ++1. Features ++---------------------------------------- ++- unite several directories into a single virtual filesystem. The member ++ directory is called as a branch. ++- you can specify the permission flags to the branch, which are 'readonly', ++ 'readwrite' and 'whiteout-able.' ++- by upper writable branch, internal copyup and whiteout, files/dirs on ++ readonly branch are modifiable logically. ++- dynamic branch manipulation, add, del. ++- etc... ++ ++Also there are many enhancements in aufs, such as: ++- test only the highest one for the directory permission (dirperm1) ++- copyup on open (coo=) ++- 'move' policy for copy-up between two writable branches, after ++ checking free space. ++- xattr, acl ++- readdir(3) in userspace. ++- keep inode number by external inode number table ++- keep the timestamps of file/dir in internal copyup operation ++- seekable directory, supporting NFS readdir. ++- whiteout is hardlinked in order to reduce the consumption of inodes ++ on branch ++- do not copyup, nor create a whiteout when it is unnecessary ++- revert a single systemcall when an error occurs in aufs ++- remount interface instead of ioctl ++- maintain /etc/mtab by an external command, /sbin/mount.aufs. ++- loopback mounted filesystem as a branch ++- kernel thread for removing the dir who has a plenty of whiteouts ++- support copyup sparse file (a file which has a 'hole' in it) ++- default permission flags for branches ++- selectable permission flags for ro branch, whether whiteout can ++ exist or not ++- export via NFS. ++- support /fs/aufs and /aufs. ++- support multiple writable branches, some policies to select one ++ among multiple writable branches. ++- a new semantics for link(2) and rename(2) to support multiple ++ writable branches. ++- no glibc changes are required. ++- pseudo hardlink (hardlink over branches) ++- allow a direct access manually to a file on branch, e.g. bypassing aufs. ++ including NFS or remote filesystem branch. ++- userspace wrapper for pathconf(3)/fpathconf(3) with _PC_LINK_MAX. ++- and more... ++ ++Currently these features are dropped temporary from aufs4. ++See design/08plan.txt in detail. ++- nested mount, i.e. aufs as readonly no-whiteout branch of another aufs ++ (robr) ++- statistics of aufs thread (/sys/fs/aufs/stat) ++ ++Features or just an idea in the future (see also design/*.txt), ++- reorder the branch index without del/re-add. ++- permanent xino files for NFSD ++- an option for refreshing the opened files after add/del branches ++- light version, without branch manipulation. (unnecessary?) ++- copyup in userspace ++- inotify in userspace ++- readv/writev ++ ++ ++2. Download ++---------------------------------------- ++There are three GIT trees for aufs4, aufs4-linux.git, ++aufs4-standalone.git, and aufs-util.git. Note that there is no "4" in ++"aufs-util.git." ++While the aufs-util is always necessary, you need either of aufs4-linux ++or aufs4-standalone. ++ ++The aufs4-linux tree includes the whole linux mainline GIT tree, ++git://git.kernel.org/.../torvalds/linux.git. ++And you cannot select CONFIG_AUFS_FS=m for this version, eg. you cannot ++build aufs4 as an external kernel module. ++Several extra patches are not included in this tree. Only ++aufs4-standalone tree contains them. They are described in the later ++section "Configuration and Compilation." ++ ++On the other hand, the aufs4-standalone tree has only aufs source files ++and necessary patches, and you can select CONFIG_AUFS_FS=m. ++But you need to apply all aufs patches manually. ++ ++You will find GIT branches whose name is in form of "aufs4.x" where "x" ++represents the linux kernel version, "linux-4.x". For instance, ++"aufs4.0" is for linux-4.0. For latest "linux-4.x-rcN", use ++"aufs4.x-rcN" branch. ++ ++o aufs4-linux tree ++$ git clone --reference /your/linux/git/tree \ ++ git://github.com/sfjro/aufs4-linux.git aufs4-linux.git ++- if you don't have linux GIT tree, then remove "--reference ..." ++$ cd aufs4-linux.git ++$ git checkout origin/aufs4.0 ++ ++Or You may want to directly git-pull aufs into your linux GIT tree, and ++leave the patch-work to GIT. ++$ cd /your/linux/git/tree ++$ git remote add aufs4 git://github.com/sfjro/aufs4-linux.git ++$ git fetch aufs4 ++$ git checkout -b my4.0 v4.0 ++$ (add your local change...) ++$ git pull aufs4 aufs4.0 ++- now you have v4.0 + your_changes + aufs4.0 in you my4.0 branch. ++- you may need to solve some conflicts between your_changes and ++ aufs4.0. in this case, git-rerere is recommended so that you can ++ solve the similar conflicts automatically when you upgrade to 4.1 or ++ later in the future. ++ ++o aufs4-standalone tree ++$ git clone git://github.com/sfjro/aufs4-standalone.git aufs4-standalone.git ++$ cd aufs4-standalone.git ++$ git checkout origin/aufs4.0 ++ ++o aufs-util tree ++$ git clone git://git.code.sf.net/p/aufs/aufs-util aufs-util.git ++- note that the public aufs-util.git is on SourceForge instead of ++ GitHUB. ++$ cd aufs-util.git ++$ git checkout origin/aufs4.0 ++ ++Note: The 4.x-rcN branch is to be used with `rc' kernel versions ONLY. ++The minor version number, 'x' in '4.x', of aufs may not always ++follow the minor version number of the kernel. ++Because changes in the kernel that cause the use of a new ++minor version number do not always require changes to aufs-util. ++ ++Since aufs-util has its own minor version number, you may not be ++able to find a GIT branch in aufs-util for your kernel's ++exact minor version number. ++In this case, you should git-checkout the branch for the ++nearest lower number. ++ ++For (an unreleased) example: ++If you are using "linux-4.10" and the "aufs4.10" branch ++does not exist in aufs-util repository, then "aufs4.9", "aufs4.8" ++or something numerically smaller is the branch for your kernel. ++ ++Also you can view all branches by ++ $ git branch -a ++ ++ ++3. Configuration and Compilation ++---------------------------------------- ++Make sure you have git-checkout'ed the correct branch. ++ ++For aufs4-linux tree, ++- enable CONFIG_AUFS_FS. ++- set other aufs configurations if necessary. ++ ++For aufs4-standalone tree, ++There are several ways to build. ++ ++1. ++- apply ./aufs4-kbuild.patch to your kernel source files. ++- apply ./aufs4-base.patch too. ++- apply ./aufs4-mmap.patch too. ++- apply ./aufs4-standalone.patch too, if you have a plan to set ++ CONFIG_AUFS_FS=m. otherwise you don't need ./aufs4-standalone.patch. ++- copy ./{Documentation,fs,include/uapi/linux/aufs_type.h} files to your ++ kernel source tree. Never copy $PWD/include/uapi/linux/Kbuild. ++- enable CONFIG_AUFS_FS, you can select either ++ =m or =y. ++- and build your kernel as usual. ++- install the built kernel. ++ Note: Since linux-3.9, every filesystem module requires an alias ++ "fs-". You should make sure that "fs-aufs" is listed in your ++ modules.aliases file if you set CONFIG_AUFS_FS=m. ++- install the header files too by "make headers_install" to the ++ directory where you specify. By default, it is $PWD/usr. ++ "make help" shows a brief note for headers_install. ++- and reboot your system. ++ ++2. ++- module only (CONFIG_AUFS_FS=m). ++- apply ./aufs4-base.patch to your kernel source files. ++- apply ./aufs4-mmap.patch too. ++- apply ./aufs4-standalone.patch too. ++- build your kernel, don't forget "make headers_install", and reboot. ++- edit ./config.mk and set other aufs configurations if necessary. ++ Note: You should read $PWD/fs/aufs/Kconfig carefully which describes ++ every aufs configurations. ++- build the module by simple "make". ++ Note: Since linux-3.9, every filesystem module requires an alias ++ "fs-". You should make sure that "fs-aufs" is listed in your ++ modules.aliases file. ++- you can specify ${KDIR} make variable which points to your kernel ++ source tree. ++- install the files ++ + run "make install" to install the aufs module, or copy the built ++ $PWD/aufs.ko to /lib/modules/... and run depmod -a (or reboot simply). ++ + run "make install_headers" (instead of headers_install) to install ++ the modified aufs header file (you can specify DESTDIR which is ++ available in aufs standalone version's Makefile only), or copy ++ $PWD/usr/include/linux/aufs_type.h to /usr/include/linux or wherever ++ you like manually. By default, the target directory is $PWD/usr. ++- no need to apply aufs4-kbuild.patch, nor copying source files to your ++ kernel source tree. ++ ++Note: The header file aufs_type.h is necessary to build aufs-util ++ as well as "make headers_install" in the kernel source tree. ++ headers_install is subject to be forgotten, but it is essentially ++ necessary, not only for building aufs-util. ++ You may not meet problems without headers_install in some older ++ version though. ++ ++And then, ++- read README in aufs-util, build and install it ++- note that your distribution may contain an obsoleted version of ++ aufs_type.h in /usr/include/linux or something. When you build aufs ++ utilities, make sure that your compiler refers the correct aufs header ++ file which is built by "make headers_install." ++- if you want to use readdir(3) in userspace or pathconf(3) wrapper, ++ then run "make install_ulib" too. And refer to the aufs manual in ++ detail. ++ ++There several other patches in aufs4-standalone.git. They are all ++optional. When you meet some problems, they will help you. ++- aufs4-loopback.patch ++ Supports a nested loopback mount in a branch-fs. This patch is ++ unnecessary until aufs produces a message like "you may want to try ++ another patch for loopback file". ++- vfs-ino.patch ++ Modifies a system global kernel internal function get_next_ino() in ++ order to stop assigning 0 for an inode-number. Not directly related to ++ aufs, but recommended generally. ++- tmpfs-idr.patch ++ Keeps the tmpfs inode number as the lowest value. Effective to reduce ++ the size of aufs XINO files for tmpfs branch. Also it prevents the ++ duplication of inode number, which is important for backup tools and ++ other utilities. When you find aufs XINO files for tmpfs branch ++ growing too much, try this patch. ++- lockdep-debug.patch ++ Because aufs is not only an ordinary filesystem (callee of VFS), but ++ also a caller of VFS functions for branch filesystems, subclassing of ++ the internal locks for LOCKDEP is necessary. LOCKDEP is a debugging ++ feature of linux kernel. If you enable CONFIG_LOCKDEP, then you will ++ need to apply this debug patch to expand several constant values. ++ If don't know what LOCKDEP, then you don't have apply this patch. ++ ++ ++4. Usage ++---------------------------------------- ++At first, make sure aufs-util are installed, and please read the aufs ++manual, aufs.5 in aufs-util.git tree. ++$ man -l aufs.5 ++ ++And then, ++$ mkdir /tmp/rw /tmp/aufs ++# mount -t aufs -o br=/tmp/rw:${HOME} none /tmp/aufs ++ ++Here is another example. The result is equivalent. ++# mount -t aufs -o br=/tmp/rw=rw:${HOME}=ro none /tmp/aufs ++ Or ++# mount -t aufs -o br:/tmp/rw none /tmp/aufs ++# mount -o remount,append:${HOME} /tmp/aufs ++ ++Then, you can see whole tree of your home dir through /tmp/aufs. If ++you modify a file under /tmp/aufs, the one on your home directory is ++not affected, instead the same named file will be newly created under ++/tmp/rw. And all of your modification to a file will be applied to ++the one under /tmp/rw. This is called the file based Copy on Write ++(COW) method. ++Aufs mount options are described in aufs.5. ++If you run chroot or something and make your aufs as a root directory, ++then you need to customize the shutdown script. See the aufs manual in ++detail. ++ ++Additionally, there are some sample usages of aufs which are a ++diskless system with network booting, and LiveCD over NFS. ++See sample dir in CVS tree on SourceForge. ++ ++ ++5. Contact ++---------------------------------------- ++When you have any problems or strange behaviour in aufs, please let me ++know with: ++- /proc/mounts (instead of the output of mount(8)) ++- /sys/module/aufs/* ++- /sys/fs/aufs/* (if you have them) ++- /debug/aufs/* (if you have them) ++- linux kernel version ++ if your kernel is not plain, for example modified by distributor, ++ the url where i can download its source is necessary too. ++- aufs version which was printed at loading the module or booting the ++ system, instead of the date you downloaded. ++- configuration (define/undefine CONFIG_AUFS_xxx) ++- kernel configuration or /proc/config.gz (if you have it) ++- behaviour which you think to be incorrect ++- actual operation, reproducible one is better ++- mailto: aufs-users at lists.sourceforge.net ++ ++Usually, I don't watch the Public Areas(Bugs, Support Requests, Patches, ++and Feature Requests) on SourceForge. Please join and write to ++aufs-users ML. ++ ++ ++6. Acknowledgements ++---------------------------------------- ++Thanks to everyone who have tried and are using aufs, whoever ++have reported a bug or any feedback. ++ ++Especially donators: ++Tomas Matejicek(slax.org) made a donation (much more than once). ++ Since Apr 2010, Tomas M (the author of Slax and Linux Live ++ scripts) is making "doubling" donations. ++ Unfortunately I cannot list all of the donators, but I really ++ appreciate. ++ It ends Aug 2010, but the ordinary donation URL is still available. ++ ++Dai Itasaka made a donation (2007/8). ++Chuck Smith made a donation (2008/4, 10 and 12). ++Henk Schoneveld made a donation (2008/9). ++Chih-Wei Huang, ASUS, CTC donated Eee PC 4G (2008/10). ++Francois Dupoux made a donation (2008/11). ++Bruno Cesar Ribas and Luis Carlos Erpen de Bona, C3SL serves public ++ aufs2 GIT tree (2009/2). ++William Grant made a donation (2009/3). ++Patrick Lane made a donation (2009/4). ++The Mail Archive (mail-archive.com) made donations (2009/5). ++Nippy Networks (Ed Wildgoose) made a donation (2009/7). ++New Dream Network, LLC (www.dreamhost.com) made a donation (2009/11). ++Pavel Pronskiy made a donation (2011/2). ++Iridium and Inmarsat satellite phone retailer (www.mailasail.com), Nippy ++ Networks (Ed Wildgoose) made a donation for hardware (2011/3). ++Max Lekomcev (DOM-TV project) made a donation (2011/7, 12, 2012/3, 6 and ++11). ++Sam Liddicott made a donation (2011/9). ++Era Scarecrow made a donation (2013/4). ++Bor Ratajc made a donation (2013/4). ++Alessandro Gorreta made a donation (2013/4). ++POIRETTE Marc made a donation (2013/4). ++Alessandro Gorreta made a donation (2013/4). ++lauri kasvandik made a donation (2013/5). ++"pemasu from Finland" made a donation (2013/7). ++The Parted Magic Project made a donation (2013/9 and 11). ++Pavel Barta made a donation (2013/10). ++Nikolay Pertsev made a donation (2014/5). ++James B made a donation (2014/7 and 2015/7). ++Stefano Di Biase made a donation (2014/8). ++Daniel Epellei made a donation (2015/1). ++OmegaPhil made a donation (2016/1). ++Tomasz Szewczyk made a donation (2016/4). ++ ++Thank you very much. ++Donations are always, including future donations, very important and ++helpful for me to keep on developing aufs. ++ ++ ++7. ++---------------------------------------- ++If you are an experienced user, no explanation is needed. Aufs is ++just a linux filesystem. ++ ++ ++Enjoy! ++ ++# Local variables: ; ++# mode: text; ++# End: ; +diff --git a/Documentation/filesystems/aufs/design/01intro.txt b/Documentation/filesystems/aufs/design/01intro.txt +new file mode 100644 +index 0000000..5d01214 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/01intro.txt +@@ -0,0 +1,157 @@ ++ ++# Copyright (C) 2005-2016 Junjiro R. Okajima ++ ++Introduction ++---------------------------------------- ++ ++aufs [ei ju: ef es] | [a u f s] ++1. abbrev. for "advanced multi-layered unification filesystem". ++2. abbrev. for "another unionfs". ++3. abbrev. for "auf das" in German which means "on the" in English. ++ Ex. "Butter aufs Brot"(G) means "butter onto bread"(E). ++ But "Filesystem aufs Filesystem" is hard to understand. ++ ++AUFS is a filesystem with features: ++- multi layered stackable unification filesystem, the member directory ++ is called as a branch. ++- branch permission and attribute, 'readonly', 'real-readonly', ++ 'readwrite', 'whiteout-able', 'link-able whiteout', etc. and their ++ combination. ++- internal "file copy-on-write". ++- logical deletion, whiteout. ++- dynamic branch manipulation, adding, deleting and changing permission. ++- allow bypassing aufs, user's direct branch access. ++- external inode number translation table and bitmap which maintains the ++ persistent aufs inode number. ++- seekable directory, including NFS readdir. ++- file mapping, mmap and sharing pages. ++- pseudo-link, hardlink over branches. ++- loopback mounted filesystem as a branch. ++- several policies to select one among multiple writable branches. ++- revert a single systemcall when an error occurs in aufs. ++- and more... ++ ++ ++Multi Layered Stackable Unification Filesystem ++---------------------------------------------------------------------- ++Most people already knows what it is. ++It is a filesystem which unifies several directories and provides a ++merged single directory. When users access a file, the access will be ++passed/re-directed/converted (sorry, I am not sure which English word is ++correct) to the real file on the member filesystem. The member ++filesystem is called 'lower filesystem' or 'branch' and has a mode ++'readonly' and 'readwrite.' And the deletion for a file on the lower ++readonly branch is handled by creating 'whiteout' on the upper writable ++branch. ++ ++On LKML, there have been discussions about UnionMount (Jan Blunck, ++Bharata B Rao and Valerie Aurora) and Unionfs (Erez Zadok). They took ++different approaches to implement the merged-view. ++The former tries putting it into VFS, and the latter implements as a ++separate filesystem. ++(If I misunderstand about these implementations, please let me know and ++I shall correct it. Because it is a long time ago when I read their ++source files last time). ++ ++UnionMount's approach will be able to small, but may be hard to share ++branches between several UnionMount since the whiteout in it is ++implemented in the inode on branch filesystem and always ++shared. According to Bharata's post, readdir does not seems to be ++finished yet. ++There are several missing features known in this implementations such as ++- for users, the inode number may change silently. eg. copy-up. ++- link(2) may break by copy-up. ++- read(2) may get an obsoleted filedata (fstat(2) too). ++- fcntl(F_SETLK) may be broken by copy-up. ++- unnecessary copy-up may happen, for example mmap(MAP_PRIVATE) after ++ open(O_RDWR). ++ ++In linux-3.18, "overlay" filesystem (formerly known as "overlayfs") was ++merged into mainline. This is another implementation of UnionMount as a ++separated filesystem. All the limitations and known problems which ++UnionMount are equally inherited to "overlay" filesystem. ++ ++Unionfs has a longer history. When I started implementing a stackable ++filesystem (Aug 2005), it already existed. It has virtual super_block, ++inode, dentry and file objects and they have an array pointing lower ++same kind objects. After contributing many patches for Unionfs, I ++re-started my project AUFS (Jun 2006). ++ ++In AUFS, the structure of filesystem resembles to Unionfs, but I ++implemented my own ideas, approaches and enhancements and it became ++totally different one. ++ ++Comparing DM snapshot and fs based implementation ++- the number of bytes to be copied between devices is much smaller. ++- the type of filesystem must be one and only. ++- the fs must be writable, no readonly fs, even for the lower original ++ device. so the compression fs will not be usable. but if we use ++ loopback mount, we may address this issue. ++ for instance, ++ mount /cdrom/squashfs.img /sq ++ losetup /sq/ext2.img ++ losetup /somewhere/cow ++ dmsetup "snapshot /dev/loop0 /dev/loop1 ..." ++- it will be difficult (or needs more operations) to extract the ++ difference between the original device and COW. ++- DM snapshot-merge may help a lot when users try merging. in the ++ fs-layer union, users will use rsync(1). ++ ++You may want to read my old paper "Filesystems in LiveCD" ++(http://aufs.sourceforge.net/aufs2/report/sq/sq.pdf). ++ ++ ++Several characters/aspects/persona of aufs ++---------------------------------------------------------------------- ++ ++Aufs has several characters, aspects or persona. ++1. a filesystem, callee of VFS helper ++2. sub-VFS, caller of VFS helper for branches ++3. a virtual filesystem which maintains persistent inode number ++4. reader/writer of files on branches such like an application ++ ++1. Callee of VFS Helper ++As an ordinary linux filesystem, aufs is a callee of VFS. For instance, ++unlink(2) from an application reaches sys_unlink() kernel function and ++then vfs_unlink() is called. vfs_unlink() is one of VFS helper and it ++calls filesystem specific unlink operation. Actually aufs implements the ++unlink operation but it behaves like a redirector. ++ ++2. Caller of VFS Helper for Branches ++aufs_unlink() passes the unlink request to the branch filesystem as if ++it were called from VFS. So the called unlink operation of the branch ++filesystem acts as usual. As a caller of VFS helper, aufs should handle ++every necessary pre/post operation for the branch filesystem. ++- acquire the lock for the parent dir on a branch ++- lookup in a branch ++- revalidate dentry on a branch ++- mnt_want_write() for a branch ++- vfs_unlink() for a branch ++- mnt_drop_write() for a branch ++- release the lock on a branch ++ ++3. Persistent Inode Number ++One of the most important issue for a filesystem is to maintain inode ++numbers. This is particularly important to support exporting a ++filesystem via NFS. Aufs is a virtual filesystem which doesn't have a ++backend block device for its own. But some storage is necessary to ++keep and maintain the inode numbers. It may be a large space and may not ++suit to keep in memory. Aufs rents some space from its first writable ++branch filesystem (by default) and creates file(s) on it. These files ++are created by aufs internally and removed soon (currently) keeping ++opened. ++Note: Because these files are removed, they are totally gone after ++ unmounting aufs. It means the inode numbers are not persistent ++ across unmount or reboot. I have a plan to make them really ++ persistent which will be important for aufs on NFS server. ++ ++4. Read/Write Files Internally (copy-on-write) ++Because a branch can be readonly, when you write a file on it, aufs will ++"copy-up" it to the upper writable branch internally. And then write the ++originally requested thing to the file. Generally kernel doesn't ++open/read/write file actively. In aufs, even a single write may cause a ++internal "file copy". This behaviour is very similar to cp(1) command. ++ ++Some people may think it is better to pass such work to user space ++helper, instead of doing in kernel space. Actually I am still thinking ++about it. But currently I have implemented it in kernel space. +diff --git a/Documentation/filesystems/aufs/design/02struct.txt b/Documentation/filesystems/aufs/design/02struct.txt +new file mode 100644 +index 0000000..783328a +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/02struct.txt +@@ -0,0 +1,245 @@ ++ ++# Copyright (C) 2005-2016 Junjiro R. Okajima ++ ++Basic Aufs Internal Structure ++ ++Superblock/Inode/Dentry/File Objects ++---------------------------------------------------------------------- ++As like an ordinary filesystem, aufs has its own ++superblock/inode/dentry/file objects. All these objects have a ++dynamically allocated array and store the same kind of pointers to the ++lower filesystem, branch. ++For example, when you build a union with one readwrite branch and one ++readonly, mounted /au, /rw and /ro respectively. ++- /au = /rw + /ro ++- /ro/fileA exists but /rw/fileA ++ ++Aufs lookup operation finds /ro/fileA and gets dentry for that. These ++pointers are stored in a aufs dentry. The array in aufs dentry will be, ++- [0] = NULL (because /rw/fileA doesn't exist) ++- [1] = /ro/fileA ++ ++This style of an array is essentially same to the aufs ++superblock/inode/dentry/file objects. ++ ++Because aufs supports manipulating branches, ie. add/delete/change ++branches dynamically, these objects has its own generation. When ++branches are changed, the generation in aufs superblock is ++incremented. And a generation in other object are compared when it is ++accessed. When a generation in other objects are obsoleted, aufs ++refreshes the internal array. ++ ++ ++Superblock ++---------------------------------------------------------------------- ++Additionally aufs superblock has some data for policies to select one ++among multiple writable branches, XIB files, pseudo-links and kobject. ++See below in detail. ++About the policies which supports copy-down a directory, see ++wbr_policy.txt too. ++ ++ ++Branch and XINO(External Inode Number Translation Table) ++---------------------------------------------------------------------- ++Every branch has its own xino (external inode number translation table) ++file. The xino file is created and unlinked by aufs internally. When two ++members of a union exist on the same filesystem, they share the single ++xino file. ++The struct of a xino file is simple, just a sequence of aufs inode ++numbers which is indexed by the lower inode number. ++In the above sample, assume the inode number of /ro/fileA is i111 and ++aufs assigns the inode number i999 for fileA. Then aufs writes 999 as ++4(8) bytes at 111 * 4(8) bytes offset in the xino file. ++ ++When the inode numbers are not contiguous, the xino file will be sparse ++which has a hole in it and doesn't consume as much disk space as it ++might appear. If your branch filesystem consumes disk space for such ++holes, then you should specify 'xino=' option at mounting aufs. ++ ++Aufs has a mount option to free the disk blocks for such holes in XINO ++files on tmpfs or ramdisk. But it is not so effective actually. If you ++meet a problem of disk shortage due to XINO files, then you should try ++"tmpfs-ino.patch" (and "vfs-ino.patch" too) in aufs4-standalone.git. ++The patch localizes the assignment inumbers per tmpfs-mount and avoid ++the holes in XINO files. ++ ++Also a writable branch has three kinds of "whiteout bases". All these ++are existed when the branch is joined to aufs, and their names are ++whiteout-ed doubly, so that users will never see their names in aufs ++hierarchy. ++1. a regular file which will be hardlinked to all whiteouts. ++2. a directory to store a pseudo-link. ++3. a directory to store an "orphan"-ed file temporary. ++ ++1. Whiteout Base ++ When you remove a file on a readonly branch, aufs handles it as a ++ logical deletion and creates a whiteout on the upper writable branch ++ as a hardlink of this file in order not to consume inode on the ++ writable branch. ++2. Pseudo-link Dir ++ See below, Pseudo-link. ++3. Step-Parent Dir ++ When "fileC" exists on the lower readonly branch only and it is ++ opened and removed with its parent dir, and then user writes ++ something into it, then aufs copies-up fileC to this ++ directory. Because there is no other dir to store fileC. After ++ creating a file under this dir, the file is unlinked. ++ ++Because aufs supports manipulating branches, ie. add/delete/change ++dynamically, a branch has its own id. When the branch order changes, ++aufs finds the new index by searching the branch id. ++ ++ ++Pseudo-link ++---------------------------------------------------------------------- ++Assume "fileA" exists on the lower readonly branch only and it is ++hardlinked to "fileB" on the branch. When you write something to fileA, ++aufs copies-up it to the upper writable branch. Additionally aufs ++creates a hardlink under the Pseudo-link Directory of the writable ++branch. The inode of a pseudo-link is kept in aufs super_block as a ++simple list. If fileB is read after unlinking fileA, aufs returns ++filedata from the pseudo-link instead of the lower readonly ++branch. Because the pseudo-link is based upon the inode, to keep the ++inode number by xino (see above) is essentially necessary. ++ ++All the hardlinks under the Pseudo-link Directory of the writable branch ++should be restored in a proper location later. Aufs provides a utility ++to do this. The userspace helpers executed at remounting and unmounting ++aufs by default. ++During this utility is running, it puts aufs into the pseudo-link ++maintenance mode. In this mode, only the process which began the ++maintenance mode (and its child processes) is allowed to operate in ++aufs. Some other processes which are not related to the pseudo-link will ++be allowed to run too, but the rest have to return an error or wait ++until the maintenance mode ends. If a process already acquires an inode ++mutex (in VFS), it has to return an error. ++ ++ ++XIB(external inode number bitmap) ++---------------------------------------------------------------------- ++Addition to the xino file per a branch, aufs has an external inode number ++bitmap in a superblock object. It is also an internal file such like a ++xino file. ++It is a simple bitmap to mark whether the aufs inode number is in-use or ++not. ++To reduce the file I/O, aufs prepares a single memory page to cache xib. ++ ++As well as XINO files, aufs has a feature to truncate/refresh XIB to ++reduce the number of consumed disk blocks for these files. ++ ++ ++Virtual or Vertical Dir, and Readdir in Userspace ++---------------------------------------------------------------------- ++In order to support multiple layers (branches), aufs readdir operation ++constructs a virtual dir block on memory. For readdir, aufs calls ++vfs_readdir() internally for each dir on branches, merges their entries ++with eliminating the whiteout-ed ones, and sets it to file (dir) ++object. So the file object has its entry list until it is closed. The ++entry list will be updated when the file position is zero and becomes ++obsoleted. This decision is made in aufs automatically. ++ ++The dynamically allocated memory block for the name of entries has a ++unit of 512 bytes (by default) and stores the names contiguously (no ++padding). Another block for each entry is handled by kmem_cache too. ++During building dir blocks, aufs creates hash list and judging whether ++the entry is whiteouted by its upper branch or already listed. ++The merged result is cached in the corresponding inode object and ++maintained by a customizable life-time option. ++ ++Some people may call it can be a security hole or invite DoS attack ++since the opened and once readdir-ed dir (file object) holds its entry ++list and becomes a pressure for system memory. But I'd say it is similar ++to files under /proc or /sys. The virtual files in them also holds a ++memory page (generally) while they are opened. When an idea to reduce ++memory for them is introduced, it will be applied to aufs too. ++For those who really hate this situation, I've developed readdir(3) ++library which operates this merging in userspace. You just need to set ++LD_PRELOAD environment variable, and aufs will not consume no memory in ++kernel space for readdir(3). ++ ++ ++Workqueue ++---------------------------------------------------------------------- ++Aufs sometimes requires privilege access to a branch. For instance, ++in copy-up/down operation. When a user process is going to make changes ++to a file which exists in the lower readonly branch only, and the mode ++of one of ancestor directories may not be writable by a user ++process. Here aufs copy-up the file with its ancestors and they may ++require privilege to set its owner/group/mode/etc. ++This is a typical case of a application character of aufs (see ++Introduction). ++ ++Aufs uses workqueue synchronously for this case. It creates its own ++workqueue. The workqueue is a kernel thread and has privilege. Aufs ++passes the request to call mkdir or write (for example), and wait for ++its completion. This approach solves a problem of a signal handler ++simply. ++If aufs didn't adopt the workqueue and changed the privilege of the ++process, then the process may receive the unexpected SIGXFSZ or other ++signals. ++ ++Also aufs uses the system global workqueue ("events" kernel thread) too ++for asynchronous tasks, such like handling inotify/fsnotify, re-creating a ++whiteout base and etc. This is unrelated to a privilege. ++Most of aufs operation tries acquiring a rw_semaphore for aufs ++superblock at the beginning, at the same time waits for the completion ++of all queued asynchronous tasks. ++ ++ ++Whiteout ++---------------------------------------------------------------------- ++The whiteout in aufs is very similar to Unionfs's. That is represented ++by its filename. UnionMount takes an approach of a file mode, but I am ++afraid several utilities (find(1) or something) will have to support it. ++ ++Basically the whiteout represents "logical deletion" which stops aufs to ++lookup further, but also it represents "dir is opaque" which also stop ++further lookup. ++ ++In aufs, rmdir(2) and rename(2) for dir uses whiteout alternatively. ++In order to make several functions in a single systemcall to be ++revertible, aufs adopts an approach to rename a directory to a temporary ++unique whiteouted name. ++For example, in rename(2) dir where the target dir already existed, aufs ++renames the target dir to a temporary unique whiteouted name before the ++actual rename on a branch, and then handles other actions (make it opaque, ++update the attributes, etc). If an error happens in these actions, aufs ++simply renames the whiteouted name back and returns an error. If all are ++succeeded, aufs registers a function to remove the whiteouted unique ++temporary name completely and asynchronously to the system global ++workqueue. ++ ++ ++Copy-up ++---------------------------------------------------------------------- ++It is a well-known feature or concept. ++When user modifies a file on a readonly branch, aufs operate "copy-up" ++internally and makes change to the new file on the upper writable branch. ++When the trigger systemcall does not update the timestamps of the parent ++dir, aufs reverts it after copy-up. ++ ++ ++Move-down (aufs3.9 and later) ++---------------------------------------------------------------------- ++"Copy-up" is one of the essential feature in aufs. It copies a file from ++the lower readonly branch to the upper writable branch when a user ++changes something about the file. ++"Move-down" is an opposite action of copy-up. Basically this action is ++ran manually instead of automatically and internally. ++For desgin and implementation, aufs has to consider these issues. ++- whiteout for the file may exist on the lower branch. ++- ancestor directories may not exist on the lower branch. ++- diropq for the ancestor directories may exist on the upper branch. ++- free space on the lower branch will reduce. ++- another access to the file may happen during moving-down, including ++ UDBA (see "Revalidate Dentry and UDBA"). ++- the file should not be hard-linked nor pseudo-linked. they should be ++ handled by auplink utility later. ++ ++Sometimes users want to move-down a file from the upper writable branch ++to the lower readonly or writable branch. For instance, ++- the free space of the upper writable branch is going to run out. ++- create a new intermediate branch between the upper and lower branch. ++- etc. ++ ++For this purpose, use "aumvdown" command in aufs-util.git. +diff --git a/Documentation/filesystems/aufs/design/03atomic_open.txt b/Documentation/filesystems/aufs/design/03atomic_open.txt +new file mode 100644 +index 0000000..741ad6d +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/03atomic_open.txt +@@ -0,0 +1,72 @@ ++ ++# Copyright (C) 2015-2016 Junjiro R. Okajima ++ ++Support for a branch who has its ->atomic_open() ++---------------------------------------------------------------------- ++The filesystems who implement its ->atomic_open() are not majority. For ++example NFSv4 does, and aufs should call NFSv4 ->atomic_open, ++particularly for open(O_CREAT|O_EXCL, 0400) case. Other than ++->atomic_open(), NFSv4 returns an error for this open(2). While I am not ++sure whether all filesystems who have ->atomic_open() behave like this, ++but NFSv4 surely returns the error. ++ ++In order to support ->atomic_open() for aufs, there are a few ++approaches. ++ ++A. Introduce aufs_atomic_open() ++ - calls one of VFS:do_last(), lookup_open() or atomic_open() for ++ branch fs. ++B. Introduce aufs_atomic_open() calling create, open and chmod. this is ++ an aufs user Pip Cet's approach ++ - calls aufs_create(), VFS finish_open() and notify_change(). ++ - pass fake-mode to finish_open(), and then correct the mode by ++ notify_change(). ++C. Extend aufs_open() to call branch fs's ->atomic_open() ++ - no aufs_atomic_open(). ++ - aufs_lookup() registers the TID to an aufs internal object. ++ - aufs_create() does nothing when the matching TID is registered, but ++ registers the mode. ++ - aufs_open() calls branch fs's ->atomic_open() when the matching ++ TID is registered. ++D. Extend aufs_open() to re-try branch fs's ->open() with superuser's ++ credential ++ - no aufs_atomic_open(). ++ - aufs_create() registers the TID to an internal object. this info ++ represents "this process created this file just now." ++ - when aufs gets EACCES from branch fs's ->open(), then confirm the ++ registered TID and re-try open() with superuser's credential. ++ ++Pros and cons for each approach. ++ ++A. ++ - straightforward but highly depends upon VFS internal. ++ - the atomic behavaiour is kept. ++ - some of parameters such as nameidata are hard to reproduce for ++ branch fs. ++ - large overhead. ++B. ++ - easy to implement. ++ - the atomic behavaiour is lost. ++C. ++ - the atomic behavaiour is kept. ++ - dirty and tricky. ++ - VFS checks whether the file is created correctly after calling ++ ->create(), which means this approach doesn't work. ++D. ++ - easy to implement. ++ - the atomic behavaiour is lost. ++ - to open a file with superuser's credential and give it to a user ++ process is a bad idea, since the file object keeps the credential ++ in it. It may affect LSM or something. This approach doesn't work ++ either. ++ ++The approach A is ideal, but it hard to implement. So here is a ++variation of A, which is to be implemented. ++ ++A-1. Introduce aufs_atomic_open() ++ - calls branch fs ->atomic_open() if exists. otherwise calls ++ vfs_create() and finish_open(). ++ - the demerit is that the several checks after branch fs ++ ->atomic_open() are lost. in the ordinary case, the checks are ++ done by VFS:do_last(), lookup_open() and atomic_open(). some can ++ be implemented in aufs, but not all I am afraid. +diff --git a/Documentation/filesystems/aufs/design/03lookup.txt b/Documentation/filesystems/aufs/design/03lookup.txt +new file mode 100644 +index 0000000..5b6b000 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/03lookup.txt +@@ -0,0 +1,100 @@ ++ ++# Copyright (C) 2005-2016 Junjiro R. Okajima ++ ++Lookup in a Branch ++---------------------------------------------------------------------- ++Since aufs has a character of sub-VFS (see Introduction), it operates ++lookup for branches as VFS does. It may be a heavy work. But almost all ++lookup operation in aufs is the simplest case, ie. lookup only an entry ++directly connected to its parent. Digging down the directory hierarchy ++is unnecessary. VFS has a function lookup_one_len() for that use, and ++aufs calls it. ++ ++When a branch is a remote filesystem, aufs basically relies upon its ++->d_revalidate(), also aufs forces the hardest revalidate tests for ++them. ++For d_revalidate, aufs implements three levels of revalidate tests. See ++"Revalidate Dentry and UDBA" in detail. ++ ++ ++Test Only the Highest One for the Directory Permission (dirperm1 option) ++---------------------------------------------------------------------- ++Let's try case study. ++- aufs has two branches, upper readwrite and lower readonly. ++ /au = /rw + /ro ++- "dirA" exists under /ro, but /rw. and its mode is 0700. ++- user invoked "chmod a+rx /au/dirA" ++- the internal copy-up is activated and "/rw/dirA" is created and its ++ permission bits are set to world readable. ++- then "/au/dirA" becomes world readable? ++ ++In this case, /ro/dirA is still 0700 since it exists in readonly branch, ++or it may be a natively readonly filesystem. If aufs respects the lower ++branch, it should not respond readdir request from other users. But user ++allowed it by chmod. Should really aufs rejects showing the entries ++under /ro/dirA? ++ ++To be honest, I don't have a good solution for this case. So aufs ++implements 'dirperm1' and 'nodirperm1' mount options, and leave it to ++users. ++When dirperm1 is specified, aufs checks only the highest one for the ++directory permission, and shows the entries. Otherwise, as usual, checks ++every dir existing on all branches and rejects the request. ++ ++As a side effect, dirperm1 option improves the performance of aufs ++because the number of permission check is reduced when the number of ++branch is many. ++ ++ ++Revalidate Dentry and UDBA (User's Direct Branch Access) ++---------------------------------------------------------------------- ++Generally VFS helpers re-validate a dentry as a part of lookup. ++0. digging down the directory hierarchy. ++1. lock the parent dir by its i_mutex. ++2. lookup the final (child) entry. ++3. revalidate it. ++4. call the actual operation (create, unlink, etc.) ++5. unlock the parent dir ++ ++If the filesystem implements its ->d_revalidate() (step 3), then it is ++called. Actually aufs implements it and checks the dentry on a branch is ++still valid. ++But it is not enough. Because aufs has to release the lock for the ++parent dir on a branch at the end of ->lookup() (step 2) and ++->d_revalidate() (step 3) while the i_mutex of the aufs dir is still ++held by VFS. ++If the file on a branch is changed directly, eg. bypassing aufs, after ++aufs released the lock, then the subsequent operation may cause ++something unpleasant result. ++ ++This situation is a result of VFS architecture, ->lookup() and ++->d_revalidate() is separated. But I never say it is wrong. It is a good ++design from VFS's point of view. It is just not suitable for sub-VFS ++character in aufs. ++ ++Aufs supports such case by three level of revalidation which is ++selectable by user. ++1. Simple Revalidate ++ Addition to the native flow in VFS's, confirm the child-parent ++ relationship on the branch just after locking the parent dir on the ++ branch in the "actual operation" (step 4). When this validation ++ fails, aufs returns EBUSY. ->d_revalidate() (step 3) in aufs still ++ checks the validation of the dentry on branches. ++2. Monitor Changes Internally by Inotify/Fsnotify ++ Addition to above, in the "actual operation" (step 4) aufs re-lookup ++ the dentry on the branch, and returns EBUSY if it finds different ++ dentry. ++ Additionally, aufs sets the inotify/fsnotify watch for every dir on branches ++ during it is in cache. When the event is notified, aufs registers a ++ function to kernel 'events' thread by schedule_work(). And the ++ function sets some special status to the cached aufs dentry and inode ++ private data. If they are not cached, then aufs has nothing to ++ do. When the same file is accessed through aufs (step 0-3) later, ++ aufs will detect the status and refresh all necessary data. ++ In this mode, aufs has to ignore the event which is fired by aufs ++ itself. ++3. No Extra Validation ++ This is the simplest test and doesn't add any additional revalidation ++ test, and skip the revalidation in step 4. It is useful and improves ++ aufs performance when system surely hide the aufs branches from user, ++ by over-mounting something (or another method). +diff --git a/Documentation/filesystems/aufs/design/04branch.txt b/Documentation/filesystems/aufs/design/04branch.txt +new file mode 100644 +index 0000000..e68f4d3 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/04branch.txt +@@ -0,0 +1,61 @@ ++ ++# Copyright (C) 2005-2016 Junjiro R. Okajima ++ ++Branch Manipulation ++ ++Since aufs supports dynamic branch manipulation, ie. add/remove a branch ++and changing its permission/attribute, there are a lot of works to do. ++ ++ ++Add a Branch ++---------------------------------------------------------------------- ++o Confirm the adding dir exists outside of aufs, including loopback ++ mount, and its various attributes. ++o Initialize the xino file and whiteout bases if necessary. ++ See struct.txt. ++ ++o Check the owner/group/mode of the directory ++ When the owner/group/mode of the adding directory differs from the ++ existing branch, aufs issues a warning because it may impose a ++ security risk. ++ For example, when a upper writable branch has a world writable empty ++ top directory, a malicious user can create any files on the writable ++ branch directly, like copy-up and modify manually. If something like ++ /etc/{passwd,shadow} exists on the lower readonly branch but the upper ++ writable branch, and the writable branch is world-writable, then a ++ malicious guy may create /etc/passwd on the writable branch directly ++ and the infected file will be valid in aufs. ++ I am afraid it can be a security issue, but aufs can do nothing except ++ producing a warning. ++ ++ ++Delete a Branch ++---------------------------------------------------------------------- ++o Confirm the deleting branch is not busy ++ To be general, there is one merit to adopt "remount" interface to ++ manipulate branches. It is to discard caches. At deleting a branch, ++ aufs checks the still cached (and connected) dentries and inodes. If ++ there are any, then they are all in-use. An inode without its ++ corresponding dentry can be alive alone (for example, inotify/fsnotify case). ++ ++ For the cached one, aufs checks whether the same named entry exists on ++ other branches. ++ If the cached one is a directory, because aufs provides a merged view ++ to users, as long as one dir is left on any branch aufs can show the ++ dir to users. In this case, the branch can be removed from aufs. ++ Otherwise aufs rejects deleting the branch. ++ ++ If any file on the deleting branch is opened by aufs, then aufs ++ rejects deleting. ++ ++ ++Modify the Permission of a Branch ++---------------------------------------------------------------------- ++o Re-initialize or remove the xino file and whiteout bases if necessary. ++ See struct.txt. ++ ++o rw --> ro: Confirm the modifying branch is not busy ++ Aufs rejects the request if any of these conditions are true. ++ - a file on the branch is mmap-ed. ++ - a regular file on the branch is opened for write and there is no ++ same named entry on the upper branch. +diff --git a/Documentation/filesystems/aufs/design/05wbr_policy.txt b/Documentation/filesystems/aufs/design/05wbr_policy.txt +new file mode 100644 +index 0000000..1726d5d +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/05wbr_policy.txt +@@ -0,0 +1,51 @@ ++ ++# Copyright (C) 2005-2016 Junjiro R. Okajima ++ ++Policies to Select One among Multiple Writable Branches ++---------------------------------------------------------------------- ++When the number of writable branch is more than one, aufs has to decide ++the target branch for file creation or copy-up. By default, the highest ++writable branch which has the parent (or ancestor) dir of the target ++file is chosen (top-down-parent policy). ++By user's request, aufs implements some other policies to select the ++writable branch, for file creation several policies, round-robin, ++most-free-space, and other policies. For copy-up, top-down-parent, ++bottom-up-parent, bottom-up and others. ++ ++As expected, the round-robin policy selects the branch in circular. When ++you have two writable branches and creates 10 new files, 5 files will be ++created for each branch. mkdir(2) systemcall is an exception. When you ++create 10 new directories, all will be created on the same branch. ++And the most-free-space policy selects the one which has most free ++space among the writable branches. The amount of free space will be ++checked by aufs internally, and users can specify its time interval. ++ ++The policies for copy-up is more simple, ++top-down-parent is equivalent to the same named on in create policy, ++bottom-up-parent selects the writable branch where the parent dir ++exists and the nearest upper one from the copyup-source, ++bottom-up selects the nearest upper writable branch from the ++copyup-source, regardless the existence of the parent dir. ++ ++There are some rules or exceptions to apply these policies. ++- If there is a readonly branch above the policy-selected branch and ++ the parent dir is marked as opaque (a variation of whiteout), or the ++ target (creating) file is whiteout-ed on the upper readonly branch, ++ then the result of the policy is ignored and the target file will be ++ created on the nearest upper writable branch than the readonly branch. ++- If there is a writable branch above the policy-selected branch and ++ the parent dir is marked as opaque or the target file is whiteouted ++ on the branch, then the result of the policy is ignored and the target ++ file will be created on the highest one among the upper writable ++ branches who has diropq or whiteout. In case of whiteout, aufs removes ++ it as usual. ++- link(2) and rename(2) systemcalls are exceptions in every policy. ++ They try selecting the branch where the source exists as possible ++ since copyup a large file will take long time. If it can't be, ++ ie. the branch where the source exists is readonly, then they will ++ follow the copyup policy. ++- There is an exception for rename(2) when the target exists. ++ If the rename target exists, aufs compares the index of the branches ++ where the source and the target exists and selects the higher ++ one. If the selected branch is readonly, then aufs follows the ++ copyup policy. +diff --git a/Documentation/filesystems/aufs/design/06fhsm.txt b/Documentation/filesystems/aufs/design/06fhsm.txt +new file mode 100644 +index 0000000..84b46dc +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/06fhsm.txt +@@ -0,0 +1,105 @@ ++ ++# Copyright (C) 2011-2016 Junjiro R. Okajima ++ ++File-based Hierarchical Storage Management (FHSM) ++---------------------------------------------------------------------- ++Hierarchical Storage Management (or HSM) is a well-known feature in the ++storage world. Aufs provides this feature as file-based with multiple ++writable branches, based upon the principle of "Colder, the Lower". ++Here the word "colder" means that the less used files, and "lower" means ++that the position in the order of the stacked branches vertically. ++These multiple writable branches are prioritized, ie. the topmost one ++should be the fastest drive and be used heavily. ++ ++o Characters in aufs FHSM story ++- aufs itself and a new branch attribute. ++- a new ioctl interface to move-down and to establish a connection with ++ the daemon ("move-down" is a converse of "copy-up"). ++- userspace tool and daemon. ++ ++The userspace daemon establishes a connection with aufs and waits for ++the notification. The notified information is very similar to struct ++statfs containing the number of consumed blocks and inodes. ++When the consumed blocks/inodes of a branch exceeds the user-specified ++upper watermark, the daemon activates its move-down process until the ++consumed blocks/inodes reaches the user-specified lower watermark. ++ ++The actual move-down is done by aufs based upon the request from ++user-space since we need to maintain the inode number and the internal ++pointer arrays in aufs. ++ ++Currently aufs FHSM handles the regular files only. Additionally they ++must not be hard-linked nor pseudo-linked. ++ ++ ++o Cowork of aufs and the user-space daemon ++ During the userspace daemon established the connection, aufs sends a ++ small notification to it whenever aufs writes something into the ++ writable branch. But it may cost high since aufs issues statfs(2) ++ internally. So user can specify a new option to cache the ++ info. Actually the notification is controlled by these factors. ++ + the specified cache time. ++ + classified as "force" by aufs internally. ++ Until the specified time expires, aufs doesn't send the info ++ except the forced cases. When aufs decide forcing, the info is always ++ notified to userspace. ++ For example, the number of free inodes is generally large enough and ++ the shortage of it happens rarely. So aufs doesn't force the ++ notification when creating a new file, directory and others. This is ++ the typical case which aufs doesn't force. ++ When aufs writes the actual filedata and the files consumes any of new ++ blocks, the aufs forces notifying. ++ ++ ++o Interfaces in aufs ++- New branch attribute. ++ + fhsm ++ Specifies that the branch is managed by FHSM feature. In other word, ++ participant in the FHSM. ++ When nofhsm is set to the branch, it will not be the source/target ++ branch of the move-down operation. This attribute is set ++ independently from coo and moo attributes, and if you want full ++ FHSM, you should specify them as well. ++- New mount option. ++ + fhsm_sec ++ Specifies a second to suppress many less important info to be ++ notified. ++- New ioctl. ++ + AUFS_CTL_FHSM_FD ++ create a new file descriptor which userspace can read the notification ++ (a subset of struct statfs) from aufs. ++- Module parameter 'brs' ++ It has to be set to 1. Otherwise the new mount option 'fhsm' will not ++ be set. ++- mount helpers /sbin/mount.aufs and /sbin/umount.aufs ++ When there are two or more branches with fhsm attributes, ++ /sbin/mount.aufs invokes the user-space daemon and /sbin/umount.aufs ++ terminates it. As a result of remounting and branch-manipulation, the ++ number of branches with fhsm attribute can be one. In this case, ++ /sbin/mount.aufs will terminate the user-space daemon. ++ ++ ++Finally the operation is done as these steps in kernel-space. ++- make sure that, ++ + no one else is using the file. ++ + the file is not hard-linked. ++ + the file is not pseudo-linked. ++ + the file is a regular file. ++ + the parent dir is not opaqued. ++- find the target writable branch. ++- make sure the file is not whiteout-ed by the upper (than the target) ++ branch. ++- make the parent dir on the target branch. ++- mutex lock the inode on the branch. ++- unlink the whiteout on the target branch (if exists). ++- lookup and create the whiteout-ed temporary name on the target branch. ++- copy the file as the whiteout-ed temporary name on the target branch. ++- rename the whiteout-ed temporary name to the original name. ++- unlink the file on the source branch. ++- maintain the internal pointer array and the external inode number ++ table (XINO). ++- maintain the timestamps and other attributes of the parent dir and the ++ file. ++ ++And of course, in every step, an error may happen. So the operation ++should restore the original file state after an error happens. +diff --git a/Documentation/filesystems/aufs/design/06mmap.txt b/Documentation/filesystems/aufs/design/06mmap.txt +new file mode 100644 +index 0000000..991c0b1 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/06mmap.txt +@@ -0,0 +1,59 @@ ++ ++# Copyright (C) 2005-2016 Junjiro R. Okajima ++ ++mmap(2) -- File Memory Mapping ++---------------------------------------------------------------------- ++In aufs, the file-mapped pages are handled by a branch fs directly, no ++interaction with aufs. It means aufs_mmap() calls the branch fs's ++->mmap(). ++This approach is simple and good, but there is one problem. ++Under /proc, several entries show the mmapped files by its path (with ++device and inode number), and the printed path will be the path on the ++branch fs's instead of virtual aufs's. ++This is not a problem in most cases, but some utilities lsof(1) (and its ++user) may expect the path on aufs. ++ ++To address this issue, aufs adds a new member called vm_prfile in struct ++vm_area_struct (and struct vm_region). The original vm_file points to ++the file on the branch fs in order to handle everything correctly as ++usual. The new vm_prfile points to a virtual file in aufs, and the ++show-functions in procfs refers to vm_prfile if it is set. ++Also we need to maintain several other places where touching vm_file ++such like ++- fork()/clone() copies vma and the reference count of vm_file is ++ incremented. ++- merging vma maintains the ref count too. ++ ++This is not a good approach. It just fakes the printed path. But it ++leaves all behaviour around f_mapping unchanged. This is surely an ++advantage. ++Actually aufs had adopted another complicated approach which calls ++generic_file_mmap() and handles struct vm_operations_struct. In this ++approach, aufs met a hard problem and I could not solve it without ++switching the approach. ++ ++There may be one more another approach which is ++- bind-mount the branch-root onto the aufs-root internally ++- grab the new vfsmount (ie. struct mount) ++- lazy-umount the branch-root internally ++- in open(2) the aufs-file, open the branch-file with the hidden ++ vfsmount (instead of the original branch's vfsmount) ++- ideally this "bind-mount and lazy-umount" should be done atomically, ++ but it may be possible from userspace by the mount helper. ++ ++Adding the internal hidden vfsmount and using it in opening a file, the ++file path under /proc will be printed correctly. This approach looks ++smarter, but is not possible I am afraid. ++- aufs-root may be bind-mount later. when it happens, another hidden ++ vfsmount will be required. ++- it is hard to get the chance to bind-mount and lazy-umount ++ + in kernel-space, FS can have vfsmount in open(2) via ++ file->f_path, and aufs can know its vfsmount. But several locks are ++ already acquired, and if aufs tries to bind-mount and lazy-umount ++ here, then it may cause a deadlock. ++ + in user-space, bind-mount doesn't invoke the mount helper. ++- since /proc shows dev and ino, aufs has to give vma these info. it ++ means a new member vm_prinode will be necessary. this is essentially ++ equivalent to vm_prfile described above. ++ ++I have to give up this "looks-smater" approach. +diff --git a/Documentation/filesystems/aufs/design/06xattr.txt b/Documentation/filesystems/aufs/design/06xattr.txt +new file mode 100644 +index 0000000..7bfa94f +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/06xattr.txt +@@ -0,0 +1,81 @@ ++ ++# Copyright (C) 2014-2016 Junjiro R. Okajima ++ ++Listing XATTR/EA and getting the value ++---------------------------------------------------------------------- ++For the inode standard attributes (owner, group, timestamps, etc.), aufs ++shows the values from the topmost existing file. This behaviour is good ++for the non-dir entries since the bahaviour exactly matches the shown ++information. But for the directories, aufs considers all the same named ++entries on the lower branches. Which means, if one of the lower entry ++rejects readdir call, then aufs returns an error even if the topmost ++entry allows it. This behaviour is necessary to respect the branch fs's ++security, but can make users confused since the user-visible standard ++attributes don't match the behaviour. ++To address this issue, aufs has a mount option called dirperm1 which ++checks the permission for the topmost entry only, and ignores the lower ++entry's permission. ++ ++A similar issue can happen around XATTR. ++getxattr(2) and listxattr(2) families behave as if dirperm1 option is ++always set. Otherwise these very unpleasant situation would happen. ++- listxattr(2) may return the duplicated entries. ++- users may not be able to remove or reset the XATTR forever, ++ ++ ++XATTR/EA support in the internal (copy,move)-(up,down) ++---------------------------------------------------------------------- ++Generally the extended attributes of inode are categorized as these. ++- "security" for LSM and capability. ++- "system" for posix ACL, 'acl' mount option is required for the branch ++ fs generally. ++- "trusted" for userspace, CAP_SYS_ADMIN is required. ++- "user" for userspace, 'user_xattr' mount option is required for the ++ branch fs generally. ++ ++Moreover there are some other categories. Aufs handles these rather ++unpopular categories as the ordinary ones, ie. there is no special ++condition nor exception. ++ ++In copy-up, the support for XATTR on the dst branch may differ from the ++src branch. In this case, the copy-up operation will get an error and ++the original user operation which triggered the copy-up will fail. It ++can happen that even all copy-up will fail. ++When both of src and dst branches support XATTR and if an error occurs ++during copying XATTR, then the copy-up should fail obviously. That is a ++good reason and aufs should return an error to userspace. But when only ++the src branch support that XATTR, aufs should not return an error. ++For example, the src branch supports ACL but the dst branch doesn't ++because the dst branch may natively un-support it or temporary ++un-support it due to "noacl" mount option. Of course, the dst branch fs ++may NOT return an error even if the XATTR is not supported. It is ++totally up to the branch fs. ++ ++Anyway when the aufs internal copy-up gets an error from the dst branch ++fs, then aufs tries removing the just copied entry and returns the error ++to the userspace. The worst case of this situation will be all copy-up ++will fail. ++ ++For the copy-up operation, there two basic approaches. ++- copy the specified XATTR only (by category above), and return the ++ error unconditionally if it happens. ++- copy all XATTR, and ignore the error on the specified category only. ++ ++In order to support XATTR and to implement the correct behaviour, aufs ++chooses the latter approach and introduces some new branch attributes, ++"icexsec", "icexsys", "icextr", "icexusr", and "icexoth". ++They correspond to the XATTR namespaces (see above). Additionally, to be ++convenient, "icex" is also provided which means all "icex*" attributes ++are set (here the word "icex" stands for "ignore copy-error on XATTR"). ++ ++The meaning of these attributes is to ignore the error from setting ++XATTR on that branch. ++Note that aufs tries copying all XATTR unconditionally, and ignores the ++error from the dst branch according to the specified attributes. ++ ++Some XATTR may have its default value. The default value may come from ++the parent dir or the environment. If the default value is set at the ++file creating-time, it will be overwritten by copy-up. ++Some contradiction may happen I am afraid. ++Do we need another attribute to stop copying XATTR? I am unsure. For ++now, aufs implements the branch attributes to ignore the error. +diff --git a/Documentation/filesystems/aufs/design/07export.txt b/Documentation/filesystems/aufs/design/07export.txt +new file mode 100644 +index 0000000..c23930b +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/07export.txt +@@ -0,0 +1,45 @@ ++ ++# Copyright (C) 2005-2016 Junjiro R. Okajima ++ ++Export Aufs via NFS ++---------------------------------------------------------------------- ++Here is an approach. ++- like xino/xib, add a new file 'xigen' which stores aufs inode ++ generation. ++- iget_locked(): initialize aufs inode generation for a new inode, and ++ store it in xigen file. ++- destroy_inode(): increment aufs inode generation and store it in xigen ++ file. it is necessary even if it is not unlinked, because any data of ++ inode may be changed by UDBA. ++- encode_fh(): for a root dir, simply return FILEID_ROOT. otherwise ++ build file handle by ++ + branch id (4 bytes) ++ + superblock generation (4 bytes) ++ + inode number (4 or 8 bytes) ++ + parent dir inode number (4 or 8 bytes) ++ + inode generation (4 bytes)) ++ + return value of exportfs_encode_fh() for the parent on a branch (4 ++ bytes) ++ + file handle for a branch (by exportfs_encode_fh()) ++- fh_to_dentry(): ++ + find the index of a branch from its id in handle, and check it is ++ still exist in aufs. ++ + 1st level: get the inode number from handle and search it in cache. ++ + 2nd level: if not found in cache, get the parent inode number from ++ the handle and search it in cache. and then open the found parent ++ dir, find the matching inode number by vfs_readdir() and get its ++ name, and call lookup_one_len() for the target dentry. ++ + 3rd level: if the parent dir is not cached, call ++ exportfs_decode_fh() for a branch and get the parent on a branch, ++ build a pathname of it, convert it a pathname in aufs, call ++ path_lookup(). now aufs gets a parent dir dentry, then handle it as ++ the 2nd level. ++ + to open the dir, aufs needs struct vfsmount. aufs keeps vfsmount ++ for every branch, but not itself. to get this, (currently) aufs ++ searches in current->nsproxy->mnt_ns list. it may not be a good ++ idea, but I didn't get other approach. ++ + test the generation of the gotten inode. ++- every inode operation: they may get EBUSY due to UDBA. in this case, ++ convert it into ESTALE for NFSD. ++- readdir(): call lockdep_on/off() because filldir in NFSD calls ++ lookup_one_len(), vfs_getattr(), encode_fh() and others. +diff --git a/Documentation/filesystems/aufs/design/08shwh.txt b/Documentation/filesystems/aufs/design/08shwh.txt +new file mode 100644 +index 0000000..ad58ebe +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/08shwh.txt +@@ -0,0 +1,39 @@ ++ ++# Copyright (C) 2005-2016 Junjiro R. Okajima ++ ++Show Whiteout Mode (shwh) ++---------------------------------------------------------------------- ++Generally aufs hides the name of whiteouts. But in some cases, to show ++them is very useful for users. For instance, creating a new middle layer ++(branch) by merging existing layers. ++ ++(borrowing aufs1 HOW-TO from a user, Michael Towers) ++When you have three branches, ++- Bottom: 'system', squashfs (underlying base system), read-only ++- Middle: 'mods', squashfs, read-only ++- Top: 'overlay', ram (tmpfs), read-write ++ ++The top layer is loaded at boot time and saved at shutdown, to preserve ++the changes made to the system during the session. ++When larger changes have been made, or smaller changes have accumulated, ++the size of the saved top layer data grows. At this point, it would be ++nice to be able to merge the two overlay branches ('mods' and 'overlay') ++and rewrite the 'mods' squashfs, clearing the top layer and thus ++restoring save and load speed. ++ ++This merging is simplified by the use of another aufs mount, of just the ++two overlay branches using the 'shwh' option. ++# mount -t aufs -o ro,shwh,br:/livesys/overlay=ro+wh:/livesys/mods=rr+wh \ ++ aufs /livesys/merge_union ++ ++A merged view of these two branches is then available at ++/livesys/merge_union, and the new feature is that the whiteouts are ++visible! ++Note that in 'shwh' mode the aufs mount must be 'ro', which will disable ++writing to all branches. Also the default mode for all branches is 'ro'. ++It is now possible to save the combined contents of the two overlay ++branches to a new squashfs, e.g.: ++# mksquashfs /livesys/merge_union /path/to/newmods.squash ++ ++This new squashfs archive can be stored on the boot device and the ++initramfs will use it to replace the old one at the next boot. +diff --git a/Documentation/filesystems/aufs/design/10dynop.txt b/Documentation/filesystems/aufs/design/10dynop.txt +new file mode 100644 +index 0000000..49afc58 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/10dynop.txt +@@ -0,0 +1,34 @@ ++ ++# Copyright (C) 2010-2016 Junjiro R. Okajima ++ ++Dynamically customizable FS operations ++---------------------------------------------------------------------- ++Generally FS operations (struct inode_operations, struct ++address_space_operations, struct file_operations, etc.) are defined as ++"static const", but it never means that FS have only one set of ++operation. Some FS have multiple sets of them. For instance, ext2 has ++three sets, one for XIP, for NOBH, and for normal. ++Since aufs overrides and redirects these operations, sometimes aufs has ++to change its behaviour according to the branch FS type. More importantly ++VFS acts differently if a function (member in the struct) is set or ++not. It means aufs should have several sets of operations and select one ++among them according to the branch FS definition. ++ ++In order to solve this problem and not to affect the behaviour of VFS, ++aufs defines these operations dynamically. For instance, aufs defines ++dummy direct_IO function for struct address_space_operations, but it may ++not be set to the address_space_operations actually. When the branch FS ++doesn't have it, aufs doesn't set it to its address_space_operations ++while the function definition itself is still alive. So the behaviour ++itself will not change, and it will return an error when direct_IO is ++not set. ++ ++The lifetime of these dynamically generated operation object is ++maintained by aufs branch object. When the branch is removed from aufs, ++the reference counter of the object is decremented. When it reaches ++zero, the dynamically generated operation object will be freed. ++ ++This approach is designed to support AIO (io_submit), Direct I/O and ++XIP (DAX) mainly. ++Currently this approach is applied to address_space_operations for ++regular files only. +diff --git a/MAINTAINERS b/MAINTAINERS +index 952fd2a..6a8f0f8 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -2210,6 +2210,19 @@ F: include/linux/audit.h + F: include/uapi/linux/audit.h + F: kernel/audit* + ++AUFS (advanced multi layered unification filesystem) FILESYSTEM ++M: "J. R. Okajima" ++L: linux-unionfs@vger.kernel.org ++L: aufs-users@lists.sourceforge.net (members only) ++W: http://aufs.sourceforge.net ++T: git://github.com/sfjro/aufs4-linux.git ++S: Supported ++F: Documentation/filesystems/aufs/ ++F: Documentation/ABI/testing/debugfs-aufs ++F: Documentation/ABI/testing/sysfs-aufs ++F: fs/aufs/ ++F: include/uapi/linux/aufs_type.h ++ + AUXILIARY DISPLAY DRIVERS + M: Miguel Ojeda Sandonis + W: http://miguelojeda.es/auxdisplay.htm +diff --git a/drivers/block/loop.c b/drivers/block/loop.c +index 1fa8cc2..7339e65 100644 +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -712,6 +712,24 @@ static inline int is_loop_device(struct file *file) + return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR; + } + ++/* ++ * for AUFS ++ * no get/put for file. ++ */ ++struct file *loop_backing_file(struct super_block *sb) ++{ ++ struct file *ret; ++ struct loop_device *l; ++ ++ ret = NULL; ++ if (MAJOR(sb->s_dev) == LOOP_MAJOR) { ++ l = sb->s_bdev->bd_disk->private_data; ++ ret = l->lo_backing_file; ++ } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(loop_backing_file); ++ + /* loop sysfs attributes */ + + static ssize_t loop_attr_show(struct device *dev, char *page, +diff --git a/fs/Kconfig b/fs/Kconfig +index b8fcb41..78adefb 100644 +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -236,6 +236,7 @@ source "fs/pstore/Kconfig" + source "fs/sysv/Kconfig" + source "fs/ufs/Kconfig" + source "fs/exofs/Kconfig" ++source "fs/aufs/Kconfig" + + endif # MISC_FILESYSTEMS + +diff --git a/fs/Makefile b/fs/Makefile +index 85b6e13..e7bb164 100644 +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -128,3 +128,4 @@ obj-y += exofs/ # Multiple modules + obj-$(CONFIG_CEPH_FS) += ceph/ + obj-$(CONFIG_PSTORE) += pstore/ + obj-$(CONFIG_EFIVAR_FS) += efivarfs/ ++obj-$(CONFIG_AUFS_FS) += aufs/ +diff --git a/fs/aufs/Kconfig b/fs/aufs/Kconfig +new file mode 100644 +index 0000000..a4efb8b +--- /dev/null ++++ b/fs/aufs/Kconfig +@@ -0,0 +1,185 @@ ++config AUFS_FS ++ bool "Aufs (Advanced multi layered unification filesystem) support" ++ help ++ Aufs is a stackable unification filesystem such as Unionfs, ++ which unifies several directories and provides a merged single ++ directory. ++ In the early days, aufs was entirely re-designed and ++ re-implemented Unionfs Version 1.x series. Introducing many ++ original ideas, approaches and improvements, it becomes totally ++ different from Unionfs while keeping the basic features. ++ ++if AUFS_FS ++choice ++ prompt "Maximum number of branches" ++ default AUFS_BRANCH_MAX_127 ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_127 ++ bool "127" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_511 ++ bool "511" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_1023 ++ bool "1023" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_32767 ++ bool "32767" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++endchoice ++ ++config AUFS_SBILIST ++ bool ++ depends on AUFS_MAGIC_SYSRQ || PROC_FS ++ default y ++ help ++ Automatic configuration for internal use. ++ When aufs supports Magic SysRq or /proc, enabled automatically. ++ ++config AUFS_HNOTIFY ++ bool "Detect direct branch access (bypassing aufs)" ++ help ++ If you want to modify files on branches directly, eg. bypassing aufs, ++ and want aufs to detect the changes of them fully, then enable this ++ option and use 'udba=notify' mount option. ++ Currently there is only one available configuration, "fsnotify". ++ It will have a negative impact to the performance. ++ See detail in aufs.5. ++ ++choice ++ prompt "method" if AUFS_HNOTIFY ++ default AUFS_HFSNOTIFY ++config AUFS_HFSNOTIFY ++ bool "fsnotify" ++ select FSNOTIFY ++endchoice ++ ++config AUFS_EXPORT ++ bool "NFS-exportable aufs" ++ depends on EXPORTFS = y ++ help ++ If you want to export your mounted aufs via NFS, then enable this ++ option. There are several requirements for this configuration. ++ See detail in aufs.5. ++ ++config AUFS_INO_T_64 ++ bool ++ depends on AUFS_EXPORT ++ depends on 64BIT && !(ALPHA || S390) ++ default y ++ help ++ Automatic configuration for internal use. ++ /* typedef unsigned long/int __kernel_ino_t */ ++ /* alpha and s390x are int */ ++ ++config AUFS_XATTR ++ bool "support for XATTR/EA (including Security Labels)" ++ help ++ If your branch fs supports XATTR/EA and you want to make them ++ available in aufs too, then enable this opsion and specify the ++ branch attributes for EA. ++ See detail in aufs.5. ++ ++config AUFS_FHSM ++ bool "File-based Hierarchical Storage Management" ++ help ++ Hierarchical Storage Management (or HSM) is a well-known feature ++ in the storage world. Aufs provides this feature as file-based. ++ with multiple branches. ++ These multiple branches are prioritized, ie. the topmost one ++ should be the fastest drive and be used heavily. ++ ++config AUFS_RDU ++ bool "Readdir in userspace" ++ help ++ Aufs has two methods to provide a merged view for a directory, ++ by a user-space library and by kernel-space natively. The latter ++ is always enabled but sometimes large and slow. ++ If you enable this option, install the library in aufs2-util ++ package, and set some environment variables for your readdir(3), ++ then the work will be handled in user-space which generally ++ shows better performance in most cases. ++ See detail in aufs.5. ++ ++config AUFS_SHWH ++ bool "Show whiteouts" ++ help ++ If you want to make the whiteouts in aufs visible, then enable ++ this option and specify 'shwh' mount option. Although it may ++ sounds like philosophy or something, but in technically it ++ simply shows the name of whiteout with keeping its behaviour. ++ ++config AUFS_BR_RAMFS ++ bool "Ramfs (initramfs/rootfs) as an aufs branch" ++ help ++ If you want to use ramfs as an aufs branch fs, then enable this ++ option. Generally tmpfs is recommended. ++ Aufs prohibited them to be a branch fs by default, because ++ initramfs becomes unusable after switch_root or something ++ generally. If you sets initramfs as an aufs branch and boot your ++ system by switch_root, you will meet a problem easily since the ++ files in initramfs may be inaccessible. ++ Unless you are going to use ramfs as an aufs branch fs without ++ switch_root or something, leave it N. ++ ++config AUFS_BR_FUSE ++ bool "Fuse fs as an aufs branch" ++ depends on FUSE_FS ++ select AUFS_POLL ++ help ++ If you want to use fuse-based userspace filesystem as an aufs ++ branch fs, then enable this option. ++ It implements the internal poll(2) operation which is ++ implemented by fuse only (curretnly). ++ ++config AUFS_POLL ++ bool ++ help ++ Automatic configuration for internal use. ++ ++config AUFS_BR_HFSPLUS ++ bool "Hfsplus as an aufs branch" ++ depends on HFSPLUS_FS ++ default y ++ help ++ If you want to use hfsplus fs as an aufs branch fs, then enable ++ this option. This option introduces a small overhead at ++ copying-up a file on hfsplus. ++ ++config AUFS_BDEV_LOOP ++ bool ++ depends on BLK_DEV_LOOP ++ default y ++ help ++ Automatic configuration for internal use. ++ Convert =[ym] into =y. ++ ++config AUFS_DEBUG ++ bool "Debug aufs" ++ help ++ Enable this to compile aufs internal debug code. ++ It will have a negative impact to the performance. ++ ++config AUFS_MAGIC_SYSRQ ++ bool ++ depends on AUFS_DEBUG && MAGIC_SYSRQ ++ default y ++ help ++ Automatic configuration for internal use. ++ When aufs supports Magic SysRq, enabled automatically. ++endif +diff --git a/fs/aufs/Makefile b/fs/aufs/Makefile +new file mode 100644 +index 0000000..c7efb62 +--- /dev/null ++++ b/fs/aufs/Makefile +@@ -0,0 +1,36 @@ ++ ++include ${srctree}/${src}/magic.mk ++ ++# cf. include/linux/kernel.h ++# enable pr_debug ++ccflags-y += -DDEBUG ++# sparse requires the full pathname ++ccflags-y += -include ${srctree}/include/uapi/linux/aufs_type.h ++ ++obj-$(CONFIG_AUFS_FS) += aufs.o ++aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \ ++ wkq.o vfsub.o dcsub.o \ ++ cpup.o whout.o wbr_policy.o \ ++ dinfo.o dentry.o \ ++ dynop.o \ ++ finfo.o file.o f_op.o \ ++ dir.o vdir.o \ ++ iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \ ++ mvdown.o ioctl.o ++ ++# all are boolean ++aufs-$(CONFIG_PROC_FS) += procfs.o plink.o ++aufs-$(CONFIG_SYSFS) += sysfs.o ++aufs-$(CONFIG_DEBUG_FS) += dbgaufs.o ++aufs-$(CONFIG_AUFS_BDEV_LOOP) += loop.o ++aufs-$(CONFIG_AUFS_HNOTIFY) += hnotify.o ++aufs-$(CONFIG_AUFS_HFSNOTIFY) += hfsnotify.o ++aufs-$(CONFIG_AUFS_EXPORT) += export.o ++aufs-$(CONFIG_AUFS_XATTR) += xattr.o ++aufs-$(CONFIG_FS_POSIX_ACL) += posix_acl.o ++aufs-$(CONFIG_AUFS_FHSM) += fhsm.o ++aufs-$(CONFIG_AUFS_POLL) += poll.o ++aufs-$(CONFIG_AUFS_RDU) += rdu.o ++aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o ++aufs-$(CONFIG_AUFS_DEBUG) += debug.o ++aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o +diff --git a/fs/aufs/aufs.h b/fs/aufs/aufs.h +new file mode 100644 +index 0000000..49f43b4 +--- /dev/null ++++ b/fs/aufs/aufs.h +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * all header files ++ */ ++ ++#ifndef __AUFS_H__ ++#define __AUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#define AuStub(type, name, body, ...) \ ++ static inline type name(__VA_ARGS__) { body; } ++ ++#define AuStubVoid(name, ...) \ ++ AuStub(void, name, , __VA_ARGS__) ++#define AuStubInt0(name, ...) \ ++ AuStub(int, name, return 0, __VA_ARGS__) ++ ++#include "debug.h" ++ ++#include "branch.h" ++#include "cpup.h" ++#include "dcsub.h" ++#include "dbgaufs.h" ++#include "dentry.h" ++#include "dir.h" ++#include "dynop.h" ++#include "file.h" ++#include "fstype.h" ++#include "inode.h" ++#include "loop.h" ++#include "module.h" ++#include "opts.h" ++#include "rwsem.h" ++#include "spl.h" ++#include "super.h" ++#include "sysaufs.h" ++#include "vfsub.h" ++#include "whout.h" ++#include "wkq.h" ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_H__ */ +diff --git a/fs/aufs/branch.c b/fs/aufs/branch.c +new file mode 100644 +index 0000000..baf786e +--- /dev/null ++++ b/fs/aufs/branch.c +@@ -0,0 +1,1393 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * branch management ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * free a single branch ++ */ ++static void au_br_do_free(struct au_branch *br) ++{ ++ int i; ++ struct au_wbr *wbr; ++ struct au_dykey **key; ++ ++ au_hnotify_fin_br(br); ++ ++ if (br->br_xino.xi_file) ++ fput(br->br_xino.xi_file); ++ mutex_destroy(&br->br_xino.xi_nondir_mtx); ++ ++ AuDebugOn(au_br_count(br)); ++ au_br_count_fin(br); ++ ++ wbr = br->br_wbr; ++ if (wbr) { ++ for (i = 0; i < AuBrWh_Last; i++) ++ dput(wbr->wbr_wh[i]); ++ AuDebugOn(atomic_read(&wbr->wbr_wh_running)); ++ AuRwDestroy(&wbr->wbr_wh_rwsem); ++ } ++ ++ if (br->br_fhsm) { ++ au_br_fhsm_fin(br->br_fhsm); ++ kfree(br->br_fhsm); ++ } ++ ++ key = br->br_dykey; ++ for (i = 0; i < AuBrDynOp; i++, key++) ++ if (*key) ++ au_dy_put(*key); ++ else ++ break; ++ ++ /* recursive lock, s_umount of branch's */ ++ lockdep_off(); ++ path_put(&br->br_path); ++ lockdep_on(); ++ kfree(wbr); ++ kfree(br); ++} ++ ++/* ++ * frees all branches ++ */ ++void au_br_free(struct au_sbinfo *sbinfo) ++{ ++ aufs_bindex_t bmax; ++ struct au_branch **br; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ bmax = sbinfo->si_bbot + 1; ++ br = sbinfo->si_branch; ++ while (bmax--) ++ au_br_do_free(*br++); ++} ++ ++/* ++ * find the index of a branch which is specified by @br_id. ++ */ ++int au_br_index(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ aufs_bindex_t bindex, bbot; ++ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (au_sbr_id(sb, bindex) == br_id) ++ return bindex; ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * add a branch ++ */ ++ ++static int test_overlap(struct super_block *sb, struct dentry *h_adding, ++ struct dentry *h_root) ++{ ++ if (unlikely(h_adding == h_root ++ || au_test_loopback_overlap(sb, h_adding))) ++ return 1; ++ if (h_adding->d_sb != h_root->d_sb) ++ return 0; ++ return au_test_subdir(h_adding, h_root) ++ || au_test_subdir(h_root, h_adding); ++} ++ ++/* ++ * returns a newly allocated branch. @new_nbranch is a number of branches ++ * after adding a branch. ++ */ ++static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch, ++ int perm) ++{ ++ struct au_branch *add_branch; ++ struct dentry *root; ++ struct inode *inode; ++ int err; ++ ++ err = -ENOMEM; ++ root = sb->s_root; ++ add_branch = kzalloc(sizeof(*add_branch), GFP_NOFS); ++ if (unlikely(!add_branch)) ++ goto out; ++ ++ err = au_hnotify_init_br(add_branch, perm); ++ if (unlikely(err)) ++ goto out_br; ++ ++ if (au_br_writable(perm)) { ++ /* may be freed separately at changing the branch permission */ ++ add_branch->br_wbr = kzalloc(sizeof(*add_branch->br_wbr), ++ GFP_NOFS); ++ if (unlikely(!add_branch->br_wbr)) ++ goto out_hnotify; ++ } ++ ++ if (au_br_fhsm(perm)) { ++ err = au_fhsm_br_alloc(add_branch); ++ if (unlikely(err)) ++ goto out_wbr; ++ } ++ ++ err = au_sbr_realloc(au_sbi(sb), new_nbranch); ++ if (!err) ++ err = au_di_realloc(au_di(root), new_nbranch); ++ if (!err) { ++ inode = d_inode(root); ++ err = au_hinode_realloc(au_ii(inode), new_nbranch); ++ } ++ if (!err) ++ return add_branch; /* success */ ++ ++out_wbr: ++ kfree(add_branch->br_wbr); ++out_hnotify: ++ au_hnotify_fin_br(add_branch); ++out_br: ++ kfree(add_branch); ++out: ++ return ERR_PTR(err); ++} ++ ++/* ++ * test if the branch permission is legal or not. ++ */ ++static int test_br(struct inode *inode, int brperm, char *path) ++{ ++ int err; ++ ++ err = (au_br_writable(brperm) && IS_RDONLY(inode)); ++ if (!err) ++ goto out; ++ ++ err = -EINVAL; ++ pr_err("write permission for readonly mount or inode, %s\n", path); ++ ++out: ++ return err; ++} ++ ++/* ++ * returns: ++ * 0: success, the caller will add it ++ * plus: success, it is already unified, the caller should ignore it ++ * minus: error ++ */ ++static int test_add(struct super_block *sb, struct au_opt_add *add, int remount) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct dentry *root, *h_dentry; ++ struct inode *inode, *h_inode; ++ ++ root = sb->s_root; ++ bbot = au_sbbot(sb); ++ if (unlikely(bbot >= 0 ++ && au_find_dbindex(root, add->path.dentry) >= 0)) { ++ err = 1; ++ if (!remount) { ++ err = -EINVAL; ++ pr_err("%s duplicated\n", add->pathname); ++ } ++ goto out; ++ } ++ ++ err = -ENOSPC; /* -E2BIG; */ ++ if (unlikely(AUFS_BRANCH_MAX <= add->bindex ++ || AUFS_BRANCH_MAX - 1 <= bbot)) { ++ pr_err("number of branches exceeded %s\n", add->pathname); ++ goto out; ++ } ++ ++ err = -EDOM; ++ if (unlikely(add->bindex < 0 || bbot + 1 < add->bindex)) { ++ pr_err("bad index %d\n", add->bindex); ++ goto out; ++ } ++ ++ inode = d_inode(add->path.dentry); ++ err = -ENOENT; ++ if (unlikely(!inode->i_nlink)) { ++ pr_err("no existence %s\n", add->pathname); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ if (unlikely(inode->i_sb == sb)) { ++ pr_err("%s must be outside\n", add->pathname); ++ goto out; ++ } ++ ++ if (unlikely(au_test_fs_unsuppoted(inode->i_sb))) { ++ pr_err("unsupported filesystem, %s (%s)\n", ++ add->pathname, au_sbtype(inode->i_sb)); ++ goto out; ++ } ++ ++ if (unlikely(inode->i_sb->s_stack_depth)) { ++ pr_err("already stacked, %s (%s)\n", ++ add->pathname, au_sbtype(inode->i_sb)); ++ goto out; ++ } ++ ++ err = test_br(d_inode(add->path.dentry), add->perm, add->pathname); ++ if (unlikely(err)) ++ goto out; ++ ++ if (bbot < 0) ++ return 0; /* success */ ++ ++ err = -EINVAL; ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (unlikely(test_overlap(sb, add->path.dentry, ++ au_h_dptr(root, bindex)))) { ++ pr_err("%s is overlapped\n", add->pathname); ++ goto out; ++ } ++ ++ err = 0; ++ if (au_opt_test(au_mntflags(sb), WARN_PERM)) { ++ h_dentry = au_h_dptr(root, 0); ++ h_inode = d_inode(h_dentry); ++ if ((h_inode->i_mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO) ++ || !uid_eq(h_inode->i_uid, inode->i_uid) ++ || !gid_eq(h_inode->i_gid, inode->i_gid)) ++ pr_warn("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n", ++ add->pathname, ++ i_uid_read(inode), i_gid_read(inode), ++ (inode->i_mode & S_IALLUGO), ++ i_uid_read(h_inode), i_gid_read(h_inode), ++ (h_inode->i_mode & S_IALLUGO)); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * initialize or clean the whiteouts for an adding branch ++ */ ++static int au_br_init_wh(struct super_block *sb, struct au_branch *br, ++ int new_perm) ++{ ++ int err, old_perm; ++ aufs_bindex_t bindex; ++ struct inode *h_inode; ++ struct au_wbr *wbr; ++ struct au_hinode *hdir; ++ struct dentry *h_dentry; ++ ++ err = vfsub_mnt_want_write(au_br_mnt(br)); ++ if (unlikely(err)) ++ goto out; ++ ++ wbr = br->br_wbr; ++ old_perm = br->br_perm; ++ br->br_perm = new_perm; ++ hdir = NULL; ++ h_inode = NULL; ++ bindex = au_br_index(sb, br->br_id); ++ if (0 <= bindex) { ++ hdir = au_hi(d_inode(sb->s_root), bindex); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ } else { ++ h_dentry = au_br_dentry(br); ++ h_inode = d_inode(h_dentry); ++ inode_lock_nested(h_inode, AuLsc_I_PARENT); ++ } ++ if (!wbr) ++ err = au_wh_init(br, sb); ++ else { ++ wbr_wh_write_lock(wbr); ++ err = au_wh_init(br, sb); ++ wbr_wh_write_unlock(wbr); ++ } ++ if (hdir) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(h_inode); ++ vfsub_mnt_drop_write(au_br_mnt(br)); ++ br->br_perm = old_perm; ++ ++ if (!err && wbr && !au_br_writable(new_perm)) { ++ kfree(wbr); ++ br->br_wbr = NULL; ++ } ++ ++out: ++ return err; ++} ++ ++static int au_wbr_init(struct au_branch *br, struct super_block *sb, ++ int perm) ++{ ++ int err; ++ struct kstatfs kst; ++ struct au_wbr *wbr; ++ ++ wbr = br->br_wbr; ++ au_rw_init(&wbr->wbr_wh_rwsem); ++ atomic_set(&wbr->wbr_wh_running, 0); ++ ++ /* ++ * a limit for rmdir/rename a dir ++ * cf. AUFS_MAX_NAMELEN in include/uapi/linux/aufs_type.h ++ */ ++ err = vfs_statfs(&br->br_path, &kst); ++ if (unlikely(err)) ++ goto out; ++ err = -EINVAL; ++ if (kst.f_namelen >= NAME_MAX) ++ err = au_br_init_wh(sb, br, perm); ++ else ++ pr_err("%pd(%s), unsupported namelen %ld\n", ++ au_br_dentry(br), ++ au_sbtype(au_br_dentry(br)->d_sb), kst.f_namelen); ++ ++out: ++ return err; ++} ++ ++/* initialize a new branch */ ++static int au_br_init(struct au_branch *br, struct super_block *sb, ++ struct au_opt_add *add) ++{ ++ int err; ++ struct inode *h_inode; ++ ++ err = 0; ++ mutex_init(&br->br_xino.xi_nondir_mtx); ++ br->br_perm = add->perm; ++ br->br_path = add->path; /* set first, path_get() later */ ++ spin_lock_init(&br->br_dykey_lock); ++ au_br_count_init(br); ++ atomic_set(&br->br_xino_running, 0); ++ br->br_id = au_new_br_id(sb); ++ AuDebugOn(br->br_id < 0); ++ ++ if (au_br_writable(add->perm)) { ++ err = au_wbr_init(br, sb, add->perm); ++ if (unlikely(err)) ++ goto out_err; ++ } ++ ++ if (au_opt_test(au_mntflags(sb), XINO)) { ++ h_inode = d_inode(add->path.dentry); ++ err = au_xino_br(sb, br, h_inode->i_ino, ++ au_sbr(sb, 0)->br_xino.xi_file, /*do_test*/1); ++ if (unlikely(err)) { ++ AuDebugOn(br->br_xino.xi_file); ++ goto out_err; ++ } ++ } ++ ++ sysaufs_br_init(br); ++ path_get(&br->br_path); ++ goto out; /* success */ ++ ++out_err: ++ memset(&br->br_path, 0, sizeof(br->br_path)); ++out: ++ return err; ++} ++ ++static void au_br_do_add_brp(struct au_sbinfo *sbinfo, aufs_bindex_t bindex, ++ struct au_branch *br, aufs_bindex_t bbot, ++ aufs_bindex_t amount) ++{ ++ struct au_branch **brp; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ brp = sbinfo->si_branch + bindex; ++ memmove(brp + 1, brp, sizeof(*brp) * amount); ++ *brp = br; ++ sbinfo->si_bbot++; ++ if (unlikely(bbot < 0)) ++ sbinfo->si_bbot = 0; ++} ++ ++static void au_br_do_add_hdp(struct au_dinfo *dinfo, aufs_bindex_t bindex, ++ aufs_bindex_t bbot, aufs_bindex_t amount) ++{ ++ struct au_hdentry *hdp; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ hdp = au_hdentry(dinfo, bindex); ++ memmove(hdp + 1, hdp, sizeof(*hdp) * amount); ++ au_h_dentry_init(hdp); ++ dinfo->di_bbot++; ++ if (unlikely(bbot < 0)) ++ dinfo->di_btop = 0; ++} ++ ++static void au_br_do_add_hip(struct au_iinfo *iinfo, aufs_bindex_t bindex, ++ aufs_bindex_t bbot, aufs_bindex_t amount) ++{ ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ hip = au_hinode(iinfo, bindex); ++ memmove(hip + 1, hip, sizeof(*hip) * amount); ++ au_hinode_init(hip); ++ iinfo->ii_bbot++; ++ if (unlikely(bbot < 0)) ++ iinfo->ii_btop = 0; ++} ++ ++static void au_br_do_add(struct super_block *sb, struct au_branch *br, ++ aufs_bindex_t bindex) ++{ ++ struct dentry *root, *h_dentry; ++ struct inode *root_inode, *h_inode; ++ aufs_bindex_t bbot, amount; ++ ++ root = sb->s_root; ++ root_inode = d_inode(root); ++ bbot = au_sbbot(sb); ++ amount = bbot + 1 - bindex; ++ h_dentry = au_br_dentry(br); ++ au_sbilist_lock(); ++ au_br_do_add_brp(au_sbi(sb), bindex, br, bbot, amount); ++ au_br_do_add_hdp(au_di(root), bindex, bbot, amount); ++ au_br_do_add_hip(au_ii(root_inode), bindex, bbot, amount); ++ au_set_h_dptr(root, bindex, dget(h_dentry)); ++ h_inode = d_inode(h_dentry); ++ au_set_h_iptr(root_inode, bindex, au_igrab(h_inode), /*flags*/0); ++ au_sbilist_unlock(); ++} ++ ++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount) ++{ ++ int err; ++ aufs_bindex_t bbot, add_bindex; ++ struct dentry *root, *h_dentry; ++ struct inode *root_inode; ++ struct au_branch *add_branch; ++ ++ root = sb->s_root; ++ root_inode = d_inode(root); ++ IMustLock(root_inode); ++ IiMustWriteLock(root_inode); ++ err = test_add(sb, add, remount); ++ if (unlikely(err < 0)) ++ goto out; ++ if (err) { ++ err = 0; ++ goto out; /* success */ ++ } ++ ++ bbot = au_sbbot(sb); ++ add_branch = au_br_alloc(sb, bbot + 2, add->perm); ++ err = PTR_ERR(add_branch); ++ if (IS_ERR(add_branch)) ++ goto out; ++ ++ err = au_br_init(add_branch, sb, add); ++ if (unlikely(err)) { ++ au_br_do_free(add_branch); ++ goto out; ++ } ++ ++ add_bindex = add->bindex; ++ if (!remount) ++ au_br_do_add(sb, add_branch, add_bindex); ++ else { ++ sysaufs_brs_del(sb, add_bindex); ++ au_br_do_add(sb, add_branch, add_bindex); ++ sysaufs_brs_add(sb, add_bindex); ++ } ++ ++ h_dentry = add->path.dentry; ++ if (!add_bindex) { ++ au_cpup_attr_all(root_inode, /*force*/1); ++ sb->s_maxbytes = h_dentry->d_sb->s_maxbytes; ++ } else ++ au_add_nlink(root_inode, d_inode(h_dentry)); ++ ++ /* ++ * this test/set prevents aufs from handling unnecesary notify events ++ * of xino files, in case of re-adding a writable branch which was ++ * once detached from aufs. ++ */ ++ if (au_xino_brid(sb) < 0 ++ && au_br_writable(add_branch->br_perm) ++ && !au_test_fs_bad_xino(h_dentry->d_sb) ++ && add_branch->br_xino.xi_file ++ && add_branch->br_xino.xi_file->f_path.dentry->d_parent == h_dentry) ++ au_xino_brid_set(sb, add_branch->br_id); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static unsigned long long au_farray_cb(struct super_block *sb, void *a, ++ unsigned long long max __maybe_unused, ++ void *arg) ++{ ++ unsigned long long n; ++ struct file **p, *f; ++ struct au_sphlhead *files; ++ struct au_finfo *finfo; ++ ++ n = 0; ++ p = a; ++ files = &au_sbi(sb)->si_files; ++ spin_lock(&files->spin); ++ hlist_for_each_entry(finfo, &files->head, fi_hlist) { ++ f = finfo->fi_file; ++ if (file_count(f) ++ && !special_file(file_inode(f)->i_mode)) { ++ get_file(f); ++ *p++ = f; ++ n++; ++ AuDebugOn(n > max); ++ } ++ } ++ spin_unlock(&files->spin); ++ ++ return n; ++} ++ ++static struct file **au_farray_alloc(struct super_block *sb, ++ unsigned long long *max) ++{ ++ *max = au_nfiles(sb); ++ return au_array_alloc(max, au_farray_cb, sb, /*arg*/NULL); ++} ++ ++static void au_farray_free(struct file **a, unsigned long long max) ++{ ++ unsigned long long ull; ++ ++ for (ull = 0; ull < max; ull++) ++ if (a[ull]) ++ fput(a[ull]); ++ kvfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * delete a branch ++ */ ++ ++/* to show the line number, do not make it inlined function */ ++#define AuVerbose(do_info, fmt, ...) do { \ ++ if (do_info) \ ++ pr_info(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++static int au_test_ibusy(struct inode *inode, aufs_bindex_t btop, ++ aufs_bindex_t bbot) ++{ ++ return (inode && !S_ISDIR(inode->i_mode)) || btop == bbot; ++} ++ ++static int au_test_dbusy(struct dentry *dentry, aufs_bindex_t btop, ++ aufs_bindex_t bbot) ++{ ++ return au_test_ibusy(d_inode(dentry), btop, bbot); ++} ++ ++/* ++ * test if the branch is deletable or not. ++ */ ++static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex, ++ unsigned int sigen, const unsigned int verbose) ++{ ++ int err, i, j, ndentry; ++ aufs_bindex_t btop, bbot; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry *d; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ for (i = 0; !err && i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = 0; !err && j < ndentry; j++) { ++ d = dpage->dentries[j]; ++ AuDebugOn(au_dcount(d) <= 0); ++ if (!au_digen_test(d, sigen)) { ++ di_read_lock_child(d, AuLock_IR); ++ if (unlikely(au_dbrange_test(d))) { ++ di_read_unlock(d, AuLock_IR); ++ continue; ++ } ++ } else { ++ di_write_lock_child(d); ++ if (unlikely(au_dbrange_test(d))) { ++ di_write_unlock(d); ++ continue; ++ } ++ err = au_reval_dpath(d, sigen); ++ if (!err) ++ di_downgrade_lock(d, AuLock_IR); ++ else { ++ di_write_unlock(d); ++ break; ++ } ++ } ++ ++ /* AuDbgDentry(d); */ ++ btop = au_dbtop(d); ++ bbot = au_dbbot(d); ++ if (btop <= bindex ++ && bindex <= bbot ++ && au_h_dptr(d, bindex) ++ && au_test_dbusy(d, btop, bbot)) { ++ err = -EBUSY; ++ AuVerbose(verbose, "busy %pd\n", d); ++ AuDbgDentry(d); ++ } ++ di_read_unlock(d, AuLock_IR); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex, ++ unsigned int sigen, const unsigned int verbose) ++{ ++ int err; ++ unsigned long long max, ull; ++ struct inode *i, **array; ++ aufs_bindex_t btop, bbot; ++ ++ array = au_iarray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ AuDbg("b%d\n", bindex); ++ for (ull = 0; !err && ull < max; ull++) { ++ i = array[ull]; ++ if (unlikely(!i)) ++ break; ++ if (i->i_ino == AUFS_ROOT_INO) ++ continue; ++ ++ /* AuDbgInode(i); */ ++ if (au_iigen(i, NULL) == sigen) ++ ii_read_lock_child(i); ++ else { ++ ii_write_lock_child(i); ++ err = au_refresh_hinode_self(i); ++ au_iigen_dec(i); ++ if (!err) ++ ii_downgrade_lock(i); ++ else { ++ ii_write_unlock(i); ++ break; ++ } ++ } ++ ++ btop = au_ibtop(i); ++ bbot = au_ibbot(i); ++ if (btop <= bindex ++ && bindex <= bbot ++ && au_h_iptr(i, bindex) ++ && au_test_ibusy(i, btop, bbot)) { ++ err = -EBUSY; ++ AuVerbose(verbose, "busy i%lu\n", i->i_ino); ++ AuDbgInode(i); ++ } ++ ii_read_unlock(i); ++ } ++ au_iarray_free(array, max); ++ ++out: ++ return err; ++} ++ ++static int test_children_busy(struct dentry *root, aufs_bindex_t bindex, ++ const unsigned int verbose) ++{ ++ int err; ++ unsigned int sigen; ++ ++ sigen = au_sigen(root->d_sb); ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(d_inode(root)); ++ di_write_unlock(root); ++ err = test_dentry_busy(root, bindex, sigen, verbose); ++ if (!err) ++ err = test_inode_busy(root->d_sb, bindex, sigen, verbose); ++ di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ ++ ++ return err; ++} ++ ++static int test_dir_busy(struct file *file, aufs_bindex_t br_id, ++ struct file **to_free, int *idx) ++{ ++ int err; ++ unsigned char matched, root; ++ aufs_bindex_t bindex, bbot; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ ++ err = 0; ++ root = IS_ROOT(file->f_path.dentry); ++ if (root) { ++ get_file(file); ++ to_free[*idx] = file; ++ (*idx)++; ++ goto out; ++ } ++ ++ matched = 0; ++ fidir = au_fi(file)->fi_hdir; ++ AuDebugOn(!fidir); ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); bindex <= bbot; bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ if (!hfile->hf_file) ++ continue; ++ ++ if (hfile->hf_br->br_id == br_id) { ++ matched = 1; ++ break; ++ } ++ } ++ if (matched) ++ err = -EBUSY; ++ ++out: ++ return err; ++} ++ ++static int test_file_busy(struct super_block *sb, aufs_bindex_t br_id, ++ struct file **to_free, int opened) ++{ ++ int err, idx; ++ unsigned long long ull, max; ++ aufs_bindex_t btop; ++ struct file *file, **array; ++ struct dentry *root; ++ struct au_hfile *hfile; ++ ++ array = au_farray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ idx = 0; ++ root = sb->s_root; ++ di_write_unlock(root); ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ fi_read_lock(file); ++ btop = au_fbtop(file); ++ if (!d_is_dir(file->f_path.dentry)) { ++ hfile = &au_fi(file)->fi_htop; ++ if (hfile->hf_br->br_id == br_id) ++ err = -EBUSY; ++ } else ++ err = test_dir_busy(file, br_id, to_free, &idx); ++ fi_read_unlock(file); ++ if (unlikely(err)) ++ break; ++ } ++ di_write_lock_child(root); ++ au_farray_free(array, max); ++ AuDebugOn(idx > opened); ++ ++out: ++ return err; ++} ++ ++static void br_del_file(struct file **to_free, unsigned long long opened, ++ aufs_bindex_t br_id) ++{ ++ unsigned long long ull; ++ aufs_bindex_t bindex, btop, bbot, bfound; ++ struct file *file; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ ++ for (ull = 0; ull < opened; ull++) { ++ file = to_free[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ AuDebugOn(!d_is_dir(file->f_path.dentry)); ++ bfound = -1; ++ fidir = au_fi(file)->fi_hdir; ++ AuDebugOn(!fidir); ++ fi_write_lock(file); ++ btop = au_fbtop(file); ++ bbot = au_fbbot_dir(file); ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ if (!hfile->hf_file) ++ continue; ++ ++ if (hfile->hf_br->br_id == br_id) { ++ bfound = bindex; ++ break; ++ } ++ } ++ AuDebugOn(bfound < 0); ++ au_set_h_fptr(file, bfound, NULL); ++ if (bfound == btop) { ++ for (btop++; btop <= bbot; btop++) ++ if (au_hf_dir(file, btop)) { ++ au_set_fbtop(file, btop); ++ break; ++ } ++ } ++ fi_write_unlock(file); ++ } ++} ++ ++static void au_br_do_del_brp(struct au_sbinfo *sbinfo, ++ const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_branch **brp, **p; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ brp = sbinfo->si_branch + bindex; ++ if (bindex < bbot) ++ memmove(brp, brp + 1, sizeof(*brp) * (bbot - bindex)); ++ sbinfo->si_branch[0 + bbot] = NULL; ++ sbinfo->si_bbot--; ++ ++ p = krealloc(sbinfo->si_branch, sizeof(*p) * bbot, AuGFP_SBILIST); ++ if (p) ++ sbinfo->si_branch = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_hdentry *hdp, *p; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ hdp = au_hdentry(dinfo, bindex); ++ if (bindex < bbot) ++ memmove(hdp, hdp + 1, sizeof(*hdp) * (bbot - bindex)); ++ /* au_h_dentry_init(au_hdentry(dinfo, bbot); */ ++ dinfo->di_bbot--; ++ ++ p = krealloc(dinfo->di_hdentry, sizeof(*p) * bbot, AuGFP_SBILIST); ++ if (p) ++ dinfo->di_hdentry = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_hinode *hip, *p; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ hip = au_hinode(iinfo, bindex); ++ if (bindex < bbot) ++ memmove(hip, hip + 1, sizeof(*hip) * (bbot - bindex)); ++ /* au_hinode_init(au_hinode(iinfo, bbot)); */ ++ iinfo->ii_bbot--; ++ ++ p = krealloc(iinfo->ii_hinode, sizeof(*p) * bbot, AuGFP_SBILIST); ++ if (p) ++ iinfo->ii_hinode = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_branch *br) ++{ ++ aufs_bindex_t bbot; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root, *h_root; ++ struct inode *inode, *h_inode; ++ struct au_hinode *hinode; ++ ++ SiMustWriteLock(sb); ++ ++ root = sb->s_root; ++ inode = d_inode(root); ++ sbinfo = au_sbi(sb); ++ bbot = sbinfo->si_bbot; ++ ++ h_root = au_h_dptr(root, bindex); ++ hinode = au_hi(inode, bindex); ++ h_inode = au_igrab(hinode->hi_inode); ++ au_hiput(hinode); ++ ++ au_sbilist_lock(); ++ au_br_do_del_brp(sbinfo, bindex, bbot); ++ au_br_do_del_hdp(au_di(root), bindex, bbot); ++ au_br_do_del_hip(au_ii(inode), bindex, bbot); ++ au_sbilist_unlock(); ++ ++ dput(h_root); ++ iput(h_inode); ++ au_br_do_free(br); ++} ++ ++static unsigned long long empty_cb(struct super_block *sb, void *array, ++ unsigned long long max, void *arg) ++{ ++ return max; ++} ++ ++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) ++{ ++ int err, rerr, i; ++ unsigned long long opened; ++ unsigned int mnt_flags; ++ aufs_bindex_t bindex, bbot, br_id; ++ unsigned char do_wh, verbose; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *root; ++ struct file **to_free; ++ ++ err = 0; ++ opened = 0; ++ to_free = NULL; ++ root = sb->s_root; ++ bindex = au_find_dbindex(root, del->h_path.dentry); ++ if (bindex < 0) { ++ if (remount) ++ goto out; /* success */ ++ err = -ENOENT; ++ pr_err("%s no such branch\n", del->pathname); ++ goto out; ++ } ++ AuDbg("bindex b%d\n", bindex); ++ ++ err = -EBUSY; ++ mnt_flags = au_mntflags(sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ bbot = au_sbbot(sb); ++ if (unlikely(!bbot)) { ++ AuVerbose(verbose, "no more branches left\n"); ++ goto out; ++ } ++ br = au_sbr(sb, bindex); ++ AuDebugOn(!path_equal(&br->br_path, &del->h_path)); ++ ++ br_id = br->br_id; ++ opened = au_br_count(br); ++ if (unlikely(opened)) { ++ to_free = au_array_alloc(&opened, empty_cb, sb, NULL); ++ err = PTR_ERR(to_free); ++ if (IS_ERR(to_free)) ++ goto out; ++ ++ err = test_file_busy(sb, br_id, to_free, opened); ++ if (unlikely(err)) { ++ AuVerbose(verbose, "%llu file(s) opened\n", opened); ++ goto out; ++ } ++ } ++ ++ wbr = br->br_wbr; ++ do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph); ++ if (do_wh) { ++ /* instead of WbrWhMustWriteLock(wbr) */ ++ SiMustWriteLock(sb); ++ for (i = 0; i < AuBrWh_Last; i++) { ++ dput(wbr->wbr_wh[i]); ++ wbr->wbr_wh[i] = NULL; ++ } ++ } ++ ++ err = test_children_busy(root, bindex, verbose); ++ if (unlikely(err)) { ++ if (do_wh) ++ goto out_wh; ++ goto out; ++ } ++ ++ err = 0; ++ if (to_free) { ++ /* ++ * now we confirmed the branch is deletable. ++ * let's free the remaining opened dirs on the branch. ++ */ ++ di_write_unlock(root); ++ br_del_file(to_free, opened, br_id); ++ di_write_lock_child(root); ++ } ++ ++ if (!remount) ++ au_br_do_del(sb, bindex, br); ++ else { ++ sysaufs_brs_del(sb, bindex); ++ au_br_do_del(sb, bindex, br); ++ sysaufs_brs_add(sb, bindex); ++ } ++ ++ if (!bindex) { ++ au_cpup_attr_all(d_inode(root), /*force*/1); ++ sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes; ++ } else ++ au_sub_nlink(d_inode(root), d_inode(del->h_path.dentry)); ++ if (au_opt_test(mnt_flags, PLINK)) ++ au_plink_half_refresh(sb, br_id); ++ ++ if (au_xino_brid(sb) == br_id) ++ au_xino_brid_set(sb, -1); ++ goto out; /* success */ ++ ++out_wh: ++ /* revert */ ++ rerr = au_br_init_wh(sb, br, br->br_perm); ++ if (rerr) ++ pr_warn("failed re-creating base whiteout, %s. (%d)\n", ++ del->pathname, rerr); ++out: ++ if (to_free) ++ au_farray_free(to_free, opened); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_ibusy(struct super_block *sb, struct aufs_ibusy __user *arg) ++{ ++ int err; ++ aufs_bindex_t btop, bbot; ++ struct aufs_ibusy ibusy; ++ struct inode *inode, *h_inode; ++ ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = copy_from_user(&ibusy, arg, sizeof(ibusy)); ++ if (!err) ++ err = !access_ok(VERIFY_WRITE, &arg->h_ino, sizeof(arg->h_ino)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ si_read_lock(sb, AuLock_FLUSH); ++ if (unlikely(ibusy.bindex < 0 || ibusy.bindex > au_sbbot(sb))) ++ goto out_unlock; ++ ++ err = 0; ++ ibusy.h_ino = 0; /* invalid */ ++ inode = ilookup(sb, ibusy.ino); ++ if (!inode ++ || inode->i_ino == AUFS_ROOT_INO ++ || au_is_bad_inode(inode)) ++ goto out_unlock; ++ ++ ii_read_lock_child(inode); ++ btop = au_ibtop(inode); ++ bbot = au_ibbot(inode); ++ if (btop <= ibusy.bindex && ibusy.bindex <= bbot) { ++ h_inode = au_h_iptr(inode, ibusy.bindex); ++ if (h_inode && au_test_ibusy(inode, btop, bbot)) ++ ibusy.h_ino = h_inode->i_ino; ++ } ++ ii_read_unlock(inode); ++ iput(inode); ++ ++out_unlock: ++ si_read_unlock(sb); ++ if (!err) { ++ err = __put_user(ibusy.h_ino, &arg->h_ino); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ } ++out: ++ return err; ++} ++ ++long au_ibusy_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_ibusy(file->f_path.dentry->d_sb, (void __user *)arg); ++} ++ ++#ifdef CONFIG_COMPAT ++long au_ibusy_compat_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_ibusy(file->f_path.dentry->d_sb, compat_ptr(arg)); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * change a branch permission ++ */ ++ ++static void au_warn_ima(void) ++{ ++#ifdef CONFIG_IMA ++ /* since it doesn't support mark_files_ro() */ ++ AuWarn1("RW -> RO makes IMA to produce wrong message\n"); ++#endif ++} ++ ++static int do_need_sigen_inc(int a, int b) ++{ ++ return au_br_whable(a) && !au_br_whable(b); ++} ++ ++static int need_sigen_inc(int old, int new) ++{ ++ return do_need_sigen_inc(old, new) ++ || do_need_sigen_inc(new, old); ++} ++ ++static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err, do_warn; ++ unsigned int mnt_flags; ++ unsigned long long ull, max; ++ aufs_bindex_t br_id; ++ unsigned char verbose, writer; ++ struct file *file, *hf, **array; ++ struct au_hfile *hfile; ++ ++ mnt_flags = au_mntflags(sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ ++ array = au_farray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ do_warn = 0; ++ br_id = au_sbr_id(sb, bindex); ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ fi_read_lock(file); ++ if (unlikely(au_test_mmapped(file))) { ++ err = -EBUSY; ++ AuVerbose(verbose, "mmapped %pD\n", file); ++ AuDbgFile(file); ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ goto out_array; ++ } ++ ++ hfile = &au_fi(file)->fi_htop; ++ hf = hfile->hf_file; ++ if (!d_is_reg(file->f_path.dentry) ++ || !(file->f_mode & FMODE_WRITE) ++ || hfile->hf_br->br_id != br_id ++ || !(hf->f_mode & FMODE_WRITE)) ++ array[ull] = NULL; ++ else { ++ do_warn = 1; ++ get_file(file); ++ } ++ ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ fput(file); ++ } ++ ++ err = 0; ++ if (do_warn) ++ au_warn_ima(); ++ ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (!file) ++ continue; ++ ++ /* todo: already flushed? */ ++ /* ++ * fs/super.c:mark_files_ro() is gone, but aufs keeps its ++ * approach which resets f_mode and calls mnt_drop_write() and ++ * file_release_write() for each file, because the branch ++ * attribute in aufs world is totally different from the native ++ * fs rw/ro mode. ++ */ ++ /* fi_read_lock(file); */ ++ hfile = &au_fi(file)->fi_htop; ++ hf = hfile->hf_file; ++ /* fi_read_unlock(file); */ ++ spin_lock(&hf->f_lock); ++ writer = !!(hf->f_mode & FMODE_WRITER); ++ hf->f_mode &= ~(FMODE_WRITE | FMODE_WRITER); ++ spin_unlock(&hf->f_lock); ++ if (writer) { ++ put_write_access(file_inode(hf)); ++ __mnt_drop_write(hf->f_path.mnt); ++ } ++ } ++ ++out_array: ++ au_farray_free(array, max); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, ++ int *do_refresh) ++{ ++ int err, rerr; ++ aufs_bindex_t bindex; ++ struct dentry *root; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ root = sb->s_root; ++ bindex = au_find_dbindex(root, mod->h_root); ++ if (bindex < 0) { ++ if (remount) ++ return 0; /* success */ ++ err = -ENOENT; ++ pr_err("%s no such branch\n", mod->path); ++ goto out; ++ } ++ AuDbg("bindex b%d\n", bindex); ++ ++ err = test_br(d_inode(mod->h_root), mod->perm, mod->path); ++ if (unlikely(err)) ++ goto out; ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(mod->h_root != au_br_dentry(br)); ++ if (br->br_perm == mod->perm) ++ return 0; /* success */ ++ ++ /* pre-allocate for non-fhsm --> fhsm */ ++ bf = NULL; ++ if (!au_br_fhsm(br->br_perm) && au_br_fhsm(mod->perm)) { ++ err = au_fhsm_br_alloc(br); ++ if (unlikely(err)) ++ goto out; ++ bf = br->br_fhsm; ++ br->br_fhsm = NULL; ++ } ++ ++ if (au_br_writable(br->br_perm)) { ++ /* remove whiteout base */ ++ err = au_br_init_wh(sb, br, mod->perm); ++ if (unlikely(err)) ++ goto out_bf; ++ ++ if (!au_br_writable(mod->perm)) { ++ /* rw --> ro, file might be mmapped */ ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(d_inode(root)); ++ di_write_unlock(root); ++ err = au_br_mod_files_ro(sb, bindex); ++ /* aufs_write_lock() calls ..._child() */ ++ di_write_lock_child(root); ++ ++ if (unlikely(err)) { ++ rerr = -ENOMEM; ++ br->br_wbr = kzalloc(sizeof(*br->br_wbr), ++ GFP_NOFS); ++ if (br->br_wbr) ++ rerr = au_wbr_init(br, sb, br->br_perm); ++ if (unlikely(rerr)) { ++ AuIOErr("nested error %d (%d)\n", ++ rerr, err); ++ br->br_perm = mod->perm; ++ } ++ } ++ } ++ } else if (au_br_writable(mod->perm)) { ++ /* ro --> rw */ ++ err = -ENOMEM; ++ br->br_wbr = kzalloc(sizeof(*br->br_wbr), GFP_NOFS); ++ if (br->br_wbr) { ++ err = au_wbr_init(br, sb, mod->perm); ++ if (unlikely(err)) { ++ kfree(br->br_wbr); ++ br->br_wbr = NULL; ++ } ++ } ++ } ++ if (unlikely(err)) ++ goto out_bf; ++ ++ if (au_br_fhsm(br->br_perm)) { ++ if (!au_br_fhsm(mod->perm)) { ++ /* fhsm --> non-fhsm */ ++ au_br_fhsm_fin(br->br_fhsm); ++ kfree(br->br_fhsm); ++ br->br_fhsm = NULL; ++ } ++ } else if (au_br_fhsm(mod->perm)) ++ /* non-fhsm --> fhsm */ ++ br->br_fhsm = bf; ++ ++ *do_refresh |= need_sigen_inc(br->br_perm, mod->perm); ++ br->br_perm = mod->perm; ++ goto out; /* success */ ++ ++out_bf: ++ kfree(bf); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs) ++{ ++ int err; ++ struct kstatfs kstfs; ++ ++ err = vfs_statfs(&br->br_path, &kstfs); ++ if (!err) { ++ stfs->f_blocks = kstfs.f_blocks; ++ stfs->f_bavail = kstfs.f_bavail; ++ stfs->f_files = kstfs.f_files; ++ stfs->f_ffree = kstfs.f_ffree; ++ } ++ ++ return err; ++} +diff --git a/fs/aufs/branch.h b/fs/aufs/branch.h +new file mode 100644 +index 0000000..32a4d8f +--- /dev/null ++++ b/fs/aufs/branch.h +@@ -0,0 +1,296 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * branch filesystems and xino for them ++ */ ++ ++#ifndef __AUFS_BRANCH_H__ ++#define __AUFS_BRANCH_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "dynop.h" ++#include "rwsem.h" ++#include "super.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* a xino file */ ++struct au_xino_file { ++ struct file *xi_file; ++ struct mutex xi_nondir_mtx; ++ ++ /* todo: make xino files an array to support huge inode number */ ++ ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *xi_dbgaufs; ++#endif ++}; ++ ++/* File-based Hierarchical Storage Management */ ++struct au_br_fhsm { ++#ifdef CONFIG_AUFS_FHSM ++ struct mutex bf_lock; ++ unsigned long bf_jiffy; ++ struct aufs_stfs bf_stfs; ++ int bf_readable; ++#endif ++}; ++ ++/* members for writable branch only */ ++enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_ORPH, AuBrWh_Last}; ++struct au_wbr { ++ struct au_rwsem wbr_wh_rwsem; ++ struct dentry *wbr_wh[AuBrWh_Last]; ++ atomic_t wbr_wh_running; ++#define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */ ++#define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */ ++#define wbr_orph wbr_wh[AuBrWh_ORPH] /* dir for orphans */ ++ ++ /* mfs mode */ ++ unsigned long long wbr_bytes; ++}; ++ ++/* ext2 has 3 types of operations at least, ext3 has 4 */ ++#define AuBrDynOp (AuDyLast * 4) ++ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++/* support for asynchronous destruction */ ++struct au_br_hfsnotify { ++ struct fsnotify_group *hfsn_group; ++}; ++#endif ++ ++/* sysfs entries */ ++struct au_brsysfs { ++ char name[16]; ++ struct attribute attr; ++}; ++ ++enum { ++ AuBrSysfs_BR, ++ AuBrSysfs_BRID, ++ AuBrSysfs_Last ++}; ++ ++/* protected by superblock rwsem */ ++struct au_branch { ++ struct au_xino_file br_xino; ++ ++ aufs_bindex_t br_id; ++ ++ int br_perm; ++ struct path br_path; ++ spinlock_t br_dykey_lock; ++ struct au_dykey *br_dykey[AuBrDynOp]; ++ struct percpu_counter br_count; ++ ++ struct au_wbr *br_wbr; ++ struct au_br_fhsm *br_fhsm; ++ ++ /* xino truncation */ ++ atomic_t br_xino_running; ++ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ struct au_br_hfsnotify *br_hfsn; ++#endif ++ ++#ifdef CONFIG_SYSFS ++ /* entries under sysfs per mount-point */ ++ struct au_brsysfs br_sysfs[AuBrSysfs_Last]; ++#endif ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct vfsmount *au_br_mnt(struct au_branch *br) ++{ ++ return br->br_path.mnt; ++} ++ ++static inline struct dentry *au_br_dentry(struct au_branch *br) ++{ ++ return br->br_path.dentry; ++} ++ ++static inline struct super_block *au_br_sb(struct au_branch *br) ++{ ++ return au_br_mnt(br)->mnt_sb; ++} ++ ++static inline void au_br_get(struct au_branch *br) ++{ ++ percpu_counter_inc(&br->br_count); ++} ++ ++static inline void au_br_put(struct au_branch *br) ++{ ++ percpu_counter_dec(&br->br_count); ++} ++ ++static inline s64 au_br_count(struct au_branch *br) ++{ ++ return percpu_counter_sum(&br->br_count); ++} ++ ++static inline void au_br_count_init(struct au_branch *br) ++{ ++ percpu_counter_init(&br->br_count, 0, GFP_NOFS); ++} ++ ++static inline void au_br_count_fin(struct au_branch *br) ++{ ++ percpu_counter_destroy(&br->br_count); ++} ++ ++static inline int au_br_rdonly(struct au_branch *br) ++{ ++ return ((au_br_sb(br)->s_flags & MS_RDONLY) ++ || !au_br_writable(br->br_perm)) ++ ? -EROFS : 0; ++} ++ ++static inline int au_br_hnotifyable(int brperm __maybe_unused) ++{ ++#ifdef CONFIG_AUFS_HNOTIFY ++ return !(brperm & AuBrPerm_RR); ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_br_test_oflag(int oflag, struct au_branch *br) ++{ ++ int err, exec_flag; ++ ++ err = 0; ++ exec_flag = oflag & __FMODE_EXEC; ++ if (unlikely(exec_flag && (au_br_mnt(br)->mnt_flags & MNT_NOEXEC))) ++ err = -EACCES; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* branch.c */ ++struct au_sbinfo; ++void au_br_free(struct au_sbinfo *sinfo); ++int au_br_index(struct super_block *sb, aufs_bindex_t br_id); ++struct au_opt_add; ++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount); ++struct au_opt_del; ++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount); ++long au_ibusy_ioctl(struct file *file, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_ibusy_compat_ioctl(struct file *file, unsigned long arg); ++#endif ++struct au_opt_mod; ++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, ++ int *do_refresh); ++struct aufs_stfs; ++int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs); ++ ++/* xino.c */ ++static const loff_t au_loff_max = LLONG_MAX; ++ ++int au_xib_trunc(struct super_block *sb); ++ssize_t xino_fread(vfs_readf_t func, struct file *file, void *buf, size_t size, ++ loff_t *pos); ++ssize_t xino_fwrite(vfs_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos); ++struct file *au_xino_create2(struct file *base_file, struct file *copy_src); ++struct file *au_xino_create(struct super_block *sb, char *fname, int silent); ++ino_t au_xino_new_ino(struct super_block *sb); ++void au_xino_delete_inode(struct inode *inode, const int unlinked); ++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino); ++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t *ino); ++int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t hino, ++ struct file *base_file, int do_test); ++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex); ++ ++struct au_opt_xino; ++int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount); ++void au_xino_clr(struct super_block *sb); ++struct file *au_xino_def(struct super_block *sb); ++int au_xino_path(struct seq_file *seq, struct file *file); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Superblock to branch */ ++static inline ++aufs_bindex_t au_sbr_id(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_sbr(sb, bindex)->br_id; ++} ++ ++static inline ++struct vfsmount *au_sbr_mnt(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_mnt(au_sbr(sb, bindex)); ++} ++ ++static inline ++struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_sb(au_sbr(sb, bindex)); ++} ++ ++static inline void au_sbr_get(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ au_br_get(au_sbr(sb, bindex)); ++} ++ ++static inline void au_sbr_put(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ au_br_put(au_sbr(sb, bindex)); ++} ++ ++static inline int au_sbr_perm(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_sbr(sb, bindex)->br_perm; ++} ++ ++static inline int au_sbr_whable(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_whable(au_sbr_perm(sb, bindex)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * wbr_wh_read_lock, wbr_wh_write_lock ++ * wbr_wh_read_unlock, wbr_wh_write_unlock, wbr_wh_downgrade_lock ++ */ ++AuSimpleRwsemFuncs(wbr_wh, struct au_wbr *wbr, &wbr->wbr_wh_rwsem); ++ ++#define WbrWhMustNoWaiters(wbr) AuRwMustNoWaiters(&wbr->wbr_wh_rwsem) ++#define WbrWhMustAnyLock(wbr) AuRwMustAnyLock(&wbr->wbr_wh_rwsem) ++#define WbrWhMustWriteLock(wbr) AuRwMustWriteLock(&wbr->wbr_wh_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_FHSM ++static inline void au_br_fhsm_init(struct au_br_fhsm *brfhsm) ++{ ++ mutex_init(&brfhsm->bf_lock); ++ brfhsm->bf_jiffy = 0; ++ brfhsm->bf_readable = 0; ++} ++ ++static inline void au_br_fhsm_fin(struct au_br_fhsm *brfhsm) ++{ ++ mutex_destroy(&brfhsm->bf_lock); ++} ++#else ++AuStubVoid(au_br_fhsm_init, struct au_br_fhsm *brfhsm) ++AuStubVoid(au_br_fhsm_fin, struct au_br_fhsm *brfhsm) ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_BRANCH_H__ */ +diff --git a/fs/aufs/cpup.c b/fs/aufs/cpup.c +new file mode 100644 +index 0000000..52f87de +--- /dev/null ++++ b/fs/aufs/cpup.c +@@ -0,0 +1,1370 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * copy-up functions, see wbr_policy.c for copy-down ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++void au_cpup_attr_flags(struct inode *dst, unsigned int iflags) ++{ ++ const unsigned int mask = S_DEAD | S_SWAPFILE | S_PRIVATE ++ | S_NOATIME | S_NOCMTIME | S_AUTOMOUNT; ++ ++ BUILD_BUG_ON(sizeof(iflags) != sizeof(dst->i_flags)); ++ ++ dst->i_flags |= iflags & ~mask; ++ if (au_test_fs_notime(dst->i_sb)) ++ dst->i_flags |= S_NOATIME | S_NOCMTIME; ++} ++ ++void au_cpup_attr_timesizes(struct inode *inode) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ fsstack_copy_attr_times(inode, h_inode); ++ fsstack_copy_inode_size(inode, h_inode); ++} ++ ++void au_cpup_attr_nlink(struct inode *inode, int force) ++{ ++ struct inode *h_inode; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ ++ sb = inode->i_sb; ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (!force ++ && !S_ISDIR(h_inode->i_mode) ++ && au_opt_test(au_mntflags(sb), PLINK) ++ && au_plink_test(inode)) ++ return; ++ ++ /* ++ * 0 can happen in revalidating. ++ * h_inode->i_mutex may not be held here, but it is harmless since once ++ * i_nlink reaches 0, it will never become positive except O_TMPFILE ++ * case. ++ * todo: O_TMPFILE+linkat(AT_SYMLINK_FOLLOW) bypassing aufs may cause ++ * the incorrect link count. ++ */ ++ set_nlink(inode, h_inode->i_nlink); ++ ++ /* ++ * fewer nlink makes find(1) noisy, but larger nlink doesn't. ++ * it may includes whplink directory. ++ */ ++ if (S_ISDIR(h_inode->i_mode)) { ++ bbot = au_ibbot(inode); ++ for (bindex++; bindex <= bbot; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (h_inode) ++ au_add_nlink(inode, h_inode); ++ } ++ } ++} ++ ++void au_cpup_attr_changeable(struct inode *inode) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ inode->i_mode = h_inode->i_mode; ++ inode->i_uid = h_inode->i_uid; ++ inode->i_gid = h_inode->i_gid; ++ au_cpup_attr_timesizes(inode); ++ au_cpup_attr_flags(inode, h_inode->i_flags); ++} ++ ++void au_cpup_igen(struct inode *inode, struct inode *h_inode) ++{ ++ struct au_iinfo *iinfo = au_ii(inode); ++ ++ IiMustWriteLock(inode); ++ ++ iinfo->ii_higen = h_inode->i_generation; ++ iinfo->ii_hsb1 = h_inode->i_sb; ++} ++ ++void au_cpup_attr_all(struct inode *inode, int force) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ au_cpup_attr_changeable(inode); ++ if (inode->i_nlink > 0) ++ au_cpup_attr_nlink(inode, force); ++ inode->i_rdev = h_inode->i_rdev; ++ inode->i_blkbits = h_inode->i_blkbits; ++ au_cpup_igen(inode, h_inode); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Note: dt_dentry and dt_h_dentry are not dget/dput-ed */ ++ ++/* keep the timestamps of the parent dir when cpup */ ++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, ++ struct path *h_path) ++{ ++ struct inode *h_inode; ++ ++ dt->dt_dentry = dentry; ++ dt->dt_h_path = *h_path; ++ h_inode = d_inode(h_path->dentry); ++ dt->dt_atime = h_inode->i_atime; ++ dt->dt_mtime = h_inode->i_mtime; ++ /* smp_mb(); */ ++} ++ ++void au_dtime_revert(struct au_dtime *dt) ++{ ++ struct iattr attr; ++ int err; ++ ++ attr.ia_atime = dt->dt_atime; ++ attr.ia_mtime = dt->dt_mtime; ++ attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET ++ | ATTR_ATIME | ATTR_ATIME_SET; ++ ++ /* no delegation since this is a directory */ ++ err = vfsub_notify_change(&dt->dt_h_path, &attr, /*delegated*/NULL); ++ if (unlikely(err)) ++ pr_warn("restoring timestamps failed(%d). ignored\n", err); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* internal use only */ ++struct au_cpup_reg_attr { ++ int valid; ++ struct kstat st; ++ unsigned int iflags; /* inode->i_flags */ ++}; ++ ++static noinline_for_stack ++int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err, sbits, icex; ++ unsigned int mnt_flags; ++ unsigned char verbose; ++ struct iattr ia; ++ struct path h_path; ++ struct inode *h_isrc, *h_idst; ++ struct kstat *h_st; ++ struct au_branch *br; ++ ++ h_path.dentry = au_h_dptr(dst, bindex); ++ h_idst = d_inode(h_path.dentry); ++ br = au_sbr(dst->d_sb, bindex); ++ h_path.mnt = au_br_mnt(br); ++ h_isrc = d_inode(h_src); ++ ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID ++ | ATTR_ATIME | ATTR_MTIME ++ | ATTR_ATIME_SET | ATTR_MTIME_SET; ++ if (h_src_attr && h_src_attr->valid) { ++ h_st = &h_src_attr->st; ++ ia.ia_uid = h_st->uid; ++ ia.ia_gid = h_st->gid; ++ ia.ia_atime = h_st->atime; ++ ia.ia_mtime = h_st->mtime; ++ if (h_idst->i_mode != h_st->mode ++ && !S_ISLNK(h_idst->i_mode)) { ++ ia.ia_valid |= ATTR_MODE; ++ ia.ia_mode = h_st->mode; ++ } ++ sbits = !!(h_st->mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(h_idst, h_src_attr->iflags); ++ } else { ++ ia.ia_uid = h_isrc->i_uid; ++ ia.ia_gid = h_isrc->i_gid; ++ ia.ia_atime = h_isrc->i_atime; ++ ia.ia_mtime = h_isrc->i_mtime; ++ if (h_idst->i_mode != h_isrc->i_mode ++ && !S_ISLNK(h_idst->i_mode)) { ++ ia.ia_valid |= ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ } ++ sbits = !!(h_isrc->i_mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(h_idst, h_isrc->i_flags); ++ } ++ /* no delegation since it is just created */ ++ err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); ++ ++ /* is this nfs only? */ ++ if (!err && sbits && au_test_nfs(h_path.dentry->d_sb)) { ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); ++ } ++ ++ icex = br->br_perm & AuBrAttr_ICEX; ++ if (!err) { ++ mnt_flags = au_mntflags(dst->d_sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ err = au_cpup_xattr(h_path.dentry, h_src, icex, verbose); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_copy_file(struct file *dst, struct file *src, loff_t len, ++ char *buf, unsigned long blksize) ++{ ++ int err; ++ size_t sz, rbytes, wbytes; ++ unsigned char all_zero; ++ char *p, *zp; ++ struct inode *h_inode; ++ /* reduce stack usage */ ++ struct iattr *ia; ++ ++ zp = page_address(ZERO_PAGE(0)); ++ if (unlikely(!zp)) ++ return -ENOMEM; /* possible? */ ++ ++ err = 0; ++ all_zero = 0; ++ while (len) { ++ AuDbg("len %lld\n", len); ++ sz = blksize; ++ if (len < blksize) ++ sz = len; ++ ++ rbytes = 0; ++ /* todo: signal_pending? */ ++ while (!rbytes || err == -EAGAIN || err == -EINTR) { ++ rbytes = vfsub_read_k(src, buf, sz, &src->f_pos); ++ err = rbytes; ++ } ++ if (unlikely(err < 0)) ++ break; ++ ++ all_zero = 0; ++ if (len >= rbytes && rbytes == blksize) ++ all_zero = !memcmp(buf, zp, rbytes); ++ if (!all_zero) { ++ wbytes = rbytes; ++ p = buf; ++ while (wbytes) { ++ size_t b; ++ ++ b = vfsub_write_k(dst, p, wbytes, &dst->f_pos); ++ err = b; ++ /* todo: signal_pending? */ ++ if (unlikely(err == -EAGAIN || err == -EINTR)) ++ continue; ++ if (unlikely(err < 0)) ++ break; ++ wbytes -= b; ++ p += b; ++ } ++ if (unlikely(err < 0)) ++ break; ++ } else { ++ loff_t res; ++ ++ AuLabel(hole); ++ res = vfsub_llseek(dst, rbytes, SEEK_CUR); ++ err = res; ++ if (unlikely(res < 0)) ++ break; ++ } ++ len -= rbytes; ++ err = 0; ++ } ++ ++ /* the last block may be a hole */ ++ if (!err && all_zero) { ++ AuLabel(last hole); ++ ++ err = 1; ++ if (au_test_nfs(dst->f_path.dentry->d_sb)) { ++ /* nfs requires this step to make last hole */ ++ /* is this only nfs? */ ++ do { ++ /* todo: signal_pending? */ ++ err = vfsub_write_k(dst, "\0", 1, &dst->f_pos); ++ } while (err == -EAGAIN || err == -EINTR); ++ if (err == 1) ++ dst->f_pos--; ++ } ++ ++ if (err == 1) { ++ ia = (void *)buf; ++ ia->ia_size = dst->f_pos; ++ ia->ia_valid = ATTR_SIZE | ATTR_FILE; ++ ia->ia_file = dst; ++ h_inode = file_inode(dst); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD2); ++ /* no delegation since it is just created */ ++ err = vfsub_notify_change(&dst->f_path, ia, ++ /*delegated*/NULL); ++ inode_unlock(h_inode); ++ } ++ } ++ ++ return err; ++} ++ ++int au_copy_file(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ unsigned long blksize; ++ unsigned char do_kfree; ++ char *buf; ++ ++ err = -ENOMEM; ++ blksize = dst->f_path.dentry->d_sb->s_blocksize; ++ if (!blksize || PAGE_SIZE < blksize) ++ blksize = PAGE_SIZE; ++ AuDbg("blksize %lu\n", blksize); ++ do_kfree = (blksize != PAGE_SIZE && blksize >= sizeof(struct iattr *)); ++ if (do_kfree) ++ buf = kmalloc(blksize, GFP_NOFS); ++ else ++ buf = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!buf)) ++ goto out; ++ ++ if (len > (1 << 22)) ++ AuDbg("copying a large file %lld\n", (long long)len); ++ ++ src->f_pos = 0; ++ dst->f_pos = 0; ++ err = au_do_copy_file(dst, src, len, buf, blksize); ++ if (do_kfree) ++ kfree(buf); ++ else ++ free_page((unsigned long)buf); ++ ++out: ++ return err; ++} ++ ++/* ++ * to support a sparse file which is opened with O_APPEND, ++ * we need to close the file. ++ */ ++static int au_cp_regular(struct au_cp_generic *cpg) ++{ ++ int err, i; ++ enum { SRC, DST }; ++ struct { ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ struct dentry *dentry; ++ int force_wr; ++ struct file *file; ++ void *label; ++ } *f, file[] = { ++ { ++ .bindex = cpg->bsrc, ++ .flags = O_RDONLY | O_NOATIME | O_LARGEFILE, ++ .label = &&out ++ }, ++ { ++ .bindex = cpg->bdst, ++ .flags = O_WRONLY | O_NOATIME | O_LARGEFILE, ++ .force_wr = !!au_ftest_cpup(cpg->flags, RWDST), ++ .label = &&out_src ++ } ++ }; ++ struct super_block *sb; ++ struct task_struct *tsk = current; ++ ++ /* bsrc branch can be ro/rw. */ ++ sb = cpg->dentry->d_sb; ++ f = file; ++ for (i = 0; i < 2; i++, f++) { ++ f->dentry = au_h_dptr(cpg->dentry, f->bindex); ++ f->file = au_h_open(cpg->dentry, f->bindex, f->flags, ++ /*file*/NULL, f->force_wr); ++ err = PTR_ERR(f->file); ++ if (IS_ERR(f->file)) ++ goto *f->label; ++ } ++ ++ /* try stopping to update while we copyup */ ++ IMustLock(d_inode(file[SRC].dentry)); ++ err = au_copy_file(file[DST].file, file[SRC].file, cpg->len); ++ ++ /* i wonder if we had O_NO_DELAY_FPUT flag */ ++ if (tsk->flags & PF_KTHREAD) ++ __fput_sync(file[DST].file); ++ else { ++ WARN(1, "%pD\nPlease report this warning to aufs-users ML", ++ file[DST].file); ++ fput(file[DST].file); ++ /* ++ * too bad. ++ * we have to call both since we don't know which place the file ++ * was added to. ++ */ ++ task_work_run(); ++ flush_delayed_fput(); ++ } ++ au_sbr_put(sb, file[DST].bindex); ++ ++out_src: ++ fput(file[SRC].file); ++ au_sbr_put(sb, file[SRC].bindex); ++out: ++ return err; ++} ++ ++static int au_do_cpup_regular(struct au_cp_generic *cpg, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err, rerr; ++ loff_t l; ++ struct path h_path; ++ struct inode *h_src_inode, *h_dst_inode; ++ ++ err = 0; ++ h_src_inode = au_h_iptr(d_inode(cpg->dentry), cpg->bsrc); ++ l = i_size_read(h_src_inode); ++ if (cpg->len == -1 || l < cpg->len) ++ cpg->len = l; ++ if (cpg->len) { ++ /* try stopping to update while we are referencing */ ++ inode_lock_nested(h_src_inode, AuLsc_I_CHILD); ++ au_pin_hdir_unlock(cpg->pin); ++ ++ h_path.dentry = au_h_dptr(cpg->dentry, cpg->bsrc); ++ h_path.mnt = au_sbr_mnt(cpg->dentry->d_sb, cpg->bsrc); ++ h_src_attr->iflags = h_src_inode->i_flags; ++ if (!au_test_nfs(h_src_inode->i_sb)) ++ err = vfs_getattr(&h_path, &h_src_attr->st); ++ else { ++ inode_unlock(h_src_inode); ++ err = vfs_getattr(&h_path, &h_src_attr->st); ++ inode_lock_nested(h_src_inode, AuLsc_I_CHILD); ++ } ++ if (unlikely(err)) { ++ inode_unlock(h_src_inode); ++ goto out; ++ } ++ h_src_attr->valid = 1; ++ err = au_cp_regular(cpg); ++ inode_unlock(h_src_inode); ++ rerr = au_pin_hdir_relock(cpg->pin); ++ if (!err && rerr) ++ err = rerr; ++ } ++ if (!err && (h_src_inode->i_state & I_LINKABLE)) { ++ h_path.dentry = au_h_dptr(cpg->dentry, cpg->bdst); ++ h_dst_inode = d_inode(h_path.dentry); ++ spin_lock(&h_dst_inode->i_lock); ++ h_dst_inode->i_state |= I_LINKABLE; ++ spin_unlock(&h_dst_inode->i_lock); ++ } ++ ++out: ++ return err; ++} ++ ++static int au_do_cpup_symlink(struct path *h_path, struct dentry *h_src, ++ struct inode *h_dir) ++{ ++ int err, symlen; ++ mm_segment_t old_fs; ++ union { ++ char *k; ++ char __user *u; ++ } sym; ++ struct inode *h_inode = d_inode(h_src); ++ const struct inode_operations *h_iop = h_inode->i_op; ++ ++ err = -ENOSYS; ++ if (unlikely(!h_iop->readlink)) ++ goto out; ++ ++ err = -ENOMEM; ++ sym.k = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!sym.k)) ++ goto out; ++ ++ /* unnecessary to support mmap_sem since symlink is not mmap-able */ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ symlen = h_iop->readlink(h_src, sym.u, PATH_MAX); ++ err = symlen; ++ set_fs(old_fs); ++ ++ if (symlen > 0) { ++ sym.k[symlen] = 0; ++ err = vfsub_symlink(h_dir, h_path, sym.k); ++ } ++ free_page((unsigned long)sym.k); ++ ++out: ++ return err; ++} ++ ++/* ++ * regardless 'acl' option, reset all ACL. ++ * All ACL will be copied up later from the original entry on the lower branch. ++ */ ++static int au_reset_acl(struct inode *h_dir, struct path *h_path, umode_t mode) ++{ ++ int err; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ h_dentry = h_path->dentry; ++ h_inode = d_inode(h_dentry); ++ /* forget_all_cached_acls(h_inode)); */ ++ err = vfsub_removexattr(h_dentry, XATTR_NAME_POSIX_ACL_ACCESS); ++ AuTraceErr(err); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ if (!err) ++ err = vfsub_acl_chmod(h_inode, mode); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_do_cpup_dir(struct au_cp_generic *cpg, struct dentry *dst_parent, ++ struct inode *h_dir, struct path *h_path) ++{ ++ int err; ++ struct inode *dir, *inode; ++ ++ err = vfsub_removexattr(h_path->dentry, XATTR_NAME_POSIX_ACL_DEFAULT); ++ AuTraceErr(err); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * strange behaviour from the users view, ++ * particularry setattr case ++ */ ++ dir = d_inode(dst_parent); ++ if (au_ibtop(dir) == cpg->bdst) ++ au_cpup_attr_nlink(dir, /*force*/1); ++ inode = d_inode(cpg->dentry); ++ au_cpup_attr_nlink(inode, /*force*/1); ++ ++out: ++ return err; ++} ++ ++static noinline_for_stack ++int cpup_entry(struct au_cp_generic *cpg, struct dentry *dst_parent, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err; ++ umode_t mode; ++ unsigned int mnt_flags; ++ unsigned char isdir, isreg, force; ++ const unsigned char do_dt = !!au_ftest_cpup(cpg->flags, DTIME); ++ struct au_dtime dt; ++ struct path h_path; ++ struct dentry *h_src, *h_dst, *h_parent; ++ struct inode *h_inode, *h_dir; ++ struct super_block *sb; ++ ++ /* bsrc branch can be ro/rw. */ ++ h_src = au_h_dptr(cpg->dentry, cpg->bsrc); ++ h_inode = d_inode(h_src); ++ AuDebugOn(h_inode != au_h_iptr(d_inode(cpg->dentry), cpg->bsrc)); ++ ++ /* try stopping to be referenced while we are creating */ ++ h_dst = au_h_dptr(cpg->dentry, cpg->bdst); ++ if (au_ftest_cpup(cpg->flags, RENAME)) ++ AuDebugOn(strncmp(h_dst->d_name.name, AUFS_WH_PFX, ++ AUFS_WH_PFX_LEN)); ++ h_parent = h_dst->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ AuDebugOn(h_parent != h_dst->d_parent); ++ ++ sb = cpg->dentry->d_sb; ++ h_path.mnt = au_sbr_mnt(sb, cpg->bdst); ++ if (do_dt) { ++ h_path.dentry = h_parent; ++ au_dtime_store(&dt, dst_parent, &h_path); ++ } ++ h_path.dentry = h_dst; ++ ++ isreg = 0; ++ isdir = 0; ++ mode = h_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ isreg = 1; ++ err = vfsub_create(h_dir, &h_path, S_IRUSR | S_IWUSR, ++ /*want_excl*/true); ++ if (!err) ++ err = au_do_cpup_regular(cpg, h_src_attr); ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ err = vfsub_mkdir(h_dir, &h_path, mode); ++ if (!err) ++ err = au_do_cpup_dir(cpg, dst_parent, h_dir, &h_path); ++ break; ++ case S_IFLNK: ++ err = au_do_cpup_symlink(&h_path, h_src, h_dir); ++ break; ++ case S_IFCHR: ++ case S_IFBLK: ++ AuDebugOn(!capable(CAP_MKNOD)); ++ /*FALLTHROUGH*/ ++ case S_IFIFO: ++ case S_IFSOCK: ++ err = vfsub_mknod(h_dir, &h_path, mode, h_inode->i_rdev); ++ break; ++ default: ++ AuIOErr("Unknown inode type 0%o\n", mode); ++ err = -EIO; ++ } ++ if (!err) ++ err = au_reset_acl(h_dir, &h_path, mode); ++ ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, UDBA_NONE) ++ && !isdir ++ && au_opt_test(mnt_flags, XINO) ++ && (h_inode->i_nlink == 1 ++ || (h_inode->i_state & I_LINKABLE)) ++ /* todo: unnecessary? */ ++ /* && d_inode(cpg->dentry)->i_nlink == 1 */ ++ && cpg->bdst < cpg->bsrc ++ && !au_ftest_cpup(cpg->flags, KEEPLINO)) ++ au_xino_write(sb, cpg->bsrc, h_inode->i_ino, /*ino*/0); ++ /* ignore this error */ ++ ++ if (!err) { ++ force = 0; ++ if (isreg) { ++ force = !!cpg->len; ++ if (cpg->len == -1) ++ force = !!i_size_read(h_inode); ++ } ++ au_fhsm_wrote(sb, cpg->bdst, force); ++ } ++ ++ if (do_dt) ++ au_dtime_revert(&dt); ++ return err; ++} ++ ++static int au_do_ren_after_cpup(struct au_cp_generic *cpg, struct path *h_path) ++{ ++ int err; ++ struct dentry *dentry, *h_dentry, *h_parent, *parent; ++ struct inode *h_dir; ++ aufs_bindex_t bdst; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ h_dentry = au_h_dptr(dentry, bdst); ++ if (!au_ftest_cpup(cpg->flags, OVERWRITE)) { ++ dget(h_dentry); ++ au_set_h_dptr(dentry, bdst, NULL); ++ err = au_lkup_neg(dentry, bdst, /*wh*/0); ++ if (!err) ++ h_path->dentry = dget(au_h_dptr(dentry, bdst)); ++ au_set_h_dptr(dentry, bdst, h_dentry); ++ } else { ++ err = 0; ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ dput(parent); ++ h_path->dentry = vfsub_lkup_one(&dentry->d_name, h_parent); ++ if (IS_ERR(h_path->dentry)) ++ err = PTR_ERR(h_path->dentry); ++ } ++ if (unlikely(err)) ++ goto out; ++ ++ h_parent = h_dentry->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ AuDbg("%pd %pd\n", h_dentry, h_path->dentry); ++ /* no delegation since it is just created */ ++ err = vfsub_rename(h_dir, h_dentry, h_dir, h_path, /*delegated*/NULL); ++ dput(h_path->dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * copyup the @dentry from @bsrc to @bdst. ++ * the caller must set the both of lower dentries. ++ * @len is for truncating when it is -1 copyup the entire file. ++ * in link/rename cases, @dst_parent may be different from the real one. ++ * basic->bsrc can be larger than basic->bdst. ++ */ ++static int au_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) ++{ ++ int err, rerr; ++ aufs_bindex_t old_ibtop; ++ unsigned char isdir, plink; ++ struct dentry *h_src, *h_dst, *h_parent; ++ struct inode *dst_inode, *h_dir, *inode, *delegated, *src_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ /* to reuduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct path h_path; ++ struct au_cpup_reg_attr h_src_attr; ++ } *a; ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->h_src_attr.valid = 0; ++ ++ sb = cpg->dentry->d_sb; ++ br = au_sbr(sb, cpg->bdst); ++ a->h_path.mnt = au_br_mnt(br); ++ h_dst = au_h_dptr(cpg->dentry, cpg->bdst); ++ h_parent = h_dst->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ h_src = au_h_dptr(cpg->dentry, cpg->bsrc); ++ inode = d_inode(cpg->dentry); ++ ++ if (!dst_parent) ++ dst_parent = dget_parent(cpg->dentry); ++ else ++ dget(dst_parent); ++ ++ plink = !!au_opt_test(au_mntflags(sb), PLINK); ++ dst_inode = au_h_iptr(inode, cpg->bdst); ++ if (dst_inode) { ++ if (unlikely(!plink)) { ++ err = -EIO; ++ AuIOErr("hi%lu(i%lu) exists on b%d " ++ "but plink is disabled\n", ++ dst_inode->i_ino, inode->i_ino, cpg->bdst); ++ goto out_parent; ++ } ++ ++ if (dst_inode->i_nlink) { ++ const int do_dt = au_ftest_cpup(cpg->flags, DTIME); ++ ++ h_src = au_plink_lkup(inode, cpg->bdst); ++ err = PTR_ERR(h_src); ++ if (IS_ERR(h_src)) ++ goto out_parent; ++ if (unlikely(d_is_negative(h_src))) { ++ err = -EIO; ++ AuIOErr("i%lu exists on b%d " ++ "but not pseudo-linked\n", ++ inode->i_ino, cpg->bdst); ++ dput(h_src); ++ goto out_parent; ++ } ++ ++ if (do_dt) { ++ a->h_path.dentry = h_parent; ++ au_dtime_store(&a->dt, dst_parent, &a->h_path); ++ } ++ ++ a->h_path.dentry = h_dst; ++ delegated = NULL; ++ err = vfsub_link(h_src, h_dir, &a->h_path, &delegated); ++ if (!err && au_ftest_cpup(cpg->flags, RENAME)) ++ err = au_do_ren_after_cpup(cpg, &a->h_path); ++ if (do_dt) ++ au_dtime_revert(&a->dt); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ dput(h_src); ++ goto out_parent; ++ } else ++ /* todo: cpup_wh_file? */ ++ /* udba work */ ++ au_update_ibrange(inode, /*do_put_zero*/1); ++ } ++ ++ isdir = S_ISDIR(inode->i_mode); ++ old_ibtop = au_ibtop(inode); ++ err = cpup_entry(cpg, dst_parent, &a->h_src_attr); ++ if (unlikely(err)) ++ goto out_rev; ++ dst_inode = d_inode(h_dst); ++ inode_lock_nested(dst_inode, AuLsc_I_CHILD2); ++ /* todo: necessary? */ ++ /* au_pin_hdir_unlock(cpg->pin); */ ++ ++ err = cpup_iattr(cpg->dentry, cpg->bdst, h_src, &a->h_src_attr); ++ if (unlikely(err)) { ++ /* todo: necessary? */ ++ /* au_pin_hdir_relock(cpg->pin); */ /* ignore an error */ ++ inode_unlock(dst_inode); ++ goto out_rev; ++ } ++ ++ if (cpg->bdst < old_ibtop) { ++ if (S_ISREG(inode->i_mode)) { ++ err = au_dy_iaop(inode, cpg->bdst, dst_inode); ++ if (unlikely(err)) { ++ /* ignore an error */ ++ /* au_pin_hdir_relock(cpg->pin); */ ++ inode_unlock(dst_inode); ++ goto out_rev; ++ } ++ } ++ au_set_ibtop(inode, cpg->bdst); ++ } else ++ au_set_ibbot(inode, cpg->bdst); ++ au_set_h_iptr(inode, cpg->bdst, au_igrab(dst_inode), ++ au_hi_flags(inode, isdir)); ++ ++ /* todo: necessary? */ ++ /* err = au_pin_hdir_relock(cpg->pin); */ ++ inode_unlock(dst_inode); ++ if (unlikely(err)) ++ goto out_rev; ++ ++ src_inode = d_inode(h_src); ++ if (!isdir ++ && (src_inode->i_nlink > 1 ++ || src_inode->i_state & I_LINKABLE) ++ && plink) ++ au_plink_append(inode, cpg->bdst, h_dst); ++ ++ if (au_ftest_cpup(cpg->flags, RENAME)) { ++ a->h_path.dentry = h_dst; ++ err = au_do_ren_after_cpup(cpg, &a->h_path); ++ } ++ if (!err) ++ goto out_parent; /* success */ ++ ++ /* revert */ ++out_rev: ++ a->h_path.dentry = h_parent; ++ au_dtime_store(&a->dt, dst_parent, &a->h_path); ++ a->h_path.dentry = h_dst; ++ rerr = 0; ++ if (d_is_positive(h_dst)) { ++ if (!isdir) { ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(h_dir, &a->h_path, ++ /*delegated*/NULL, /*force*/0); ++ } else ++ rerr = vfsub_rmdir(h_dir, &a->h_path); ++ } ++ au_dtime_revert(&a->dt); ++ if (rerr) { ++ AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr); ++ err = -EIO; ++ } ++out_parent: ++ dput(dst_parent); ++ kfree(a); ++out: ++ return err; ++} ++ ++#if 0 /* reserved */ ++struct au_cpup_single_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++ struct dentry *dst_parent; ++}; ++ ++static void au_call_cpup_single(void *args) ++{ ++ struct au_cpup_single_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_single(a->cpg, a->dst_parent); ++ au_pin_hdir_release(a->cpg->pin); ++} ++#endif ++ ++/* ++ * prevent SIGXFSZ in copy-up. ++ * testing CAP_MKNOD is for generic fs, ++ * but CAP_FSETID is for xfs only, currently. ++ */ ++static int au_cpup_sio_test(struct au_pin *pin, umode_t mode) ++{ ++ int do_sio; ++ struct super_block *sb; ++ struct inode *h_dir; ++ ++ do_sio = 0; ++ sb = au_pinned_parent(pin)->d_sb; ++ if (!au_wkq_test() ++ && (!au_sbi(sb)->si_plink_maint_pid ++ || au_plink_maint(sb, AuLock_NOPLM))) { ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ /* no condition about RLIMIT_FSIZE and the file size */ ++ do_sio = 1; ++ break; ++ case S_IFCHR: ++ case S_IFBLK: ++ do_sio = !capable(CAP_MKNOD); ++ break; ++ } ++ if (!do_sio) ++ do_sio = ((mode & (S_ISUID | S_ISGID)) ++ && !capable(CAP_FSETID)); ++ /* this workaround may be removed in the future */ ++ if (!do_sio) { ++ h_dir = au_pinned_h_dir(pin); ++ do_sio = h_dir->i_mode & S_ISVTX; ++ } ++ } ++ ++ return do_sio; ++} ++ ++#if 0 /* reserved */ ++int au_sio_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) ++{ ++ int err, wkq_err; ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(cpg->dentry, cpg->bsrc); ++ if (!au_cpup_sio_test(pin, d_inode(h_dentry)->i_mode)) ++ err = au_cpup_single(cpg, dst_parent); ++ else { ++ struct au_cpup_single_args args = { ++ .errp = &err, ++ .cpg = cpg, ++ .dst_parent = dst_parent ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_single, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++#endif ++ ++/* ++ * copyup the @dentry from the first active lower branch to @bdst, ++ * using au_cpup_single(). ++ */ ++static int au_cpup_simple(struct au_cp_generic *cpg) ++{ ++ int err; ++ unsigned int flags_orig; ++ struct dentry *dentry; ++ ++ AuDebugOn(cpg->bsrc < 0); ++ ++ dentry = cpg->dentry; ++ DiMustWriteLock(dentry); ++ ++ err = au_lkup_neg(dentry, cpg->bdst, /*wh*/1); ++ if (!err) { ++ flags_orig = cpg->flags; ++ au_fset_cpup(cpg->flags, RENAME); ++ err = au_cpup_single(cpg, NULL); ++ cpg->flags = flags_orig; ++ if (!err) ++ return 0; /* success */ ++ ++ /* revert */ ++ au_set_h_dptr(dentry, cpg->bdst, NULL); ++ au_set_dbtop(dentry, cpg->bsrc); ++ } ++ ++ return err; ++} ++ ++struct au_cpup_simple_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++}; ++ ++static void au_call_cpup_simple(void *args) ++{ ++ struct au_cpup_simple_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_simple(a->cpg); ++ au_pin_hdir_release(a->cpg->pin); ++} ++ ++static int au_do_sio_cpup_simple(struct au_cp_generic *cpg) ++{ ++ int err, wkq_err; ++ struct dentry *dentry, *parent; ++ struct file *h_file; ++ struct inode *h_dir; ++ ++ dentry = cpg->dentry; ++ h_file = NULL; ++ if (au_ftest_cpup(cpg->flags, HOPEN)) { ++ AuDebugOn(cpg->bsrc < 0); ++ h_file = au_h_open_pre(dentry, cpg->bsrc, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ } ++ ++ parent = dget_parent(dentry); ++ h_dir = au_h_iptr(d_inode(parent), cpg->bdst); ++ if (!au_test_h_perm_sio(h_dir, MAY_EXEC | MAY_WRITE) ++ && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode)) ++ err = au_cpup_simple(cpg); ++ else { ++ struct au_cpup_simple_args args = { ++ .errp = &err, ++ .cpg = cpg ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_simple, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ dput(parent); ++ if (h_file) ++ au_h_open_post(dentry, cpg->bsrc, h_file); ++ ++out: ++ return err; ++} ++ ++int au_sio_cpup_simple(struct au_cp_generic *cpg) ++{ ++ aufs_bindex_t bsrc, bbot; ++ struct dentry *dentry, *h_dentry; ++ ++ if (cpg->bsrc < 0) { ++ dentry = cpg->dentry; ++ bbot = au_dbbot(dentry); ++ for (bsrc = cpg->bdst + 1; bsrc <= bbot; bsrc++) { ++ h_dentry = au_h_dptr(dentry, bsrc); ++ if (h_dentry) { ++ AuDebugOn(d_is_negative(h_dentry)); ++ break; ++ } ++ } ++ AuDebugOn(bsrc > bbot); ++ cpg->bsrc = bsrc; ++ } ++ AuDebugOn(cpg->bsrc <= cpg->bdst); ++ return au_do_sio_cpup_simple(cpg); ++} ++ ++int au_sio_cpdown_simple(struct au_cp_generic *cpg) ++{ ++ AuDebugOn(cpg->bdst <= cpg->bsrc); ++ return au_do_sio_cpup_simple(cpg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * copyup the deleted file for writing. ++ */ ++static int au_do_cpup_wh(struct au_cp_generic *cpg, struct dentry *wh_dentry, ++ struct file *file) ++{ ++ int err; ++ unsigned int flags_orig; ++ aufs_bindex_t bsrc_orig; ++ struct au_dinfo *dinfo; ++ struct { ++ struct au_hdentry *hd; ++ struct dentry *h_dentry; ++ } hdst, hsrc; ++ ++ dinfo = au_di(cpg->dentry); ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ bsrc_orig = cpg->bsrc; ++ cpg->bsrc = dinfo->di_btop; ++ hdst.hd = au_hdentry(dinfo, cpg->bdst); ++ hdst.h_dentry = hdst.hd->hd_dentry; ++ hdst.hd->hd_dentry = wh_dentry; ++ dinfo->di_btop = cpg->bdst; ++ ++ hsrc.h_dentry = NULL; ++ if (file) { ++ hsrc.hd = au_hdentry(dinfo, cpg->bsrc); ++ hsrc.h_dentry = hsrc.hd->hd_dentry; ++ hsrc.hd->hd_dentry = au_hf_top(file)->f_path.dentry; ++ } ++ flags_orig = cpg->flags; ++ cpg->flags = !AuCpup_DTIME; ++ err = au_cpup_single(cpg, /*h_parent*/NULL); ++ cpg->flags = flags_orig; ++ if (file) { ++ if (!err) ++ err = au_reopen_nondir(file); ++ hsrc.hd->hd_dentry = hsrc.h_dentry; ++ } ++ hdst.hd->hd_dentry = hdst.h_dentry; ++ dinfo->di_btop = cpg->bsrc; ++ cpg->bsrc = bsrc_orig; ++ ++ return err; ++} ++ ++static int au_cpup_wh(struct au_cp_generic *cpg, struct file *file) ++{ ++ int err; ++ aufs_bindex_t bdst; ++ struct au_dtime dt; ++ struct dentry *dentry, *parent, *h_parent, *wh_dentry; ++ struct au_branch *br; ++ struct path h_path; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ br = au_sbr(dentry->d_sb, bdst); ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ wh_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ h_path.dentry = h_parent; ++ h_path.mnt = au_br_mnt(br); ++ au_dtime_store(&dt, parent, &h_path); ++ err = au_do_cpup_wh(cpg, wh_dentry, file); ++ if (unlikely(err)) ++ goto out_wh; ++ ++ dget(wh_dentry); ++ h_path.dentry = wh_dentry; ++ if (!d_is_dir(wh_dentry)) { ++ /* no delegation since it is just created */ ++ err = vfsub_unlink(d_inode(h_parent), &h_path, ++ /*delegated*/NULL, /*force*/0); ++ } else ++ err = vfsub_rmdir(d_inode(h_parent), &h_path); ++ if (unlikely(err)) { ++ AuIOErr("failed remove copied-up tmp file %pd(%d)\n", ++ wh_dentry, err); ++ err = -EIO; ++ } ++ au_dtime_revert(&dt); ++ au_set_hi_wh(d_inode(dentry), bdst, wh_dentry); ++ ++out_wh: ++ dput(wh_dentry); ++out: ++ dput(parent); ++ return err; ++} ++ ++struct au_cpup_wh_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++ struct file *file; ++}; ++ ++static void au_call_cpup_wh(void *args) ++{ ++ struct au_cpup_wh_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_wh(a->cpg, a->file); ++ au_pin_hdir_release(a->cpg->pin); ++} ++ ++int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file) ++{ ++ int err, wkq_err; ++ aufs_bindex_t bdst; ++ struct dentry *dentry, *parent, *h_orph, *h_parent; ++ struct inode *dir, *h_dir, *h_tmpdir; ++ struct au_wbr *wbr; ++ struct au_pin wh_pin, *pin_orig; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ h_orph = NULL; ++ h_parent = NULL; ++ h_dir = au_igrab(au_h_iptr(dir, bdst)); ++ h_tmpdir = h_dir; ++ pin_orig = NULL; ++ if (!h_dir->i_nlink) { ++ wbr = au_sbr(dentry->d_sb, bdst)->br_wbr; ++ h_orph = wbr->wbr_orph; ++ ++ h_parent = dget(au_h_dptr(parent, bdst)); ++ au_set_h_dptr(parent, bdst, dget(h_orph)); ++ h_tmpdir = d_inode(h_orph); ++ au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0); ++ ++ inode_lock_nested(h_tmpdir, AuLsc_I_PARENT3); ++ /* todo: au_h_open_pre()? */ ++ ++ pin_orig = cpg->pin; ++ au_pin_init(&wh_pin, dentry, bdst, AuLsc_DI_PARENT, ++ AuLsc_I_PARENT3, cpg->pin->udba, AuPin_DI_LOCKED); ++ cpg->pin = &wh_pin; ++ } ++ ++ if (!au_test_h_perm_sio(h_tmpdir, MAY_EXEC | MAY_WRITE) ++ && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode)) ++ err = au_cpup_wh(cpg, file); ++ else { ++ struct au_cpup_wh_args args = { ++ .errp = &err, ++ .cpg = cpg, ++ .file = file ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_wh, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ if (h_orph) { ++ inode_unlock(h_tmpdir); ++ /* todo: au_h_open_post()? */ ++ au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0); ++ au_set_h_dptr(parent, bdst, h_parent); ++ AuDebugOn(!pin_orig); ++ cpg->pin = pin_orig; ++ } ++ iput(h_dir); ++ dput(parent); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * generic routine for both of copy-up and copy-down. ++ */ ++/* cf. revalidate function in file.c */ ++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg), ++ void *arg) ++{ ++ int err; ++ struct au_pin pin; ++ struct dentry *d, *parent, *h_parent, *real_parent, *h_dentry; ++ ++ err = 0; ++ parent = dget_parent(dentry); ++ if (IS_ROOT(parent)) ++ goto out; ++ ++ au_pin_init(&pin, dentry, bdst, AuLsc_DI_PARENT2, AuLsc_I_PARENT2, ++ au_opt_udba(dentry->d_sb), AuPin_MNT_WRITE); ++ ++ /* do not use au_dpage */ ++ real_parent = parent; ++ while (1) { ++ dput(parent); ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ if (h_parent) ++ goto out; /* success */ ++ ++ /* find top dir which is necessary to cpup */ ++ do { ++ d = parent; ++ dput(parent); ++ parent = dget_parent(d); ++ di_read_lock_parent3(parent, !AuLock_IR); ++ h_parent = au_h_dptr(parent, bdst); ++ di_read_unlock(parent, !AuLock_IR); ++ } while (!h_parent); ++ ++ if (d != real_parent) ++ di_write_lock_child3(d); ++ ++ /* somebody else might create while we were sleeping */ ++ h_dentry = au_h_dptr(d, bdst); ++ if (!h_dentry || d_is_negative(h_dentry)) { ++ if (h_dentry) ++ au_update_dbtop(d); ++ ++ au_pin_set_dentry(&pin, d); ++ err = au_do_pin(&pin); ++ if (!err) { ++ err = cp(d, bdst, &pin, h_parent, arg); ++ au_unpin(&pin); ++ } ++ } ++ ++ if (d != real_parent) ++ di_write_unlock(d); ++ if (unlikely(err)) ++ break; ++ } ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++static int au_cpup_dir(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent __maybe_unused, ++ void *arg __maybe_unused) ++{ ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = bdst, ++ .bsrc = -1, ++ .len = 0, ++ .pin = pin, ++ .flags = AuCpup_DTIME ++ }; ++ return au_sio_cpup_simple(&cpg); ++} ++ ++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ return au_cp_dirs(dentry, bdst, au_cpup_dir, NULL); ++} ++ ++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ int err; ++ struct dentry *parent; ++ struct inode *dir; ++ ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ err = 0; ++ if (au_h_iptr(dir, bdst)) ++ goto out; ++ ++ di_read_unlock(parent, AuLock_IR); ++ di_write_lock_parent(parent); ++ /* someone else might change our inode while we were sleeping */ ++ if (!au_h_iptr(dir, bdst)) ++ err = au_cpup_dirs(dentry, bdst); ++ di_downgrade_lock(parent, AuLock_IR); ++ ++out: ++ dput(parent); ++ return err; ++} +diff --git a/fs/aufs/cpup.h b/fs/aufs/cpup.h +new file mode 100644 +index 0000000..ccba2c4 +--- /dev/null ++++ b/fs/aufs/cpup.h +@@ -0,0 +1,81 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * copy-up/down functions ++ */ ++ ++#ifndef __AUFS_CPUP_H__ ++#define __AUFS_CPUP_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct inode; ++struct file; ++struct au_pin; ++ ++void au_cpup_attr_flags(struct inode *dst, unsigned int iflags); ++void au_cpup_attr_timesizes(struct inode *inode); ++void au_cpup_attr_nlink(struct inode *inode, int force); ++void au_cpup_attr_changeable(struct inode *inode); ++void au_cpup_igen(struct inode *inode, struct inode *h_inode); ++void au_cpup_attr_all(struct inode *inode, int force); ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_cp_generic { ++ struct dentry *dentry; ++ aufs_bindex_t bdst, bsrc; ++ loff_t len; ++ struct au_pin *pin; ++ unsigned int flags; ++}; ++ ++/* cpup flags */ ++#define AuCpup_DTIME 1 /* do dtime_store/revert */ ++#define AuCpup_KEEPLINO (1 << 1) /* do not clear the lower xino, ++ for link(2) */ ++#define AuCpup_RENAME (1 << 2) /* rename after cpup */ ++#define AuCpup_HOPEN (1 << 3) /* call h_open_pre/post() in ++ cpup */ ++#define AuCpup_OVERWRITE (1 << 4) /* allow overwriting the ++ existing entry */ ++#define AuCpup_RWDST (1 << 5) /* force write target even if ++ the branch is marked as RO */ ++ ++#define au_ftest_cpup(flags, name) ((flags) & AuCpup_##name) ++#define au_fset_cpup(flags, name) \ ++ do { (flags) |= AuCpup_##name; } while (0) ++#define au_fclr_cpup(flags, name) \ ++ do { (flags) &= ~AuCpup_##name; } while (0) ++ ++int au_copy_file(struct file *dst, struct file *src, loff_t len); ++int au_sio_cpup_simple(struct au_cp_generic *cpg); ++int au_sio_cpdown_simple(struct au_cp_generic *cpg); ++int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file); ++ ++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg), ++ void *arg); ++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* keep timestamps when copyup */ ++struct au_dtime { ++ struct dentry *dt_dentry; ++ struct path dt_h_path; ++ struct timespec dt_atime, dt_mtime; ++}; ++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, ++ struct path *h_path); ++void au_dtime_revert(struct au_dtime *dt); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_CPUP_H__ */ +diff --git a/fs/aufs/dbgaufs.c b/fs/aufs/dbgaufs.c +new file mode 100644 +index 0000000..21ac773 +--- /dev/null ++++ b/fs/aufs/dbgaufs.c +@@ -0,0 +1,419 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * debugfs interface ++ */ ++ ++#include ++#include "aufs.h" ++ ++#ifndef CONFIG_SYSFS ++#error DEBUG_FS depends upon SYSFS ++#endif ++ ++static struct dentry *dbgaufs; ++static const mode_t dbgaufs_mode = S_IRUSR | S_IRGRP | S_IROTH; ++ ++/* 20 is max digits length of ulong 64 */ ++struct dbgaufs_arg { ++ int n; ++ char a[20 * 4]; ++}; ++ ++/* ++ * common function for all XINO files ++ */ ++static int dbgaufs_xi_release(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ kfree(file->private_data); ++ return 0; ++} ++ ++static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt) ++{ ++ int err; ++ struct kstat st; ++ struct dbgaufs_arg *p; ++ ++ err = -ENOMEM; ++ p = kmalloc(sizeof(*p), GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = 0; ++ p->n = 0; ++ file->private_data = p; ++ if (!xf) ++ goto out; ++ ++ err = vfs_getattr(&xf->f_path, &st); ++ if (!err) { ++ if (do_fcnt) ++ p->n = snprintf ++ (p->a, sizeof(p->a), "%ld, %llux%lu %lld\n", ++ (long)file_count(xf), st.blocks, st.blksize, ++ (long long)st.size); ++ else ++ p->n = snprintf(p->a, sizeof(p->a), "%llux%lu %lld\n", ++ st.blocks, st.blksize, ++ (long long)st.size); ++ AuDebugOn(p->n >= sizeof(p->a)); ++ } else { ++ p->n = snprintf(p->a, sizeof(p->a), "err %d\n", err); ++ err = 0; ++ } ++ ++out: ++ return err; ++ ++} ++ ++static ssize_t dbgaufs_xi_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct dbgaufs_arg *p; ++ ++ p = file->private_data; ++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dbgaufs_plink_arg { ++ int n; ++ char a[]; ++}; ++ ++static int dbgaufs_plink_release(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ free_page((unsigned long)file->private_data); ++ return 0; ++} ++ ++static int dbgaufs_plink_open(struct inode *inode, struct file *file) ++{ ++ int err, i, limit; ++ unsigned long n, sum; ++ struct dbgaufs_plink_arg *p; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct au_sphlhead *sphl; ++ ++ err = -ENOMEM; ++ p = (void *)get_zeroed_page(GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = -EFBIG; ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ limit = PAGE_SIZE - sizeof(p->n); ++ ++ /* the number of buckets */ ++ n = snprintf(p->a + p->n, limit, "%d\n", AuPlink_NHASH); ++ p->n += n; ++ limit -= n; ++ ++ sum = 0; ++ for (i = 0, sphl = sbinfo->si_plink; ++ i < AuPlink_NHASH; ++ i++, sphl++) { ++ n = au_sphl_count(sphl); ++ sum += n; ++ ++ n = snprintf(p->a + p->n, limit, "%lu ", n); ++ p->n += n; ++ limit -= n; ++ if (unlikely(limit <= 0)) ++ goto out_free; ++ } ++ p->a[p->n - 1] = '\n'; ++ ++ /* the sum of plinks */ ++ n = snprintf(p->a + p->n, limit, "%lu\n", sum); ++ p->n += n; ++ limit -= n; ++ if (unlikely(limit <= 0)) ++ goto out_free; ++ } else { ++#define str "1\n0\n0\n" ++ p->n = sizeof(str) - 1; ++ strcpy(p->a, str); ++#undef str ++ } ++ si_read_unlock(sb); ++ ++ err = 0; ++ file->private_data = p; ++ goto out; /* success */ ++ ++out_free: ++ free_page((unsigned long)p); ++out: ++ return err; ++} ++ ++static ssize_t dbgaufs_plink_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct dbgaufs_plink_arg *p; ++ ++ p = file->private_data; ++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n); ++} ++ ++static const struct file_operations dbgaufs_plink_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_plink_open, ++ .release = dbgaufs_plink_release, ++ .read = dbgaufs_plink_read ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int dbgaufs_xib_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0); ++ si_read_unlock(sb); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xib_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xib_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define DbgaufsXi_PREFIX "xi" ++ ++static int dbgaufs_xino_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ long l; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct file *xf; ++ struct qstr *name; ++ ++ err = -ENOENT; ++ xf = NULL; ++ name = &file->f_path.dentry->d_name; ++ if (unlikely(name->len < sizeof(DbgaufsXi_PREFIX) ++ || memcmp(name->name, DbgaufsXi_PREFIX, ++ sizeof(DbgaufsXi_PREFIX) - 1))) ++ goto out; ++ err = kstrtol(name->name + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l); ++ if (unlikely(err)) ++ goto out; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ if (l <= au_sbbot(sb)) { ++ xf = au_sbr(sb, (aufs_bindex_t)l)->br_xino.xi_file; ++ err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1); ++ } else ++ err = -ENOENT; ++ si_read_unlock(sb); ++ ++out: ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xino_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xino_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ aufs_bindex_t bbot; ++ struct au_branch *br; ++ struct au_xino_file *xi; ++ ++ if (!au_sbi(sb)->si_dbgaufs) ++ return; ++ ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ xi = &br->br_xino; ++ debugfs_remove(xi->xi_dbgaufs); ++ xi->xi_dbgaufs = NULL; ++ } ++} ++ ++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_sbinfo *sbinfo; ++ struct dentry *parent; ++ struct au_branch *br; ++ struct au_xino_file *xi; ++ aufs_bindex_t bbot; ++ char name[sizeof(DbgaufsXi_PREFIX) + 5]; /* "xi" bindex NULL */ ++ ++ sbinfo = au_sbi(sb); ++ parent = sbinfo->si_dbgaufs; ++ if (!parent) ++ return; ++ ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex); ++ br = au_sbr(sb, bindex); ++ xi = &br->br_xino; ++ AuDebugOn(xi->xi_dbgaufs); ++ xi->xi_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent, ++ sbinfo, &dbgaufs_xino_fop); ++ /* ignore an error */ ++ if (unlikely(!xi->xi_dbgaufs)) ++ AuWarn1("failed %s under debugfs\n", name); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++static int dbgaufs_xigen_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0); ++ si_read_unlock(sb); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xigen_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xigen_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ err = -EIO; ++ sbinfo->si_dbgaufs_xigen = debugfs_create_file ++ ("xigen", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_xigen_fop); ++ if (sbinfo->si_dbgaufs_xigen) ++ err = 0; ++ ++ return err; ++} ++#else ++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) ++{ ++ return 0; ++} ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++void dbgaufs_si_fin(struct au_sbinfo *sbinfo) ++{ ++ /* ++ * This function is a dynamic '__fin' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ debugfs_remove_recursive(sbinfo->si_dbgaufs); ++ sbinfo->si_dbgaufs = NULL; ++ kobject_put(&sbinfo->si_kobj); ++} ++ ++int dbgaufs_si_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ char name[SysaufsSiNameLen]; ++ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ err = -ENOENT; ++ if (!dbgaufs) { ++ AuErr1("/debug/aufs is uninitialized\n"); ++ goto out; ++ } ++ ++ err = -EIO; ++ sysaufs_name(sbinfo, name); ++ sbinfo->si_dbgaufs = debugfs_create_dir(name, dbgaufs); ++ if (unlikely(!sbinfo->si_dbgaufs)) ++ goto out; ++ kobject_get(&sbinfo->si_kobj); ++ ++ sbinfo->si_dbgaufs_xib = debugfs_create_file ++ ("xib", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_xib_fop); ++ if (unlikely(!sbinfo->si_dbgaufs_xib)) ++ goto out_dir; ++ ++ sbinfo->si_dbgaufs_plink = debugfs_create_file ++ ("plink", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_plink_fop); ++ if (unlikely(!sbinfo->si_dbgaufs_plink)) ++ goto out_dir; ++ ++ err = dbgaufs_xigen_init(sbinfo); ++ if (!err) ++ goto out; /* success */ ++ ++out_dir: ++ dbgaufs_si_fin(sbinfo); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void dbgaufs_fin(void) ++{ ++ debugfs_remove(dbgaufs); ++} ++ ++int __init dbgaufs_init(void) ++{ ++ int err; ++ ++ err = -EIO; ++ dbgaufs = debugfs_create_dir(AUFS_NAME, NULL); ++ if (dbgaufs) ++ err = 0; ++ return err; ++} +diff --git a/fs/aufs/dbgaufs.h b/fs/aufs/dbgaufs.h +new file mode 100644 +index 0000000..81f272e +--- /dev/null ++++ b/fs/aufs/dbgaufs.h +@@ -0,0 +1,35 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * debugfs interface ++ */ ++ ++#ifndef __DBGAUFS_H__ ++#define __DBGAUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++struct super_block; ++struct au_sbinfo; ++ ++#ifdef CONFIG_DEBUG_FS ++/* dbgaufs.c */ ++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); ++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); ++void dbgaufs_si_fin(struct au_sbinfo *sbinfo); ++int dbgaufs_si_init(struct au_sbinfo *sbinfo); ++void dbgaufs_fin(void); ++int __init dbgaufs_init(void); ++#else ++AuStubVoid(dbgaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(dbgaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(dbgaufs_si_fin, struct au_sbinfo *sbinfo) ++AuStubInt0(dbgaufs_si_init, struct au_sbinfo *sbinfo) ++AuStubVoid(dbgaufs_fin, void) ++AuStubInt0(__init dbgaufs_init, void) ++#endif /* CONFIG_DEBUG_FS */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __DBGAUFS_H__ */ +diff --git a/fs/aufs/dcsub.c b/fs/aufs/dcsub.c +new file mode 100644 +index 0000000..e72acce +--- /dev/null ++++ b/fs/aufs/dcsub.c +@@ -0,0 +1,211 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * sub-routines for dentry cache ++ */ ++ ++#include "aufs.h" ++ ++static void au_dpage_free(struct au_dpage *dpage) ++{ ++ int i; ++ struct dentry **p; ++ ++ p = dpage->dentries; ++ for (i = 0; i < dpage->ndentry; i++) ++ dput(*p++); ++ free_page((unsigned long)dpage->dentries); ++} ++ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp) ++{ ++ int err; ++ void *p; ++ ++ err = -ENOMEM; ++ dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp); ++ if (unlikely(!dpages->dpages)) ++ goto out; ++ ++ p = (void *)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out_dpages; ++ ++ dpages->dpages[0].ndentry = 0; ++ dpages->dpages[0].dentries = p; ++ dpages->ndpage = 1; ++ return 0; /* success */ ++ ++out_dpages: ++ kfree(dpages->dpages); ++out: ++ return err; ++} ++ ++void au_dpages_free(struct au_dcsub_pages *dpages) ++{ ++ int i; ++ struct au_dpage *p; ++ ++ p = dpages->dpages; ++ for (i = 0; i < dpages->ndpage; i++) ++ au_dpage_free(p++); ++ kfree(dpages->dpages); ++} ++ ++static int au_dpages_append(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, gfp_t gfp) ++{ ++ int err, sz; ++ struct au_dpage *dpage; ++ void *p; ++ ++ dpage = dpages->dpages + dpages->ndpage - 1; ++ sz = PAGE_SIZE / sizeof(dentry); ++ if (unlikely(dpage->ndentry >= sz)) { ++ AuLabel(new dpage); ++ err = -ENOMEM; ++ sz = dpages->ndpage * sizeof(*dpages->dpages); ++ p = au_kzrealloc(dpages->dpages, sz, ++ sz + sizeof(*dpages->dpages), gfp); ++ if (unlikely(!p)) ++ goto out; ++ ++ dpages->dpages = p; ++ dpage = dpages->dpages + dpages->ndpage; ++ p = (void *)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out; ++ ++ dpage->ndentry = 0; ++ dpage->dentries = p; ++ dpages->ndpage++; ++ } ++ ++ AuDebugOn(au_dcount(dentry) <= 0); ++ dpage->dentries[dpage->ndentry++] = dget_dlock(dentry); ++ return 0; /* success */ ++ ++out: ++ return err; ++} ++ ++/* todo: BAD approach */ ++/* copied from linux/fs/dcache.c */ ++enum d_walk_ret { ++ D_WALK_CONTINUE, ++ D_WALK_QUIT, ++ D_WALK_NORETRY, ++ D_WALK_SKIP, ++}; ++ ++extern void d_walk(struct dentry *parent, void *data, ++ enum d_walk_ret (*enter)(void *, struct dentry *), ++ void (*finish)(void *)); ++ ++struct ac_dpages_arg { ++ int err; ++ struct au_dcsub_pages *dpages; ++ struct super_block *sb; ++ au_dpages_test test; ++ void *arg; ++}; ++ ++static enum d_walk_ret au_call_dpages_append(void *_arg, struct dentry *dentry) ++{ ++ enum d_walk_ret ret; ++ struct ac_dpages_arg *arg = _arg; ++ ++ ret = D_WALK_CONTINUE; ++ if (dentry->d_sb == arg->sb ++ && !IS_ROOT(dentry) ++ && au_dcount(dentry) > 0 ++ && au_di(dentry) ++ && (!arg->test || arg->test(dentry, arg->arg))) { ++ arg->err = au_dpages_append(arg->dpages, dentry, GFP_ATOMIC); ++ if (unlikely(arg->err)) ++ ret = D_WALK_QUIT; ++ } ++ ++ return ret; ++} ++ ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg) ++{ ++ struct ac_dpages_arg args = { ++ .err = 0, ++ .dpages = dpages, ++ .sb = root->d_sb, ++ .test = test, ++ .arg = arg ++ }; ++ ++ d_walk(root, &args, au_call_dpages_append, NULL); ++ ++ return args.err; ++} ++ ++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, ++ int do_include, au_dpages_test test, void *arg) ++{ ++ int err; ++ ++ err = 0; ++ write_seqlock(&rename_lock); ++ spin_lock(&dentry->d_lock); ++ if (do_include ++ && au_dcount(dentry) > 0 ++ && (!test || test(dentry, arg))) ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ spin_unlock(&dentry->d_lock); ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * RCU for vfsmount is unnecessary since this is a traverse in a single ++ * mount ++ */ ++ while (!IS_ROOT(dentry)) { ++ dentry = dentry->d_parent; /* rename_lock is locked */ ++ spin_lock(&dentry->d_lock); ++ if (au_dcount(dentry) > 0 ++ && (!test || test(dentry, arg))) ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ spin_unlock(&dentry->d_lock); ++ if (unlikely(err)) ++ break; ++ } ++ ++out: ++ write_sequnlock(&rename_lock); ++ return err; ++} ++ ++static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg) ++{ ++ return au_di(dentry) && dentry->d_sb == arg; ++} ++ ++int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, int do_include) ++{ ++ return au_dcsub_pages_rev(dpages, dentry, do_include, ++ au_dcsub_dpages_aufs, dentry->d_sb); ++} ++ ++int au_test_subdir(struct dentry *d1, struct dentry *d2) ++{ ++ struct path path[2] = { ++ { ++ .dentry = d1 ++ }, ++ { ++ .dentry = d2 ++ } ++ }; ++ ++ return path_is_under(path + 0, path + 1); ++} +diff --git a/fs/aufs/dcsub.h b/fs/aufs/dcsub.h +new file mode 100644 +index 0000000..5d2cf66 +--- /dev/null ++++ b/fs/aufs/dcsub.h +@@ -0,0 +1,123 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * sub-routines for dentry cache ++ */ ++ ++#ifndef __AUFS_DCSUB_H__ ++#define __AUFS_DCSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++struct au_dpage { ++ int ndentry; ++ struct dentry **dentries; ++}; ++ ++struct au_dcsub_pages { ++ int ndpage; ++ struct au_dpage *dpages; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dcsub.c */ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp); ++void au_dpages_free(struct au_dcsub_pages *dpages); ++typedef int (*au_dpages_test)(struct dentry *dentry, void *arg); ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg); ++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, ++ int do_include, au_dpages_test test, void *arg); ++int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, int do_include); ++int au_test_subdir(struct dentry *d1, struct dentry *d2); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * todo: in linux-3.13, several similar (but faster) helpers are added to ++ * include/linux/dcache.h. Try them (in the future). ++ */ ++ ++static inline int au_d_hashed_positive(struct dentry *d) ++{ ++ int err; ++ struct inode *inode = d_inode(d); ++ ++ err = 0; ++ if (unlikely(d_unhashed(d) ++ || d_is_negative(d) ++ || !inode->i_nlink)) ++ err = -ENOENT; ++ return err; ++} ++ ++static inline int au_d_linkable(struct dentry *d) ++{ ++ int err; ++ struct inode *inode = d_inode(d); ++ ++ err = au_d_hashed_positive(d); ++ if (err ++ && d_is_positive(d) ++ && (inode->i_state & I_LINKABLE)) ++ err = 0; ++ return err; ++} ++ ++static inline int au_d_alive(struct dentry *d) ++{ ++ int err; ++ struct inode *inode; ++ ++ err = 0; ++ if (!IS_ROOT(d)) ++ err = au_d_hashed_positive(d); ++ else { ++ inode = d_inode(d); ++ if (unlikely(d_unlinked(d) ++ || d_is_negative(d) ++ || !inode->i_nlink)) ++ err = -ENOENT; ++ } ++ return err; ++} ++ ++static inline int au_alive_dir(struct dentry *d) ++{ ++ int err; ++ ++ err = au_d_alive(d); ++ if (unlikely(err || IS_DEADDIR(d_inode(d)))) ++ err = -ENOENT; ++ return err; ++} ++ ++static inline int au_qstreq(struct qstr *a, struct qstr *b) ++{ ++ return a->len == b->len ++ && !memcmp(a->name, b->name, a->len); ++} ++ ++/* ++ * by the commit ++ * 360f547 2015-01-25 dcache: let the dentry count go down to zero without ++ * taking d_lock ++ * the type of d_lockref.count became int, but the inlined function d_count() ++ * still returns unsigned int. ++ * I don't know why. Maybe it is for every d_count() users? ++ * Anyway au_dcount() lives on. ++ */ ++static inline int au_dcount(struct dentry *d) ++{ ++ return (int)d_count(d); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DCSUB_H__ */ +diff --git a/fs/aufs/debug.c b/fs/aufs/debug.c +new file mode 100644 +index 0000000..44bdb5f +--- /dev/null ++++ b/fs/aufs/debug.c +@@ -0,0 +1,428 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * debug print functions ++ */ ++ ++#include "aufs.h" ++ ++/* Returns 0, or -errno. arg is in kp->arg. */ ++static int param_atomic_t_set(const char *val, const struct kernel_param *kp) ++{ ++ int err, n; ++ ++ err = kstrtoint(val, 0, &n); ++ if (!err) { ++ if (n > 0) ++ au_debug_on(); ++ else ++ au_debug_off(); ++ } ++ return err; ++} ++ ++/* Returns length written or -errno. Buffer is 4k (ie. be short!) */ ++static int param_atomic_t_get(char *buffer, const struct kernel_param *kp) ++{ ++ atomic_t *a; ++ ++ a = kp->arg; ++ return sprintf(buffer, "%d", atomic_read(a)); ++} ++ ++static struct kernel_param_ops param_ops_atomic_t = { ++ .set = param_atomic_t_set, ++ .get = param_atomic_t_get ++ /* void (*free)(void *arg) */ ++}; ++ ++atomic_t aufs_debug = ATOMIC_INIT(0); ++MODULE_PARM_DESC(debug, "debug print"); ++module_param_named(debug, aufs_debug, atomic_t, S_IRUGO | S_IWUSR | S_IWGRP); ++ ++DEFINE_MUTEX(au_dbg_mtx); /* just to serialize the dbg msgs */ ++char *au_plevel = KERN_DEBUG; ++#define dpri(fmt, ...) do { \ ++ if ((au_plevel \ ++ && strcmp(au_plevel, KERN_DEBUG)) \ ++ || au_debug_test()) \ ++ printk("%s" fmt, au_plevel, ##__VA_ARGS__); \ ++} while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_dpri_whlist(struct au_nhash *whlist) ++{ ++ unsigned long ul, n; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (ul = 0; ul < n; ul++) { ++ hlist_for_each_entry(pos, head, wh_hash) ++ dpri("b%d, %.*s, %d\n", ++ pos->wh_bindex, ++ pos->wh_str.len, pos->wh_str.name, ++ pos->wh_str.len); ++ head++; ++ } ++} ++ ++void au_dpri_vdir(struct au_vdir *vdir) ++{ ++ unsigned long ul; ++ union au_vdir_deblk_p p; ++ unsigned char *o; ++ ++ if (!vdir || IS_ERR(vdir)) { ++ dpri("err %ld\n", PTR_ERR(vdir)); ++ return; ++ } ++ ++ dpri("deblk %u, nblk %lu, deblk %p, last{%lu, %p}, ver %lu\n", ++ vdir->vd_deblk_sz, vdir->vd_nblk, vdir->vd_deblk, ++ vdir->vd_last.ul, vdir->vd_last.p.deblk, vdir->vd_version); ++ for (ul = 0; ul < vdir->vd_nblk; ul++) { ++ p.deblk = vdir->vd_deblk[ul]; ++ o = p.deblk; ++ dpri("[%lu]: %p\n", ul, o); ++ } ++} ++ ++static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode, int hn, ++ struct dentry *wh) ++{ ++ char *n = NULL; ++ int l = 0; ++ ++ if (!inode || IS_ERR(inode)) { ++ dpri("i%d: err %ld\n", bindex, PTR_ERR(inode)); ++ return -1; ++ } ++ ++ /* the type of i_blocks depends upon CONFIG_LBDAF */ ++ BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long) ++ && sizeof(inode->i_blocks) != sizeof(u64)); ++ if (wh) { ++ n = (void *)wh->d_name.name; ++ l = wh->d_name.len; ++ } ++ ++ dpri("i%d: %p, i%lu, %s, cnt %d, nl %u, 0%o, sz %llu, blk %llu," ++ " hn %d, ct %lld, np %lu, st 0x%lx, f 0x%x, v %llu, g %x%s%.*s\n", ++ bindex, inode, ++ inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??", ++ atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode, ++ i_size_read(inode), (unsigned long long)inode->i_blocks, ++ hn, (long long)timespec_to_ns(&inode->i_ctime) & 0x0ffff, ++ inode->i_mapping ? inode->i_mapping->nrpages : 0, ++ inode->i_state, inode->i_flags, inode->i_version, ++ inode->i_generation, ++ l ? ", wh " : "", l, n); ++ return 0; ++} ++ ++void au_dpri_inode(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ aufs_bindex_t bindex; ++ int err, hn; ++ ++ err = do_pri_inode(-1, inode, -1, NULL); ++ if (err || !au_test_aufs(inode->i_sb) || au_is_bad_inode(inode)) ++ return; ++ ++ iinfo = au_ii(inode); ++ dpri("i-1: btop %d, bbot %d, gen %d\n", ++ iinfo->ii_btop, iinfo->ii_bbot, au_iigen(inode, NULL)); ++ if (iinfo->ii_btop < 0) ++ return; ++ hn = 0; ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; bindex++) { ++ hi = au_hinode(iinfo, bindex); ++ hn = !!au_hn(hi); ++ do_pri_inode(bindex, hi->hi_inode, hn, hi->hi_whdentry); ++ } ++} ++ ++void au_dpri_dalias(struct inode *inode) ++{ ++ struct dentry *d; ++ ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) ++ au_dpri_dentry(d); ++ spin_unlock(&inode->i_lock); ++} ++ ++static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry) ++{ ++ struct dentry *wh = NULL; ++ int hn; ++ struct inode *inode; ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ ++ if (!dentry || IS_ERR(dentry)) { ++ dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry)); ++ return -1; ++ } ++ /* do not call dget_parent() here */ ++ /* note: access d_xxx without d_lock */ ++ dpri("d%d: %p, %pd2?, %s, cnt %d, flags 0x%x, %shashed\n", ++ bindex, dentry, dentry, ++ dentry->d_sb ? au_sbtype(dentry->d_sb) : "??", ++ au_dcount(dentry), dentry->d_flags, ++ d_unhashed(dentry) ? "un" : ""); ++ hn = -1; ++ inode = NULL; ++ if (d_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (inode ++ && au_test_aufs(dentry->d_sb) ++ && bindex >= 0 ++ && !au_is_bad_inode(inode)) { ++ iinfo = au_ii(inode); ++ hi = au_hinode(iinfo, bindex); ++ hn = !!au_hn(hi); ++ wh = hi->hi_whdentry; ++ } ++ do_pri_inode(bindex, inode, hn, wh); ++ return 0; ++} ++ ++void au_dpri_dentry(struct dentry *dentry) ++{ ++ struct au_dinfo *dinfo; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_dentry(-1, dentry); ++ if (err || !au_test_aufs(dentry->d_sb)) ++ return; ++ ++ dinfo = au_di(dentry); ++ if (!dinfo) ++ return; ++ dpri("d-1: btop %d, bbot %d, bwh %d, bdiropq %d, gen %d, tmp %d\n", ++ dinfo->di_btop, dinfo->di_bbot, ++ dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry), ++ dinfo->di_tmpfile); ++ if (dinfo->di_btop < 0) ++ return; ++ for (bindex = dinfo->di_btop; bindex <= dinfo->di_bbot; bindex++) ++ do_pri_dentry(bindex, au_hdentry(dinfo, bindex)->hd_dentry); ++} ++ ++static int do_pri_file(aufs_bindex_t bindex, struct file *file) ++{ ++ char a[32]; ++ ++ if (!file || IS_ERR(file)) { ++ dpri("f%d: err %ld\n", bindex, PTR_ERR(file)); ++ return -1; ++ } ++ a[0] = 0; ++ if (bindex < 0 ++ && !IS_ERR_OR_NULL(file->f_path.dentry) ++ && au_test_aufs(file->f_path.dentry->d_sb) ++ && au_fi(file)) ++ snprintf(a, sizeof(a), ", gen %d, mmapped %d", ++ au_figen(file), atomic_read(&au_fi(file)->fi_mmapped)); ++ dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, v %llu, pos %llu%s\n", ++ bindex, file->f_mode, file->f_flags, (long)file_count(file), ++ file->f_version, file->f_pos, a); ++ if (!IS_ERR_OR_NULL(file->f_path.dentry)) ++ do_pri_dentry(bindex, file->f_path.dentry); ++ return 0; ++} ++ ++void au_dpri_file(struct file *file) ++{ ++ struct au_finfo *finfo; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_file(-1, file); ++ if (err ++ || IS_ERR_OR_NULL(file->f_path.dentry) ++ || !au_test_aufs(file->f_path.dentry->d_sb)) ++ return; ++ ++ finfo = au_fi(file); ++ if (!finfo) ++ return; ++ if (finfo->fi_btop < 0) ++ return; ++ fidir = finfo->fi_hdir; ++ if (!fidir) ++ do_pri_file(finfo->fi_btop, finfo->fi_htop.hf_file); ++ else ++ for (bindex = finfo->fi_btop; ++ bindex >= 0 && bindex <= fidir->fd_bbot; ++ bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ do_pri_file(bindex, hfile ? hfile->hf_file : NULL); ++ } ++} ++ ++static int do_pri_br(aufs_bindex_t bindex, struct au_branch *br) ++{ ++ struct vfsmount *mnt; ++ struct super_block *sb; ++ ++ if (!br || IS_ERR(br)) ++ goto out; ++ mnt = au_br_mnt(br); ++ if (!mnt || IS_ERR(mnt)) ++ goto out; ++ sb = mnt->mnt_sb; ++ if (!sb || IS_ERR(sb)) ++ goto out; ++ ++ dpri("s%d: {perm 0x%x, id %d, cnt %lld, wbr %p}, " ++ "%s, dev 0x%02x%02x, flags 0x%lx, cnt %d, active %d, " ++ "xino %d\n", ++ bindex, br->br_perm, br->br_id, au_br_count(br), ++ br->br_wbr, au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev), ++ sb->s_flags, sb->s_count, ++ atomic_read(&sb->s_active), !!br->br_xino.xi_file); ++ return 0; ++ ++out: ++ dpri("s%d: err %ld\n", bindex, PTR_ERR(br)); ++ return -1; ++} ++ ++void au_dpri_sb(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ aufs_bindex_t bindex; ++ int err; ++ /* to reuduce stack size */ ++ struct { ++ struct vfsmount mnt; ++ struct au_branch fake; ++ } *a; ++ ++ /* this function can be called from magic sysrq */ ++ a = kzalloc(sizeof(*a), GFP_ATOMIC); ++ if (unlikely(!a)) { ++ dpri("no memory\n"); ++ return; ++ } ++ ++ a->mnt.mnt_sb = sb; ++ a->fake.br_path.mnt = &a->mnt; ++ au_br_count_init(&a->fake); ++ err = do_pri_br(-1, &a->fake); ++ au_br_count_fin(&a->fake); ++ kfree(a); ++ dpri("dev 0x%x\n", sb->s_dev); ++ if (err || !au_test_aufs(sb)) ++ return; ++ ++ sbinfo = au_sbi(sb); ++ if (!sbinfo) ++ return; ++ dpri("nw %lld, gen %u, kobj %d\n", ++ percpu_counter_sum(&sbinfo->si_nowait.nw_len), ++ sbinfo->si_generation, ++ atomic_read(&sbinfo->si_kobj.kref.refcount)); ++ for (bindex = 0; bindex <= sbinfo->si_bbot; bindex++) ++ do_pri_br(bindex, sbinfo->si_branch[0 + bindex]); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line) ++{ ++ struct inode *h_inode, *inode = d_inode(dentry); ++ struct dentry *h_dentry; ++ aufs_bindex_t bindex, bbot, bi; ++ ++ if (!inode /* || au_di(dentry)->di_lsc == AuLsc_DI_TMP */) ++ return; ++ ++ bbot = au_dbbot(dentry); ++ bi = au_ibbot(inode); ++ if (bi < bbot) ++ bbot = bi; ++ bindex = au_dbtop(dentry); ++ bi = au_ibtop(inode); ++ if (bi > bindex) ++ bindex = bi; ++ ++ for (; bindex <= bbot; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(h_inode != d_inode(h_dentry))) { ++ au_debug_on(); ++ AuDbg("b%d, %s:%d\n", bindex, func, line); ++ AuDbgDentry(dentry); ++ AuDbgInode(inode); ++ au_debug_off(); ++ BUG(); ++ } ++ } ++} ++ ++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen) ++{ ++ int err, i, j; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ AuDebugOn(err); ++ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/1); ++ AuDebugOn(err); ++ for (i = dpages.ndpage - 1; !err && i >= 0; i--) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ for (j = dpage->ndentry - 1; !err && j >= 0; j--) ++ AuDebugOn(au_digen_test(dentries[j], sigen)); ++ } ++ au_dpages_free(&dpages); ++} ++ ++void au_dbg_verify_kthread(void) ++{ ++ if (au_wkq_test()) { ++ au_dbg_blocked(); ++ /* ++ * It may be recursive, but udba=notify between two aufs mounts, ++ * where a single ro branch is shared, is not a problem. ++ */ ++ /* WARN_ON(1); */ ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int __init au_debug_init(void) ++{ ++ aufs_bindex_t bindex; ++ struct au_vdir_destr destr; ++ ++ bindex = -1; ++ AuDebugOn(bindex >= 0); ++ ++ destr.len = -1; ++ AuDebugOn(destr.len < NAME_MAX); ++ ++#ifdef CONFIG_4KSTACKS ++ pr_warn("CONFIG_4KSTACKS is defined.\n"); ++#endif ++ ++ return 0; ++} +diff --git a/fs/aufs/debug.h b/fs/aufs/debug.h +new file mode 100644 +index 0000000..0567f31 +--- /dev/null ++++ b/fs/aufs/debug.h +@@ -0,0 +1,212 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * debug print functions ++ */ ++ ++#ifndef __AUFS_DEBUG_H__ ++#define __AUFS_DEBUG_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define AuDebugOn(a) BUG_ON(a) ++ ++/* module parameter */ ++extern atomic_t aufs_debug; ++static inline void au_debug_on(void) ++{ ++ atomic_inc(&aufs_debug); ++} ++static inline void au_debug_off(void) ++{ ++ atomic_dec_if_positive(&aufs_debug); ++} ++ ++static inline int au_debug_test(void) ++{ ++ return atomic_read(&aufs_debug) > 0; ++} ++#else ++#define AuDebugOn(a) do {} while (0) ++AuStubVoid(au_debug_on, void) ++AuStubVoid(au_debug_off, void) ++AuStubInt0(au_debug_test, void) ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++#define param_check_atomic_t(name, p) __param_check(name, p, atomic_t) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* debug print */ ++ ++#define AuDbg(fmt, ...) do { \ ++ if (au_debug_test()) \ ++ pr_debug("DEBUG: " fmt, ##__VA_ARGS__); \ ++} while (0) ++#define AuLabel(l) AuDbg(#l "\n") ++#define AuIOErr(fmt, ...) pr_err("I/O Error, " fmt, ##__VA_ARGS__) ++#define AuWarn1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ pr_warn(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuErr1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ pr_err(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuIOErr1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ AuIOErr(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuUnsupportMsg "This operation is not supported." \ ++ " Please report this application to aufs-users ML." ++#define AuUnsupport(fmt, ...) do { \ ++ pr_err(AuUnsupportMsg "\n" fmt, ##__VA_ARGS__); \ ++ dump_stack(); \ ++} while (0) ++ ++#define AuTraceErr(e) do { \ ++ if (unlikely((e) < 0)) \ ++ AuDbg("err %d\n", (int)(e)); \ ++} while (0) ++ ++#define AuTraceErrPtr(p) do { \ ++ if (IS_ERR(p)) \ ++ AuDbg("err %ld\n", PTR_ERR(p)); \ ++} while (0) ++ ++/* dirty macros for debug print, use with "%.*s" and caution */ ++#define AuLNPair(qstr) (qstr)->len, (qstr)->name ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry; ++#ifdef CONFIG_AUFS_DEBUG ++extern struct mutex au_dbg_mtx; ++extern char *au_plevel; ++struct au_nhash; ++void au_dpri_whlist(struct au_nhash *whlist); ++struct au_vdir; ++void au_dpri_vdir(struct au_vdir *vdir); ++struct inode; ++void au_dpri_inode(struct inode *inode); ++void au_dpri_dalias(struct inode *inode); ++void au_dpri_dentry(struct dentry *dentry); ++struct file; ++void au_dpri_file(struct file *filp); ++struct super_block; ++void au_dpri_sb(struct super_block *sb); ++ ++#define au_dbg_verify_dinode(d) __au_dbg_verify_dinode(d, __func__, __LINE__) ++void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line); ++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen); ++void au_dbg_verify_kthread(void); ++ ++int __init au_debug_init(void); ++ ++#define AuDbgWhlist(w) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#w "\n"); \ ++ au_dpri_whlist(w); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgVdir(v) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#v "\n"); \ ++ au_dpri_vdir(v); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgInode(i) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#i "\n"); \ ++ au_dpri_inode(i); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgDAlias(i) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#i "\n"); \ ++ au_dpri_dalias(i); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgDentry(d) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#d "\n"); \ ++ au_dpri_dentry(d); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgFile(f) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#f "\n"); \ ++ au_dpri_file(f); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgSb(sb) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#sb "\n"); \ ++ au_dpri_sb(sb); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgSym(addr) do { \ ++ char sym[KSYM_SYMBOL_LEN]; \ ++ sprint_symbol(sym, (unsigned long)addr); \ ++ AuDbg("%s\n", sym); \ ++} while (0) ++#else ++AuStubVoid(au_dbg_verify_dinode, struct dentry *dentry) ++AuStubVoid(au_dbg_verify_gen, struct dentry *parent, unsigned int sigen) ++AuStubVoid(au_dbg_verify_kthread, void) ++AuStubInt0(__init au_debug_init, void) ++ ++#define AuDbgWhlist(w) do {} while (0) ++#define AuDbgVdir(v) do {} while (0) ++#define AuDbgInode(i) do {} while (0) ++#define AuDbgDAlias(i) do {} while (0) ++#define AuDbgDentry(d) do {} while (0) ++#define AuDbgFile(f) do {} while (0) ++#define AuDbgSb(sb) do {} while (0) ++#define AuDbgSym(addr) do {} while (0) ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_MAGIC_SYSRQ ++int __init au_sysrq_init(void); ++void au_sysrq_fin(void); ++ ++#ifdef CONFIG_HW_CONSOLE ++#define au_dbg_blocked() do { \ ++ WARN_ON(1); \ ++ handle_sysrq('w'); \ ++} while (0) ++#else ++AuStubVoid(au_dbg_blocked, void) ++#endif ++ ++#else ++AuStubInt0(__init au_sysrq_init, void) ++AuStubVoid(au_sysrq_fin, void) ++AuStubVoid(au_dbg_blocked, void) ++#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DEBUG_H__ */ +diff --git a/fs/aufs/dentry.c b/fs/aufs/dentry.c +new file mode 100644 +index 0000000..4bb1530 +--- /dev/null ++++ b/fs/aufs/dentry.c +@@ -0,0 +1,1115 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#include ++#include "aufs.h" ++ ++struct au_do_lookup_args { ++ unsigned int flags; ++ mode_t type; ++}; ++ ++/* ++ * returns positive/negative dentry, NULL or an error. ++ * NULL means whiteout-ed or not-found. ++ */ ++static struct dentry* ++au_do_lookup(struct dentry *h_parent, struct dentry *dentry, ++ aufs_bindex_t bindex, struct qstr *wh_name, ++ struct au_do_lookup_args *args) ++{ ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_branch *br; ++ int wh_found, opq; ++ unsigned char wh_able; ++ const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG); ++ const unsigned char ignore_perm = !!au_ftest_lkup(args->flags, ++ IGNORE_PERM); ++ ++ wh_found = 0; ++ br = au_sbr(dentry->d_sb, bindex); ++ wh_able = !!au_br_whable(br->br_perm); ++ if (wh_able) ++ wh_found = au_wh_test(h_parent, wh_name, /*try_sio*/0); ++ h_dentry = ERR_PTR(wh_found); ++ if (!wh_found) ++ goto real_lookup; ++ if (unlikely(wh_found < 0)) ++ goto out; ++ ++ /* We found a whiteout */ ++ /* au_set_dbbot(dentry, bindex); */ ++ au_set_dbwh(dentry, bindex); ++ if (!allow_neg) ++ return NULL; /* success */ ++ ++real_lookup: ++ if (!ignore_perm) ++ h_dentry = vfsub_lkup_one(&dentry->d_name, h_parent); ++ else ++ h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent); ++ if (IS_ERR(h_dentry)) { ++ if (PTR_ERR(h_dentry) == -ENAMETOOLONG ++ && !allow_neg) ++ h_dentry = NULL; ++ goto out; ++ } ++ ++ h_inode = d_inode(h_dentry); ++ if (d_is_negative(h_dentry)) { ++ if (!allow_neg) ++ goto out_neg; ++ } else if (wh_found ++ || (args->type && args->type != (h_inode->i_mode & S_IFMT))) ++ goto out_neg; ++ ++ if (au_dbbot(dentry) <= bindex) ++ au_set_dbbot(dentry, bindex); ++ if (au_dbtop(dentry) < 0 || bindex < au_dbtop(dentry)) ++ au_set_dbtop(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, h_dentry); ++ ++ if (!d_is_dir(h_dentry) ++ || !wh_able ++ || (d_really_is_positive(dentry) && !d_is_dir(dentry))) ++ goto out; /* success */ ++ ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ opq = au_diropq_test(h_dentry); ++ inode_unlock(h_inode); ++ if (opq > 0) ++ au_set_dbdiropq(dentry, bindex); ++ else if (unlikely(opq < 0)) { ++ au_set_h_dptr(dentry, bindex, NULL); ++ h_dentry = ERR_PTR(opq); ++ } ++ goto out; ++ ++out_neg: ++ dput(h_dentry); ++ h_dentry = NULL; ++out: ++ return h_dentry; ++} ++ ++static int au_test_shwh(struct super_block *sb, const struct qstr *name) ++{ ++ if (unlikely(!au_opt_test(au_mntflags(sb), SHWH) ++ && !strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))) ++ return -EPERM; ++ return 0; ++} ++ ++/* ++ * returns the number of lower positive dentries, ++ * otherwise an error. ++ * can be called at unlinking with @type is zero. ++ */ ++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t btop, ++ unsigned int flags) ++{ ++ int npositive, err; ++ aufs_bindex_t bindex, btail, bdiropq; ++ unsigned char isdir, dirperm1; ++ struct qstr whname; ++ struct au_do_lookup_args args = { ++ .flags = flags ++ }; ++ const struct qstr *name = &dentry->d_name; ++ struct dentry *parent; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ err = au_test_shwh(sb, name); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_wh_name_alloc(&whname, name); ++ if (unlikely(err)) ++ goto out; ++ ++ isdir = !!d_is_dir(dentry); ++ dirperm1 = !!au_opt_test(au_mntflags(sb), DIRPERM1); ++ ++ npositive = 0; ++ parent = dget_parent(dentry); ++ btail = au_dbtaildir(parent); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ struct dentry *h_parent, *h_dentry; ++ struct inode *h_inode, *h_dir; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) { ++ if (d_is_positive(h_dentry)) ++ npositive++; ++ break; ++ } ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || !d_is_dir(h_parent)) ++ continue; ++ ++ h_dir = d_inode(h_parent); ++ inode_lock_nested(h_dir, AuLsc_I_PARENT); ++ h_dentry = au_do_lookup(h_parent, dentry, bindex, &whname, ++ &args); ++ inode_unlock(h_dir); ++ err = PTR_ERR(h_dentry); ++ if (IS_ERR(h_dentry)) ++ goto out_parent; ++ if (h_dentry) ++ au_fclr_lkup(args.flags, ALLOW_NEG); ++ if (dirperm1) ++ au_fset_lkup(args.flags, IGNORE_PERM); ++ ++ if (au_dbwh(dentry) == bindex) ++ break; ++ if (!h_dentry) ++ continue; ++ if (d_is_negative(h_dentry)) ++ continue; ++ h_inode = d_inode(h_dentry); ++ npositive++; ++ if (!args.type) ++ args.type = h_inode->i_mode & S_IFMT; ++ if (args.type != S_IFDIR) ++ break; ++ else if (isdir) { ++ /* the type of lower may be different */ ++ bdiropq = au_dbdiropq(dentry); ++ if (bdiropq >= 0 && bdiropq <= bindex) ++ break; ++ } ++ } ++ ++ if (npositive) { ++ AuLabel(positive); ++ au_update_dbtop(dentry); ++ } ++ err = npositive; ++ if (unlikely(!au_opt_test(au_mntflags(sb), UDBA_NONE) ++ && au_dbtop(dentry) < 0)) { ++ err = -EIO; ++ AuIOErr("both of real entry and whiteout found, %pd, err %d\n", ++ dentry, err); ++ } ++ ++out_parent: ++ dput(parent); ++ kfree(whname.name); ++out: ++ return err; ++} ++ ++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent) ++{ ++ struct dentry *dentry; ++ int wkq_err; ++ ++ if (!au_test_h_perm_sio(d_inode(parent), MAY_EXEC)) ++ dentry = vfsub_lkup_one(name, parent); ++ else { ++ struct vfsub_lkup_one_args args = { ++ .errp = &dentry, ++ .name = name, ++ .parent = parent ++ }; ++ ++ wkq_err = au_wkq_wait(vfsub_call_lkup_one, &args); ++ if (unlikely(wkq_err)) ++ dentry = ERR_PTR(wkq_err); ++ } ++ ++ return dentry; ++} ++ ++/* ++ * lookup @dentry on @bindex which should be negative. ++ */ ++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh) ++{ ++ int err; ++ struct dentry *parent, *h_parent, *h_dentry; ++ struct au_branch *br; ++ ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bindex); ++ br = au_sbr(dentry->d_sb, bindex); ++ if (wh) ++ h_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); ++ else ++ h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent); ++ err = PTR_ERR(h_dentry); ++ if (IS_ERR(h_dentry)) ++ goto out; ++ if (unlikely(d_is_positive(h_dentry))) { ++ err = -EIO; ++ AuIOErr("%pd should be negative on b%d.\n", h_dentry, bindex); ++ dput(h_dentry); ++ goto out; ++ } ++ ++ err = 0; ++ if (bindex < au_dbtop(dentry)) ++ au_set_dbtop(dentry, bindex); ++ if (au_dbbot(dentry) < bindex) ++ au_set_dbbot(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, h_dentry); ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* subset of struct inode */ ++struct au_iattr { ++ unsigned long i_ino; ++ /* unsigned int i_nlink; */ ++ kuid_t i_uid; ++ kgid_t i_gid; ++ u64 i_version; ++/* ++ loff_t i_size; ++ blkcnt_t i_blocks; ++*/ ++ umode_t i_mode; ++}; ++ ++static void au_iattr_save(struct au_iattr *ia, struct inode *h_inode) ++{ ++ ia->i_ino = h_inode->i_ino; ++ /* ia->i_nlink = h_inode->i_nlink; */ ++ ia->i_uid = h_inode->i_uid; ++ ia->i_gid = h_inode->i_gid; ++ ia->i_version = h_inode->i_version; ++/* ++ ia->i_size = h_inode->i_size; ++ ia->i_blocks = h_inode->i_blocks; ++*/ ++ ia->i_mode = (h_inode->i_mode & S_IFMT); ++} ++ ++static int au_iattr_test(struct au_iattr *ia, struct inode *h_inode) ++{ ++ return ia->i_ino != h_inode->i_ino ++ /* || ia->i_nlink != h_inode->i_nlink */ ++ || !uid_eq(ia->i_uid, h_inode->i_uid) ++ || !gid_eq(ia->i_gid, h_inode->i_gid) ++ || ia->i_version != h_inode->i_version ++/* ++ || ia->i_size != h_inode->i_size ++ || ia->i_blocks != h_inode->i_blocks ++*/ ++ || ia->i_mode != (h_inode->i_mode & S_IFMT); ++} ++ ++static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent, ++ struct au_branch *br) ++{ ++ int err; ++ struct au_iattr ia; ++ struct inode *h_inode; ++ struct dentry *h_d; ++ struct super_block *h_sb; ++ ++ err = 0; ++ memset(&ia, -1, sizeof(ia)); ++ h_sb = h_dentry->d_sb; ++ h_inode = NULL; ++ if (d_is_positive(h_dentry)) { ++ h_inode = d_inode(h_dentry); ++ au_iattr_save(&ia, h_inode); ++ } else if (au_test_nfs(h_sb) || au_test_fuse(h_sb)) ++ /* nfs d_revalidate may return 0 for negative dentry */ ++ /* fuse d_revalidate always return 0 for negative dentry */ ++ goto out; ++ ++ /* main purpose is namei.c:cached_lookup() and d_revalidate */ ++ h_d = vfsub_lkup_one(&h_dentry->d_name, h_parent); ++ err = PTR_ERR(h_d); ++ if (IS_ERR(h_d)) ++ goto out; ++ ++ err = 0; ++ if (unlikely(h_d != h_dentry ++ || d_inode(h_d) != h_inode ++ || (h_inode && au_iattr_test(&ia, h_inode)))) ++ err = au_busy_or_stale(); ++ dput(h_d); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, ++ struct dentry *h_parent, struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ if (udba == AuOpt_UDBA_REVAL ++ && !au_test_fs_remote(h_dentry->d_sb)) { ++ IMustLock(h_dir); ++ err = (d_inode(h_dentry->d_parent) != h_dir); ++ } else if (udba != AuOpt_UDBA_NONE) ++ err = au_h_verify_dentry(h_dentry, h_parent, br); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_refresh_hdentry(struct dentry *dentry, struct dentry *parent) ++{ ++ int err; ++ aufs_bindex_t new_bindex, bindex, bbot, bwh, bdiropq; ++ struct au_hdentry tmp, *p, *q; ++ struct au_dinfo *dinfo; ++ struct super_block *sb; ++ ++ DiMustWriteLock(dentry); ++ ++ sb = dentry->d_sb; ++ dinfo = au_di(dentry); ++ bbot = dinfo->di_bbot; ++ bwh = dinfo->di_bwh; ++ bdiropq = dinfo->di_bdiropq; ++ bindex = dinfo->di_btop; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, p++) { ++ if (!p->hd_dentry) ++ continue; ++ ++ new_bindex = au_br_index(sb, p->hd_id); ++ if (new_bindex == bindex) ++ continue; ++ ++ if (dinfo->di_bwh == bindex) ++ bwh = new_bindex; ++ if (dinfo->di_bdiropq == bindex) ++ bdiropq = new_bindex; ++ if (new_bindex < 0) { ++ au_hdput(p); ++ p->hd_dentry = NULL; ++ continue; ++ } ++ ++ /* swap two lower dentries, and loop again */ ++ q = au_hdentry(dinfo, new_bindex); ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hd_dentry) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ dinfo->di_bwh = -1; ++ if (bwh >= 0 && bwh <= au_sbbot(sb) && au_sbr_whable(sb, bwh)) ++ dinfo->di_bwh = bwh; ++ ++ dinfo->di_bdiropq = -1; ++ if (bdiropq >= 0 ++ && bdiropq <= au_sbbot(sb) ++ && au_sbr_whable(sb, bdiropq)) ++ dinfo->di_bdiropq = bdiropq; ++ ++ err = -EIO; ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ bbot = au_dbbot(parent); ++ bindex = 0; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, p++) ++ if (p->hd_dentry) { ++ dinfo->di_btop = bindex; ++ break; ++ } ++ ++ if (dinfo->di_btop >= 0) { ++ bindex = bbot; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex >= 0; bindex--, p--) ++ if (p->hd_dentry) { ++ dinfo->di_bbot = bindex; ++ err = 0; ++ break; ++ } ++ } ++ ++ return err; ++} ++ ++static void au_do_hide(struct dentry *dentry) ++{ ++ struct inode *inode; ++ ++ if (d_really_is_positive(dentry)) { ++ inode = d_inode(dentry); ++ if (!d_is_dir(dentry)) { ++ if (inode->i_nlink && !d_unhashed(dentry)) ++ drop_nlink(inode); ++ } else { ++ clear_nlink(inode); ++ /* stop next lookup */ ++ inode->i_flags |= S_DEAD; ++ } ++ smp_mb(); /* necessary? */ ++ } ++ d_drop(dentry); ++} ++ ++static int au_hide_children(struct dentry *parent) ++{ ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry *dentry; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, parent, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ /* in reverse order */ ++ for (i = dpages.ndpage - 1; i >= 0; i--) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = ndentry - 1; j >= 0; j--) { ++ dentry = dpage->dentries[j]; ++ if (dentry != parent) ++ au_do_hide(dentry); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static void au_hide(struct dentry *dentry) ++{ ++ int err; ++ ++ AuDbgDentry(dentry); ++ if (d_is_dir(dentry)) { ++ /* shrink_dcache_parent(dentry); */ ++ err = au_hide_children(dentry); ++ if (unlikely(err)) ++ AuIOErr("%pd, failed hiding children, ignored %d\n", ++ dentry, err); ++ } ++ au_do_hide(dentry); ++} ++ ++/* ++ * By adding a dirty branch, a cached dentry may be affected in various ways. ++ * ++ * a dirty branch is added ++ * - on the top of layers ++ * - in the middle of layers ++ * - to the bottom of layers ++ * ++ * on the added branch there exists ++ * - a whiteout ++ * - a diropq ++ * - a same named entry ++ * + exist ++ * * negative --> positive ++ * * positive --> positive ++ * - type is unchanged ++ * - type is changed ++ * + doesn't exist ++ * * negative --> negative ++ * * positive --> negative (rejected by au_br_del() for non-dir case) ++ * - none ++ */ ++static int au_refresh_by_dinfo(struct dentry *dentry, struct au_dinfo *dinfo, ++ struct au_dinfo *tmp) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct { ++ struct dentry *dentry; ++ struct inode *inode; ++ mode_t mode; ++ } orig_h, tmp_h = { ++ .dentry = NULL ++ }; ++ struct au_hdentry *hd; ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry; ++ ++ err = 0; ++ AuDebugOn(dinfo->di_btop < 0); ++ orig_h.mode = 0; ++ orig_h.dentry = au_hdentry(dinfo, dinfo->di_btop)->hd_dentry; ++ orig_h.inode = NULL; ++ if (d_is_positive(orig_h.dentry)) { ++ orig_h.inode = d_inode(orig_h.dentry); ++ orig_h.mode = orig_h.inode->i_mode & S_IFMT; ++ } ++ if (tmp->di_btop >= 0) { ++ tmp_h.dentry = au_hdentry(tmp, tmp->di_btop)->hd_dentry; ++ if (d_is_positive(tmp_h.dentry)) { ++ tmp_h.inode = d_inode(tmp_h.dentry); ++ tmp_h.mode = tmp_h.inode->i_mode & S_IFMT; ++ } ++ } ++ ++ inode = NULL; ++ if (d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (!orig_h.inode) { ++ AuDbg("nagative originally\n"); ++ if (inode) { ++ au_hide(dentry); ++ goto out; ++ } ++ AuDebugOn(inode); ++ AuDebugOn(dinfo->di_btop != dinfo->di_bbot); ++ AuDebugOn(dinfo->di_bdiropq != -1); ++ ++ if (!tmp_h.inode) { ++ AuDbg("negative --> negative\n"); ++ /* should have only one negative lower */ ++ if (tmp->di_btop >= 0 ++ && tmp->di_btop < dinfo->di_btop) { ++ AuDebugOn(tmp->di_btop != tmp->di_bbot); ++ AuDebugOn(dinfo->di_btop != dinfo->di_bbot); ++ au_set_h_dptr(dentry, dinfo->di_btop, NULL); ++ au_di_cp(dinfo, tmp); ++ hd = au_hdentry(tmp, tmp->di_btop); ++ au_set_h_dptr(dentry, tmp->di_btop, ++ dget(hd->hd_dentry)); ++ } ++ au_dbg_verify_dinode(dentry); ++ } else { ++ AuDbg("negative --> positive\n"); ++ /* ++ * similar to the behaviour of creating with bypassing ++ * aufs. ++ * unhash it in order to force an error in the ++ * succeeding create operation. ++ * we should not set S_DEAD here. ++ */ ++ d_drop(dentry); ++ /* au_di_swap(tmp, dinfo); */ ++ au_dbg_verify_dinode(dentry); ++ } ++ } else { ++ AuDbg("positive originally\n"); ++ /* inode may be NULL */ ++ AuDebugOn(inode && (inode->i_mode & S_IFMT) != orig_h.mode); ++ if (!tmp_h.inode) { ++ AuDbg("positive --> negative\n"); ++ /* or bypassing aufs */ ++ au_hide(dentry); ++ if (tmp->di_bwh >= 0 && tmp->di_bwh <= dinfo->di_btop) ++ dinfo->di_bwh = tmp->di_bwh; ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } else if (orig_h.mode == tmp_h.mode) { ++ AuDbg("positive --> positive, same type\n"); ++ if (!S_ISDIR(orig_h.mode) ++ && dinfo->di_btop > tmp->di_btop) { ++ /* ++ * similar to the behaviour of removing and ++ * creating. ++ */ ++ au_hide(dentry); ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } else { ++ /* fill empty slots */ ++ if (dinfo->di_btop > tmp->di_btop) ++ dinfo->di_btop = tmp->di_btop; ++ if (dinfo->di_bbot < tmp->di_bbot) ++ dinfo->di_bbot = tmp->di_bbot; ++ dinfo->di_bwh = tmp->di_bwh; ++ dinfo->di_bdiropq = tmp->di_bdiropq; ++ bbot = dinfo->di_bbot; ++ bindex = tmp->di_btop; ++ hd = au_hdentry(tmp, bindex); ++ for (; bindex <= bbot; bindex++, hd++) { ++ if (au_h_dptr(dentry, bindex)) ++ continue; ++ h_dentry = hd->hd_dentry; ++ if (!h_dentry) ++ continue; ++ AuDebugOn(d_is_negative(h_dentry)); ++ h_inode = d_inode(h_dentry); ++ AuDebugOn(orig_h.mode ++ != (h_inode->i_mode ++ & S_IFMT)); ++ au_set_h_dptr(dentry, bindex, ++ dget(h_dentry)); ++ } ++ if (inode) ++ err = au_refresh_hinode(inode, dentry); ++ au_dbg_verify_dinode(dentry); ++ } ++ } else { ++ AuDbg("positive --> positive, different type\n"); ++ /* similar to the behaviour of removing and creating */ ++ au_hide(dentry); ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } ++ } ++ ++out: ++ return err; ++} ++ ++void au_refresh_dop(struct dentry *dentry, int force_reval) ++{ ++ const struct dentry_operations *dop ++ = force_reval ? &aufs_dop : dentry->d_sb->s_d_op; ++ static const unsigned int mask ++ = DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE; ++ ++ BUILD_BUG_ON(sizeof(mask) != sizeof(dentry->d_flags)); ++ ++ if (dentry->d_op == dop) ++ return; ++ ++ AuDbg("%pd\n", dentry); ++ spin_lock(&dentry->d_lock); ++ if (dop == &aufs_dop) ++ dentry->d_flags |= mask; ++ else ++ dentry->d_flags &= ~mask; ++ dentry->d_op = dop; ++ spin_unlock(&dentry->d_lock); ++} ++ ++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent) ++{ ++ int err, ebrange; ++ unsigned int sigen; ++ struct au_dinfo *dinfo, *tmp; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ DiMustWriteLock(dentry); ++ AuDebugOn(IS_ROOT(dentry)); ++ AuDebugOn(d_really_is_negative(parent)); ++ ++ sb = dentry->d_sb; ++ sigen = au_sigen(sb); ++ err = au_digen_test(parent, sigen); ++ if (unlikely(err)) ++ goto out; ++ ++ dinfo = au_di(dentry); ++ err = au_di_realloc(dinfo, au_sbbot(sb) + 1); ++ if (unlikely(err)) ++ goto out; ++ ebrange = au_dbrange_test(dentry); ++ if (!ebrange) ++ ebrange = au_do_refresh_hdentry(dentry, parent); ++ ++ if (d_unhashed(dentry) || ebrange /* || dinfo->di_tmpfile */) { ++ AuDebugOn(au_dbtop(dentry) < 0 && au_dbbot(dentry) >= 0); ++ if (d_really_is_positive(dentry)) { ++ inode = d_inode(dentry); ++ err = au_refresh_hinode_self(inode); ++ } ++ au_dbg_verify_dinode(dentry); ++ if (!err) ++ goto out_dgen; /* success */ ++ goto out; ++ } ++ ++ /* temporary dinfo */ ++ AuDbgDentry(dentry); ++ err = -ENOMEM; ++ tmp = au_di_alloc(sb, AuLsc_DI_TMP); ++ if (unlikely(!tmp)) ++ goto out; ++ au_di_swap(tmp, dinfo); ++ /* returns the number of positive dentries */ ++ /* ++ * if current working dir is removed, it returns an error. ++ * but the dentry is legal. ++ */ ++ err = au_lkup_dentry(dentry, /*btop*/0, AuLkup_ALLOW_NEG); ++ AuDbgDentry(dentry); ++ au_di_swap(tmp, dinfo); ++ if (err == -ENOENT) ++ err = 0; ++ if (err >= 0) { ++ /* compare/refresh by dinfo */ ++ AuDbgDentry(dentry); ++ err = au_refresh_by_dinfo(dentry, dinfo, tmp); ++ au_dbg_verify_dinode(dentry); ++ AuTraceErr(err); ++ } ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ if (unlikely(err)) ++ goto out; ++ ++out_dgen: ++ au_update_digen(dentry); ++out: ++ if (unlikely(err && !(dentry->d_flags & DCACHE_NFSFS_RENAMED))) { ++ AuIOErr("failed refreshing %pd, %d\n", dentry, err); ++ AuDbgDentry(dentry); ++ } ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_do_h_d_reval(struct dentry *h_dentry, unsigned int flags, ++ struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err, valid; ++ ++ err = 0; ++ if (!(h_dentry->d_flags & DCACHE_OP_REVALIDATE)) ++ goto out; ++ ++ AuDbg("b%d\n", bindex); ++ /* ++ * gave up supporting LOOKUP_CREATE/OPEN for lower fs, ++ * due to whiteout and branch permission. ++ */ ++ flags &= ~(/*LOOKUP_PARENT |*/ LOOKUP_OPEN | LOOKUP_CREATE ++ | LOOKUP_FOLLOW | LOOKUP_EXCL); ++ /* it may return tri-state */ ++ valid = h_dentry->d_op->d_revalidate(h_dentry, flags); ++ ++ if (unlikely(valid < 0)) ++ err = valid; ++ else if (!valid) ++ err = -EINVAL; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* todo: remove this */ ++static int h_d_revalidate(struct dentry *dentry, struct inode *inode, ++ unsigned int flags, int do_udba) ++{ ++ int err; ++ umode_t mode, h_mode; ++ aufs_bindex_t bindex, btail, btop, ibs, ibe; ++ unsigned char plus, unhashed, is_root, h_plus, h_nfs, tmpfile; ++ struct inode *h_inode, *h_cached_inode; ++ struct dentry *h_dentry; ++ struct qstr *name, *h_name; ++ ++ err = 0; ++ plus = 0; ++ mode = 0; ++ ibs = -1; ++ ibe = -1; ++ unhashed = !!d_unhashed(dentry); ++ is_root = !!IS_ROOT(dentry); ++ name = &dentry->d_name; ++ tmpfile = au_di(dentry)->di_tmpfile; ++ ++ /* ++ * Theoretically, REVAL test should be unnecessary in case of ++ * {FS,I}NOTIFY. ++ * But {fs,i}notify doesn't fire some necessary events, ++ * IN_ATTRIB for atime/nlink/pageio ++ * Let's do REVAL test too. ++ */ ++ if (do_udba && inode) { ++ mode = (inode->i_mode & S_IFMT); ++ plus = (inode->i_nlink > 0); ++ ibs = au_ibtop(inode); ++ ibe = au_ibbot(inode); ++ } ++ ++ btop = au_dbtop(dentry); ++ btail = btop; ++ if (inode && S_ISDIR(inode->i_mode)) ++ btail = au_dbtaildir(dentry); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ ++ AuDbg("b%d, %pd\n", bindex, h_dentry); ++ h_nfs = !!au_test_nfs(h_dentry->d_sb); ++ spin_lock(&h_dentry->d_lock); ++ h_name = &h_dentry->d_name; ++ if (unlikely(do_udba ++ && !is_root ++ && ((!h_nfs ++ && (unhashed != !!d_unhashed(h_dentry) ++ || (!tmpfile ++ && !au_qstreq(name, h_name)) ++ )) ++ || (h_nfs ++ && !(flags & LOOKUP_OPEN) ++ && (h_dentry->d_flags ++ & DCACHE_NFSFS_RENAMED))) ++ )) { ++ int h_unhashed; ++ ++ h_unhashed = d_unhashed(h_dentry); ++ spin_unlock(&h_dentry->d_lock); ++ AuDbg("unhash 0x%x 0x%x, %pd %pd\n", ++ unhashed, h_unhashed, dentry, h_dentry); ++ goto err; ++ } ++ spin_unlock(&h_dentry->d_lock); ++ ++ err = au_do_h_d_reval(h_dentry, flags, dentry, bindex); ++ if (unlikely(err)) ++ /* do not goto err, to keep the errno */ ++ break; ++ ++ /* todo: plink too? */ ++ if (!do_udba) ++ continue; ++ ++ /* UDBA tests */ ++ if (unlikely(!!inode != d_is_positive(h_dentry))) ++ goto err; ++ ++ h_inode = NULL; ++ if (d_is_positive(h_dentry)) ++ h_inode = d_inode(h_dentry); ++ h_plus = plus; ++ h_mode = mode; ++ h_cached_inode = h_inode; ++ if (h_inode) { ++ h_mode = (h_inode->i_mode & S_IFMT); ++ h_plus = (h_inode->i_nlink > 0); ++ } ++ if (inode && ibs <= bindex && bindex <= ibe) ++ h_cached_inode = au_h_iptr(inode, bindex); ++ ++ if (!h_nfs) { ++ if (unlikely(plus != h_plus && !tmpfile)) ++ goto err; ++ } else { ++ if (unlikely(!(h_dentry->d_flags & DCACHE_NFSFS_RENAMED) ++ && !is_root ++ && !IS_ROOT(h_dentry) ++ && unhashed != d_unhashed(h_dentry))) ++ goto err; ++ } ++ if (unlikely(mode != h_mode ++ || h_cached_inode != h_inode)) ++ goto err; ++ continue; ++ ++err: ++ err = -EINVAL; ++ break; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* todo: consolidate with do_refresh() and au_reval_for_attr() */ ++static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *parent; ++ ++ if (!au_digen_test(dentry, sigen)) ++ return 0; ++ ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ AuDebugOn(au_digen_test(parent, sigen)); ++ au_dbg_verify_gen(parent, sigen); ++ err = au_refresh_dentry(dentry, parent); ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_reval_dpath(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *d, *parent; ++ ++ if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR)) ++ return simple_reval_dpath(dentry, sigen); ++ ++ /* slow loop, keep it simple and stupid */ ++ /* cf: au_cpup_dirs() */ ++ err = 0; ++ parent = NULL; ++ while (au_digen_test(dentry, sigen)) { ++ d = dentry; ++ while (1) { ++ dput(parent); ++ parent = dget_parent(d); ++ if (!au_digen_test(parent, sigen)) ++ break; ++ d = parent; ++ } ++ ++ if (d != dentry) ++ di_write_lock_child2(d); ++ ++ /* someone might update our dentry while we were sleeping */ ++ if (au_digen_test(d, sigen)) { ++ /* ++ * todo: consolidate with simple_reval_dpath(), ++ * do_refresh() and au_reval_for_attr(). ++ */ ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(d, parent); ++ di_read_unlock(parent, AuLock_IR); ++ } ++ ++ if (d != dentry) ++ di_write_unlock(d); ++ dput(parent); ++ if (unlikely(err)) ++ break; ++ } ++ ++ return err; ++} ++ ++/* ++ * if valid returns 1, otherwise 0. ++ */ ++static int aufs_d_revalidate(struct dentry *dentry, unsigned int flags) ++{ ++ int valid, err; ++ unsigned int sigen; ++ unsigned char do_udba; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ /* todo: support rcu-walk? */ ++ if (flags & LOOKUP_RCU) ++ return -ECHILD; ++ ++ valid = 0; ++ if (unlikely(!au_di(dentry))) ++ goto out; ++ ++ valid = 1; ++ sb = dentry->d_sb; ++ /* ++ * todo: very ugly ++ * i_mutex of parent dir may be held, ++ * but we should not return 'invalid' due to busy. ++ */ ++ err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW | AuLock_NOPLM); ++ if (unlikely(err)) { ++ valid = err; ++ AuTraceErr(err); ++ goto out; ++ } ++ inode = NULL; ++ if (d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (unlikely(inode && au_is_bad_inode(inode))) { ++ err = -EINVAL; ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ if (unlikely(au_dbrange_test(dentry))) { ++ err = -EINVAL; ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ ++ sigen = au_sigen(sb); ++ if (au_digen_test(dentry, sigen)) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_dpath(dentry, sigen); ++ if (unlikely(err)) { ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ } ++ di_downgrade_lock(dentry, AuLock_IR); ++ ++ err = -EINVAL; ++ if (!(flags & (LOOKUP_OPEN | LOOKUP_EMPTY)) ++ && inode ++ && !(inode->i_state && I_LINKABLE) ++ && (IS_DEADDIR(inode) || !inode->i_nlink)) { ++ AuTraceErr(err); ++ goto out_inval; ++ } ++ ++ do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE); ++ if (do_udba && inode) { ++ aufs_bindex_t btop = au_ibtop(inode); ++ struct inode *h_inode; ++ ++ if (btop >= 0) { ++ h_inode = au_h_iptr(inode, btop); ++ if (h_inode && au_test_higen(inode, h_inode)) { ++ AuTraceErr(err); ++ goto out_inval; ++ } ++ } ++ } ++ ++ err = h_d_revalidate(dentry, inode, flags, do_udba); ++ if (unlikely(!err && do_udba && au_dbtop(dentry) < 0)) { ++ err = -EIO; ++ AuDbg("both of real entry and whiteout found, %p, err %d\n", ++ dentry, err); ++ } ++ goto out_inval; ++ ++out_dgrade: ++ di_downgrade_lock(dentry, AuLock_IR); ++out_inval: ++ aufs_read_unlock(dentry, AuLock_IR); ++ AuTraceErr(err); ++ valid = !err; ++out: ++ if (!valid) { ++ AuDbg("%pd invalid, %d\n", dentry, valid); ++ d_drop(dentry); ++ } ++ return valid; ++} ++ ++static void aufs_d_release(struct dentry *dentry) ++{ ++ if (au_di(dentry)) { ++ au_di_fin(dentry); ++ au_hn_di_reinit(dentry); ++ } ++} ++ ++const struct dentry_operations aufs_dop = { ++ .d_revalidate = aufs_d_revalidate, ++ .d_weak_revalidate = aufs_d_revalidate, ++ .d_release = aufs_d_release ++}; ++ ++/* aufs_dop without d_revalidate */ ++const struct dentry_operations aufs_dop_noreval = { ++ .d_release = aufs_d_release ++}; +diff --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h +new file mode 100644 +index 0000000..bdc1af6 +--- /dev/null ++++ b/fs/aufs/dentry.h +@@ -0,0 +1,239 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#ifndef __AUFS_DENTRY_H__ ++#define __AUFS_DENTRY_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "rwsem.h" ++ ++struct au_hdentry { ++ struct dentry *hd_dentry; ++ aufs_bindex_t hd_id; ++}; ++ ++struct au_dinfo { ++ atomic_t di_generation; ++ ++ struct au_rwsem di_rwsem; ++ aufs_bindex_t di_btop, di_bbot, di_bwh, di_bdiropq; ++ unsigned char di_tmpfile; /* to allow the different name */ ++ struct au_hdentry *di_hdentry; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* flags for au_lkup_dentry() */ ++#define AuLkup_ALLOW_NEG 1 ++#define AuLkup_IGNORE_PERM (1 << 1) ++#define au_ftest_lkup(flags, name) ((flags) & AuLkup_##name) ++#define au_fset_lkup(flags, name) \ ++ do { (flags) |= AuLkup_##name; } while (0) ++#define au_fclr_lkup(flags, name) \ ++ do { (flags) &= ~AuLkup_##name; } while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dentry.c */ ++extern const struct dentry_operations aufs_dop, aufs_dop_noreval; ++struct au_branch; ++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent); ++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, ++ struct dentry *h_parent, struct au_branch *br); ++ ++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t btop, ++ unsigned int flags); ++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh); ++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent); ++int au_reval_dpath(struct dentry *dentry, unsigned int sigen); ++void au_refresh_dop(struct dentry *dentry, int force_reval); ++ ++/* dinfo.c */ ++void au_di_init_once(void *_di); ++struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc); ++void au_di_free(struct au_dinfo *dinfo); ++void au_di_swap(struct au_dinfo *a, struct au_dinfo *b); ++void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src); ++int au_di_init(struct dentry *dentry); ++void au_di_fin(struct dentry *dentry); ++int au_di_realloc(struct au_dinfo *dinfo, int nbr); ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc); ++void di_read_unlock(struct dentry *d, int flags); ++void di_downgrade_lock(struct dentry *d, int flags); ++void di_write_lock(struct dentry *d, unsigned int lsc); ++void di_write_unlock(struct dentry *d); ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex); ++struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex); ++aufs_bindex_t au_dbtail(struct dentry *dentry); ++aufs_bindex_t au_dbtaildir(struct dentry *dentry); ++ ++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++int au_digen_test(struct dentry *dentry, unsigned int sigen); ++int au_dbrange_test(struct dentry *dentry); ++void au_update_digen(struct dentry *dentry); ++void au_update_dbrange(struct dentry *dentry, int do_put_zero); ++void au_update_dbtop(struct dentry *dentry); ++void au_update_dbbot(struct dentry *dentry); ++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_dinfo *au_di(struct dentry *dentry) ++{ ++ return dentry->d_fsdata; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for dinfo */ ++enum { ++ AuLsc_DI_CHILD, /* child first */ ++ AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hnotify */ ++ AuLsc_DI_CHILD3, /* copyup dirs */ ++ AuLsc_DI_PARENT, ++ AuLsc_DI_PARENT2, ++ AuLsc_DI_PARENT3, ++ AuLsc_DI_TMP /* temp for replacing dinfo */ ++}; ++ ++/* ++ * di_read_lock_child, di_write_lock_child, ++ * di_read_lock_child2, di_write_lock_child2, ++ * di_read_lock_child3, di_write_lock_child3, ++ * di_read_lock_parent, di_write_lock_parent, ++ * di_read_lock_parent2, di_write_lock_parent2, ++ * di_read_lock_parent3, di_write_lock_parent3, ++ */ ++#define AuReadLockFunc(name, lsc) \ ++static inline void di_read_lock_##name(struct dentry *d, int flags) \ ++{ di_read_lock(d, flags, AuLsc_DI_##lsc); } ++ ++#define AuWriteLockFunc(name, lsc) \ ++static inline void di_write_lock_##name(struct dentry *d) \ ++{ di_write_lock(d, AuLsc_DI_##lsc); } ++ ++#define AuRWLockFuncs(name, lsc) \ ++ AuReadLockFunc(name, lsc) \ ++ AuWriteLockFunc(name, lsc) ++ ++AuRWLockFuncs(child, CHILD); ++AuRWLockFuncs(child2, CHILD2); ++AuRWLockFuncs(child3, CHILD3); ++AuRWLockFuncs(parent, PARENT); ++AuRWLockFuncs(parent2, PARENT2); ++AuRWLockFuncs(parent3, PARENT3); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++#define DiMustNoWaiters(d) AuRwMustNoWaiters(&au_di(d)->di_rwsem) ++#define DiMustAnyLock(d) AuRwMustAnyLock(&au_di(d)->di_rwsem) ++#define DiMustWriteLock(d) AuRwMustWriteLock(&au_di(d)->di_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: memory barrier? */ ++static inline unsigned int au_digen(struct dentry *d) ++{ ++ return atomic_read(&au_di(d)->di_generation); ++} ++ ++static inline void au_h_dentry_init(struct au_hdentry *hdentry) ++{ ++ hdentry->hd_dentry = NULL; ++} ++ ++static inline struct au_hdentry *au_hdentry(struct au_dinfo *di, ++ aufs_bindex_t bindex) ++{ ++ return di->di_hdentry + bindex; ++} ++ ++static inline void au_hdput(struct au_hdentry *hd) ++{ ++ if (hd) ++ dput(hd->hd_dentry); ++} ++ ++static inline aufs_bindex_t au_dbtop(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_btop; ++} ++ ++static inline aufs_bindex_t au_dbbot(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bbot; ++} ++ ++static inline aufs_bindex_t au_dbwh(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bwh; ++} ++ ++static inline aufs_bindex_t au_dbdiropq(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bdiropq; ++} ++ ++/* todo: hard/soft set? */ ++static inline void au_set_dbtop(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_btop = bindex; ++} ++ ++static inline void au_set_dbbot(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bbot = bindex; ++} ++ ++static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ /* dbwh can be outside of btop - bbot range */ ++ au_di(dentry)->di_bwh = bindex; ++} ++ ++static inline void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bdiropq = bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_HNOTIFY ++static inline void au_digen_dec(struct dentry *d) ++{ ++ atomic_dec(&au_di(d)->di_generation); ++} ++ ++static inline void au_hn_di_reinit(struct dentry *dentry) ++{ ++ dentry->d_fsdata = NULL; ++} ++#else ++AuStubVoid(au_hn_di_reinit, struct dentry *dentry __maybe_unused) ++#endif /* CONFIG_AUFS_HNOTIFY */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DENTRY_H__ */ +diff --git a/fs/aufs/dinfo.c b/fs/aufs/dinfo.c +new file mode 100644 +index 0000000..43b5509 +--- /dev/null ++++ b/fs/aufs/dinfo.c +@@ -0,0 +1,539 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * dentry private data ++ */ ++ ++#include "aufs.h" ++ ++void au_di_init_once(void *_dinfo) ++{ ++ struct au_dinfo *dinfo = _dinfo; ++ ++ au_rw_init(&dinfo->di_rwsem); ++} ++ ++struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc) ++{ ++ struct au_dinfo *dinfo; ++ int nbr, i; ++ ++ dinfo = au_cache_alloc_dinfo(); ++ if (unlikely(!dinfo)) ++ goto out; ++ ++ nbr = au_sbbot(sb) + 1; ++ if (nbr <= 0) ++ nbr = 1; ++ dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS); ++ if (dinfo->di_hdentry) { ++ au_rw_write_lock_nested(&dinfo->di_rwsem, lsc); ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ dinfo->di_bwh = -1; ++ dinfo->di_bdiropq = -1; ++ dinfo->di_tmpfile = 0; ++ for (i = 0; i < nbr; i++) ++ dinfo->di_hdentry[i].hd_id = -1; ++ goto out; ++ } ++ ++ au_cache_free_dinfo(dinfo); ++ dinfo = NULL; ++ ++out: ++ return dinfo; ++} ++ ++void au_di_free(struct au_dinfo *dinfo) ++{ ++ struct au_hdentry *p; ++ aufs_bindex_t bbot, bindex; ++ ++ /* dentry may not be revalidated */ ++ bindex = dinfo->di_btop; ++ if (bindex >= 0) { ++ bbot = dinfo->di_bbot; ++ p = au_hdentry(dinfo, bindex); ++ while (bindex++ <= bbot) ++ au_hdput(p++); ++ } ++ kfree(dinfo->di_hdentry); ++ au_cache_free_dinfo(dinfo); ++} ++ ++void au_di_swap(struct au_dinfo *a, struct au_dinfo *b) ++{ ++ struct au_hdentry *p; ++ aufs_bindex_t bi; ++ ++ AuRwMustWriteLock(&a->di_rwsem); ++ AuRwMustWriteLock(&b->di_rwsem); ++ ++#define DiSwap(v, name) \ ++ do { \ ++ v = a->di_##name; \ ++ a->di_##name = b->di_##name; \ ++ b->di_##name = v; \ ++ } while (0) ++ ++ DiSwap(p, hdentry); ++ DiSwap(bi, btop); ++ DiSwap(bi, bbot); ++ DiSwap(bi, bwh); ++ DiSwap(bi, bdiropq); ++ /* smp_mb(); */ ++ ++#undef DiSwap ++} ++ ++void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src) ++{ ++ AuRwMustWriteLock(&dst->di_rwsem); ++ AuRwMustWriteLock(&src->di_rwsem); ++ ++ dst->di_btop = src->di_btop; ++ dst->di_bbot = src->di_bbot; ++ dst->di_bwh = src->di_bwh; ++ dst->di_bdiropq = src->di_bdiropq; ++ /* smp_mb(); */ ++} ++ ++int au_di_init(struct dentry *dentry) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_dinfo *dinfo; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ dinfo = au_di_alloc(sb, AuLsc_DI_CHILD); ++ if (dinfo) { ++ atomic_set(&dinfo->di_generation, au_sigen(sb)); ++ /* smp_mb(); */ /* atomic_set */ ++ dentry->d_fsdata = dinfo; ++ } else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++void au_di_fin(struct dentry *dentry) ++{ ++ struct au_dinfo *dinfo; ++ ++ dinfo = au_di(dentry); ++ AuRwDestroy(&dinfo->di_rwsem); ++ au_di_free(dinfo); ++} ++ ++int au_di_realloc(struct au_dinfo *dinfo, int nbr) ++{ ++ int err, sz; ++ struct au_hdentry *hdp; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*hdp) * (dinfo->di_bbot + 1); ++ if (!sz) ++ sz = sizeof(*hdp); ++ hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS); ++ if (hdp) { ++ dinfo->di_hdentry = hdp; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void do_ii_write_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_write_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_write_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_write_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_write_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_write_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_write_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static void do_ii_read_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_read_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_read_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_read_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_read_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_read_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_read_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc) ++{ ++ struct inode *inode; ++ ++ au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc); ++ if (d_really_is_positive(d)) { ++ inode = d_inode(d); ++ if (au_ftest_lock(flags, IW)) ++ do_ii_write_lock(inode, lsc); ++ else if (au_ftest_lock(flags, IR)) ++ do_ii_read_lock(inode, lsc); ++ } ++} ++ ++void di_read_unlock(struct dentry *d, int flags) ++{ ++ struct inode *inode; ++ ++ if (d_really_is_positive(d)) { ++ inode = d_inode(d); ++ if (au_ftest_lock(flags, IW)) { ++ au_dbg_verify_dinode(d); ++ ii_write_unlock(inode); ++ } else if (au_ftest_lock(flags, IR)) { ++ au_dbg_verify_dinode(d); ++ ii_read_unlock(inode); ++ } ++ } ++ au_rw_read_unlock(&au_di(d)->di_rwsem); ++} ++ ++void di_downgrade_lock(struct dentry *d, int flags) ++{ ++ if (d_really_is_positive(d) && au_ftest_lock(flags, IR)) ++ ii_downgrade_lock(d_inode(d)); ++ au_rw_dgrade_lock(&au_di(d)->di_rwsem); ++} ++ ++void di_write_lock(struct dentry *d, unsigned int lsc) ++{ ++ au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc); ++ if (d_really_is_positive(d)) ++ do_ii_write_lock(d_inode(d), lsc); ++} ++ ++void di_write_unlock(struct dentry *d) ++{ ++ au_dbg_verify_dinode(d); ++ if (d_really_is_positive(d)) ++ ii_write_unlock(d_inode(d)); ++ au_rw_write_unlock(&au_di(d)->di_rwsem); ++} ++ ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ AuDebugOn(d1 == d2 ++ || d_inode(d1) == d_inode(d2) ++ || d1->d_sb != d2->d_sb); ++ ++ if (isdir && au_test_subdir(d1, d2)) { ++ di_write_lock_child(d1); ++ di_write_lock_child2(d2); ++ } else { ++ /* there should be no races */ ++ di_write_lock_child(d2); ++ di_write_lock_child2(d1); ++ } ++} ++ ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ AuDebugOn(d1 == d2 ++ || d_inode(d1) == d_inode(d2) ++ || d1->d_sb != d2->d_sb); ++ ++ if (isdir && au_test_subdir(d1, d2)) { ++ di_write_lock_parent(d1); ++ di_write_lock_parent2(d2); ++ } else { ++ /* there should be no races */ ++ di_write_lock_parent(d2); ++ di_write_lock_parent2(d1); ++ } ++} ++ ++void di_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ di_write_unlock(d1); ++ if (d_inode(d1) == d_inode(d2)) ++ au_rw_write_unlock(&au_di(d2)->di_rwsem); ++ else ++ di_write_unlock(d2); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ struct dentry *d; ++ ++ DiMustAnyLock(dentry); ++ ++ if (au_dbtop(dentry) < 0 || bindex < au_dbtop(dentry)) ++ return NULL; ++ AuDebugOn(bindex < 0); ++ d = au_hdentry(au_di(dentry), bindex)->hd_dentry; ++ AuDebugOn(d && au_dcount(d) <= 0); ++ return d; ++} ++ ++/* ++ * extended version of au_h_dptr(). ++ * returns a hashed and positive (or linkable) h_dentry in bindex, NULL, or ++ * error. ++ */ ++struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ struct dentry *h_dentry; ++ struct inode *inode, *h_inode; ++ ++ AuDebugOn(d_really_is_negative(dentry)); ++ ++ h_dentry = NULL; ++ if (au_dbtop(dentry) <= bindex ++ && bindex <= au_dbbot(dentry)) ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && !au_d_linkable(h_dentry)) { ++ dget(h_dentry); ++ goto out; /* success */ ++ } ++ ++ inode = d_inode(dentry); ++ AuDebugOn(bindex < au_ibtop(inode)); ++ AuDebugOn(au_ibbot(inode) < bindex); ++ h_inode = au_h_iptr(inode, bindex); ++ h_dentry = d_find_alias(h_inode); ++ if (h_dentry) { ++ if (!IS_ERR(h_dentry)) { ++ if (!au_d_linkable(h_dentry)) ++ goto out; /* success */ ++ dput(h_dentry); ++ } else ++ goto out; ++ } ++ ++ if (au_opt_test(au_mntflags(dentry->d_sb), PLINK)) { ++ h_dentry = au_plink_lkup(inode, bindex); ++ AuDebugOn(!h_dentry); ++ if (!IS_ERR(h_dentry)) { ++ if (!au_d_hashed_positive(h_dentry)) ++ goto out; /* success */ ++ dput(h_dentry); ++ h_dentry = NULL; ++ } ++ } ++ ++out: ++ AuDbgDentry(h_dentry); ++ return h_dentry; ++} ++ ++aufs_bindex_t au_dbtail(struct dentry *dentry) ++{ ++ aufs_bindex_t bbot, bwh; ++ ++ bbot = au_dbbot(dentry); ++ if (0 <= bbot) { ++ bwh = au_dbwh(dentry); ++ if (!bwh) ++ return bwh; ++ if (0 < bwh && bwh < bbot) ++ return bwh - 1; ++ } ++ return bbot; ++} ++ ++aufs_bindex_t au_dbtaildir(struct dentry *dentry) ++{ ++ aufs_bindex_t bbot, bopq; ++ ++ bbot = au_dbtail(dentry); ++ if (0 <= bbot) { ++ bopq = au_dbdiropq(dentry); ++ if (0 <= bopq && bopq < bbot) ++ bbot = bopq; ++ } ++ return bbot; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry) ++{ ++ struct au_dinfo *dinfo; ++ struct au_hdentry *hd; ++ struct au_branch *br; ++ ++ DiMustWriteLock(dentry); ++ ++ dinfo = au_di(dentry); ++ hd = au_hdentry(dinfo, bindex); ++ au_hdput(hd); ++ hd->hd_dentry = h_dentry; ++ if (h_dentry) { ++ br = au_sbr(dentry->d_sb, bindex); ++ hd->hd_id = br->br_id; ++ } ++} ++ ++int au_dbrange_test(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t btop, bbot; ++ ++ err = 0; ++ btop = au_dbtop(dentry); ++ bbot = au_dbbot(dentry); ++ if (btop >= 0) ++ AuDebugOn(bbot < 0 && btop > bbot); ++ else { ++ err = -EIO; ++ AuDebugOn(bbot >= 0); ++ } ++ ++ return err; ++} ++ ++int au_digen_test(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(au_digen(dentry) != sigen ++ || au_iigen_test(d_inode(dentry), sigen))) ++ err = -EIO; ++ ++ return err; ++} ++ ++void au_update_digen(struct dentry *dentry) ++{ ++ atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb)); ++ /* smp_mb(); */ /* atomic_set */ ++} ++ ++void au_update_dbrange(struct dentry *dentry, int do_put_zero) ++{ ++ struct au_dinfo *dinfo; ++ struct dentry *h_d; ++ struct au_hdentry *hdp; ++ aufs_bindex_t bindex, bbot; ++ ++ DiMustWriteLock(dentry); ++ ++ dinfo = au_di(dentry); ++ if (!dinfo || dinfo->di_btop < 0) ++ return; ++ ++ if (do_put_zero) { ++ bbot = dinfo->di_bbot; ++ bindex = dinfo->di_btop; ++ hdp = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, hdp++) { ++ h_d = hdp->hd_dentry; ++ if (h_d && d_is_negative(h_d)) ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++ } ++ ++ dinfo->di_btop = 0; ++ hdp = au_hdentry(dinfo, dinfo->di_btop); ++ for (; dinfo->di_btop <= dinfo->di_bbot; dinfo->di_btop++, hdp++) ++ if (hdp->hd_dentry) ++ break; ++ if (dinfo->di_btop > dinfo->di_bbot) { ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ return; ++ } ++ ++ hdp = au_hdentry(dinfo, dinfo->di_bbot); ++ for (; dinfo->di_bbot >= 0; dinfo->di_bbot--, hdp--) ++ if (hdp->hd_dentry) ++ break; ++ AuDebugOn(dinfo->di_btop > dinfo->di_bbot || dinfo->di_bbot < 0); ++} ++ ++void au_update_dbtop(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct dentry *h_dentry; ++ ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ if (d_is_positive(h_dentry)) { ++ au_set_dbtop(dentry, bindex); ++ return; ++ } ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++} ++ ++void au_update_dbbot(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, btop; ++ struct dentry *h_dentry; ++ ++ btop = au_dbtop(dentry); ++ for (bindex = au_dbbot(dentry); bindex >= btop; bindex--) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ if (d_is_positive(h_dentry)) { ++ au_set_dbbot(dentry, bindex); ++ return; ++ } ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++} ++ ++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry) ++{ ++ aufs_bindex_t bindex, bbot; ++ ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) ++ if (au_h_dptr(dentry, bindex) == h_dentry) ++ return bindex; ++ return -1; ++} +diff --git a/fs/aufs/dir.c b/fs/aufs/dir.c +new file mode 100644 +index 0000000..27bef0b +--- /dev/null ++++ b/fs/aufs/dir.c +@@ -0,0 +1,743 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * directory operations ++ */ ++ ++#include ++#include "aufs.h" ++ ++void au_add_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ unsigned int nlink; ++ ++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ ++ nlink = dir->i_nlink; ++ nlink += h_dir->i_nlink - 2; ++ if (h_dir->i_nlink < 2) ++ nlink += 2; ++ smp_mb(); /* for i_nlink */ ++ /* 0 can happen in revaliding */ ++ set_nlink(dir, nlink); ++} ++ ++void au_sub_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ unsigned int nlink; ++ ++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ ++ nlink = dir->i_nlink; ++ nlink -= h_dir->i_nlink - 2; ++ if (h_dir->i_nlink < 2) ++ nlink -= 2; ++ smp_mb(); /* for i_nlink */ ++ /* nlink == 0 means the branch-fs is broken */ ++ set_nlink(dir, nlink); ++} ++ ++loff_t au_dir_size(struct file *file, struct dentry *dentry) ++{ ++ loff_t sz; ++ aufs_bindex_t bindex, bbot; ++ struct file *h_file; ++ struct dentry *h_dentry; ++ ++ sz = 0; ++ if (file) { ++ AuDebugOn(!d_is_dir(file->f_path.dentry)); ++ ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); ++ bindex <= bbot && sz < KMALLOC_MAX_SIZE; ++ bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (h_file && file_inode(h_file)) ++ sz += vfsub_f_size_read(h_file); ++ } ++ } else { ++ AuDebugOn(!dentry); ++ AuDebugOn(!d_is_dir(dentry)); ++ ++ bbot = au_dbtaildir(dentry); ++ for (bindex = au_dbtop(dentry); ++ bindex <= bbot && sz < KMALLOC_MAX_SIZE; ++ bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) ++ sz += i_size_read(d_inode(h_dentry)); ++ } ++ } ++ if (sz < KMALLOC_MAX_SIZE) ++ sz = roundup_pow_of_two(sz); ++ if (sz > KMALLOC_MAX_SIZE) ++ sz = KMALLOC_MAX_SIZE; ++ else if (sz < NAME_MAX) { ++ BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX); ++ sz = AUFS_RDBLK_DEF; ++ } ++ return sz; ++} ++ ++struct au_dir_ts_arg { ++ struct dentry *dentry; ++ aufs_bindex_t brid; ++}; ++ ++static void au_do_dir_ts(void *arg) ++{ ++ struct au_dir_ts_arg *a = arg; ++ struct au_dtime dt; ++ struct path h_path; ++ struct inode *dir, *h_dir; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_hinode *hdir; ++ int err; ++ aufs_bindex_t btop, bindex; ++ ++ sb = a->dentry->d_sb; ++ if (d_really_is_negative(a->dentry)) ++ goto out; ++ /* no dir->i_mutex lock */ ++ aufs_read_lock(a->dentry, AuLock_DW); /* noflush */ ++ ++ dir = d_inode(a->dentry); ++ btop = au_ibtop(dir); ++ bindex = au_br_index(sb, a->brid); ++ if (bindex < btop) ++ goto out_unlock; ++ ++ br = au_sbr(sb, bindex); ++ h_path.dentry = au_h_dptr(a->dentry, bindex); ++ if (!h_path.dentry) ++ goto out_unlock; ++ h_path.mnt = au_br_mnt(br); ++ au_dtime_store(&dt, a->dentry, &h_path); ++ ++ br = au_sbr(sb, btop); ++ if (!au_br_writable(br->br_perm)) ++ goto out_unlock; ++ h_path.dentry = au_h_dptr(a->dentry, btop); ++ h_path.mnt = au_br_mnt(br); ++ err = vfsub_mnt_want_write(h_path.mnt); ++ if (err) ++ goto out_unlock; ++ hdir = au_hi(dir, btop); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ h_dir = au_h_iptr(dir, btop); ++ if (h_dir->i_nlink ++ && timespec_compare(&h_dir->i_mtime, &dt.dt_mtime) < 0) { ++ dt.dt_h_path = h_path; ++ au_dtime_revert(&dt); ++ } ++ au_hn_inode_unlock(hdir); ++ vfsub_mnt_drop_write(h_path.mnt); ++ au_cpup_attr_timesizes(dir); ++ ++out_unlock: ++ aufs_read_unlock(a->dentry, AuLock_DW); ++out: ++ dput(a->dentry); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ kfree(arg); ++} ++ ++void au_dir_ts(struct inode *dir, aufs_bindex_t bindex) ++{ ++ int perm, wkq_err; ++ aufs_bindex_t btop; ++ struct au_dir_ts_arg *arg; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ IMustLock(dir); ++ ++ dentry = d_find_any_alias(dir); ++ AuDebugOn(!dentry); ++ sb = dentry->d_sb; ++ btop = au_ibtop(dir); ++ if (btop == bindex) { ++ au_cpup_attr_timesizes(dir); ++ goto out; ++ } ++ ++ perm = au_sbr_perm(sb, btop); ++ if (!au_br_writable(perm)) ++ goto out; ++ ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (!arg) ++ goto out; ++ ++ arg->dentry = dget(dentry); /* will be dput-ted by au_do_dir_ts() */ ++ arg->brid = au_sbr_id(sb, bindex); ++ wkq_err = au_wkq_nowait(au_do_dir_ts, arg, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ pr_err("wkq %d\n", wkq_err); ++ dput(dentry); ++ kfree(arg); ++ } ++ ++out: ++ dput(dentry); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int reopen_dir(struct file *file) ++{ ++ int err; ++ unsigned int flags; ++ aufs_bindex_t bindex, btail, btop; ++ struct dentry *dentry, *h_dentry; ++ struct file *h_file; ++ ++ /* open all lower dirs */ ++ dentry = file->f_path.dentry; ++ btop = au_dbtop(dentry); ++ for (bindex = au_fbtop(file); bindex < btop; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbtop(file, btop); ++ ++ btail = au_dbtaildir(dentry); ++ for (bindex = au_fbbot_dir(file); btail < bindex; bindex--) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbbot_dir(file, btail); ++ ++ flags = vfsub_file_flags(file); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ h_file = au_hf_dir(file, bindex); ++ if (h_file) ++ continue; ++ ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; /* close all? */ ++ au_set_h_fptr(file, bindex, h_file); ++ } ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static int do_open_dir(struct file *file, int flags, struct file *h_file) ++{ ++ int err; ++ aufs_bindex_t bindex, btail; ++ struct dentry *dentry, *h_dentry; ++ struct vfsmount *mnt; ++ ++ FiMustWriteLock(file); ++ AuDebugOn(h_file); ++ ++ err = 0; ++ mnt = file->f_path.mnt; ++ dentry = file->f_path.dentry; ++ file->f_version = d_inode(dentry)->i_version; ++ bindex = au_dbtop(dentry); ++ au_set_fbtop(file, bindex); ++ btail = au_dbtaildir(dentry); ++ au_set_fbbot_dir(file, btail); ++ for (; !err && bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ ++ err = vfsub_test_mntns(mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ break; ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ break; ++ } ++ au_set_h_fptr(file, bindex, h_file); ++ } ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ if (!err) ++ return 0; /* success */ ++ ++ /* close all */ ++ for (bindex = au_fbtop(file); bindex <= btail; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbtop(file, -1); ++ au_set_fbbot_dir(file, -1); ++ ++ return err; ++} ++ ++static int aufs_open_dir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_fidir *fidir; ++ ++ err = -ENOMEM; ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ fidir = au_fidir_alloc(sb); ++ if (fidir) { ++ struct au_do_open_args args = { ++ .open = do_open_dir, ++ .fidir = fidir ++ }; ++ err = au_do_open(file, &args); ++ if (unlikely(err)) ++ kfree(fidir); ++ } ++ si_read_unlock(sb); ++ return err; ++} ++ ++static int aufs_release_dir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ struct au_vdir *vdir_cache; ++ struct au_finfo *finfo; ++ struct au_fidir *fidir; ++ aufs_bindex_t bindex, bbot; ++ ++ finfo = au_fi(file); ++ fidir = finfo->fi_hdir; ++ if (fidir) { ++ au_sphl_del(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ vdir_cache = fidir->fd_vdir_cache; /* lock-free */ ++ if (vdir_cache) ++ au_vdir_free(vdir_cache); ++ ++ bindex = finfo->fi_btop; ++ if (bindex >= 0) { ++ /* ++ * calls fput() instead of filp_close(), ++ * since no dnotify or lock for the lower file. ++ */ ++ bbot = fidir->fd_bbot; ++ for (; bindex <= bbot; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ } ++ kfree(fidir); ++ finfo->fi_hdir = NULL; ++ } ++ au_finfo_fin(file); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_flush_dir(struct file *file, fl_owner_t id) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct file *h_file; ++ ++ err = 0; ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); !err && bindex <= bbot; bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (h_file) ++ err = vfsub_flush(h_file, id); ++ } ++ return err; ++} ++ ++static int aufs_flush_dir(struct file *file, fl_owner_t id) ++{ ++ return au_do_flush(file, id, au_do_flush_dir); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_fsync_dir_no_file(struct dentry *dentry, int datasync) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); !err && bindex <= bbot; bindex++) { ++ struct path h_path; ++ ++ if (au_test_ro(sb, bindex, inode)) ++ continue; ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ if (!h_path.dentry) ++ continue; ++ ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_fsync(NULL, &h_path, datasync); ++ } ++ ++ return err; ++} ++ ++static int au_do_fsync_dir(struct file *file, int datasync) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct file *h_file; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1); ++ if (unlikely(err)) ++ goto out; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); !err && bindex <= bbot; bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (!h_file || au_test_ro(sb, bindex, inode)) ++ continue; ++ ++ err = vfsub_fsync(h_file, &h_file->f_path, datasync); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * @file may be NULL ++ */ ++static int aufs_fsync_dir(struct file *file, loff_t start, loff_t end, ++ int datasync) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ inode_lock(inode); ++ sb = dentry->d_sb; ++ si_noflush_read_lock(sb); ++ if (file) ++ err = au_do_fsync_dir(file, datasync); ++ else { ++ di_write_lock_child(dentry); ++ err = au_do_fsync_dir_no_file(dentry, datasync); ++ } ++ au_cpup_attr_timesizes(inode); ++ di_write_unlock(dentry); ++ if (file) ++ fi_write_unlock(file); ++ ++ si_read_unlock(sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_iterate_shared(struct file *file, struct dir_context *ctx) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode, *h_inode; ++ struct super_block *sb; ++ ++ AuDbg("%pD, ctx{%pf, %llu}\n", file, ctx->actor, ctx->pos); ++ ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1); ++ if (unlikely(err)) ++ goto out; ++ err = au_alive_dir(dentry); ++ if (!err) ++ err = au_vdir_init(file); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ if (!au_test_nfsd()) { ++ err = au_vdir_fill_de(file, ctx); ++ fsstack_copy_attr_atime(inode, h_inode); ++ } else { ++ /* ++ * nfsd filldir may call lookup_one_len(), vfs_getattr(), ++ * encode_fh() and others. ++ */ ++ atomic_inc(&h_inode->i_count); ++ di_read_unlock(dentry, AuLock_IR); ++ si_read_unlock(sb); ++ err = au_vdir_fill_de(file, ctx); ++ fsstack_copy_attr_atime(inode, h_inode); ++ fi_write_unlock(file); ++ iput(h_inode); ++ ++ AuTraceErr(err); ++ return err; ++ } ++ ++out_unlock: ++ di_read_unlock(dentry, AuLock_IR); ++ fi_write_unlock(file); ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuTestEmpty_WHONLY 1 ++#define AuTestEmpty_CALLED (1 << 1) ++#define AuTestEmpty_SHWH (1 << 2) ++#define au_ftest_testempty(flags, name) ((flags) & AuTestEmpty_##name) ++#define au_fset_testempty(flags, name) \ ++ do { (flags) |= AuTestEmpty_##name; } while (0) ++#define au_fclr_testempty(flags, name) \ ++ do { (flags) &= ~AuTestEmpty_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_SHWH ++#undef AuTestEmpty_SHWH ++#define AuTestEmpty_SHWH 0 ++#endif ++ ++struct test_empty_arg { ++ struct dir_context ctx; ++ struct au_nhash *whlist; ++ unsigned int flags; ++ int err; ++ aufs_bindex_t bindex; ++}; ++ ++static int test_empty_cb(struct dir_context *ctx, const char *__name, ++ int namelen, loff_t offset __maybe_unused, u64 ino, ++ unsigned int d_type) ++{ ++ struct test_empty_arg *arg = container_of(ctx, struct test_empty_arg, ++ ctx); ++ char *name = (void *)__name; ++ ++ arg->err = 0; ++ au_fset_testempty(arg->flags, CALLED); ++ /* smp_mb(); */ ++ if (name[0] == '.' ++ && (namelen == 1 || (name[1] == '.' && namelen == 2))) ++ goto out; /* success */ ++ ++ if (namelen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ if (au_ftest_testempty(arg->flags, WHONLY) ++ && !au_nhash_test_known_wh(arg->whlist, name, namelen)) ++ arg->err = -ENOTEMPTY; ++ goto out; ++ } ++ ++ name += AUFS_WH_PFX_LEN; ++ namelen -= AUFS_WH_PFX_LEN; ++ if (!au_nhash_test_known_wh(arg->whlist, name, namelen)) ++ arg->err = au_nhash_append_wh ++ (arg->whlist, name, namelen, ino, d_type, arg->bindex, ++ au_ftest_testempty(arg->flags, SHWH)); ++ ++out: ++ /* smp_mb(); */ ++ AuTraceErr(arg->err); ++ return arg->err; ++} ++ ++static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err; ++ struct file *h_file; ++ ++ h_file = au_h_open(dentry, arg->bindex, ++ O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_LARGEFILE, ++ /*file*/NULL, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = 0; ++ if (!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE) ++ && !file_inode(h_file)->i_nlink) ++ goto out_put; ++ ++ do { ++ arg->err = 0; ++ au_fclr_testempty(arg->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(h_file, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && au_ftest_testempty(arg->flags, CALLED)); ++ ++out_put: ++ fput(h_file); ++ au_sbr_put(dentry->d_sb, arg->bindex); ++out: ++ return err; ++} ++ ++struct do_test_empty_args { ++ int *errp; ++ struct dentry *dentry; ++ struct test_empty_arg *arg; ++}; ++ ++static void call_do_test_empty(void *args) ++{ ++ struct do_test_empty_args *a = args; ++ *a->errp = do_test_empty(a->dentry, a->arg); ++} ++ ++static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err, wkq_err; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ h_dentry = au_h_dptr(dentry, arg->bindex); ++ h_inode = d_inode(h_dentry); ++ /* todo: i_mode changes anytime? */ ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ err = au_test_h_perm_sio(h_inode, MAY_EXEC | MAY_READ); ++ inode_unlock(h_inode); ++ if (!err) ++ err = do_test_empty(dentry, arg); ++ else { ++ struct do_test_empty_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .arg = arg ++ }; ++ unsigned int flags = arg->flags; ++ ++ wkq_err = au_wkq_wait(call_do_test_empty, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ arg->flags = flags; ++ } ++ ++ return err; ++} ++ ++int au_test_empty_lower(struct dentry *dentry) ++{ ++ int err; ++ unsigned int rdhash; ++ aufs_bindex_t bindex, btop, btail; ++ struct au_nhash whlist; ++ struct test_empty_arg arg = { ++ .ctx = { ++ .actor = test_empty_cb ++ } ++ }; ++ int (*test_empty)(struct dentry *dentry, struct test_empty_arg *arg); ++ ++ SiMustAnyLock(dentry->d_sb); ++ ++ rdhash = au_sbi(dentry->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry)); ++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ ++ arg.flags = 0; ++ arg.whlist = &whlist; ++ btop = au_dbtop(dentry); ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) ++ au_fset_testempty(arg.flags, SHWH); ++ test_empty = do_test_empty; ++ if (au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1)) ++ test_empty = sio_test_empty; ++ arg.bindex = btop; ++ err = test_empty(dentry, &arg); ++ if (unlikely(err)) ++ goto out_whlist; ++ ++ au_fset_testempty(arg.flags, WHONLY); ++ btail = au_dbtaildir(dentry); ++ for (bindex = btop + 1; !err && bindex <= btail; bindex++) { ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) { ++ arg.bindex = bindex; ++ err = test_empty(dentry, &arg); ++ } ++ } ++ ++out_whlist: ++ au_nhash_wh_free(&whlist); ++out: ++ return err; ++} ++ ++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist) ++{ ++ int err; ++ struct test_empty_arg arg = { ++ .ctx = { ++ .actor = test_empty_cb ++ } ++ }; ++ aufs_bindex_t bindex, btail; ++ ++ err = 0; ++ arg.whlist = whlist; ++ arg.flags = AuTestEmpty_WHONLY; ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) ++ au_fset_testempty(arg.flags, SHWH); ++ btail = au_dbtaildir(dentry); ++ for (bindex = au_dbtop(dentry); !err && bindex <= btail; bindex++) { ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) { ++ arg.bindex = bindex; ++ err = sio_test_empty(dentry, &arg); ++ } ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++const struct file_operations aufs_dir_fop = { ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++ .read = generic_read_dir, ++ .iterate_shared = aufs_iterate_shared, ++ .unlocked_ioctl = aufs_ioctl_dir, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = aufs_compat_ioctl_dir, ++#endif ++ .open = aufs_open_dir, ++ .release = aufs_release_dir, ++ .flush = aufs_flush_dir, ++ .fsync = aufs_fsync_dir ++}; +diff --git a/fs/aufs/dir.h b/fs/aufs/dir.h +new file mode 100644 +index 0000000..b0a79d7 +--- /dev/null ++++ b/fs/aufs/dir.h +@@ -0,0 +1,118 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * directory operations ++ */ ++ ++#ifndef __AUFS_DIR_H__ ++#define __AUFS_DIR_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* need to be faster and smaller */ ++ ++struct au_nhash { ++ unsigned int nh_num; ++ struct hlist_head *nh_head; ++}; ++ ++struct au_vdir_destr { ++ unsigned char len; ++ unsigned char name[0]; ++} __packed; ++ ++struct au_vdir_dehstr { ++ struct hlist_node hash; ++ struct au_vdir_destr *str; ++} ____cacheline_aligned_in_smp; ++ ++struct au_vdir_de { ++ ino_t de_ino; ++ unsigned char de_type; ++ /* caution: packed */ ++ struct au_vdir_destr de_str; ++} __packed; ++ ++struct au_vdir_wh { ++ struct hlist_node wh_hash; ++#ifdef CONFIG_AUFS_SHWH ++ ino_t wh_ino; ++ aufs_bindex_t wh_bindex; ++ unsigned char wh_type; ++#else ++ aufs_bindex_t wh_bindex; ++#endif ++ /* caution: packed */ ++ struct au_vdir_destr wh_str; ++} __packed; ++ ++union au_vdir_deblk_p { ++ unsigned char *deblk; ++ struct au_vdir_de *de; ++}; ++ ++struct au_vdir { ++ unsigned char **vd_deblk; ++ unsigned long vd_nblk; ++ struct { ++ unsigned long ul; ++ union au_vdir_deblk_p p; ++ } vd_last; ++ ++ unsigned long vd_version; ++ unsigned int vd_deblk_sz; ++ unsigned long vd_jiffy; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dir.c */ ++extern const struct file_operations aufs_dir_fop; ++void au_add_nlink(struct inode *dir, struct inode *h_dir); ++void au_sub_nlink(struct inode *dir, struct inode *h_dir); ++loff_t au_dir_size(struct file *file, struct dentry *dentry); ++void au_dir_ts(struct inode *dir, aufs_bindex_t bsrc); ++int au_test_empty_lower(struct dentry *dentry); ++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist); ++ ++/* vdir.c */ ++unsigned int au_rdhash_est(loff_t sz); ++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp); ++void au_nhash_wh_free(struct au_nhash *whlist); ++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, ++ int limit); ++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen); ++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, ++ unsigned int d_type, aufs_bindex_t bindex, ++ unsigned char shwh); ++void au_vdir_free(struct au_vdir *vdir); ++int au_vdir_init(struct file *file); ++int au_vdir_fill_de(struct file *file, struct dir_context *ctx); ++ ++/* ioctl.c */ ++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg); ++ ++#ifdef CONFIG_AUFS_RDU ++/* rdu.c */ ++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg); ++#endif ++#else ++AuStub(long, au_rdu_ioctl, return -EINVAL, struct file *file, ++ unsigned int cmd, unsigned long arg) ++#ifdef CONFIG_COMPAT ++AuStub(long, au_rdu_compat_ioctl, return -EINVAL, struct file *file, ++ unsigned int cmd, unsigned long arg) ++#endif ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DIR_H__ */ +diff --git a/fs/aufs/dynop.c b/fs/aufs/dynop.c +new file mode 100644 +index 0000000..dfb3a71 +--- /dev/null ++++ b/fs/aufs/dynop.c +@@ -0,0 +1,356 @@ ++/* ++ * Copyright (C) 2010-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * dynamically customizable operations for regular files ++ */ ++ ++#include "aufs.h" ++ ++#define DyPrSym(key) AuDbgSym(key->dk_op.dy_hop) ++ ++/* ++ * How large will these lists be? ++ * Usually just a few elements, 20-30 at most for each, I guess. ++ */ ++static struct au_splhead dynop[AuDyLast]; ++ ++static struct au_dykey *dy_gfind_get(struct au_splhead *spl, const void *h_op) ++{ ++ struct au_dykey *key, *tmp; ++ struct list_head *head; ++ ++ key = NULL; ++ head = &spl->head; ++ rcu_read_lock(); ++ list_for_each_entry_rcu(tmp, head, dk_list) ++ if (tmp->dk_op.dy_hop == h_op) { ++ key = tmp; ++ kref_get(&key->dk_kref); ++ break; ++ } ++ rcu_read_unlock(); ++ ++ return key; ++} ++ ++static struct au_dykey *dy_bradd(struct au_branch *br, struct au_dykey *key) ++{ ++ struct au_dykey **k, *found; ++ const void *h_op = key->dk_op.dy_hop; ++ int i; ++ ++ found = NULL; ++ k = br->br_dykey; ++ for (i = 0; i < AuBrDynOp; i++) ++ if (k[i]) { ++ if (k[i]->dk_op.dy_hop == h_op) { ++ found = k[i]; ++ break; ++ } ++ } else ++ break; ++ if (!found) { ++ spin_lock(&br->br_dykey_lock); ++ for (; i < AuBrDynOp; i++) ++ if (k[i]) { ++ if (k[i]->dk_op.dy_hop == h_op) { ++ found = k[i]; ++ break; ++ } ++ } else { ++ k[i] = key; ++ break; ++ } ++ spin_unlock(&br->br_dykey_lock); ++ BUG_ON(i == AuBrDynOp); /* expand the array */ ++ } ++ ++ return found; ++} ++ ++/* kref_get() if @key is already added */ ++static struct au_dykey *dy_gadd(struct au_splhead *spl, struct au_dykey *key) ++{ ++ struct au_dykey *tmp, *found; ++ struct list_head *head; ++ const void *h_op = key->dk_op.dy_hop; ++ ++ found = NULL; ++ head = &spl->head; ++ spin_lock(&spl->spin); ++ list_for_each_entry(tmp, head, dk_list) ++ if (tmp->dk_op.dy_hop == h_op) { ++ kref_get(&tmp->dk_kref); ++ found = tmp; ++ break; ++ } ++ if (!found) ++ list_add_rcu(&key->dk_list, head); ++ spin_unlock(&spl->spin); ++ ++ if (!found) ++ DyPrSym(key); ++ return found; ++} ++ ++static void dy_free_rcu(struct rcu_head *rcu) ++{ ++ struct au_dykey *key; ++ ++ key = container_of(rcu, struct au_dykey, dk_rcu); ++ DyPrSym(key); ++ kfree(key); ++} ++ ++static void dy_free(struct kref *kref) ++{ ++ struct au_dykey *key; ++ struct au_splhead *spl; ++ ++ key = container_of(kref, struct au_dykey, dk_kref); ++ spl = dynop + key->dk_op.dy_type; ++ au_spl_del_rcu(&key->dk_list, spl); ++ call_rcu(&key->dk_rcu, dy_free_rcu); ++} ++ ++void au_dy_put(struct au_dykey *key) ++{ ++ kref_put(&key->dk_kref, dy_free); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define DyDbgSize(cnt, op) AuDebugOn(cnt != sizeof(op)/sizeof(void *)) ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define DyDbgDeclare(cnt) unsigned int cnt = 0 ++#define DyDbgInc(cnt) do { cnt++; } while (0) ++#else ++#define DyDbgDeclare(cnt) do {} while (0) ++#define DyDbgInc(cnt) do {} while (0) ++#endif ++ ++#define DySet(func, dst, src, h_op, h_sb) do { \ ++ DyDbgInc(cnt); \ ++ if (h_op->func) { \ ++ if (src.func) \ ++ dst.func = src.func; \ ++ else \ ++ AuDbg("%s %s\n", au_sbtype(h_sb), #func); \ ++ } \ ++} while (0) ++ ++#define DySetForce(func, dst, src) do { \ ++ AuDebugOn(!src.func); \ ++ DyDbgInc(cnt); \ ++ dst.func = src.func; \ ++} while (0) ++ ++#define DySetAop(func) \ ++ DySet(func, dyaop->da_op, aufs_aop, h_aop, h_sb) ++#define DySetAopForce(func) \ ++ DySetForce(func, dyaop->da_op, aufs_aop) ++ ++static void dy_aop(struct au_dykey *key, const void *h_op, ++ struct super_block *h_sb __maybe_unused) ++{ ++ struct au_dyaop *dyaop = (void *)key; ++ const struct address_space_operations *h_aop = h_op; ++ DyDbgDeclare(cnt); ++ ++ AuDbg("%s\n", au_sbtype(h_sb)); ++ ++ DySetAop(writepage); ++ DySetAopForce(readpage); /* force */ ++ DySetAop(writepages); ++ DySetAop(set_page_dirty); ++ DySetAop(readpages); ++ DySetAop(write_begin); ++ DySetAop(write_end); ++ DySetAop(bmap); ++ DySetAop(invalidatepage); ++ DySetAop(releasepage); ++ DySetAop(freepage); ++ /* this one will be changed according to an aufs mount option */ ++ DySetAop(direct_IO); ++ DySetAop(migratepage); ++ DySetAop(launder_page); ++ DySetAop(is_partially_uptodate); ++ DySetAop(is_dirty_writeback); ++ DySetAop(error_remove_page); ++ DySetAop(swap_activate); ++ DySetAop(swap_deactivate); ++ ++ DyDbgSize(cnt, *h_aop); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void dy_bug(struct kref *kref) ++{ ++ BUG(); ++} ++ ++static struct au_dykey *dy_get(struct au_dynop *op, struct au_branch *br) ++{ ++ struct au_dykey *key, *old; ++ struct au_splhead *spl; ++ struct op { ++ unsigned int sz; ++ void (*set)(struct au_dykey *key, const void *h_op, ++ struct super_block *h_sb __maybe_unused); ++ }; ++ static const struct op a[] = { ++ [AuDy_AOP] = { ++ .sz = sizeof(struct au_dyaop), ++ .set = dy_aop ++ } ++ }; ++ const struct op *p; ++ ++ spl = dynop + op->dy_type; ++ key = dy_gfind_get(spl, op->dy_hop); ++ if (key) ++ goto out_add; /* success */ ++ ++ p = a + op->dy_type; ++ key = kzalloc(p->sz, GFP_NOFS); ++ if (unlikely(!key)) { ++ key = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ key->dk_op.dy_hop = op->dy_hop; ++ kref_init(&key->dk_kref); ++ p->set(key, op->dy_hop, au_br_sb(br)); ++ old = dy_gadd(spl, key); ++ if (old) { ++ kfree(key); ++ key = old; ++ } ++ ++out_add: ++ old = dy_bradd(br, key); ++ if (old) ++ /* its ref-count should never be zero here */ ++ kref_put(&key->dk_kref, dy_bug); ++out: ++ return key; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * Aufs prohibits O_DIRECT by defaut even if the branch supports it. ++ * This behaviour is necessary to return an error from open(O_DIRECT) instead ++ * of the succeeding I/O. The dio mount option enables O_DIRECT and makes ++ * open(O_DIRECT) always succeed, but the succeeding I/O may return an error. ++ * See the aufs manual in detail. ++ */ ++static void dy_adx(struct au_dyaop *dyaop, int do_dx) ++{ ++ if (!do_dx) ++ dyaop->da_op.direct_IO = NULL; ++ else ++ dyaop->da_op.direct_IO = aufs_aop.direct_IO; ++} ++ ++static struct au_dyaop *dy_aget(struct au_branch *br, ++ const struct address_space_operations *h_aop, ++ int do_dx) ++{ ++ struct au_dyaop *dyaop; ++ struct au_dynop op; ++ ++ op.dy_type = AuDy_AOP; ++ op.dy_haop = h_aop; ++ dyaop = (void *)dy_get(&op, br); ++ if (IS_ERR(dyaop)) ++ goto out; ++ dy_adx(dyaop, do_dx); ++ ++out: ++ return dyaop; ++} ++ ++int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode) ++{ ++ int err, do_dx; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_dyaop *dyaop; ++ ++ AuDebugOn(!S_ISREG(h_inode->i_mode)); ++ IiMustWriteLock(inode); ++ ++ sb = inode->i_sb; ++ br = au_sbr(sb, bindex); ++ do_dx = !!au_opt_test(au_mntflags(sb), DIO); ++ dyaop = dy_aget(br, h_inode->i_mapping->a_ops, do_dx); ++ err = PTR_ERR(dyaop); ++ if (IS_ERR(dyaop)) ++ /* unnecessary to call dy_fput() */ ++ goto out; ++ ++ err = 0; ++ inode->i_mapping->a_ops = &dyaop->da_op; ++ ++out: ++ return err; ++} ++ ++/* ++ * Is it safe to replace a_ops during the inode/file is in operation? ++ * Yes, I hope so. ++ */ ++int au_dy_irefresh(struct inode *inode) ++{ ++ int err; ++ aufs_bindex_t btop; ++ struct inode *h_inode; ++ ++ err = 0; ++ if (S_ISREG(inode->i_mode)) { ++ btop = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, btop); ++ err = au_dy_iaop(inode, btop, h_inode); ++ } ++ return err; ++} ++ ++void au_dy_arefresh(int do_dx) ++{ ++ struct au_splhead *spl; ++ struct list_head *head; ++ struct au_dykey *key; ++ ++ spl = dynop + AuDy_AOP; ++ head = &spl->head; ++ spin_lock(&spl->spin); ++ list_for_each_entry(key, head, dk_list) ++ dy_adx((void *)key, do_dx); ++ spin_unlock(&spl->spin); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void __init au_dy_init(void) ++{ ++ int i; ++ ++ /* make sure that 'struct au_dykey *' can be any type */ ++ BUILD_BUG_ON(offsetof(struct au_dyaop, da_key)); ++ ++ for (i = 0; i < AuDyLast; i++) ++ au_spl_init(dynop + i); ++} ++ ++void au_dy_fin(void) ++{ ++ int i; ++ ++ for (i = 0; i < AuDyLast; i++) ++ WARN_ON(!list_empty(&dynop[i].head)); ++} +diff --git a/fs/aufs/dynop.h b/fs/aufs/dynop.h +new file mode 100644 +index 0000000..8680bfc +--- /dev/null ++++ b/fs/aufs/dynop.h +@@ -0,0 +1,61 @@ ++/* ++ * Copyright (C) 2010-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * dynamically customizable operations (for regular files only) ++ */ ++ ++#ifndef __AUFS_DYNOP_H__ ++#define __AUFS_DYNOP_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++enum {AuDy_AOP, AuDyLast}; ++ ++struct au_dynop { ++ int dy_type; ++ union { ++ const void *dy_hop; ++ const struct address_space_operations *dy_haop; ++ }; ++}; ++ ++struct au_dykey { ++ union { ++ struct list_head dk_list; ++ struct rcu_head dk_rcu; ++ }; ++ struct au_dynop dk_op; ++ ++ /* ++ * during I am in the branch local array, kref is gotten. when the ++ * branch is removed, kref is put. ++ */ ++ struct kref dk_kref; ++}; ++ ++/* stop unioning since their sizes are very different from each other */ ++struct au_dyaop { ++ struct au_dykey da_key; ++ struct address_space_operations da_op; /* not const */ ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dynop.c */ ++struct au_branch; ++void au_dy_put(struct au_dykey *key); ++int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode); ++int au_dy_irefresh(struct inode *inode); ++void au_dy_arefresh(int do_dio); ++ ++void __init au_dy_init(void); ++void au_dy_fin(void); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DYNOP_H__ */ +diff --git a/fs/aufs/export.c b/fs/aufs/export.c +new file mode 100644 +index 0000000..98a7036 +--- /dev/null ++++ b/fs/aufs/export.c +@@ -0,0 +1,824 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * export via nfs ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../fs/mount.h" ++#include "aufs.h" ++ ++union conv { ++#ifdef CONFIG_AUFS_INO_T_64 ++ __u32 a[2]; ++#else ++ __u32 a[1]; ++#endif ++ ino_t ino; ++}; ++ ++static ino_t decode_ino(__u32 *a) ++{ ++ union conv u; ++ ++ BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a)); ++ u.a[0] = a[0]; ++#ifdef CONFIG_AUFS_INO_T_64 ++ u.a[1] = a[1]; ++#endif ++ return u.ino; ++} ++ ++static void encode_ino(__u32 *a, ino_t ino) ++{ ++ union conv u; ++ ++ u.ino = ino; ++ a[0] = u.a[0]; ++#ifdef CONFIG_AUFS_INO_T_64 ++ a[1] = u.a[1]; ++#endif ++} ++ ++/* NFS file handle */ ++enum { ++ Fh_br_id, ++ Fh_sigen, ++#ifdef CONFIG_AUFS_INO_T_64 ++ /* support 64bit inode number */ ++ Fh_ino1, ++ Fh_ino2, ++ Fh_dir_ino1, ++ Fh_dir_ino2, ++#else ++ Fh_ino1, ++ Fh_dir_ino1, ++#endif ++ Fh_igen, ++ Fh_h_type, ++ Fh_tail, ++ ++ Fh_ino = Fh_ino1, ++ Fh_dir_ino = Fh_dir_ino1 ++}; ++ ++static int au_test_anon(struct dentry *dentry) ++{ ++ /* note: read d_flags without d_lock */ ++ return !!(dentry->d_flags & DCACHE_DISCONNECTED); ++} ++ ++int au_test_nfsd(void) ++{ ++ int ret; ++ struct task_struct *tsk = current; ++ char comm[sizeof(tsk->comm)]; ++ ++ ret = 0; ++ if (tsk->flags & PF_KTHREAD) { ++ get_task_comm(comm, tsk); ++ ret = !strcmp(comm, "nfsd"); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* inode generation external table */ ++ ++void au_xigen_inc(struct inode *inode) ++{ ++ loff_t pos; ++ ssize_t sz; ++ __u32 igen; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ sb = inode->i_sb; ++ AuDebugOn(!au_opt_test(au_mntflags(sb), XINO)); ++ ++ sbinfo = au_sbi(sb); ++ pos = inode->i_ino; ++ pos *= sizeof(igen); ++ igen = inode->i_generation + 1; ++ sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xigen, &igen, ++ sizeof(igen), &pos); ++ if (sz == sizeof(igen)) ++ return; /* success */ ++ ++ if (unlikely(sz >= 0)) ++ AuIOErr("xigen error (%zd)\n", sz); ++} ++ ++int au_xigen_new(struct inode *inode) ++{ ++ int err; ++ loff_t pos; ++ ssize_t sz; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ err = 0; ++ /* todo: dirty, at mount time */ ++ if (inode->i_ino == AUFS_ROOT_INO) ++ goto out; ++ sb = inode->i_sb; ++ SiMustAnyLock(sb); ++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) ++ goto out; ++ ++ err = -EFBIG; ++ pos = inode->i_ino; ++ if (unlikely(au_loff_max / sizeof(inode->i_generation) - 1 < pos)) { ++ AuIOErr1("too large i%lld\n", pos); ++ goto out; ++ } ++ pos *= sizeof(inode->i_generation); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ file = sbinfo->si_xigen; ++ BUG_ON(!file); ++ ++ if (vfsub_f_size_read(file) ++ < pos + sizeof(inode->i_generation)) { ++ inode->i_generation = atomic_inc_return(&sbinfo->si_xigen_next); ++ sz = xino_fwrite(sbinfo->si_xwrite, file, &inode->i_generation, ++ sizeof(inode->i_generation), &pos); ++ } else ++ sz = xino_fread(sbinfo->si_xread, file, &inode->i_generation, ++ sizeof(inode->i_generation), &pos); ++ if (sz == sizeof(inode->i_generation)) ++ goto out; /* success */ ++ ++ err = sz; ++ if (unlikely(sz >= 0)) { ++ err = -EIO; ++ AuIOErr("xigen error (%zd)\n", sz); ++ } ++ ++out: ++ return err; ++} ++ ++int au_xigen_set(struct super_block *sb, struct file *base) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ file = au_xino_create2(base, sbinfo->si_xigen); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ err = 0; ++ if (sbinfo->si_xigen) ++ fput(sbinfo->si_xigen); ++ sbinfo->si_xigen = file; ++ ++out: ++ return err; ++} ++ ++void au_xigen_clr(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo->si_xigen) { ++ fput(sbinfo->si_xigen); ++ sbinfo->si_xigen = NULL; ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino, ++ ino_t dir_ino) ++{ ++ struct dentry *dentry, *d; ++ struct inode *inode; ++ unsigned int sigen; ++ ++ dentry = NULL; ++ inode = ilookup(sb, ino); ++ if (!inode) ++ goto out; ++ ++ dentry = ERR_PTR(-ESTALE); ++ sigen = au_sigen(sb); ++ if (unlikely(au_is_bad_inode(inode) ++ || IS_DEADDIR(inode) ++ || sigen != au_iigen(inode, NULL))) ++ goto out_iput; ++ ++ dentry = NULL; ++ if (!dir_ino || S_ISDIR(inode->i_mode)) ++ dentry = d_find_alias(inode); ++ else { ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) { ++ spin_lock(&d->d_lock); ++ if (!au_test_anon(d) ++ && d_inode(d->d_parent)->i_ino == dir_ino) { ++ dentry = dget_dlock(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ spin_unlock(&d->d_lock); ++ } ++ spin_unlock(&inode->i_lock); ++ } ++ if (unlikely(dentry && au_digen_test(dentry, sigen))) { ++ /* need to refresh */ ++ dput(dentry); ++ dentry = NULL; ++ } ++ ++out_iput: ++ iput(inode); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: dirty? */ ++/* if exportfs_decode_fh() passed vfsmount*, we could be happy */ ++ ++struct au_compare_mnt_args { ++ /* input */ ++ struct super_block *sb; ++ ++ /* output */ ++ struct vfsmount *mnt; ++}; ++ ++static int au_compare_mnt(struct vfsmount *mnt, void *arg) ++{ ++ struct au_compare_mnt_args *a = arg; ++ ++ if (mnt->mnt_sb != a->sb) ++ return 0; ++ a->mnt = mntget(mnt); ++ return 1; ++} ++ ++static struct vfsmount *au_mnt_get(struct super_block *sb) ++{ ++ int err; ++ struct path root; ++ struct au_compare_mnt_args args = { ++ .sb = sb ++ }; ++ ++ get_fs_root(current->fs, &root); ++ rcu_read_lock(); ++ err = iterate_mounts(au_compare_mnt, &args, root.mnt); ++ rcu_read_unlock(); ++ path_put(&root); ++ AuDebugOn(!err); ++ AuDebugOn(!args.mnt); ++ return args.mnt; ++} ++ ++struct au_nfsd_si_lock { ++ unsigned int sigen; ++ aufs_bindex_t bindex, br_id; ++ unsigned char force_lock; ++}; ++ ++static int si_nfsd_read_lock(struct super_block *sb, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ ++ si_read_lock(sb, AuLock_FLUSH); ++ ++ /* branch id may be wrapped around */ ++ err = 0; ++ bindex = au_br_index(sb, nsi_lock->br_id); ++ if (bindex >= 0 && nsi_lock->sigen + AUFS_BRANCH_MAX > au_sigen(sb)) ++ goto out; /* success */ ++ ++ err = -ESTALE; ++ bindex = -1; ++ if (!nsi_lock->force_lock) ++ si_read_unlock(sb); ++ ++out: ++ nsi_lock->bindex = bindex; ++ return err; ++} ++ ++struct find_name_by_ino { ++ struct dir_context ctx; ++ int called, found; ++ ino_t ino; ++ char *name; ++ int namelen; ++}; ++ ++static int ++find_name_by_ino(struct dir_context *ctx, const char *name, int namelen, ++ loff_t offset, u64 ino, unsigned int d_type) ++{ ++ struct find_name_by_ino *a = container_of(ctx, struct find_name_by_ino, ++ ctx); ++ ++ a->called++; ++ if (a->ino != ino) ++ return 0; ++ ++ memcpy(a->name, name, namelen); ++ a->namelen = namelen; ++ a->found = 1; ++ return 1; ++} ++ ++static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry, *parent; ++ struct file *file; ++ struct inode *dir; ++ struct find_name_by_ino arg = { ++ .ctx = { ++ .actor = find_name_by_ino ++ } ++ }; ++ int err; ++ ++ parent = path->dentry; ++ if (nsi_lock) ++ si_read_unlock(parent->d_sb); ++ file = vfsub_dentry_open(path, au_dir_roflags); ++ dentry = (void *)file; ++ if (IS_ERR(file)) ++ goto out; ++ ++ dentry = ERR_PTR(-ENOMEM); ++ arg.name = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!arg.name)) ++ goto out_file; ++ arg.ino = ino; ++ arg.found = 0; ++ do { ++ arg.called = 0; ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(file, &arg.ctx); ++ } while (!err && !arg.found && arg.called); ++ dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_name; ++ /* instead of ENOENT */ ++ dentry = ERR_PTR(-ESTALE); ++ if (!arg.found) ++ goto out_name; ++ ++ /* do not call vfsub_lkup_one() */ ++ dir = d_inode(parent); ++ dentry = vfsub_lookup_one_len_unlocked(arg.name, parent, arg.namelen); ++ AuTraceErrPtr(dentry); ++ if (IS_ERR(dentry)) ++ goto out_name; ++ AuDebugOn(au_test_anon(dentry)); ++ if (unlikely(d_really_is_negative(dentry))) { ++ dput(dentry); ++ dentry = ERR_PTR(-ENOENT); ++ } ++ ++out_name: ++ free_page((unsigned long)arg.name); ++out_file: ++ fput(file); ++out: ++ if (unlikely(nsi_lock ++ && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0)) ++ if (!IS_ERR(dentry)) { ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++ } ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino, ++ ino_t dir_ino, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry; ++ struct path path; ++ ++ if (dir_ino != AUFS_ROOT_INO) { ++ path.dentry = decode_by_ino(sb, dir_ino, 0); ++ dentry = path.dentry; ++ if (!path.dentry || IS_ERR(path.dentry)) ++ goto out; ++ AuDebugOn(au_test_anon(path.dentry)); ++ } else ++ path.dentry = dget(sb->s_root); ++ ++ path.mnt = au_mnt_get(sb); ++ dentry = au_lkup_by_ino(&path, ino, nsi_lock); ++ path_put(&path); ++ ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int h_acceptable(void *expv, struct dentry *dentry) ++{ ++ return 1; ++} ++ ++static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath, ++ char *buf, int len, struct super_block *sb) ++{ ++ char *p; ++ int n; ++ struct path path; ++ ++ p = d_path(h_rootpath, buf, len); ++ if (IS_ERR(p)) ++ goto out; ++ n = strlen(p); ++ ++ path.mnt = h_rootpath->mnt; ++ path.dentry = h_parent; ++ p = d_path(&path, buf, len); ++ if (IS_ERR(p)) ++ goto out; ++ if (n != 1) ++ p += n; ++ ++ path.mnt = au_mnt_get(sb); ++ path.dentry = sb->s_root; ++ p = d_path(&path, buf, len - strlen(p)); ++ mntput(path.mnt); ++ if (IS_ERR(p)) ++ goto out; ++ if (n != 1) ++ p[strlen(p)] = '/'; ++ ++out: ++ AuTraceErrPtr(p); ++ return p; ++} ++ ++static ++struct dentry *decode_by_path(struct super_block *sb, ino_t ino, __u32 *fh, ++ int fh_len, struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry, *h_parent, *root; ++ struct super_block *h_sb; ++ char *pathname, *p; ++ struct vfsmount *h_mnt; ++ struct au_branch *br; ++ int err; ++ struct path path; ++ ++ br = au_sbr(sb, nsi_lock->bindex); ++ h_mnt = au_br_mnt(br); ++ h_sb = h_mnt->mnt_sb; ++ /* todo: call lower fh_to_dentry()? fh_to_parent()? */ ++ lockdep_off(); ++ h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail), ++ fh_len - Fh_tail, fh[Fh_h_type], ++ h_acceptable, /*context*/NULL); ++ lockdep_on(); ++ dentry = h_parent; ++ if (unlikely(!h_parent || IS_ERR(h_parent))) { ++ AuWarn1("%s decode_fh failed, %ld\n", ++ au_sbtype(h_sb), PTR_ERR(h_parent)); ++ goto out; ++ } ++ dentry = NULL; ++ if (unlikely(au_test_anon(h_parent))) { ++ AuWarn1("%s decode_fh returned a disconnected dentry\n", ++ au_sbtype(h_sb)); ++ goto out_h_parent; ++ } ++ ++ dentry = ERR_PTR(-ENOMEM); ++ pathname = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!pathname)) ++ goto out_h_parent; ++ ++ root = sb->s_root; ++ path.mnt = h_mnt; ++ di_read_lock_parent(root, !AuLock_IR); ++ path.dentry = au_h_dptr(root, nsi_lock->bindex); ++ di_read_unlock(root, !AuLock_IR); ++ p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb); ++ dentry = (void *)p; ++ if (IS_ERR(p)) ++ goto out_pathname; ++ ++ si_read_unlock(sb); ++ err = vfsub_kern_path(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); ++ dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_relock; ++ ++ dentry = ERR_PTR(-ENOENT); ++ AuDebugOn(au_test_anon(path.dentry)); ++ if (unlikely(d_really_is_negative(path.dentry))) ++ goto out_path; ++ ++ if (ino != d_inode(path.dentry)->i_ino) ++ dentry = au_lkup_by_ino(&path, ino, /*nsi_lock*/NULL); ++ else ++ dentry = dget(path.dentry); ++ ++out_path: ++ path_put(&path); ++out_relock: ++ if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0)) ++ if (!IS_ERR(dentry)) { ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++ } ++out_pathname: ++ free_page((unsigned long)pathname); ++out_h_parent: ++ dput(h_parent); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry * ++aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, ++ int fh_type) ++{ ++ struct dentry *dentry; ++ __u32 *fh = fid->raw; ++ struct au_branch *br; ++ ino_t ino, dir_ino; ++ struct au_nfsd_si_lock nsi_lock = { ++ .force_lock = 0 ++ }; ++ ++ dentry = ERR_PTR(-ESTALE); ++ /* it should never happen, but the file handle is unreliable */ ++ if (unlikely(fh_len < Fh_tail)) ++ goto out; ++ nsi_lock.sigen = fh[Fh_sigen]; ++ nsi_lock.br_id = fh[Fh_br_id]; ++ ++ /* branch id may be wrapped around */ ++ br = NULL; ++ if (unlikely(si_nfsd_read_lock(sb, &nsi_lock))) ++ goto out; ++ nsi_lock.force_lock = 1; ++ ++ /* is this inode still cached? */ ++ ino = decode_ino(fh + Fh_ino); ++ /* it should never happen */ ++ if (unlikely(ino == AUFS_ROOT_INO)) ++ goto out_unlock; ++ ++ dir_ino = decode_ino(fh + Fh_dir_ino); ++ dentry = decode_by_ino(sb, ino, dir_ino); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (dentry) ++ goto accept; ++ ++ /* is the parent dir cached? */ ++ br = au_sbr(sb, nsi_lock.bindex); ++ au_br_get(br); ++ dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (dentry) ++ goto accept; ++ ++ /* lookup path */ ++ dentry = decode_by_path(sb, ino, fh, fh_len, &nsi_lock); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (unlikely(!dentry)) ++ /* todo?: make it ESTALE */ ++ goto out_unlock; ++ ++accept: ++ if (!au_digen_test(dentry, au_sigen(sb)) ++ && d_inode(dentry)->i_generation == fh[Fh_igen]) ++ goto out_unlock; /* success */ ++ ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++out_unlock: ++ if (br) ++ au_br_put(br); ++ si_read_unlock(sb); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++#if 0 /* reserved for future use */ ++/* support subtreecheck option */ ++static struct dentry *aufs_fh_to_parent(struct super_block *sb, struct fid *fid, ++ int fh_len, int fh_type) ++{ ++ struct dentry *parent; ++ __u32 *fh = fid->raw; ++ ino_t dir_ino; ++ ++ dir_ino = decode_ino(fh + Fh_dir_ino); ++ parent = decode_by_ino(sb, dir_ino, 0); ++ if (IS_ERR(parent)) ++ goto out; ++ if (!parent) ++ parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]), ++ dir_ino, fh, fh_len); ++ ++out: ++ AuTraceErrPtr(parent); ++ return parent; ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_encode_fh(struct inode *inode, __u32 *fh, int *max_len, ++ struct inode *dir) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb, *h_sb; ++ struct dentry *dentry, *parent, *h_parent; ++ struct inode *h_dir; ++ struct au_branch *br; ++ ++ err = -ENOSPC; ++ if (unlikely(*max_len <= Fh_tail)) { ++ AuWarn1("NFSv2 client (max_len %d)?\n", *max_len); ++ goto out; ++ } ++ ++ err = FILEID_ROOT; ++ if (inode->i_ino == AUFS_ROOT_INO) { ++ AuDebugOn(inode->i_ino != AUFS_ROOT_INO); ++ goto out; ++ } ++ ++ h_parent = NULL; ++ sb = inode->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH); ++ if (unlikely(err)) ++ goto out; ++ ++#ifdef CONFIG_AUFS_DEBUG ++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) ++ AuWarn1("NFS-exporting requires xino\n"); ++#endif ++ err = -EIO; ++ parent = NULL; ++ ii_read_lock_child(inode); ++ bindex = au_ibtop(inode); ++ if (!dir) { ++ dentry = d_find_any_alias(inode); ++ if (unlikely(!dentry)) ++ goto out_unlock; ++ AuDebugOn(au_test_anon(dentry)); ++ parent = dget_parent(dentry); ++ dput(dentry); ++ if (unlikely(!parent)) ++ goto out_unlock; ++ if (d_really_is_positive(parent)) ++ dir = d_inode(parent); ++ } ++ ++ ii_read_lock_parent(dir); ++ h_dir = au_h_iptr(dir, bindex); ++ ii_read_unlock(dir); ++ if (unlikely(!h_dir)) ++ goto out_parent; ++ h_parent = d_find_any_alias(h_dir); ++ if (unlikely(!h_parent)) ++ goto out_hparent; ++ ++ err = -EPERM; ++ br = au_sbr(sb, bindex); ++ h_sb = au_br_sb(br); ++ if (unlikely(!h_sb->s_export_op)) { ++ AuErr1("%s branch is not exportable\n", au_sbtype(h_sb)); ++ goto out_hparent; ++ } ++ ++ fh[Fh_br_id] = br->br_id; ++ fh[Fh_sigen] = au_sigen(sb); ++ encode_ino(fh + Fh_ino, inode->i_ino); ++ encode_ino(fh + Fh_dir_ino, dir->i_ino); ++ fh[Fh_igen] = inode->i_generation; ++ ++ *max_len -= Fh_tail; ++ fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail), ++ max_len, ++ /*connectable or subtreecheck*/0); ++ err = fh[Fh_h_type]; ++ *max_len += Fh_tail; ++ /* todo: macros? */ ++ if (err != FILEID_INVALID) ++ err = 99; ++ else ++ AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb)); ++ ++out_hparent: ++ dput(h_parent); ++out_parent: ++ dput(parent); ++out_unlock: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++out: ++ if (unlikely(err < 0)) ++ err = FILEID_INVALID; ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_commit_metadata(struct inode *inode) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct inode *h_inode; ++ int (*f)(struct inode *inode); ++ ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ii_write_lock_child(inode); ++ bindex = au_ibtop(inode); ++ AuDebugOn(bindex < 0); ++ h_inode = au_h_iptr(inode, bindex); ++ ++ f = h_inode->i_sb->s_export_op->commit_metadata; ++ if (f) ++ err = f(h_inode); ++ else { ++ struct writeback_control wbc = { ++ .sync_mode = WB_SYNC_ALL, ++ .nr_to_write = 0 /* metadata only */ ++ }; ++ ++ err = sync_inode(h_inode, &wbc); ++ } ++ ++ au_cpup_attr_timesizes(inode); ++ ii_write_unlock(inode); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct export_operations aufs_export_op = { ++ .fh_to_dentry = aufs_fh_to_dentry, ++ /* .fh_to_parent = aufs_fh_to_parent, */ ++ .encode_fh = aufs_encode_fh, ++ .commit_metadata = aufs_commit_metadata ++}; ++ ++void au_export_init(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ __u32 u; ++ ++ BUILD_BUG_ON_MSG(IS_BUILTIN(CONFIG_AUFS_FS) ++ && IS_MODULE(CONFIG_EXPORTFS), ++ AUFS_NAME ": unsupported configuration " ++ "CONFIG_EXPORTFS=m and CONFIG_AUFS_FS=y"); ++ ++ sb->s_export_op = &aufs_export_op; ++ sbinfo = au_sbi(sb); ++ sbinfo->si_xigen = NULL; ++ get_random_bytes(&u, sizeof(u)); ++ BUILD_BUG_ON(sizeof(u) != sizeof(int)); ++ atomic_set(&sbinfo->si_xigen_next, u); ++} +diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c +new file mode 100644 +index 0000000..504b767 +--- /dev/null ++++ b/fs/aufs/f_op.c +@@ -0,0 +1,757 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * file and vm operations ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++int au_do_open_nondir(struct file *file, int flags, struct file *h_file) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct dentry *dentry, *h_dentry; ++ struct au_finfo *finfo; ++ struct inode *h_inode; ++ ++ FiMustWriteLock(file); ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ AuDebugOn(IS_ERR_OR_NULL(dentry)); ++ finfo = au_fi(file); ++ memset(&finfo->fi_htop, 0, sizeof(finfo->fi_htop)); ++ atomic_set(&finfo->fi_mmapped, 0); ++ bindex = au_dbtop(dentry); ++ if (!h_file) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ goto out; ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ } else { ++ h_dentry = h_file->f_path.dentry; ++ err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ goto out; ++ get_file(h_file); ++ } ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ if ((flags & __O_TMPFILE) ++ && !(flags & O_EXCL)) { ++ h_inode = file_inode(h_file); ++ spin_lock(&h_inode->i_lock); ++ h_inode->i_state |= I_LINKABLE; ++ spin_unlock(&h_inode->i_lock); ++ } ++ au_set_fbtop(file, bindex); ++ au_set_h_fptr(file, bindex, h_file); ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ } ++ ++out: ++ return err; ++} ++ ++static int aufs_open_nondir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_do_open_args args = { ++ .open = au_do_open_nondir ++ }; ++ ++ AuDbg("%pD, f_flags 0x%x, f_mode 0x%x\n", ++ file, vfsub_file_flags(file), file->f_mode); ++ ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_do_open(file, &args); ++ si_read_unlock(sb); ++ return err; ++} ++ ++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file) ++{ ++ struct au_finfo *finfo; ++ aufs_bindex_t bindex; ++ ++ finfo = au_fi(file); ++ au_sphl_del(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ bindex = finfo->fi_btop; ++ if (bindex >= 0) ++ au_set_h_fptr(file, bindex, NULL); ++ ++ au_finfo_fin(file); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_flush_nondir(struct file *file, fl_owner_t id) ++{ ++ int err; ++ struct file *h_file; ++ ++ err = 0; ++ h_file = au_hf_top(file); ++ if (h_file) ++ err = vfsub_flush(h_file, id); ++ return err; ++} ++ ++static int aufs_flush_nondir(struct file *file, fl_owner_t id) ++{ ++ return au_do_flush(file, id, au_do_flush_nondir); ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * read and write functions acquire [fdi]_rwsem once, but release before ++ * mmap_sem. This is because to stop a race condition between mmap(2). ++ * Releasing these aufs-rwsem should be safe, no branch-mamagement (by keeping ++ * si_rwsem), no harmful copy-up should happen. Actually copy-up may happen in ++ * read functions after [fdi]_rwsem are released, but it should be harmless. ++ */ ++ ++/* Callers should call au_read_post() or fput() in the end */ ++struct file *au_read_pre(struct file *file, int keep_fi) ++{ ++ struct file *h_file; ++ int err; ++ ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); ++ if (!err) { ++ di_read_unlock(file->f_path.dentry, AuLock_IR); ++ h_file = au_hf_top(file); ++ get_file(h_file); ++ if (!keep_fi) ++ fi_read_unlock(file); ++ } else ++ h_file = ERR_PTR(err); ++ ++ return h_file; ++} ++ ++static void au_read_post(struct inode *inode, struct file *h_file) ++{ ++ /* update without lock, I don't think it a problem */ ++ fsstack_copy_attr_atime(inode, file_inode(h_file)); ++ fput(h_file); ++} ++ ++struct au_write_pre { ++ blkcnt_t blks; ++ aufs_bindex_t btop; ++}; ++ ++/* ++ * return with iinfo is write-locked ++ * callers should call au_write_post() or iinfo_write_unlock() + fput() in the ++ * end ++ */ ++static struct file *au_write_pre(struct file *file, int do_ready, ++ struct au_write_pre *wpre) ++{ ++ struct file *h_file; ++ struct dentry *dentry; ++ int err; ++ struct au_pin pin; ++ ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); ++ h_file = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ if (do_ready) { ++ err = au_ready_to_write(file, -1, &pin); ++ if (unlikely(err)) { ++ h_file = ERR_PTR(err); ++ di_write_unlock(dentry); ++ goto out_fi; ++ } ++ } ++ ++ di_downgrade_lock(dentry, /*flags*/0); ++ if (wpre) ++ wpre->btop = au_fbtop(file); ++ h_file = au_hf_top(file); ++ get_file(h_file); ++ if (wpre) ++ wpre->blks = file_inode(h_file)->i_blocks; ++ if (do_ready) ++ au_unpin(&pin); ++ di_read_unlock(dentry, /*flags*/0); ++ ++out_fi: ++ fi_write_unlock(file); ++out: ++ return h_file; ++} ++ ++static void au_write_post(struct inode *inode, struct file *h_file, ++ struct au_write_pre *wpre, ssize_t written) ++{ ++ struct inode *h_inode; ++ ++ au_cpup_attr_timesizes(inode); ++ AuDebugOn(au_ibtop(inode) != wpre->btop); ++ h_inode = file_inode(h_file); ++ inode->i_mode = h_inode->i_mode; ++ ii_write_unlock(inode); ++ fput(h_file); ++ ++ /* AuDbg("blks %llu, %llu\n", (u64)blks, (u64)h_inode->i_blocks); */ ++ if (written > 0) ++ au_fhsm_wrote(inode->i_sb, wpre->btop, ++ /*force*/h_inode->i_blocks > wpre->blks); ++} ++ ++static ssize_t aufs_read(struct file *file, char __user *buf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ struct inode *inode; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ /* filedata may be obsoleted by concurrent copyup, but no problem */ ++ err = vfsub_read_u(h_file, buf, count, ppos); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_read_post(inode, h_file); ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ++ * todo: very ugly ++ * it locks both of i_mutex and si_rwsem for read in safe. ++ * if the plink maintenance mode continues forever (that is the problem), ++ * may loop forever. ++ */ ++static void au_mtx_and_read_lock(struct inode *inode) ++{ ++ int err; ++ struct super_block *sb = inode->i_sb; ++ ++ while (1) { ++ inode_lock(inode); ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (!err) ++ break; ++ inode_unlock(inode); ++ si_read_lock(sb, AuLock_NOPLMW); ++ si_read_unlock(sb); ++ } ++} ++ ++static ssize_t aufs_write(struct file *file, const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ char __user *buf = (char __user *)ubuf; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = vfsub_write_u(h_file, buf, count, ppos); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++static ssize_t au_do_iter(struct file *h_file, int rw, struct kiocb *kio, ++ struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct file *file; ++ ssize_t (*iter)(struct kiocb *, struct iov_iter *); ++ ++ err = security_file_permission(h_file, rw); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOSYS; ++ iter = NULL; ++ if (rw == MAY_READ) ++ iter = h_file->f_op->read_iter; ++ else if (rw == MAY_WRITE) ++ iter = h_file->f_op->write_iter; ++ ++ file = kio->ki_filp; ++ kio->ki_filp = h_file; ++ if (iter) { ++ lockdep_off(); ++ err = iter(kio, iov_iter); ++ lockdep_on(); ++ } else ++ /* currently there is no such fs */ ++ WARN_ON_ONCE(1); ++ kio->ki_filp = file; ++ ++out: ++ return err; ++} ++ ++static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct file *file, *h_file; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ file = kio->ki_filp; ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/1); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ if (au_test_loopback_kthread()) { ++ au_warn_loopback(h_file->f_path.dentry->d_sb); ++ if (file->f_mapping != h_file->f_mapping) { ++ file->f_mapping = h_file->f_mapping; ++ smp_mb(); /* unnecessary? */ ++ } ++ } ++ fi_read_unlock(file); ++ ++ err = au_do_iter(h_file, MAY_READ, kio, iov_iter); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_read_post(inode, h_file); ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static ssize_t aufs_write_iter(struct kiocb *kio, struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *file, *h_file; ++ ++ file = kio->ki_filp; ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = au_do_iter(h_file, MAY_WRITE, kio, iov_iter); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++static ssize_t aufs_splice_read(struct file *file, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) ++{ ++ ssize_t err; ++ struct file *h_file; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = vfsub_splice_to(h_file, ppos, pipe, len, flags); ++ /* todo: necessasry? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_read_post(inode, h_file); ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static ssize_t ++aufs_splice_write(struct pipe_inode_info *pipe, struct file *file, loff_t *ppos, ++ size_t len, unsigned int flags) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = vfsub_splice_from(pipe, h_file, ppos, len, flags); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++static long aufs_fallocate(struct file *file, int mode, loff_t offset, ++ loff_t len) ++{ ++ long err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_fallocate(h_file, mode, offset, len); ++ lockdep_on(); ++ au_write_post(inode, h_file, &wpre, /*written*/1); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * The locking order around current->mmap_sem. ++ * - in most and regular cases ++ * file I/O syscall -- aufs_read() or something ++ * -- si_rwsem for read -- mmap_sem ++ * (Note that [fdi]i_rwsem are released before mmap_sem). ++ * - in mmap case ++ * mmap(2) -- mmap_sem -- aufs_mmap() -- si_rwsem for read -- [fdi]i_rwsem ++ * This AB-BA order is definitly bad, but is not a problem since "si_rwsem for ++ * read" allows muliple processes to acquire it and [fdi]i_rwsem are not held in ++ * file I/O. Aufs needs to stop lockdep in aufs_mmap() though. ++ * It means that when aufs acquires si_rwsem for write, the process should never ++ * acquire mmap_sem. ++ * ++ * Actually aufs_iterate() holds [fdi]i_rwsem before mmap_sem, but this is not a ++ * problem either since any directory is not able to be mmap-ed. ++ * The similar scenario is applied to aufs_readlink() too. ++ */ ++ ++#if 0 /* stop calling security_file_mmap() */ ++/* cf. linux/include/linux/mman.h: calc_vm_prot_bits() */ ++#define AuConv_VM_PROT(f, b) _calc_vm_trans(f, VM_##b, PROT_##b) ++ ++static unsigned long au_arch_prot_conv(unsigned long flags) ++{ ++ /* currently ppc64 only */ ++#ifdef CONFIG_PPC64 ++ /* cf. linux/arch/powerpc/include/asm/mman.h */ ++ AuDebugOn(arch_calc_vm_prot_bits(-1) != VM_SAO); ++ return AuConv_VM_PROT(flags, SAO); ++#else ++ AuDebugOn(arch_calc_vm_prot_bits(-1)); ++ return 0; ++#endif ++} ++ ++static unsigned long au_prot_conv(unsigned long flags) ++{ ++ return AuConv_VM_PROT(flags, READ) ++ | AuConv_VM_PROT(flags, WRITE) ++ | AuConv_VM_PROT(flags, EXEC) ++ | au_arch_prot_conv(flags); ++} ++ ++/* cf. linux/include/linux/mman.h: calc_vm_flag_bits() */ ++#define AuConv_VM_MAP(f, b) _calc_vm_trans(f, VM_##b, MAP_##b) ++ ++static unsigned long au_flag_conv(unsigned long flags) ++{ ++ return AuConv_VM_MAP(flags, GROWSDOWN) ++ | AuConv_VM_MAP(flags, DENYWRITE) ++ | AuConv_VM_MAP(flags, LOCKED); ++} ++#endif ++ ++static int aufs_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int err; ++ const unsigned char wlock ++ = (file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED); ++ struct super_block *sb; ++ struct file *h_file; ++ struct inode *inode; ++ ++ AuDbgVmRegion(file, vma); ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ lockdep_off(); ++ si_read_lock(sb, AuLock_NOPLMW); ++ ++ h_file = au_write_pre(file, wlock, /*wpre*/NULL); ++ lockdep_on(); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = 0; ++ au_set_mmapped(file); ++ au_vm_file_reset(vma, h_file); ++ /* ++ * we cannot call security_mmap_file() here since it may acquire ++ * mmap_sem or i_mutex. ++ * ++ * err = security_mmap_file(h_file, au_prot_conv(vma->vm_flags), ++ * au_flag_conv(vma->vm_flags)); ++ */ ++ if (!err) ++ err = h_file->f_op->mmap(h_file, vma); ++ if (!err) { ++ au_vm_prfile_set(vma, file); ++ fsstack_copy_attr_atime(inode, file_inode(h_file)); ++ goto out_fput; /* success */ ++ } ++ au_unset_mmapped(file); ++ au_vm_file_reset(vma, file); ++ ++out_fput: ++ lockdep_off(); ++ ii_write_unlock(inode); ++ lockdep_on(); ++ fput(h_file); ++out: ++ lockdep_off(); ++ si_read_unlock(sb); ++ lockdep_on(); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_fsync_nondir(struct file *file, loff_t start, loff_t end, ++ int datasync) ++{ ++ int err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ err = 0; /* -EBADF; */ /* posix? */ ++ if (unlikely(!(file->f_mode & FMODE_WRITE))) ++ goto out; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out_unlock; ++ ++ err = vfsub_fsync(h_file, &h_file->f_path, datasync); ++ au_write_post(inode, h_file, &wpre, /*written*/0); ++ ++out_unlock: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++out: ++ return err; ++} ++ ++/* no one supports this operation, currently */ ++#if 0 ++static int aufs_aio_fsync_nondir(struct kiocb *kio, int datasync) ++{ ++ int err; ++ struct au_write_pre wpre; ++ struct inode *inode, *h_inode; ++ struct file *file, *h_file; ++ ++ err = 0; /* -EBADF; */ /* posix? */ ++ if (unlikely(!(file->f_mode & FMODE_WRITE))) ++ goto out; ++ ++ file = kio->ki_filp; ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out_unlock; ++ ++ err = -ENOSYS; ++ h_file = au_hf_top(file); ++ if (h_file->f_op->aio_fsync) { ++ h_inode = file_inode(h_file); ++ if (!is_sync_kiocb(kio)) { ++ get_file(h_file); ++ fput(file); ++ } ++ kio->ki_filp = h_file; ++ err = h_file->f_op->aio_fsync(kio, datasync); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ if (!err) ++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); ++ /*ignore*/ ++ inode_unlock(h_inode); ++ } ++ au_write_post(inode, h_file, &wpre, /*written*/0); ++ ++out_unlock: ++ si_read_unlock(inode->sb); ++ inode_unlock(inode); ++out: ++ return err; ++} ++#endif ++ ++static int aufs_fasync(int fd, struct file *file, int flag) ++{ ++ int err; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ if (h_file->f_op->fasync) ++ err = h_file->f_op->fasync(fd, h_file, flag); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static int aufs_setfl(struct file *file, unsigned long arg) ++{ ++ int err; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ arg |= vfsub_file_flags(file) & FASYNC; /* stop calling h_file->fasync */ ++ err = setfl(/*unused fd*/-1, h_file, arg); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* no one supports this operation, currently */ ++#if 0 ++static ssize_t aufs_sendpage(struct file *file, struct page *page, int offset, ++ size_t len, loff_t *pos, int more) ++{ ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++const struct file_operations aufs_file_fop = { ++ .owner = THIS_MODULE, ++ ++ .llseek = default_llseek, ++ ++ .read = aufs_read, ++ .write = aufs_write, ++ .read_iter = aufs_read_iter, ++ .write_iter = aufs_write_iter, ++ ++#ifdef CONFIG_AUFS_POLL ++ .poll = aufs_poll, ++#endif ++ .unlocked_ioctl = aufs_ioctl_nondir, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = aufs_compat_ioctl_nondir, ++#endif ++ .mmap = aufs_mmap, ++ .open = aufs_open_nondir, ++ .flush = aufs_flush_nondir, ++ .release = aufs_release_nondir, ++ .fsync = aufs_fsync_nondir, ++ /* .aio_fsync = aufs_aio_fsync_nondir, */ ++ .fasync = aufs_fasync, ++ /* .sendpage = aufs_sendpage, */ ++ .setfl = aufs_setfl, ++ .splice_write = aufs_splice_write, ++ .splice_read = aufs_splice_read, ++#if 0 ++ .aio_splice_write = aufs_aio_splice_write, ++ .aio_splice_read = aufs_aio_splice_read, ++#endif ++ .fallocate = aufs_fallocate ++}; +diff --git a/fs/aufs/fhsm.c b/fs/aufs/fhsm.c +new file mode 100644 +index 0000000..e3cb6ed +--- /dev/null ++++ b/fs/aufs/fhsm.c +@@ -0,0 +1,412 @@ ++/* ++ * Copyright (C) 2011-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * File-based Hierarchy Storage Management ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++static aufs_bindex_t au_fhsm_bottom(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ AuDebugOn(!fhsm); ++ return fhsm->fhsm_bottom; ++} ++ ++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ AuDebugOn(!fhsm); ++ fhsm->fhsm_bottom = bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_fhsm_test_jiffy(struct au_sbinfo *sbinfo, struct au_branch *br) ++{ ++ struct au_br_fhsm *bf; ++ ++ bf = br->br_fhsm; ++ MtxMustLock(&bf->bf_lock); ++ ++ return !bf->bf_readable ++ || time_after(jiffies, ++ bf->bf_jiffy + sbinfo->si_fhsm.fhsm_expire); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_fhsm_notify(struct super_block *sb, int val) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ if (au_fhsm_pid(fhsm) ++ && atomic_read(&fhsm->fhsm_readable) != -1) { ++ atomic_set(&fhsm->fhsm_readable, val); ++ if (val) ++ wake_up(&fhsm->fhsm_wqh); ++ } ++} ++ ++static int au_fhsm_stfs(struct super_block *sb, aufs_bindex_t bindex, ++ struct aufs_stfs *rstfs, int do_lock, int do_notify) ++{ ++ int err; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(au_br_rdonly(br)); ++ bf = br->br_fhsm; ++ AuDebugOn(!bf); ++ ++ if (do_lock) ++ mutex_lock(&bf->bf_lock); ++ else ++ MtxMustLock(&bf->bf_lock); ++ ++ /* sb->s_root for NFS is unreliable */ ++ err = au_br_stfs(br, &bf->bf_stfs); ++ if (unlikely(err)) { ++ AuErr1("FHSM failed (%d), b%d, ignored.\n", bindex, err); ++ goto out; ++ } ++ ++ bf->bf_jiffy = jiffies; ++ bf->bf_readable = 1; ++ if (do_notify) ++ au_fhsm_notify(sb, /*val*/1); ++ if (rstfs) ++ *rstfs = bf->bf_stfs; ++ ++out: ++ if (do_lock) ++ mutex_unlock(&bf->bf_lock); ++ au_fhsm_notify(sb, /*val*/1); ++ ++ return err; ++} ++ ++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ AuDbg("b%d, force %d\n", bindex, force); ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ if (!au_ftest_si(sbinfo, FHSM) ++ || fhsm->fhsm_bottom == bindex) ++ return; ++ ++ br = au_sbr(sb, bindex); ++ bf = br->br_fhsm; ++ AuDebugOn(!bf); ++ mutex_lock(&bf->bf_lock); ++ if (force ++ || au_fhsm_pid(fhsm) ++ || au_fhsm_test_jiffy(sbinfo, br)) ++ err = au_fhsm_stfs(sb, bindex, /*rstfs*/NULL, /*do_lock*/0, ++ /*do_notify*/1); ++ mutex_unlock(&bf->bf_lock); ++} ++ ++void au_fhsm_wrote_all(struct super_block *sb, int force) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ /* exclude the bottom */ ++ bbot = au_fhsm_bottom(sb); ++ for (bindex = 0; bindex < bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) ++ au_fhsm_wrote(sb, bindex, force); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static unsigned int au_fhsm_poll(struct file *file, ++ struct poll_table_struct *wait) ++{ ++ unsigned int mask; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ mask = 0; ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++ poll_wait(file, &fhsm->fhsm_wqh, wait); ++ if (atomic_read(&fhsm->fhsm_readable)) ++ mask = POLLIN /* | POLLRDNORM */; ++ ++ AuTraceErr((int)mask); ++ return mask; ++} ++ ++static int au_fhsm_do_read_one(struct aufs_stbr __user *stbr, ++ struct aufs_stfs *stfs, __s16 brid) ++{ ++ int err; ++ ++ err = copy_to_user(&stbr->stfs, stfs, sizeof(*stfs)); ++ if (!err) ++ err = __put_user(brid, &stbr->brid); ++ if (unlikely(err)) ++ err = -EFAULT; ++ ++ return err; ++} ++ ++static ssize_t au_fhsm_do_read(struct super_block *sb, ++ struct aufs_stbr __user *stbr, size_t count) ++{ ++ ssize_t err; ++ int nstbr; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ /* except the bottom branch */ ++ err = 0; ++ nstbr = 0; ++ bbot = au_fhsm_bottom(sb); ++ for (bindex = 0; !err && bindex < bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_fhsm(br->br_perm)) ++ continue; ++ ++ bf = br->br_fhsm; ++ mutex_lock(&bf->bf_lock); ++ if (bf->bf_readable) { ++ err = -EFAULT; ++ if (count >= sizeof(*stbr)) ++ err = au_fhsm_do_read_one(stbr++, &bf->bf_stfs, ++ br->br_id); ++ if (!err) { ++ bf->bf_readable = 0; ++ count -= sizeof(*stbr); ++ nstbr++; ++ } ++ } ++ mutex_unlock(&bf->bf_lock); ++ } ++ if (!err) ++ err = sizeof(*stbr) * nstbr; ++ ++ return err; ++} ++ ++static ssize_t au_fhsm_read(struct file *file, char __user *buf, size_t count, ++ loff_t *pos) ++{ ++ ssize_t err; ++ int readable; ++ aufs_bindex_t nfhsm, bindex, bbot; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ struct au_branch *br; ++ struct super_block *sb; ++ ++ err = 0; ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++need_data: ++ spin_lock_irq(&fhsm->fhsm_wqh.lock); ++ if (!atomic_read(&fhsm->fhsm_readable)) { ++ if (vfsub_file_flags(file) & O_NONBLOCK) ++ err = -EAGAIN; ++ else ++ err = wait_event_interruptible_locked_irq ++ (fhsm->fhsm_wqh, ++ atomic_read(&fhsm->fhsm_readable)); ++ } ++ spin_unlock_irq(&fhsm->fhsm_wqh.lock); ++ if (unlikely(err)) ++ goto out; ++ ++ /* sb may already be dead */ ++ au_rw_read_lock(&sbinfo->si_rwsem); ++ readable = atomic_read(&fhsm->fhsm_readable); ++ if (readable > 0) { ++ sb = sbinfo->si_sb; ++ AuDebugOn(!sb); ++ /* exclude the bottom branch */ ++ nfhsm = 0; ++ bbot = au_fhsm_bottom(sb); ++ for (bindex = 0; bindex < bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) ++ nfhsm++; ++ } ++ err = -EMSGSIZE; ++ if (nfhsm * sizeof(struct aufs_stbr) <= count) { ++ atomic_set(&fhsm->fhsm_readable, 0); ++ err = au_fhsm_do_read(sbinfo->si_sb, (void __user *)buf, ++ count); ++ } ++ } ++ au_rw_read_unlock(&sbinfo->si_rwsem); ++ if (!readable) ++ goto need_data; ++ ++out: ++ return err; ++} ++ ++static int au_fhsm_release(struct inode *inode, struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ /* sb may already be dead */ ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock(&fhsm->fhsm_spin); ++ fhsm->fhsm_pid = 0; ++ spin_unlock(&fhsm->fhsm_spin); ++ kobject_put(&sbinfo->si_kobj); ++ ++ return 0; ++} ++ ++static const struct file_operations au_fhsm_fops = { ++ .owner = THIS_MODULE, ++ .llseek = noop_llseek, ++ .read = au_fhsm_read, ++ .poll = au_fhsm_poll, ++ .release = au_fhsm_release ++}; ++ ++int au_fhsm_fd(struct super_block *sb, int oflags) ++{ ++ int err, fd; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(oflags & ~(O_CLOEXEC | O_NONBLOCK))) ++ goto out; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock(&fhsm->fhsm_spin); ++ if (!fhsm->fhsm_pid) ++ fhsm->fhsm_pid = current->pid; ++ else ++ err = -EBUSY; ++ spin_unlock(&fhsm->fhsm_spin); ++ if (unlikely(err)) ++ goto out; ++ ++ oflags |= O_RDONLY; ++ /* oflags |= FMODE_NONOTIFY; */ ++ fd = anon_inode_getfd("[aufs_fhsm]", &au_fhsm_fops, sbinfo, oflags); ++ err = fd; ++ if (unlikely(fd < 0)) ++ goto out_pid; ++ ++ /* succeed reglardless 'fhsm' status */ ++ kobject_get(&sbinfo->si_kobj); ++ si_noflush_read_lock(sb); ++ if (au_ftest_si(sbinfo, FHSM)) ++ au_fhsm_wrote_all(sb, /*force*/0); ++ si_read_unlock(sb); ++ goto out; /* success */ ++ ++out_pid: ++ spin_lock(&fhsm->fhsm_spin); ++ fhsm->fhsm_pid = 0; ++ spin_unlock(&fhsm->fhsm_spin); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_fhsm_br_alloc(struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ br->br_fhsm = kmalloc(sizeof(*br->br_fhsm), GFP_NOFS); ++ if (br->br_fhsm) ++ au_br_fhsm_init(br->br_fhsm); ++ else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_fhsm_fin(struct super_block *sb) ++{ ++ au_fhsm_notify(sb, /*val*/-1); ++} ++ ++void au_fhsm_init(struct au_sbinfo *sbinfo) ++{ ++ struct au_fhsm *fhsm; ++ ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock_init(&fhsm->fhsm_spin); ++ init_waitqueue_head(&fhsm->fhsm_wqh); ++ atomic_set(&fhsm->fhsm_readable, 0); ++ fhsm->fhsm_expire ++ = msecs_to_jiffies(AUFS_FHSM_CACHE_DEF_SEC * MSEC_PER_SEC); ++ fhsm->fhsm_bottom = -1; ++} ++ ++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec) ++{ ++ sbinfo->si_fhsm.fhsm_expire ++ = msecs_to_jiffies(sec * MSEC_PER_SEC); ++} ++ ++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo) ++{ ++ unsigned int u; ++ ++ if (!au_ftest_si(sbinfo, FHSM)) ++ return; ++ ++ u = jiffies_to_msecs(sbinfo->si_fhsm.fhsm_expire) / MSEC_PER_SEC; ++ if (u != AUFS_FHSM_CACHE_DEF_SEC) ++ seq_printf(seq, ",fhsm_sec=%u", u); ++} +diff --git a/fs/aufs/file.c b/fs/aufs/file.c +new file mode 100644 +index 0000000..4b68aef +--- /dev/null ++++ b/fs/aufs/file.c +@@ -0,0 +1,830 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * handling file/dir, and address_space operation ++ */ ++ ++#ifdef CONFIG_AUFS_DEBUG ++#include ++#endif ++#include ++#include "aufs.h" ++ ++/* drop flags for writing */ ++unsigned int au_file_roflags(unsigned int flags) ++{ ++ flags &= ~(O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC); ++ flags |= O_RDONLY | O_NOATIME; ++ return flags; ++} ++ ++/* common functions to regular file and dir */ ++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, ++ struct file *file, int force_wr) ++{ ++ struct file *h_file; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct path h_path; ++ int err; ++ ++ /* a race condition can happen between open and unlink/rmdir */ ++ h_file = ERR_PTR(-ENOENT); ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (au_test_nfsd() && (!h_dentry || d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ spin_lock(&h_dentry->d_lock); ++ err = (!d_unhashed(dentry) && d_unlinked(h_dentry)) ++ /* || !d_inode(dentry)->i_nlink */ ++ ; ++ spin_unlock(&h_dentry->d_lock); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ err = au_br_test_oflag(flags, br); ++ h_file = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ /* drop flags for writing */ ++ if (au_test_ro(sb, bindex, d_inode(dentry))) { ++ if (force_wr && !(flags & O_WRONLY)) ++ force_wr = 0; ++ flags = au_file_roflags(flags); ++ if (force_wr) { ++ h_file = ERR_PTR(-EROFS); ++ flags = au_file_roflags(flags); ++ if (unlikely(vfsub_native_ro(h_inode) ++ || IS_APPEND(h_inode))) ++ goto out; ++ flags &= ~O_ACCMODE; ++ flags |= O_WRONLY; ++ } ++ } ++ flags &= ~O_CREAT; ++ au_br_get(br); ++ h_path.dentry = h_dentry; ++ h_path.mnt = au_br_mnt(br); ++ h_file = vfsub_dentry_open(&h_path, flags); ++ if (IS_ERR(h_file)) ++ goto out_br; ++ ++ if (flags & __FMODE_EXEC) { ++ err = deny_write_access(h_file); ++ if (unlikely(err)) { ++ fput(h_file); ++ h_file = ERR_PTR(err); ++ goto out_br; ++ } ++ } ++ fsnotify_open(h_file); ++ goto out; /* success */ ++ ++out_br: ++ au_br_put(br); ++out: ++ return h_file; ++} ++ ++static int au_cmoo(struct dentry *dentry) ++{ ++ int err, cmoo; ++ unsigned int udba; ++ struct path h_path; ++ struct au_pin pin; ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ struct inode *delegated; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ pid_t pid; ++ struct au_branch *br; ++ struct dentry *parent; ++ struct au_hinode *hdir; ++ ++ DiMustWriteLock(dentry); ++ IiMustWriteLock(d_inode(dentry)); ++ ++ err = 0; ++ if (IS_ROOT(dentry)) ++ goto out; ++ cpg.bsrc = au_dbtop(dentry); ++ if (!cpg.bsrc) ++ goto out; ++ ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ pid = au_fhsm_pid(fhsm); ++ if (pid ++ && (current->pid == pid ++ || current->real_parent->pid == pid)) ++ goto out; ++ ++ br = au_sbr(sb, cpg.bsrc); ++ cmoo = au_br_cmoo(br->br_perm); ++ if (!cmoo) ++ goto out; ++ if (!d_is_reg(dentry)) ++ cmoo &= AuBrAttr_COO_ALL; ++ if (!cmoo) ++ goto out; ++ ++ parent = dget_parent(dentry); ++ di_write_lock_parent(parent); ++ err = au_wbr_do_copyup_bu(dentry, cpg.bsrc - 1); ++ cpg.bdst = err; ++ if (unlikely(err < 0)) { ++ err = 0; /* there is no upper writable branch */ ++ goto out_dgrade; ++ } ++ AuDbg("bsrc %d, bdst %d\n", cpg.bsrc, cpg.bdst); ++ ++ /* do not respect the coo attrib for the target branch */ ++ err = au_cpup_dirs(dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_dgrade; ++ ++ di_downgrade_lock(parent, AuLock_IR); ++ udba = au_opt_udba(sb); ++ err = au_pin(&pin, dentry, cpg.bdst, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ if (unlikely(err)) ++ goto out_parent; ++ if (!(cmoo & AuBrWAttr_MOO)) ++ goto out_parent; /* success */ ++ ++ err = au_pin(&pin, dentry, cpg.bsrc, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ h_path.mnt = au_br_mnt(br); ++ h_path.dentry = au_h_dptr(dentry, cpg.bsrc); ++ hdir = au_hi(d_inode(parent), cpg.bsrc); ++ delegated = NULL; ++ err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, /*force*/1); ++ au_unpin(&pin); ++ /* todo: keep h_dentry or not? */ ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) { ++ pr_err("unlink %pd after coo failed (%d), ignored\n", ++ dentry, err); ++ err = 0; ++ } ++ goto out_parent; /* success */ ++ ++out_dgrade: ++ di_downgrade_lock(parent, AuLock_IR); ++out_parent: ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_do_open(struct file *file, struct au_do_open_args *args) ++{ ++ int err, no_lock = args->no_lock; ++ struct dentry *dentry; ++ struct au_finfo *finfo; ++ ++ if (!no_lock) ++ err = au_finfo_init(file, args->fidir); ++ else { ++ lockdep_off(); ++ err = au_finfo_init(file, args->fidir); ++ lockdep_on(); ++ } ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ AuDebugOn(IS_ERR_OR_NULL(dentry)); ++ if (!no_lock) { ++ di_write_lock_child(dentry); ++ err = au_cmoo(dentry); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (!err) ++ err = args->open(file, vfsub_file_flags(file), NULL); ++ di_read_unlock(dentry, AuLock_IR); ++ } else { ++ err = au_cmoo(dentry); ++ if (!err) ++ err = args->open(file, vfsub_file_flags(file), ++ args->h_file); ++ if (!err && au_fbtop(file) != au_dbtop(dentry)) ++ /* ++ * cmoo happens after h_file was opened. ++ * need to refresh file later. ++ */ ++ atomic_dec(&au_fi(file)->fi_generation); ++ } ++ ++ finfo = au_fi(file); ++ if (!err) { ++ finfo->fi_file = file; ++ au_sphl_add(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ } ++ if (!no_lock) ++ fi_write_unlock(file); ++ else { ++ lockdep_off(); ++ fi_write_unlock(file); ++ lockdep_on(); ++ } ++ if (unlikely(err)) { ++ finfo->fi_hdir = NULL; ++ au_finfo_fin(file); ++ } ++ ++out: ++ return err; ++} ++ ++int au_reopen_nondir(struct file *file) ++{ ++ int err; ++ aufs_bindex_t btop; ++ struct dentry *dentry; ++ struct file *h_file, *h_file_tmp; ++ ++ dentry = file->f_path.dentry; ++ btop = au_dbtop(dentry); ++ h_file_tmp = NULL; ++ if (au_fbtop(file) == btop) { ++ h_file = au_hf_top(file); ++ if (file->f_mode == h_file->f_mode) ++ return 0; /* success */ ++ h_file_tmp = h_file; ++ get_file(h_file_tmp); ++ au_set_h_fptr(file, btop, NULL); ++ } ++ AuDebugOn(au_fi(file)->fi_hdir); ++ /* ++ * it can happen ++ * file exists on both of rw and ro ++ * open --> dbtop and fbtop are both 0 ++ * prepend a branch as rw, "rw" become ro ++ * remove rw/file ++ * delete the top branch, "rw" becomes rw again ++ * --> dbtop is 1, fbtop is still 0 ++ * write --> fbtop is 0 but dbtop is 1 ++ */ ++ /* AuDebugOn(au_fbtop(file) < btop); */ ++ ++ h_file = au_h_open(dentry, btop, vfsub_file_flags(file) & ~O_TRUNC, ++ file, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) { ++ if (h_file_tmp) { ++ au_sbr_get(dentry->d_sb, btop); ++ au_set_h_fptr(file, btop, h_file_tmp); ++ h_file_tmp = NULL; ++ } ++ goto out; /* todo: close all? */ ++ } ++ ++ err = 0; ++ au_set_fbtop(file, btop); ++ au_set_h_fptr(file, btop, h_file); ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ ++out: ++ if (h_file_tmp) ++ fput(h_file_tmp); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_reopen_wh(struct file *file, aufs_bindex_t btgt, ++ struct dentry *hi_wh) ++{ ++ int err; ++ aufs_bindex_t btop; ++ struct au_dinfo *dinfo; ++ struct dentry *h_dentry; ++ struct au_hdentry *hdp; ++ ++ dinfo = au_di(file->f_path.dentry); ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ btop = dinfo->di_btop; ++ dinfo->di_btop = btgt; ++ hdp = au_hdentry(dinfo, btgt); ++ h_dentry = hdp->hd_dentry; ++ hdp->hd_dentry = hi_wh; ++ err = au_reopen_nondir(file); ++ hdp->hd_dentry = h_dentry; ++ dinfo->di_btop = btop; ++ ++ return err; ++} ++ ++static int au_ready_to_write_wh(struct file *file, loff_t len, ++ aufs_bindex_t bcpup, struct au_pin *pin) ++{ ++ int err; ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry, *hi_wh; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_path.dentry, ++ .bdst = bcpup, ++ .bsrc = -1, ++ .len = len, ++ .pin = pin ++ }; ++ ++ au_update_dbtop(cpg.dentry); ++ inode = d_inode(cpg.dentry); ++ h_inode = NULL; ++ if (au_dbtop(cpg.dentry) <= bcpup ++ && au_dbbot(cpg.dentry) >= bcpup) { ++ h_dentry = au_h_dptr(cpg.dentry, bcpup); ++ if (h_dentry && d_is_positive(h_dentry)) ++ h_inode = d_inode(h_dentry); ++ } ++ hi_wh = au_hi_wh(inode, bcpup); ++ if (!hi_wh && !h_inode) ++ err = au_sio_cpup_wh(&cpg, file); ++ else ++ /* already copied-up after unlink */ ++ err = au_reopen_wh(file, bcpup, hi_wh); ++ ++ if (!err ++ && (inode->i_nlink > 1 ++ || (inode->i_state & I_LINKABLE)) ++ && au_opt_test(au_mntflags(cpg.dentry->d_sb), PLINK)) ++ au_plink_append(inode, bcpup, au_h_dptr(cpg.dentry, bcpup)); ++ ++ return err; ++} ++ ++/* ++ * prepare the @file for writing. ++ */ ++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin) ++{ ++ int err; ++ aufs_bindex_t dbtop; ++ struct dentry *parent; ++ struct inode *inode; ++ struct super_block *sb; ++ struct file *h_file; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_path.dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = len, ++ .pin = pin, ++ .flags = AuCpup_DTIME ++ }; ++ ++ sb = cpg.dentry->d_sb; ++ inode = d_inode(cpg.dentry); ++ cpg.bsrc = au_fbtop(file); ++ err = au_test_ro(sb, cpg.bsrc, inode); ++ if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) { ++ err = au_pin(pin, cpg.dentry, cpg.bsrc, AuOpt_UDBA_NONE, ++ /*flags*/0); ++ goto out; ++ } ++ ++ /* need to cpup or reopen */ ++ parent = dget_parent(cpg.dentry); ++ di_write_lock_parent(parent); ++ err = AuWbrCopyup(au_sbi(sb), cpg.dentry); ++ cpg.bdst = err; ++ if (unlikely(err < 0)) ++ goto out_dgrade; ++ err = 0; ++ ++ if (!d_unhashed(cpg.dentry) && !au_h_dptr(parent, cpg.bdst)) { ++ err = au_cpup_dirs(cpg.dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_dgrade; ++ } ++ ++ err = au_pin(pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_dgrade; ++ ++ dbtop = au_dbtop(cpg.dentry); ++ if (dbtop <= cpg.bdst) ++ cpg.bsrc = cpg.bdst; ++ ++ if (dbtop <= cpg.bdst /* just reopen */ ++ || !d_unhashed(cpg.dentry) /* copyup and reopen */ ++ ) { ++ h_file = au_h_open_pre(cpg.dentry, cpg.bsrc, /*force_wr*/0); ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ di_downgrade_lock(parent, AuLock_IR); ++ if (dbtop > cpg.bdst) ++ err = au_sio_cpup_simple(&cpg); ++ if (!err) ++ err = au_reopen_nondir(file); ++ au_h_open_post(cpg.dentry, cpg.bsrc, h_file); ++ } ++ } else { /* copyup as wh and reopen */ ++ /* ++ * since writable hfsplus branch is not supported, ++ * h_open_pre/post() are unnecessary. ++ */ ++ err = au_ready_to_write_wh(file, len, cpg.bdst, pin); ++ di_downgrade_lock(parent, AuLock_IR); ++ } ++ ++ if (!err) { ++ au_pin_set_parent_lflag(pin, /*lflag*/0); ++ goto out_dput; /* success */ ++ } ++ au_unpin(pin); ++ goto out_unlock; ++ ++out_dgrade: ++ di_downgrade_lock(parent, AuLock_IR); ++out_unlock: ++ di_read_unlock(parent, AuLock_IR); ++out_dput: ++ dput(parent); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_do_flush(struct file *file, fl_owner_t id, ++ int (*flush)(struct file *file, fl_owner_t id)) ++{ ++ int err; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_noflush_read_lock(sb); ++ fi_read_lock(file); ++ ii_read_lock_child(inode); ++ ++ err = flush(file, id); ++ au_cpup_attr_timesizes(inode); ++ ++ ii_read_unlock(inode); ++ fi_read_unlock(file); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_file_refresh_by_inode(struct file *file, int *need_reopen) ++{ ++ int err; ++ struct au_pin pin; ++ struct au_finfo *finfo; ++ struct dentry *parent, *hi_wh; ++ struct inode *inode; ++ struct super_block *sb; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_path.dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME ++ }; ++ ++ FiMustWriteLock(file); ++ ++ err = 0; ++ finfo = au_fi(file); ++ sb = cpg.dentry->d_sb; ++ inode = d_inode(cpg.dentry); ++ cpg.bdst = au_ibtop(inode); ++ if (cpg.bdst == finfo->fi_btop || IS_ROOT(cpg.dentry)) ++ goto out; ++ ++ parent = dget_parent(cpg.dentry); ++ if (au_test_ro(sb, cpg.bdst, inode)) { ++ di_read_lock_parent(parent, !AuLock_IR); ++ err = AuWbrCopyup(au_sbi(sb), cpg.dentry); ++ cpg.bdst = err; ++ di_read_unlock(parent, !AuLock_IR); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ err = 0; ++ } ++ ++ di_read_lock_parent(parent, AuLock_IR); ++ hi_wh = au_hi_wh(inode, cpg.bdst); ++ if (!S_ISDIR(inode->i_mode) ++ && au_opt_test(au_mntflags(sb), PLINK) ++ && au_plink_test(inode) ++ && !d_unhashed(cpg.dentry) ++ && cpg.bdst < au_dbtop(cpg.dentry)) { ++ err = au_test_and_cpup_dirs(cpg.dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ /* always superio. */ ++ err = au_pin(&pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ } else if (hi_wh) { ++ /* already copied-up after unlink */ ++ err = au_reopen_wh(file, cpg.bdst, hi_wh); ++ *need_reopen = 0; ++ } ++ ++out_unlock: ++ di_read_unlock(parent, AuLock_IR); ++out_parent: ++ dput(parent); ++out: ++ return err; ++} ++ ++static void au_do_refresh_dir(struct file *file) ++{ ++ aufs_bindex_t bindex, bbot, new_bindex, brid; ++ struct au_hfile *p, tmp, *q; ++ struct au_finfo *finfo; ++ struct super_block *sb; ++ struct au_fidir *fidir; ++ ++ FiMustWriteLock(file); ++ ++ sb = file->f_path.dentry->d_sb; ++ finfo = au_fi(file); ++ fidir = finfo->fi_hdir; ++ AuDebugOn(!fidir); ++ p = fidir->fd_hfile + finfo->fi_btop; ++ brid = p->hf_br->br_id; ++ bbot = fidir->fd_bbot; ++ for (bindex = finfo->fi_btop; bindex <= bbot; bindex++, p++) { ++ if (!p->hf_file) ++ continue; ++ ++ new_bindex = au_br_index(sb, p->hf_br->br_id); ++ if (new_bindex == bindex) ++ continue; ++ if (new_bindex < 0) { ++ au_set_h_fptr(file, bindex, NULL); ++ continue; ++ } ++ ++ /* swap two lower inode, and loop again */ ++ q = fidir->fd_hfile + new_bindex; ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hf_file) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ p = fidir->fd_hfile; ++ if (!au_test_mmapped(file) && !d_unlinked(file->f_path.dentry)) { ++ bbot = au_sbbot(sb); ++ for (finfo->fi_btop = 0; finfo->fi_btop <= bbot; ++ finfo->fi_btop++, p++) ++ if (p->hf_file) { ++ if (file_inode(p->hf_file)) ++ break; ++ au_hfput(p, file); ++ } ++ } else { ++ bbot = au_br_index(sb, brid); ++ for (finfo->fi_btop = 0; finfo->fi_btop < bbot; ++ finfo->fi_btop++, p++) ++ if (p->hf_file) ++ au_hfput(p, file); ++ bbot = au_sbbot(sb); ++ } ++ ++ p = fidir->fd_hfile + bbot; ++ for (fidir->fd_bbot = bbot; fidir->fd_bbot >= finfo->fi_btop; ++ fidir->fd_bbot--, p--) ++ if (p->hf_file) { ++ if (file_inode(p->hf_file)) ++ break; ++ au_hfput(p, file); ++ } ++ AuDebugOn(fidir->fd_bbot < finfo->fi_btop); ++} ++ ++/* ++ * after branch manipulating, refresh the file. ++ */ ++static int refresh_file(struct file *file, int (*reopen)(struct file *file)) ++{ ++ int err, need_reopen; ++ aufs_bindex_t bbot, bindex; ++ struct dentry *dentry; ++ struct au_finfo *finfo; ++ struct au_hfile *hfile; ++ ++ dentry = file->f_path.dentry; ++ finfo = au_fi(file); ++ if (!finfo->fi_hdir) { ++ hfile = &finfo->fi_htop; ++ AuDebugOn(!hfile->hf_file); ++ bindex = au_br_index(dentry->d_sb, hfile->hf_br->br_id); ++ AuDebugOn(bindex < 0); ++ if (bindex != finfo->fi_btop) ++ au_set_fbtop(file, bindex); ++ } else { ++ err = au_fidir_realloc(finfo, au_sbbot(dentry->d_sb) + 1); ++ if (unlikely(err)) ++ goto out; ++ au_do_refresh_dir(file); ++ } ++ ++ err = 0; ++ need_reopen = 1; ++ if (!au_test_mmapped(file)) ++ err = au_file_refresh_by_inode(file, &need_reopen); ++ if (!err && need_reopen && !d_unlinked(dentry)) ++ err = reopen(file); ++ if (!err) { ++ au_update_figen(file); ++ goto out; /* success */ ++ } ++ ++ /* error, close all lower files */ ++ if (finfo->fi_hdir) { ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); bindex <= bbot; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ } ++ ++out: ++ return err; ++} ++ ++/* common function to regular file and dir */ ++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), ++ int wlock) ++{ ++ int err; ++ unsigned int sigen, figen; ++ aufs_bindex_t btop; ++ unsigned char pseudo_link; ++ struct dentry *dentry; ++ struct inode *inode; ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ sigen = au_sigen(dentry->d_sb); ++ fi_write_lock(file); ++ figen = au_figen(file); ++ di_write_lock_child(dentry); ++ btop = au_dbtop(dentry); ++ pseudo_link = (btop != au_ibtop(inode)); ++ if (sigen == figen && !pseudo_link && au_fbtop(file) == btop) { ++ if (!wlock) { ++ di_downgrade_lock(dentry, AuLock_IR); ++ fi_downgrade_lock(file); ++ } ++ goto out; /* success */ ++ } ++ ++ AuDbg("sigen %d, figen %d\n", sigen, figen); ++ if (au_digen_test(dentry, sigen)) { ++ err = au_reval_dpath(dentry, sigen); ++ AuDebugOn(!err && au_digen_test(dentry, sigen)); ++ } ++ ++ if (!err) ++ err = refresh_file(file, reopen); ++ if (!err) { ++ if (!wlock) { ++ di_downgrade_lock(dentry, AuLock_IR); ++ fi_downgrade_lock(file); ++ } ++ } else { ++ di_write_unlock(dentry); ++ fi_write_unlock(file); ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* cf. aufs_nopage() */ ++/* for madvise(2) */ ++static int aufs_readpage(struct file *file __maybe_unused, struct page *page) ++{ ++ unlock_page(page); ++ return 0; ++} ++ ++/* it will never be called, but necessary to support O_DIRECT */ ++static ssize_t aufs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ++{ BUG(); return 0; } ++ ++/* they will never be called. */ ++#ifdef CONFIG_AUFS_DEBUG ++static int aufs_write_begin(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned flags, ++ struct page **pagep, void **fsdata) ++{ AuUnsupport(); return 0; } ++static int aufs_write_end(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned copied, ++ struct page *page, void *fsdata) ++{ AuUnsupport(); return 0; } ++static int aufs_writepage(struct page *page, struct writeback_control *wbc) ++{ AuUnsupport(); return 0; } ++ ++static int aufs_set_page_dirty(struct page *page) ++{ AuUnsupport(); return 0; } ++static void aufs_invalidatepage(struct page *page, unsigned int offset, ++ unsigned int length) ++{ AuUnsupport(); } ++static int aufs_releasepage(struct page *page, gfp_t gfp) ++{ AuUnsupport(); return 0; } ++#if 0 /* called by memory compaction regardless file */ ++static int aufs_migratepage(struct address_space *mapping, struct page *newpage, ++ struct page *page, enum migrate_mode mode) ++{ AuUnsupport(); return 0; } ++#endif ++static int aufs_launder_page(struct page *page) ++{ AuUnsupport(); return 0; } ++static int aufs_is_partially_uptodate(struct page *page, ++ unsigned long from, ++ unsigned long count) ++{ AuUnsupport(); return 0; } ++static void aufs_is_dirty_writeback(struct page *page, bool *dirty, ++ bool *writeback) ++{ AuUnsupport(); } ++static int aufs_error_remove_page(struct address_space *mapping, ++ struct page *page) ++{ AuUnsupport(); return 0; } ++static int aufs_swap_activate(struct swap_info_struct *sis, struct file *file, ++ sector_t *span) ++{ AuUnsupport(); return 0; } ++static void aufs_swap_deactivate(struct file *file) ++{ AuUnsupport(); } ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++const struct address_space_operations aufs_aop = { ++ .readpage = aufs_readpage, ++ .direct_IO = aufs_direct_IO, ++#ifdef CONFIG_AUFS_DEBUG ++ .writepage = aufs_writepage, ++ /* no writepages, because of writepage */ ++ .set_page_dirty = aufs_set_page_dirty, ++ /* no readpages, because of readpage */ ++ .write_begin = aufs_write_begin, ++ .write_end = aufs_write_end, ++ /* no bmap, no block device */ ++ .invalidatepage = aufs_invalidatepage, ++ .releasepage = aufs_releasepage, ++ /* is fallback_migrate_page ok? */ ++ /* .migratepage = aufs_migratepage, */ ++ .launder_page = aufs_launder_page, ++ .is_partially_uptodate = aufs_is_partially_uptodate, ++ .is_dirty_writeback = aufs_is_dirty_writeback, ++ .error_remove_page = aufs_error_remove_page, ++ .swap_activate = aufs_swap_activate, ++ .swap_deactivate = aufs_swap_deactivate ++#endif /* CONFIG_AUFS_DEBUG */ ++}; +diff --git a/fs/aufs/file.h b/fs/aufs/file.h +new file mode 100644 +index 0000000..96ab0a0 +--- /dev/null ++++ b/fs/aufs/file.h +@@ -0,0 +1,278 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * file operations ++ */ ++ ++#ifndef __AUFS_FILE_H__ ++#define __AUFS_FILE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include "rwsem.h" ++ ++struct au_branch; ++struct au_hfile { ++ struct file *hf_file; ++ struct au_branch *hf_br; ++}; ++ ++struct au_vdir; ++struct au_fidir { ++ aufs_bindex_t fd_bbot; ++ aufs_bindex_t fd_nent; ++ struct au_vdir *fd_vdir_cache; ++ struct au_hfile fd_hfile[]; ++}; ++ ++static inline int au_fidir_sz(int nent) ++{ ++ AuDebugOn(nent < 0); ++ return sizeof(struct au_fidir) + sizeof(struct au_hfile) * nent; ++} ++ ++struct au_finfo { ++ atomic_t fi_generation; ++ ++ struct au_rwsem fi_rwsem; ++ aufs_bindex_t fi_btop; ++ ++ /* do not union them */ ++ struct { /* for non-dir */ ++ struct au_hfile fi_htop; ++ atomic_t fi_mmapped; ++ }; ++ struct au_fidir *fi_hdir; /* for dir only */ ++ ++ struct hlist_node fi_hlist; ++ struct file *fi_file; /* very ugly */ ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* file.c */ ++extern const struct address_space_operations aufs_aop; ++unsigned int au_file_roflags(unsigned int flags); ++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, ++ struct file *file, int force_wr); ++struct au_do_open_args { ++ int no_lock; ++ int (*open)(struct file *file, int flags, ++ struct file *h_file); ++ struct au_fidir *fidir; ++ struct file *h_file; ++}; ++int au_do_open(struct file *file, struct au_do_open_args *args); ++int au_reopen_nondir(struct file *file); ++struct au_pin; ++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin); ++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), ++ int wlock); ++int au_do_flush(struct file *file, fl_owner_t id, ++ int (*flush)(struct file *file, fl_owner_t id)); ++ ++/* poll.c */ ++#ifdef CONFIG_AUFS_POLL ++unsigned int aufs_poll(struct file *file, poll_table *wait); ++#endif ++ ++#ifdef CONFIG_AUFS_BR_HFSPLUS ++/* hfsplus.c */ ++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, ++ int force_wr); ++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file); ++#else ++AuStub(struct file *, au_h_open_pre, return NULL, struct dentry *dentry, ++ aufs_bindex_t bindex, int force_wr) ++AuStubVoid(au_h_open_post, struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file); ++#endif ++ ++/* f_op.c */ ++extern const struct file_operations aufs_file_fop; ++int au_do_open_nondir(struct file *file, int flags, struct file *h_file); ++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file); ++struct file *au_read_pre(struct file *file, int keep_fi); ++ ++/* finfo.c */ ++void au_hfput(struct au_hfile *hf, struct file *file); ++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, ++ struct file *h_file); ++ ++void au_update_figen(struct file *file); ++struct au_fidir *au_fidir_alloc(struct super_block *sb); ++int au_fidir_realloc(struct au_finfo *finfo, int nbr); ++ ++void au_fi_init_once(void *_fi); ++void au_finfo_fin(struct file *file); ++int au_finfo_init(struct file *file, struct au_fidir *fidir); ++ ++/* ioctl.c */ ++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, ++ unsigned long arg); ++long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, ++ unsigned long arg); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_finfo *au_fi(struct file *file) ++{ ++ return file->private_data; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * fi_read_lock, fi_write_lock, ++ * fi_read_unlock, fi_write_unlock, fi_downgrade_lock ++ */ ++AuSimpleRwsemFuncs(fi, struct file *f, &au_fi(f)->fi_rwsem); ++ ++#define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem) ++#define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem) ++#define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: hard/soft set? */ ++static inline aufs_bindex_t au_fbtop(struct file *file) ++{ ++ FiMustAnyLock(file); ++ return au_fi(file)->fi_btop; ++} ++ ++static inline aufs_bindex_t au_fbbot_dir(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_bbot; ++} ++ ++static inline struct au_vdir *au_fvdir_cache(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_vdir_cache; ++} ++ ++static inline void au_set_fbtop(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ au_fi(file)->fi_btop = bindex; ++} ++ ++static inline void au_set_fbbot_dir(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ au_fi(file)->fi_hdir->fd_bbot = bindex; ++} ++ ++static inline void au_set_fvdir_cache(struct file *file, ++ struct au_vdir *vdir_cache) ++{ ++ FiMustWriteLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ au_fi(file)->fi_hdir->fd_vdir_cache = vdir_cache; ++} ++ ++static inline struct file *au_hf_top(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_htop.hf_file; ++} ++ ++static inline struct file *au_hf_dir(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_hfile[0 + bindex].hf_file; ++} ++ ++/* todo: memory barrier? */ ++static inline unsigned int au_figen(struct file *f) ++{ ++ return atomic_read(&au_fi(f)->fi_generation); ++} ++ ++static inline void au_set_mmapped(struct file *f) ++{ ++ if (atomic_inc_return(&au_fi(f)->fi_mmapped)) ++ return; ++ pr_warn("fi_mmapped wrapped around\n"); ++ while (!atomic_inc_return(&au_fi(f)->fi_mmapped)) ++ ; ++} ++ ++static inline void au_unset_mmapped(struct file *f) ++{ ++ atomic_dec(&au_fi(f)->fi_mmapped); ++} ++ ++static inline int au_test_mmapped(struct file *f) ++{ ++ return atomic_read(&au_fi(f)->fi_mmapped); ++} ++ ++/* customize vma->vm_file */ ++ ++static inline void au_do_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ struct file *f; ++ ++ f = vma->vm_file; ++ get_file(file); ++ vma->vm_file = file; ++ fput(f); ++} ++ ++#ifdef CONFIG_MMU ++#define AuDbgVmRegion(file, vma) do {} while (0) ++ ++static inline void au_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ au_do_vm_file_reset(vma, file); ++} ++#else ++#define AuDbgVmRegion(file, vma) \ ++ AuDebugOn((vma)->vm_region && (vma)->vm_region->vm_file != (file)) ++ ++static inline void au_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ struct file *f; ++ ++ au_do_vm_file_reset(vma, file); ++ f = vma->vm_region->vm_file; ++ get_file(file); ++ vma->vm_region->vm_file = file; ++ fput(f); ++} ++#endif /* CONFIG_MMU */ ++ ++/* handle vma->vm_prfile */ ++static inline void au_vm_prfile_set(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ get_file(file); ++ vma->vm_prfile = file; ++#ifndef CONFIG_MMU ++ get_file(file); ++ vma->vm_region->vm_prfile = file; ++#endif ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FILE_H__ */ +diff --git a/fs/aufs/finfo.c b/fs/aufs/finfo.c +new file mode 100644 +index 0000000..07f6eb3 +--- /dev/null ++++ b/fs/aufs/finfo.c +@@ -0,0 +1,136 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * file private data ++ */ ++ ++#include "aufs.h" ++ ++void au_hfput(struct au_hfile *hf, struct file *file) ++{ ++ /* todo: direct access f_flags */ ++ if (vfsub_file_flags(file) & __FMODE_EXEC) ++ allow_write_access(hf->hf_file); ++ fput(hf->hf_file); ++ hf->hf_file = NULL; ++ au_br_put(hf->hf_br); ++ hf->hf_br = NULL; ++} ++ ++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val) ++{ ++ struct au_finfo *finfo = au_fi(file); ++ struct au_hfile *hf; ++ struct au_fidir *fidir; ++ ++ fidir = finfo->fi_hdir; ++ if (!fidir) { ++ AuDebugOn(finfo->fi_btop != bindex); ++ hf = &finfo->fi_htop; ++ } else ++ hf = fidir->fd_hfile + bindex; ++ ++ if (hf && hf->hf_file) ++ au_hfput(hf, file); ++ if (val) { ++ FiMustWriteLock(file); ++ AuDebugOn(IS_ERR_OR_NULL(file->f_path.dentry)); ++ hf->hf_file = val; ++ hf->hf_br = au_sbr(file->f_path.dentry->d_sb, bindex); ++ } ++} ++ ++void au_update_figen(struct file *file) ++{ ++ atomic_set(&au_fi(file)->fi_generation, au_digen(file->f_path.dentry)); ++ /* smp_mb(); */ /* atomic_set */ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_fidir *au_fidir_alloc(struct super_block *sb) ++{ ++ struct au_fidir *fidir; ++ int nbr; ++ ++ nbr = au_sbbot(sb) + 1; ++ if (nbr < 2) ++ nbr = 2; /* initial allocate for 2 branches */ ++ fidir = kzalloc(au_fidir_sz(nbr), GFP_NOFS); ++ if (fidir) { ++ fidir->fd_bbot = -1; ++ fidir->fd_nent = nbr; ++ } ++ ++ return fidir; ++} ++ ++int au_fidir_realloc(struct au_finfo *finfo, int nbr) ++{ ++ int err; ++ struct au_fidir *fidir, *p; ++ ++ AuRwMustWriteLock(&finfo->fi_rwsem); ++ fidir = finfo->fi_hdir; ++ AuDebugOn(!fidir); ++ ++ err = -ENOMEM; ++ p = au_kzrealloc(fidir, au_fidir_sz(fidir->fd_nent), au_fidir_sz(nbr), ++ GFP_NOFS); ++ if (p) { ++ p->fd_nent = nbr; ++ finfo->fi_hdir = p; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_finfo_fin(struct file *file) ++{ ++ struct au_finfo *finfo; ++ ++ au_nfiles_dec(file->f_path.dentry->d_sb); ++ ++ finfo = au_fi(file); ++ AuDebugOn(finfo->fi_hdir); ++ AuRwDestroy(&finfo->fi_rwsem); ++ au_cache_free_finfo(finfo); ++} ++ ++void au_fi_init_once(void *_finfo) ++{ ++ struct au_finfo *finfo = _finfo; ++ ++ au_rw_init(&finfo->fi_rwsem); ++} ++ ++int au_finfo_init(struct file *file, struct au_fidir *fidir) ++{ ++ int err; ++ struct au_finfo *finfo; ++ struct dentry *dentry; ++ ++ err = -ENOMEM; ++ dentry = file->f_path.dentry; ++ finfo = au_cache_alloc_finfo(); ++ if (unlikely(!finfo)) ++ goto out; ++ ++ err = 0; ++ au_nfiles_inc(dentry->d_sb); ++ au_rw_write_lock(&finfo->fi_rwsem); ++ finfo->fi_btop = -1; ++ finfo->fi_hdir = fidir; ++ atomic_set(&finfo->fi_generation, au_digen(dentry)); ++ /* smp_mb(); */ /* atomic_set */ ++ ++ file->private_data = finfo; ++ ++out: ++ return err; ++} +diff --git a/fs/aufs/fstype.h b/fs/aufs/fstype.h +new file mode 100644 +index 0000000..725b2ff +--- /dev/null ++++ b/fs/aufs/fstype.h +@@ -0,0 +1,387 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * judging filesystem type ++ */ ++ ++#ifndef __AUFS_FSTYPE_H__ ++#define __AUFS_FSTYPE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++ ++static inline int au_test_aufs(struct super_block *sb) ++{ ++ return sb->s_magic == AUFS_SUPER_MAGIC; ++} ++ ++static inline const char *au_sbtype(struct super_block *sb) ++{ ++ return sb->s_type->name; ++} ++ ++static inline int au_test_iso9660(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_ISO9660_FS) || defined(CONFIG_ISO9660_FS_MODULE) ++ return sb->s_magic == ISOFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_romfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_ROMFS_FS) || defined(CONFIG_ROMFS_FS_MODULE) ++ return sb->s_magic == ROMFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_cramfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_CRAMFS) || defined(CONFIG_CRAMFS_MODULE) ++ return sb->s_magic == CRAMFS_MAGIC; ++#endif ++ return 0; ++} ++ ++static inline int au_test_nfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_NFS_FS) || defined(CONFIG_NFS_FS_MODULE) ++ return sb->s_magic == NFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_fuse(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_FUSE_FS) || defined(CONFIG_FUSE_FS_MODULE) ++ return sb->s_magic == FUSE_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_xfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_XFS_FS) || defined(CONFIG_XFS_FS_MODULE) ++ return sb->s_magic == XFS_SB_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_tmpfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_TMPFS ++ return sb->s_magic == TMPFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_ecryptfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_ECRYPT_FS) || defined(CONFIG_ECRYPT_FS_MODULE) ++ return !strcmp(au_sbtype(sb), "ecryptfs"); ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_ramfs(struct super_block *sb) ++{ ++ return sb->s_magic == RAMFS_MAGIC; ++} ++ ++static inline int au_test_ubifs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_UBIFS_FS) || defined(CONFIG_UBIFS_FS_MODULE) ++ return sb->s_magic == UBIFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_procfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_PROC_FS ++ return sb->s_magic == PROC_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_sysfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_SYSFS ++ return sb->s_magic == SYSFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_configfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_CONFIGFS_FS) || defined(CONFIG_CONFIGFS_FS_MODULE) ++ return sb->s_magic == CONFIGFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_minix(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_MINIX_FS) || defined(CONFIG_MINIX_FS_MODULE) ++ return sb->s_magic == MINIX3_SUPER_MAGIC ++ || sb->s_magic == MINIX2_SUPER_MAGIC ++ || sb->s_magic == MINIX2_SUPER_MAGIC2 ++ || sb->s_magic == MINIX_SUPER_MAGIC ++ || sb->s_magic == MINIX_SUPER_MAGIC2; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_fat(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_FAT_FS) || defined(CONFIG_FAT_FS_MODULE) ++ return sb->s_magic == MSDOS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_msdos(struct super_block *sb) ++{ ++ return au_test_fat(sb); ++} ++ ++static inline int au_test_vfat(struct super_block *sb) ++{ ++ return au_test_fat(sb); ++} ++ ++static inline int au_test_securityfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_SECURITYFS ++ return sb->s_magic == SECURITYFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_squashfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_SQUASHFS) || defined(CONFIG_SQUASHFS_MODULE) ++ return sb->s_magic == SQUASHFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_btrfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_BTRFS_FS) || defined(CONFIG_BTRFS_FS_MODULE) ++ return sb->s_magic == BTRFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_xenfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_XENFS) || defined(CONFIG_XENFS_MODULE) ++ return sb->s_magic == XENFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_debugfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_DEBUG_FS ++ return sb->s_magic == DEBUGFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_nilfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_NILFS) || defined(CONFIG_NILFS_MODULE) ++ return sb->s_magic == NILFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_hfsplus(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_HFSPLUS_FS) || defined(CONFIG_HFSPLUS_FS_MODULE) ++ return sb->s_magic == HFSPLUS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * they can't be an aufs branch. ++ */ ++static inline int au_test_fs_unsuppoted(struct super_block *sb) ++{ ++ return ++#ifndef CONFIG_AUFS_BR_RAMFS ++ au_test_ramfs(sb) || ++#endif ++ au_test_procfs(sb) ++ || au_test_sysfs(sb) ++ || au_test_configfs(sb) ++ || au_test_debugfs(sb) ++ || au_test_securityfs(sb) ++ || au_test_xenfs(sb) ++ || au_test_ecryptfs(sb) ++ /* || !strcmp(au_sbtype(sb), "unionfs") */ ++ || au_test_aufs(sb); /* will be supported in next version */ ++} ++ ++static inline int au_test_fs_remote(struct super_block *sb) ++{ ++ return !au_test_tmpfs(sb) ++#ifdef CONFIG_AUFS_BR_RAMFS ++ && !au_test_ramfs(sb) ++#endif ++ && !(sb->s_type->fs_flags & FS_REQUIRES_DEV); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * Note: these functions (below) are created after reading ->getattr() in all ++ * filesystems under linux/fs. it means we have to do so in every update... ++ */ ++ ++/* ++ * some filesystems require getattr to refresh the inode attributes before ++ * referencing. ++ * in most cases, we can rely on the inode attribute in NFS (or every remote fs) ++ * and leave the work for d_revalidate() ++ */ ++static inline int au_test_fs_refresh_iattr(struct super_block *sb) ++{ ++ return au_test_nfs(sb) ++ || au_test_fuse(sb) ++ /* || au_test_btrfs(sb) */ /* untested */ ++ ; ++} ++ ++/* ++ * filesystems which don't maintain i_size or i_blocks. ++ */ ++static inline int au_test_fs_bad_iattr_size(struct super_block *sb) ++{ ++ return au_test_xfs(sb) ++ || au_test_btrfs(sb) ++ || au_test_ubifs(sb) ++ || au_test_hfsplus(sb) /* maintained, but incorrect */ ++ /* || au_test_minix(sb) */ /* untested */ ++ ; ++} ++ ++/* ++ * filesystems which don't store the correct value in some of their inode ++ * attributes. ++ */ ++static inline int au_test_fs_bad_iattr(struct super_block *sb) ++{ ++ return au_test_fs_bad_iattr_size(sb) ++ || au_test_fat(sb) ++ || au_test_msdos(sb) ++ || au_test_vfat(sb); ++} ++ ++/* they don't check i_nlink in link(2) */ ++static inline int au_test_fs_no_limit_nlink(struct super_block *sb) ++{ ++ return au_test_tmpfs(sb) ++#ifdef CONFIG_AUFS_BR_RAMFS ++ || au_test_ramfs(sb) ++#endif ++ || au_test_ubifs(sb) ++ || au_test_hfsplus(sb); ++} ++ ++/* ++ * filesystems which sets S_NOATIME and S_NOCMTIME. ++ */ ++static inline int au_test_fs_notime(struct super_block *sb) ++{ ++ return au_test_nfs(sb) ++ || au_test_fuse(sb) ++ || au_test_ubifs(sb) ++ ; ++} ++ ++/* temporary support for i#1 in cramfs */ ++static inline int au_test_fs_unique_ino(struct inode *inode) ++{ ++ if (au_test_cramfs(inode->i_sb)) ++ return inode->i_ino != 1; ++ return 1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * the filesystem where the xino files placed must support i/o after unlink and ++ * maintain i_size and i_blocks. ++ */ ++static inline int au_test_fs_bad_xino(struct super_block *sb) ++{ ++ return au_test_fs_remote(sb) ++ || au_test_fs_bad_iattr_size(sb) ++ /* don't want unnecessary work for xino */ ++ || au_test_aufs(sb) ++ || au_test_ecryptfs(sb) ++ || au_test_nilfs(sb); ++} ++ ++static inline int au_test_fs_trunc_xino(struct super_block *sb) ++{ ++ return au_test_tmpfs(sb) ++ || au_test_ramfs(sb); ++} ++ ++/* ++ * test if the @sb is real-readonly. ++ */ ++static inline int au_test_fs_rr(struct super_block *sb) ++{ ++ return au_test_squashfs(sb) ++ || au_test_iso9660(sb) ++ || au_test_cramfs(sb) ++ || au_test_romfs(sb); ++} ++ ++/* ++ * test if the @inode is nfs with 'noacl' option ++ * NFS always sets MS_POSIXACL regardless its mount option 'noacl.' ++ */ ++static inline int au_test_nfs_noacl(struct inode *inode) ++{ ++ return au_test_nfs(inode->i_sb) ++ /* && IS_POSIXACL(inode) */ ++ && !nfs_server_capable(inode, NFS_CAP_ACLS); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FSTYPE_H__ */ +diff --git a/fs/aufs/hfsnotify.c b/fs/aufs/hfsnotify.c +new file mode 100644 +index 0000000..6afef3f +--- /dev/null ++++ b/fs/aufs/hfsnotify.c +@@ -0,0 +1,274 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * fsnotify for the lower directories ++ */ ++ ++#include "aufs.h" ++ ++/* FS_IN_IGNORED is unnecessary */ ++static const __u32 AuHfsnMask = (FS_MOVED_TO | FS_MOVED_FROM | FS_DELETE ++ | FS_CREATE | FS_EVENT_ON_CHILD); ++static DECLARE_WAIT_QUEUE_HEAD(au_hfsn_wq); ++static __cacheline_aligned_in_smp atomic64_t au_hfsn_ifree = ATOMIC64_INIT(0); ++ ++static void au_hfsn_free_mark(struct fsnotify_mark *mark) ++{ ++ struct au_hnotify *hn = container_of(mark, struct au_hnotify, ++ hn_mark); ++ /* AuDbg("here\n"); */ ++ au_cache_free_hnotify(hn); ++ smp_mb__before_atomic(); ++ if (atomic64_dec_and_test(&au_hfsn_ifree)) ++ wake_up(&au_hfsn_wq); ++} ++ ++static int au_hfsn_alloc(struct au_hinode *hinode) ++{ ++ int err; ++ struct au_hnotify *hn; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct fsnotify_mark *mark; ++ aufs_bindex_t bindex; ++ ++ hn = hinode->hi_notify; ++ sb = hn->hn_aufs_inode->i_sb; ++ bindex = au_br_index(sb, hinode->hi_id); ++ br = au_sbr(sb, bindex); ++ AuDebugOn(!br->br_hfsn); ++ ++ mark = &hn->hn_mark; ++ fsnotify_init_mark(mark, au_hfsn_free_mark); ++ mark->mask = AuHfsnMask; ++ /* ++ * by udba rename or rmdir, aufs assign a new inode to the known ++ * h_inode, so specify 1 to allow dups. ++ */ ++ lockdep_off(); ++ err = fsnotify_add_mark(mark, br->br_hfsn->hfsn_group, hinode->hi_inode, ++ /*mnt*/NULL, /*allow_dups*/1); ++ lockdep_on(); ++ ++ return err; ++} ++ ++static int au_hfsn_free(struct au_hinode *hinode, struct au_hnotify *hn) ++{ ++ struct fsnotify_mark *mark; ++ unsigned long long ull; ++ struct fsnotify_group *group; ++ ++ ull = atomic64_inc_return(&au_hfsn_ifree); ++ BUG_ON(!ull); ++ ++ mark = &hn->hn_mark; ++ spin_lock(&mark->lock); ++ group = mark->group; ++ fsnotify_get_group(group); ++ spin_unlock(&mark->lock); ++ lockdep_off(); ++ fsnotify_destroy_mark(mark, group); ++ fsnotify_put_mark(mark); ++ fsnotify_put_group(group); ++ lockdep_on(); ++ ++ /* free hn by myself */ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_ctl(struct au_hinode *hinode, int do_set) ++{ ++ struct fsnotify_mark *mark; ++ ++ mark = &hinode->hi_notify->hn_mark; ++ spin_lock(&mark->lock); ++ if (do_set) { ++ AuDebugOn(mark->mask & AuHfsnMask); ++ mark->mask |= AuHfsnMask; ++ } else { ++ AuDebugOn(!(mark->mask & AuHfsnMask)); ++ mark->mask &= ~AuHfsnMask; ++ } ++ spin_unlock(&mark->lock); ++ /* fsnotify_recalc_inode_mask(hinode->hi_inode); */ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* #define AuDbgHnotify */ ++#ifdef AuDbgHnotify ++static char *au_hfsn_name(u32 mask) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++#define test_ret(flag) \ ++ do { \ ++ if (mask & flag) \ ++ return #flag; \ ++ } while (0) ++ test_ret(FS_ACCESS); ++ test_ret(FS_MODIFY); ++ test_ret(FS_ATTRIB); ++ test_ret(FS_CLOSE_WRITE); ++ test_ret(FS_CLOSE_NOWRITE); ++ test_ret(FS_OPEN); ++ test_ret(FS_MOVED_FROM); ++ test_ret(FS_MOVED_TO); ++ test_ret(FS_CREATE); ++ test_ret(FS_DELETE); ++ test_ret(FS_DELETE_SELF); ++ test_ret(FS_MOVE_SELF); ++ test_ret(FS_UNMOUNT); ++ test_ret(FS_Q_OVERFLOW); ++ test_ret(FS_IN_IGNORED); ++ test_ret(FS_ISDIR); ++ test_ret(FS_IN_ONESHOT); ++ test_ret(FS_EVENT_ON_CHILD); ++ return ""; ++#undef test_ret ++#else ++ return "??"; ++#endif ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_free_group(struct fsnotify_group *group) ++{ ++ struct au_br_hfsnotify *hfsn = group->private; ++ ++ /* AuDbg("here\n"); */ ++ kfree(hfsn); ++} ++ ++static int au_hfsn_handle_event(struct fsnotify_group *group, ++ struct inode *inode, ++ struct fsnotify_mark *inode_mark, ++ struct fsnotify_mark *vfsmount_mark, ++ u32 mask, void *data, int data_type, ++ const unsigned char *file_name, u32 cookie) ++{ ++ int err; ++ struct au_hnotify *hnotify; ++ struct inode *h_dir, *h_inode; ++ struct qstr h_child_qstr = QSTR_INIT(file_name, strlen(file_name)); ++ ++ AuDebugOn(data_type != FSNOTIFY_EVENT_INODE); ++ ++ err = 0; ++ /* if FS_UNMOUNT happens, there must be another bug */ ++ AuDebugOn(mask & FS_UNMOUNT); ++ if (mask & (FS_IN_IGNORED | FS_UNMOUNT)) ++ goto out; ++ ++ h_dir = inode; ++ h_inode = NULL; ++#ifdef AuDbgHnotify ++ au_debug_on(); ++ if (1 || h_child_qstr.len != sizeof(AUFS_XINO_FNAME) - 1 ++ || strncmp(h_child_qstr.name, AUFS_XINO_FNAME, h_child_qstr.len)) { ++ AuDbg("i%lu, mask 0x%x %s, hcname %.*s, hi%lu\n", ++ h_dir->i_ino, mask, au_hfsn_name(mask), ++ AuLNPair(&h_child_qstr), h_inode ? h_inode->i_ino : 0); ++ /* WARN_ON(1); */ ++ } ++ au_debug_off(); ++#endif ++ ++ AuDebugOn(!inode_mark); ++ hnotify = container_of(inode_mark, struct au_hnotify, hn_mark); ++ err = au_hnotify(h_dir, hnotify, mask, &h_child_qstr, h_inode); ++ ++out: ++ return err; ++} ++ ++static struct fsnotify_ops au_hfsn_ops = { ++ .handle_event = au_hfsn_handle_event, ++ .free_group_priv = au_hfsn_free_group ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_fin_br(struct au_branch *br) ++{ ++ struct au_br_hfsnotify *hfsn; ++ ++ hfsn = br->br_hfsn; ++ if (hfsn) { ++ lockdep_off(); ++ fsnotify_put_group(hfsn->hfsn_group); ++ lockdep_on(); ++ } ++} ++ ++static int au_hfsn_init_br(struct au_branch *br, int perm) ++{ ++ int err; ++ struct fsnotify_group *group; ++ struct au_br_hfsnotify *hfsn; ++ ++ err = 0; ++ br->br_hfsn = NULL; ++ if (!au_br_hnotifyable(perm)) ++ goto out; ++ ++ err = -ENOMEM; ++ hfsn = kmalloc(sizeof(*hfsn), GFP_NOFS); ++ if (unlikely(!hfsn)) ++ goto out; ++ ++ err = 0; ++ group = fsnotify_alloc_group(&au_hfsn_ops); ++ if (IS_ERR(group)) { ++ err = PTR_ERR(group); ++ pr_err("fsnotify_alloc_group() failed, %d\n", err); ++ goto out_hfsn; ++ } ++ ++ group->private = hfsn; ++ hfsn->hfsn_group = group; ++ br->br_hfsn = hfsn; ++ goto out; /* success */ ++ ++out_hfsn: ++ kfree(hfsn); ++out: ++ return err; ++} ++ ++static int au_hfsn_reset_br(unsigned int udba, struct au_branch *br, int perm) ++{ ++ int err; ++ ++ err = 0; ++ if (!br->br_hfsn) ++ err = au_hfsn_init_br(br, perm); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_fin(void) ++{ ++ AuDbg("au_hfsn_ifree %lld\n", (long long)atomic64_read(&au_hfsn_ifree)); ++ wait_event(au_hfsn_wq, !atomic64_read(&au_hfsn_ifree)); ++} ++ ++const struct au_hnotify_op au_hnotify_op = { ++ .ctl = au_hfsn_ctl, ++ .alloc = au_hfsn_alloc, ++ .free = au_hfsn_free, ++ ++ .fin = au_hfsn_fin, ++ ++ .reset_br = au_hfsn_reset_br, ++ .fin_br = au_hfsn_fin_br, ++ .init_br = au_hfsn_init_br ++}; +diff --git a/fs/aufs/hfsplus.c b/fs/aufs/hfsplus.c +new file mode 100644 +index 0000000..145c6ac +--- /dev/null ++++ b/fs/aufs/hfsplus.c +@@ -0,0 +1,43 @@ ++/* ++ * Copyright (C) 2010-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * special support for filesystems which aqucires an inode mutex ++ * at final closing a file, eg, hfsplus. ++ * ++ * This trick is very simple and stupid, just to open the file before really ++ * neceeary open to tell hfsplus that this is not the final closing. ++ * The caller should call au_h_open_pre() after acquiring the inode mutex, ++ * and au_h_open_post() after releasing it. ++ */ ++ ++#include "aufs.h" ++ ++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, ++ int force_wr) ++{ ++ struct file *h_file; ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ AuDebugOn(!h_dentry); ++ AuDebugOn(d_is_negative(h_dentry)); ++ ++ h_file = NULL; ++ if (au_test_hfsplus(h_dentry->d_sb) ++ && d_is_reg(h_dentry)) ++ h_file = au_h_open(dentry, bindex, ++ O_RDONLY | O_NOATIME | O_LARGEFILE, ++ /*file*/NULL, force_wr); ++ return h_file; ++} ++ ++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file) ++{ ++ if (h_file) { ++ fput(h_file); ++ au_sbr_put(dentry->d_sb, bindex); ++ } ++} +diff --git a/fs/aufs/hnotify.c b/fs/aufs/hnotify.c +new file mode 100644 +index 0000000..3016c5e +--- /dev/null ++++ b/fs/aufs/hnotify.c +@@ -0,0 +1,697 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * abstraction to notify the direct changes on lower directories ++ */ ++ ++#include "aufs.h" ++ ++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode) ++{ ++ int err; ++ struct au_hnotify *hn; ++ ++ err = -ENOMEM; ++ hn = au_cache_alloc_hnotify(); ++ if (hn) { ++ hn->hn_aufs_inode = inode; ++ hinode->hi_notify = hn; ++ err = au_hnotify_op.alloc(hinode); ++ AuTraceErr(err); ++ if (unlikely(err)) { ++ hinode->hi_notify = NULL; ++ au_cache_free_hnotify(hn); ++ /* ++ * The upper dir was removed by udba, but the same named ++ * dir left. In this case, aufs assignes a new inode ++ * number and set the monitor again. ++ * For the lower dir, the old monitnor is still left. ++ */ ++ if (err == -EEXIST) ++ err = 0; ++ } ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_hn_free(struct au_hinode *hinode) ++{ ++ struct au_hnotify *hn; ++ ++ hn = hinode->hi_notify; ++ if (hn) { ++ hinode->hi_notify = NULL; ++ if (au_hnotify_op.free(hinode, hn)) ++ au_cache_free_hnotify(hn); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_hn_ctl(struct au_hinode *hinode, int do_set) ++{ ++ if (hinode->hi_notify) ++ au_hnotify_op.ctl(hinode, do_set); ++} ++ ++void au_hn_reset(struct inode *inode, unsigned int flags) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct inode *hi; ++ struct dentry *iwhdentry; ++ ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); bindex <= bbot; bindex++) { ++ hi = au_h_iptr(inode, bindex); ++ if (!hi) ++ continue; ++ ++ /* inode_lock_nested(hi, AuLsc_I_CHILD); */ ++ iwhdentry = au_hi_wh(inode, bindex); ++ if (iwhdentry) ++ dget(iwhdentry); ++ au_igrab(hi); ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ au_set_h_iptr(inode, bindex, au_igrab(hi), ++ flags & ~AuHi_XINO); ++ iput(hi); ++ dput(iwhdentry); ++ /* inode_unlock(hi); */ ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int hn_xino(struct inode *inode, struct inode *h_inode) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot, bfound, btop; ++ struct inode *h_i; ++ ++ err = 0; ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("branch root dir was changed\n"); ++ goto out; ++ } ++ ++ bfound = -1; ++ bbot = au_ibbot(inode); ++ btop = au_ibtop(inode); ++#if 0 /* reserved for future use */ ++ if (bindex == bbot) { ++ /* keep this ino in rename case */ ++ goto out; ++ } ++#endif ++ for (bindex = btop; bindex <= bbot; bindex++) ++ if (au_h_iptr(inode, bindex) == h_inode) { ++ bfound = bindex; ++ break; ++ } ++ if (bfound < 0) ++ goto out; ++ ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ h_i = au_h_iptr(inode, bindex); ++ if (!h_i) ++ continue; ++ ++ err = au_xino_write(inode->i_sb, bindex, h_i->i_ino, /*ino*/0); ++ /* ignore this error */ ++ /* bad action? */ ++ } ++ ++ /* children inode number will be broken */ ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int hn_gen_tree(struct dentry *dentry) ++{ ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, dentry, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ struct dentry *d; ++ ++ d = dentries[j]; ++ if (IS_ROOT(d)) ++ continue; ++ ++ au_digen_dec(d); ++ if (d_really_is_positive(d)) ++ /* todo: reset children xino? ++ cached children only? */ ++ au_iigen_dec(d_inode(d)); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++ ++#if 0 ++ /* discard children */ ++ dentry_unhash(dentry); ++ dput(dentry); ++#endif ++out: ++ return err; ++} ++ ++/* ++ * return 0 if processed. ++ */ ++static int hn_gen_by_inode(char *name, unsigned int nlen, struct inode *inode, ++ const unsigned int isdir) ++{ ++ int err; ++ struct dentry *d; ++ struct qstr *dname; ++ ++ err = 1; ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("branch root dir was changed\n"); ++ err = 0; ++ goto out; ++ } ++ ++ if (!isdir) { ++ AuDebugOn(!name); ++ au_iigen_dec(inode); ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) { ++ spin_lock(&d->d_lock); ++ dname = &d->d_name; ++ if (dname->len != nlen ++ && memcmp(dname->name, name, nlen)) { ++ spin_unlock(&d->d_lock); ++ continue; ++ } ++ err = 0; ++ au_digen_dec(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ spin_unlock(&inode->i_lock); ++ } else { ++ au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIR); ++ d = d_find_any_alias(inode); ++ if (!d) { ++ au_iigen_dec(inode); ++ goto out; ++ } ++ ++ spin_lock(&d->d_lock); ++ dname = &d->d_name; ++ if (dname->len == nlen && !memcmp(dname->name, name, nlen)) { ++ spin_unlock(&d->d_lock); ++ err = hn_gen_tree(d); ++ spin_lock(&d->d_lock); ++ } ++ spin_unlock(&d->d_lock); ++ dput(d); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int hn_gen_by_name(struct dentry *dentry, const unsigned int isdir) ++{ ++ int err; ++ ++ if (IS_ROOT(dentry)) { ++ pr_warn("branch root dir was changed\n"); ++ return 0; ++ } ++ ++ err = 0; ++ if (!isdir) { ++ au_digen_dec(dentry); ++ if (d_really_is_positive(dentry)) ++ au_iigen_dec(d_inode(dentry)); ++ } else { ++ au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR); ++ if (d_really_is_positive(dentry)) ++ err = hn_gen_tree(dentry); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* hnotify job flags */ ++#define AuHnJob_XINO0 1 ++#define AuHnJob_GEN (1 << 1) ++#define AuHnJob_DIRENT (1 << 2) ++#define AuHnJob_ISDIR (1 << 3) ++#define AuHnJob_TRYXINO0 (1 << 4) ++#define AuHnJob_MNTPNT (1 << 5) ++#define au_ftest_hnjob(flags, name) ((flags) & AuHnJob_##name) ++#define au_fset_hnjob(flags, name) \ ++ do { (flags) |= AuHnJob_##name; } while (0) ++#define au_fclr_hnjob(flags, name) \ ++ do { (flags) &= ~AuHnJob_##name; } while (0) ++ ++enum { ++ AuHn_CHILD, ++ AuHn_PARENT, ++ AuHnLast ++}; ++ ++struct au_hnotify_args { ++ struct inode *h_dir, *dir, *h_child_inode; ++ u32 mask; ++ unsigned int flags[AuHnLast]; ++ unsigned int h_child_nlen; ++ char h_child_name[]; ++}; ++ ++struct hn_job_args { ++ unsigned int flags; ++ struct inode *inode, *h_inode, *dir, *h_dir; ++ struct dentry *dentry; ++ char *h_name; ++ int h_nlen; ++}; ++ ++static int hn_job(struct hn_job_args *a) ++{ ++ const unsigned int isdir = au_ftest_hnjob(a->flags, ISDIR); ++ int e; ++ ++ /* reset xino */ ++ if (au_ftest_hnjob(a->flags, XINO0) && a->inode) ++ hn_xino(a->inode, a->h_inode); /* ignore this error */ ++ ++ if (au_ftest_hnjob(a->flags, TRYXINO0) ++ && a->inode ++ && a->h_inode) { ++ inode_lock_nested(a->h_inode, AuLsc_I_CHILD); ++ if (!a->h_inode->i_nlink ++ && !(a->h_inode->i_state & I_LINKABLE)) ++ hn_xino(a->inode, a->h_inode); /* ignore this error */ ++ inode_unlock(a->h_inode); ++ } ++ ++ /* make the generation obsolete */ ++ if (au_ftest_hnjob(a->flags, GEN)) { ++ e = -1; ++ if (a->inode) ++ e = hn_gen_by_inode(a->h_name, a->h_nlen, a->inode, ++ isdir); ++ if (e && a->dentry) ++ hn_gen_by_name(a->dentry, isdir); ++ /* ignore this error */ ++ } ++ ++ /* make dir entries obsolete */ ++ if (au_ftest_hnjob(a->flags, DIRENT) && a->inode) { ++ struct au_vdir *vdir; ++ ++ vdir = au_ivdir(a->inode); ++ if (vdir) ++ vdir->vd_jiffy = 0; ++ /* IMustLock(a->inode); */ ++ /* a->inode->i_version++; */ ++ } ++ ++ /* can do nothing but warn */ ++ if (au_ftest_hnjob(a->flags, MNTPNT) ++ && a->dentry ++ && d_mountpoint(a->dentry)) ++ pr_warn("mount-point %pd is removed or renamed\n", a->dentry); ++ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen, ++ struct inode *dir) ++{ ++ struct dentry *dentry, *d, *parent; ++ struct qstr *dname; ++ ++ parent = d_find_any_alias(dir); ++ if (!parent) ++ return NULL; ++ ++ dentry = NULL; ++ spin_lock(&parent->d_lock); ++ list_for_each_entry(d, &parent->d_subdirs, d_child) { ++ /* AuDbg("%pd\n", d); */ ++ spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); ++ dname = &d->d_name; ++ if (dname->len != nlen || memcmp(dname->name, name, nlen)) ++ goto cont_unlock; ++ if (au_di(d)) ++ au_digen_dec(d); ++ else ++ goto cont_unlock; ++ if (au_dcount(d) > 0) { ++ dentry = dget_dlock(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ ++cont_unlock: ++ spin_unlock(&d->d_lock); ++ } ++ spin_unlock(&parent->d_lock); ++ dput(parent); ++ ++ if (dentry) ++ di_write_lock_child(dentry); ++ ++ return dentry; ++} ++ ++static struct inode *lookup_wlock_by_ino(struct super_block *sb, ++ aufs_bindex_t bindex, ino_t h_ino) ++{ ++ struct inode *inode; ++ ino_t ino; ++ int err; ++ ++ inode = NULL; ++ err = au_xino_read(sb, bindex, h_ino, &ino); ++ if (!err && ino) ++ inode = ilookup(sb, ino); ++ if (!inode) ++ goto out; ++ ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("wrong root branch\n"); ++ iput(inode); ++ inode = NULL; ++ goto out; ++ } ++ ++ ii_write_lock_child(inode); ++ ++out: ++ return inode; ++} ++ ++static void au_hn_bh(void *_args) ++{ ++ struct au_hnotify_args *a = _args; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot, bfound; ++ unsigned char xino, try_iput; ++ int err; ++ struct inode *inode; ++ ino_t h_ino; ++ struct hn_job_args args; ++ struct dentry *dentry; ++ struct au_sbinfo *sbinfo; ++ ++ AuDebugOn(!_args); ++ AuDebugOn(!a->h_dir); ++ AuDebugOn(!a->dir); ++ AuDebugOn(!a->mask); ++ AuDbg("mask 0x%x, i%lu, hi%lu, hci%lu\n", ++ a->mask, a->dir->i_ino, a->h_dir->i_ino, ++ a->h_child_inode ? a->h_child_inode->i_ino : 0); ++ ++ inode = NULL; ++ dentry = NULL; ++ /* ++ * do not lock a->dir->i_mutex here ++ * because of d_revalidate() may cause a deadlock. ++ */ ++ sb = a->dir->i_sb; ++ AuDebugOn(!sb); ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!sbinfo); ++ si_write_lock(sb, AuLock_NOPLMW); ++ ++ ii_read_lock_parent(a->dir); ++ bfound = -1; ++ bbot = au_ibbot(a->dir); ++ for (bindex = au_ibtop(a->dir); bindex <= bbot; bindex++) ++ if (au_h_iptr(a->dir, bindex) == a->h_dir) { ++ bfound = bindex; ++ break; ++ } ++ ii_read_unlock(a->dir); ++ if (unlikely(bfound < 0)) ++ goto out; ++ ++ xino = !!au_opt_test(au_mntflags(sb), XINO); ++ h_ino = 0; ++ if (a->h_child_inode) ++ h_ino = a->h_child_inode->i_ino; ++ ++ if (a->h_child_nlen ++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], GEN) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], MNTPNT))) ++ dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen, ++ a->dir); ++ try_iput = 0; ++ if (dentry && d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (xino && !inode && h_ino ++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], XINO0) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], TRYXINO0) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], GEN))) { ++ inode = lookup_wlock_by_ino(sb, bfound, h_ino); ++ try_iput = 1; ++ } ++ ++ args.flags = a->flags[AuHn_CHILD]; ++ args.dentry = dentry; ++ args.inode = inode; ++ args.h_inode = a->h_child_inode; ++ args.dir = a->dir; ++ args.h_dir = a->h_dir; ++ args.h_name = a->h_child_name; ++ args.h_nlen = a->h_child_nlen; ++ err = hn_job(&args); ++ if (dentry) { ++ if (au_di(dentry)) ++ di_write_unlock(dentry); ++ dput(dentry); ++ } ++ if (inode && try_iput) { ++ ii_write_unlock(inode); ++ iput(inode); ++ } ++ ++ ii_write_lock_parent(a->dir); ++ args.flags = a->flags[AuHn_PARENT]; ++ args.dentry = NULL; ++ args.inode = a->dir; ++ args.h_inode = a->h_dir; ++ args.dir = NULL; ++ args.h_dir = NULL; ++ args.h_name = NULL; ++ args.h_nlen = 0; ++ err = hn_job(&args); ++ ii_write_unlock(a->dir); ++ ++out: ++ iput(a->h_child_inode); ++ iput(a->h_dir); ++ iput(a->dir); ++ si_write_unlock(sb); ++ au_nwt_done(&sbinfo->si_nowait); ++ kfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, ++ struct qstr *h_child_qstr, struct inode *h_child_inode) ++{ ++ int err, len; ++ unsigned int flags[AuHnLast], f; ++ unsigned char isdir, isroot, wh; ++ struct inode *dir; ++ struct au_hnotify_args *args; ++ char *p, *h_child_name; ++ ++ err = 0; ++ AuDebugOn(!hnotify || !hnotify->hn_aufs_inode); ++ dir = igrab(hnotify->hn_aufs_inode); ++ if (!dir) ++ goto out; ++ ++ isroot = (dir->i_ino == AUFS_ROOT_INO); ++ wh = 0; ++ h_child_name = (void *)h_child_qstr->name; ++ len = h_child_qstr->len; ++ if (h_child_name) { ++ if (len > AUFS_WH_PFX_LEN ++ && !memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ h_child_name += AUFS_WH_PFX_LEN; ++ len -= AUFS_WH_PFX_LEN; ++ wh = 1; ++ } ++ } ++ ++ isdir = 0; ++ if (h_child_inode) ++ isdir = !!S_ISDIR(h_child_inode->i_mode); ++ flags[AuHn_PARENT] = AuHnJob_ISDIR; ++ flags[AuHn_CHILD] = 0; ++ if (isdir) ++ flags[AuHn_CHILD] = AuHnJob_ISDIR; ++ au_fset_hnjob(flags[AuHn_PARENT], DIRENT); ++ au_fset_hnjob(flags[AuHn_CHILD], GEN); ++ switch (mask & FS_EVENTS_POSS_ON_CHILD) { ++ case FS_MOVED_FROM: ++ case FS_MOVED_TO: ++ au_fset_hnjob(flags[AuHn_CHILD], XINO0); ++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); ++ /*FALLTHROUGH*/ ++ case FS_CREATE: ++ AuDebugOn(!h_child_name); ++ break; ++ ++ case FS_DELETE: ++ /* ++ * aufs never be able to get this child inode. ++ * revalidation should be in d_revalidate() ++ * by checking i_nlink, i_generation or d_unhashed(). ++ */ ++ AuDebugOn(!h_child_name); ++ au_fset_hnjob(flags[AuHn_CHILD], TRYXINO0); ++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); ++ break; ++ ++ default: ++ AuDebugOn(1); ++ } ++ ++ if (wh) ++ h_child_inode = NULL; ++ ++ err = -ENOMEM; ++ /* iput() and kfree() will be called in au_hnotify() */ ++ args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS); ++ if (unlikely(!args)) { ++ AuErr1("no memory\n"); ++ iput(dir); ++ goto out; ++ } ++ args->flags[AuHn_PARENT] = flags[AuHn_PARENT]; ++ args->flags[AuHn_CHILD] = flags[AuHn_CHILD]; ++ args->mask = mask; ++ args->dir = dir; ++ args->h_dir = igrab(h_dir); ++ if (h_child_inode) ++ h_child_inode = igrab(h_child_inode); /* can be NULL */ ++ args->h_child_inode = h_child_inode; ++ args->h_child_nlen = len; ++ if (len) { ++ p = (void *)args; ++ p += sizeof(*args); ++ memcpy(p, h_child_name, len); ++ p[len] = 0; ++ } ++ ++ /* NFS fires the event for silly-renamed one from kworker */ ++ f = 0; ++ if (!dir->i_nlink ++ || (au_test_nfs(h_dir->i_sb) && (mask & FS_DELETE))) ++ f = AuWkq_NEST; ++ err = au_wkq_nowait(au_hn_bh, args, dir->i_sb, f); ++ if (unlikely(err)) { ++ pr_err("wkq %d\n", err); ++ iput(args->h_child_inode); ++ iput(args->h_dir); ++ iput(args->dir); ++ kfree(args); ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm) ++{ ++ int err; ++ ++ AuDebugOn(!(udba & AuOptMask_UDBA)); ++ ++ err = 0; ++ if (au_hnotify_op.reset_br) ++ err = au_hnotify_op.reset_br(udba, br, perm); ++ ++ return err; ++} ++ ++int au_hnotify_init_br(struct au_branch *br, int perm) ++{ ++ int err; ++ ++ err = 0; ++ if (au_hnotify_op.init_br) ++ err = au_hnotify_op.init_br(br, perm); ++ ++ return err; ++} ++ ++void au_hnotify_fin_br(struct au_branch *br) ++{ ++ if (au_hnotify_op.fin_br) ++ au_hnotify_op.fin_br(br); ++} ++ ++static void au_hn_destroy_cache(void) ++{ ++ kmem_cache_destroy(au_cachep[AuCache_HNOTIFY]); ++ au_cachep[AuCache_HNOTIFY] = NULL; ++} ++ ++int __init au_hnotify_init(void) ++{ ++ int err; ++ ++ err = -ENOMEM; ++ au_cachep[AuCache_HNOTIFY] = AuCache(au_hnotify); ++ if (au_cachep[AuCache_HNOTIFY]) { ++ err = 0; ++ if (au_hnotify_op.init) ++ err = au_hnotify_op.init(); ++ if (unlikely(err)) ++ au_hn_destroy_cache(); ++ } ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_hnotify_fin(void) ++{ ++ if (au_hnotify_op.fin) ++ au_hnotify_op.fin(); ++ /* cf. au_cache_fin() */ ++ if (au_cachep[AuCache_HNOTIFY]) ++ au_hn_destroy_cache(); ++} +diff --git a/fs/aufs/i_op.c b/fs/aufs/i_op.c +new file mode 100644 +index 0000000..cc1e312 +--- /dev/null ++++ b/fs/aufs/i_op.c +@@ -0,0 +1,1401 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations (except add/del/rename) ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++static int h_permission(struct inode *h_inode, int mask, ++ struct vfsmount *h_mnt, int brperm) ++{ ++ int err; ++ const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); ++ ++ err = -EACCES; ++ if ((write_mask && IS_IMMUTABLE(h_inode)) ++ || ((mask & MAY_EXEC) ++ && S_ISREG(h_inode->i_mode) ++ && ((h_mnt->mnt_flags & MNT_NOEXEC) ++ || !(h_inode->i_mode & S_IXUGO)))) ++ goto out; ++ ++ /* ++ * - skip the lower fs test in the case of write to ro branch. ++ * - nfs dir permission write check is optimized, but a policy for ++ * link/rename requires a real check. ++ * - nfs always sets MS_POSIXACL regardless its mount option 'noacl.' ++ * in this case, generic_permission() returns -EOPNOTSUPP. ++ */ ++ if ((write_mask && !au_br_writable(brperm)) ++ || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode) ++ && write_mask && !(mask & MAY_READ)) ++ || !h_inode->i_op->permission) { ++ /* AuLabel(generic_permission); */ ++ /* AuDbg("get_acl %pf\n", h_inode->i_op->get_acl); */ ++ err = generic_permission(h_inode, mask); ++ if (err == -EOPNOTSUPP && au_test_nfs_noacl(h_inode)) ++ err = h_inode->i_op->permission(h_inode, mask); ++ AuTraceErr(err); ++ } else { ++ /* AuLabel(h_inode->permission); */ ++ err = h_inode->i_op->permission(h_inode, mask); ++ AuTraceErr(err); ++ } ++ ++ if (!err) ++ err = devcgroup_inode_permission(h_inode, mask); ++ if (!err) ++ err = security_inode_permission(h_inode, mask); ++ ++#if 0 ++ if (!err) { ++ /* todo: do we need to call ima_path_check()? */ ++ struct path h_path = { ++ .dentry = ++ .mnt = h_mnt ++ }; ++ err = ima_path_check(&h_path, ++ mask & (MAY_READ | MAY_WRITE | MAY_EXEC), ++ IMA_COUNT_LEAVE); ++ } ++#endif ++ ++out: ++ return err; ++} ++ ++static int aufs_permission(struct inode *inode, int mask) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ const unsigned char isdir = !!S_ISDIR(inode->i_mode), ++ write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ ++ /* todo: support rcu-walk? */ ++ if (mask & MAY_NOT_BLOCK) ++ return -ECHILD; ++ ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_read_lock_child(inode); ++#if 0 ++ err = au_iigen_test(inode, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out; ++#endif ++ ++ if (!isdir ++ || write_mask ++ || au_opt_test(au_mntflags(sb), DIRPERM1)) { ++ err = au_busy_or_stale(); ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ if (unlikely(!h_inode ++ || (h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT))) ++ goto out; ++ ++ err = 0; ++ bindex = au_ibtop(inode); ++ br = au_sbr(sb, bindex); ++ err = h_permission(h_inode, mask, au_br_mnt(br), br->br_perm); ++ if (write_mask ++ && !err ++ && !special_file(h_inode->i_mode)) { ++ /* test whether the upper writable branch exists */ ++ err = -EROFS; ++ for (; bindex >= 0; bindex--) ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = 0; ++ break; ++ } ++ } ++ goto out; ++ } ++ ++ /* non-write to dir */ ++ err = 0; ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); !err && bindex <= bbot; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (h_inode) { ++ err = au_busy_or_stale(); ++ if (unlikely(!S_ISDIR(h_inode->i_mode))) ++ break; ++ ++ br = au_sbr(sb, bindex); ++ err = h_permission(h_inode, mask, au_br_mnt(br), ++ br->br_perm); ++ } ++ } ++ ++out: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry, ++ unsigned int flags) ++{ ++ struct dentry *ret, *parent; ++ struct inode *inode; ++ struct super_block *sb; ++ int err, npositive; ++ ++ IMustLock(dir); ++ ++ /* todo: support rcu-walk? */ ++ ret = ERR_PTR(-ECHILD); ++ if (flags & LOOKUP_RCU) ++ goto out; ++ ++ ret = ERR_PTR(-ENAMETOOLONG); ++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ goto out; ++ ++ sb = dir->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ ret = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_di_init(dentry); ++ ret = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_si; ++ ++ inode = NULL; ++ npositive = 0; /* suppress a warning */ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_alive_dir(parent); ++ if (!err) ++ err = au_digen_test(parent, au_sigen(sb)); ++ if (!err) { ++ /* regardless LOOKUP_CREATE, always ALLOW_NEG */ ++ npositive = au_lkup_dentry(dentry, au_dbtop(parent), ++ AuLkup_ALLOW_NEG); ++ err = npositive; ++ } ++ di_read_unlock(parent, AuLock_IR); ++ ret = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out_unlock; ++ ++ if (npositive) { ++ inode = au_new_inode(dentry, /*must_new*/0); ++ if (IS_ERR(inode)) { ++ ret = (void *)inode; ++ inode = NULL; ++ goto out_unlock; ++ } ++ } ++ ++ if (inode) ++ atomic_inc(&inode->i_count); ++ ret = d_splice_alias(inode, dentry); ++#if 0 ++ if (unlikely(d_need_lookup(dentry))) { ++ spin_lock(&dentry->d_lock); ++ dentry->d_flags &= ~DCACHE_NEED_LOOKUP; ++ spin_unlock(&dentry->d_lock); ++ } else ++#endif ++ if (inode) { ++ if (!IS_ERR(ret)) { ++ iput(inode); ++ if (ret && ret != dentry) ++ ii_write_unlock(inode); ++ } else { ++ ii_write_unlock(inode); ++ iput(inode); ++ inode = NULL; ++ } ++ } ++ ++out_unlock: ++ di_write_unlock(dentry); ++out_si: ++ si_read_unlock(sb); ++out: ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aopen_node { ++ struct hlist_node hlist; ++ struct file *file, *h_file; ++}; ++ ++static int au_do_aopen(struct inode *inode, struct file *file) ++{ ++ struct au_sphlhead *aopen; ++ struct aopen_node *node; ++ struct au_do_open_args args = { ++ .no_lock = 1, ++ .open = au_do_open_nondir ++ }; ++ ++ aopen = &au_sbi(inode->i_sb)->si_aopen; ++ spin_lock(&aopen->spin); ++ hlist_for_each_entry(node, &aopen->head, hlist) ++ if (node->file == file) { ++ args.h_file = node->h_file; ++ break; ++ } ++ spin_unlock(&aopen->spin); ++ /* AuDebugOn(!args.h_file); */ ++ ++ return au_do_open(file, &args); ++} ++ ++static int aufs_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct file *file, unsigned int open_flag, ++ umode_t create_mode, int *opened) ++{ ++ int err, h_opened = *opened; ++ unsigned int lkup_flags; ++ struct dentry *parent; ++ struct dentry *d; ++ struct au_sphlhead *aopen; ++ struct vfsub_aopen_args args = { ++ .open_flag = open_flag, ++ .create_mode = create_mode, ++ .opened = &h_opened ++ }; ++ struct aopen_node aopen_node = { ++ .file = file ++ }; ++ ++ IMustLock(dir); ++ AuDbg("open_flag 0%o\n", open_flag); ++ AuDbgDentry(dentry); ++ ++ err = 0; ++ if (!au_di(dentry)) { ++ lkup_flags = LOOKUP_OPEN; ++ if (open_flag & O_CREAT) ++ lkup_flags |= LOOKUP_CREATE; ++ d = aufs_lookup(dir, dentry, lkup_flags); ++ if (IS_ERR(d)) { ++ err = PTR_ERR(d); ++ AuTraceErr(err); ++ goto out; ++ } else if (d) { ++ /* ++ * obsoleted dentry found. ++ * another error will be returned later. ++ */ ++ d_drop(d); ++ AuDbgDentry(d); ++ dput(d); ++ } ++ AuDbgDentry(dentry); ++ } ++ ++ if (d_is_positive(dentry) ++ || d_unhashed(dentry) ++ || d_unlinked(dentry) ++ || !(open_flag & O_CREAT)) ++ goto out_no_open; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); ++ if (unlikely(err)) ++ goto out; ++ ++ parent = dentry->d_parent; /* dir is locked */ ++ di_write_lock_parent(parent); ++ err = au_lkup_dentry(dentry, /*btop*/0, AuLkup_ALLOW_NEG); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ AuDbgDentry(dentry); ++ if (d_is_positive(dentry)) ++ goto out_unlock; ++ ++ args.file = get_empty_filp(); ++ err = PTR_ERR(args.file); ++ if (IS_ERR(args.file)) ++ goto out_unlock; ++ ++ args.file->f_flags = file->f_flags; ++ err = au_aopen_or_create(dir, dentry, &args); ++ AuTraceErr(err); ++ AuDbgFile(args.file); ++ if (unlikely(err < 0)) { ++ if (h_opened & FILE_OPENED) ++ fput(args.file); ++ else ++ put_filp(args.file); ++ goto out_unlock; ++ } ++ ++ /* some filesystems don't set FILE_CREATED while succeeded? */ ++ *opened |= FILE_CREATED; ++ if (h_opened & FILE_OPENED) ++ aopen_node.h_file = args.file; ++ else { ++ put_filp(args.file); ++ args.file = NULL; ++ } ++ aopen = &au_sbi(dir->i_sb)->si_aopen; ++ au_sphl_add(&aopen_node.hlist, aopen); ++ err = finish_open(file, dentry, au_do_aopen, opened); ++ au_sphl_del(&aopen_node.hlist, aopen); ++ AuTraceErr(err); ++ AuDbgFile(file); ++ if (aopen_node.h_file) ++ fput(aopen_node.h_file); ++ ++out_unlock: ++ di_write_unlock(parent); ++ aufs_read_unlock(dentry, AuLock_DW); ++ AuDbgDentry(dentry); ++ if (unlikely(err)) ++ goto out; ++out_no_open: ++ if (!err && !(*opened & FILE_CREATED)) { ++ AuLabel(out_no_open); ++ dget(dentry); ++ err = finish_no_open(file, dentry); ++ } ++out: ++ AuDbg("%pd%s%s\n", dentry, ++ (*opened & FILE_CREATED) ? " created" : "", ++ (*opened & FILE_OPENED) ? " opened" : ""); ++ AuTraceErr(err); ++ return err; ++} ++ ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent, ++ const unsigned char add_entry, aufs_bindex_t bcpup, ++ aufs_bindex_t btop) ++{ ++ int err; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ ++ if (add_entry) ++ IMustLock(d_inode(parent)); ++ else ++ di_write_lock_parent(parent); ++ ++ err = 0; ++ if (!au_h_dptr(parent, bcpup)) { ++ if (btop > bcpup) ++ err = au_cpup_dirs(dentry, bcpup); ++ else if (btop < bcpup) ++ err = au_cpdown_dirs(dentry, bcpup); ++ else ++ BUG(); ++ } ++ if (!err && add_entry && !au_ftest_wrdir(add_entry, TMPFILE)) { ++ h_parent = au_h_dptr(parent, bcpup); ++ h_dir = d_inode(h_parent); ++ inode_lock_nested(h_dir, AuLsc_I_PARENT); ++ err = au_lkup_neg(dentry, bcpup, /*wh*/0); ++ /* todo: no unlock here */ ++ inode_unlock(h_dir); ++ ++ AuDbg("bcpup %d\n", bcpup); ++ if (!err) { ++ if (d_really_is_negative(dentry)) ++ au_set_h_dptr(dentry, btop, NULL); ++ au_update_dbrange(dentry, /*do_put_zero*/0); ++ } ++ } ++ ++ if (!add_entry) ++ di_write_unlock(parent); ++ if (!err) ++ err = bcpup; /* success */ ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * decide the branch and the parent dir where we will create a new entry. ++ * returns new bindex or an error. ++ * copyup the parent dir if needed. ++ */ ++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, ++ struct au_wr_dir_args *args) ++{ ++ int err; ++ unsigned int flags; ++ aufs_bindex_t bcpup, btop, src_btop; ++ const unsigned char add_entry ++ = au_ftest_wrdir(args->flags, ADD_ENTRY) ++ | au_ftest_wrdir(args->flags, TMPFILE); ++ struct super_block *sb; ++ struct dentry *parent; ++ struct au_sbinfo *sbinfo; ++ ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ parent = dget_parent(dentry); ++ btop = au_dbtop(dentry); ++ bcpup = btop; ++ if (args->force_btgt < 0) { ++ if (src_dentry) { ++ src_btop = au_dbtop(src_dentry); ++ if (src_btop < btop) ++ bcpup = src_btop; ++ } else if (add_entry) { ++ flags = 0; ++ if (au_ftest_wrdir(args->flags, ISDIR)) ++ au_fset_wbr(flags, DIR); ++ err = AuWbrCreate(sbinfo, dentry, flags); ++ bcpup = err; ++ } ++ ++ if (bcpup < 0 || au_test_ro(sb, bcpup, d_inode(dentry))) { ++ if (add_entry) ++ err = AuWbrCopyup(sbinfo, dentry); ++ else { ++ if (!IS_ROOT(dentry)) { ++ di_read_lock_parent(parent, !AuLock_IR); ++ err = AuWbrCopyup(sbinfo, dentry); ++ di_read_unlock(parent, !AuLock_IR); ++ } else ++ err = AuWbrCopyup(sbinfo, dentry); ++ } ++ bcpup = err; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else { ++ bcpup = args->force_btgt; ++ AuDebugOn(au_test_ro(sb, bcpup, d_inode(dentry))); ++ } ++ ++ AuDbg("btop %d, bcpup %d\n", btop, bcpup); ++ err = bcpup; ++ if (bcpup == btop) ++ goto out; /* success */ ++ ++ /* copyup the new parent into the branch we process */ ++ err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, btop); ++ if (err >= 0) { ++ if (d_really_is_negative(dentry)) { ++ au_set_h_dptr(dentry, btop, NULL); ++ au_set_dbtop(dentry, bcpup); ++ au_set_dbbot(dentry, bcpup); ++ } ++ AuDebugOn(add_entry ++ && !au_ftest_wrdir(args->flags, TMPFILE) ++ && !au_h_dptr(dentry, bcpup)); ++ } ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_pin_hdir_unlock(struct au_pin *p) ++{ ++ if (p->hdir) ++ au_hn_inode_unlock(p->hdir); ++} ++ ++int au_pin_hdir_lock(struct au_pin *p) ++{ ++ int err; ++ ++ err = 0; ++ if (!p->hdir) ++ goto out; ++ ++ /* even if an error happens later, keep this lock */ ++ au_hn_inode_lock_nested(p->hdir, p->lsc_hi); ++ ++ err = -EBUSY; ++ if (unlikely(p->hdir->hi_inode != d_inode(p->h_parent))) ++ goto out; ++ ++ err = 0; ++ if (p->h_dentry) ++ err = au_h_verify(p->h_dentry, p->udba, p->hdir->hi_inode, ++ p->h_parent, p->br); ++ ++out: ++ return err; ++} ++ ++int au_pin_hdir_relock(struct au_pin *p) ++{ ++ int err, i; ++ struct inode *h_i; ++ struct dentry *h_d[] = { ++ p->h_dentry, ++ p->h_parent ++ }; ++ ++ err = au_pin_hdir_lock(p); ++ if (unlikely(err)) ++ goto out; ++ ++ for (i = 0; !err && i < sizeof(h_d)/sizeof(*h_d); i++) { ++ if (!h_d[i]) ++ continue; ++ if (d_is_positive(h_d[i])) { ++ h_i = d_inode(h_d[i]); ++ err = !h_i->i_nlink; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++static void au_pin_hdir_set_owner(struct au_pin *p, struct task_struct *task) ++{ ++#if !defined(CONFIG_RWSEM_GENERIC_SPINLOCK) && defined(CONFIG_RWSEM_SPIN_ON_OWNER) ++ p->hdir->hi_inode->i_rwsem.owner = task; ++#endif ++} ++ ++void au_pin_hdir_acquire_nest(struct au_pin *p) ++{ ++ if (p->hdir) { ++ rwsem_acquire_nest(&p->hdir->hi_inode->i_rwsem.dep_map, ++ p->lsc_hi, 0, NULL, _RET_IP_); ++ au_pin_hdir_set_owner(p, current); ++ } ++} ++ ++void au_pin_hdir_release(struct au_pin *p) ++{ ++ if (p->hdir) { ++ au_pin_hdir_set_owner(p, p->task); ++ rwsem_release(&p->hdir->hi_inode->i_rwsem.dep_map, 1, _RET_IP_); ++ } ++} ++ ++struct dentry *au_pinned_h_parent(struct au_pin *pin) ++{ ++ if (pin && pin->parent) ++ return au_h_dptr(pin->parent, pin->bindex); ++ return NULL; ++} ++ ++void au_unpin(struct au_pin *p) ++{ ++ if (p->hdir) ++ au_pin_hdir_unlock(p); ++ if (p->h_mnt && au_ftest_pin(p->flags, MNT_WRITE)) ++ vfsub_mnt_drop_write(p->h_mnt); ++ if (!p->hdir) ++ return; ++ ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ iput(p->hdir->hi_inode); ++ dput(p->parent); ++ p->parent = NULL; ++ p->hdir = NULL; ++ p->h_mnt = NULL; ++ /* do not clear p->task */ ++} ++ ++int au_do_pin(struct au_pin *p) ++{ ++ int err; ++ struct super_block *sb; ++ struct inode *h_dir; ++ ++ err = 0; ++ sb = p->dentry->d_sb; ++ p->br = au_sbr(sb, p->bindex); ++ if (IS_ROOT(p->dentry)) { ++ if (au_ftest_pin(p->flags, MNT_WRITE)) { ++ p->h_mnt = au_br_mnt(p->br); ++ err = vfsub_mnt_want_write(p->h_mnt); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ goto out_err; ++ } ++ } ++ goto out; ++ } ++ ++ p->h_dentry = NULL; ++ if (p->bindex <= au_dbbot(p->dentry)) ++ p->h_dentry = au_h_dptr(p->dentry, p->bindex); ++ ++ p->parent = dget_parent(p->dentry); ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_lock(p->parent, AuLock_IR, p->lsc_di); ++ ++ h_dir = NULL; ++ p->h_parent = au_h_dptr(p->parent, p->bindex); ++ p->hdir = au_hi(d_inode(p->parent), p->bindex); ++ if (p->hdir) ++ h_dir = p->hdir->hi_inode; ++ ++ /* ++ * udba case, or ++ * if DI_LOCKED is not set, then p->parent may be different ++ * and h_parent can be NULL. ++ */ ++ if (unlikely(!p->hdir || !h_dir || !p->h_parent)) { ++ err = -EBUSY; ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ dput(p->parent); ++ p->parent = NULL; ++ goto out_err; ++ } ++ ++ if (au_ftest_pin(p->flags, MNT_WRITE)) { ++ p->h_mnt = au_br_mnt(p->br); ++ err = vfsub_mnt_want_write(p->h_mnt); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ dput(p->parent); ++ p->parent = NULL; ++ goto out_err; ++ } ++ } ++ ++ au_igrab(h_dir); ++ err = au_pin_hdir_lock(p); ++ if (!err) ++ goto out; /* success */ ++ ++ au_unpin(p); ++ ++out_err: ++ pr_err("err %d\n", err); ++ err = au_busy_or_stale(); ++out: ++ return err; ++} ++ ++void au_pin_init(struct au_pin *p, struct dentry *dentry, ++ aufs_bindex_t bindex, int lsc_di, int lsc_hi, ++ unsigned int udba, unsigned char flags) ++{ ++ p->dentry = dentry; ++ p->udba = udba; ++ p->lsc_di = lsc_di; ++ p->lsc_hi = lsc_hi; ++ p->flags = flags; ++ p->bindex = bindex; ++ ++ p->parent = NULL; ++ p->hdir = NULL; ++ p->h_mnt = NULL; ++ ++ p->h_dentry = NULL; ++ p->h_parent = NULL; ++ p->br = NULL; ++ p->task = current; ++} ++ ++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int udba, unsigned char flags) ++{ ++ au_pin_init(pin, dentry, bindex, AuLsc_DI_PARENT, AuLsc_I_PARENT2, ++ udba, flags); ++ return au_do_pin(pin); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * ->setattr() and ->getattr() are called in various cases. ++ * chmod, stat: dentry is revalidated. ++ * fchmod, fstat: file and dentry are not revalidated, additionally they may be ++ * unhashed. ++ * for ->setattr(), ia->ia_file is passed from ftruncate only. ++ */ ++/* todo: consolidate with do_refresh() and simple_reval_dpath() */ ++int au_reval_for_attr(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *parent; ++ ++ err = 0; ++ if (au_digen_test(dentry, sigen)) { ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(dentry, parent); ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, ++ struct au_icpup_args *a) ++{ ++ int err; ++ loff_t sz; ++ aufs_bindex_t btop, ibtop; ++ struct dentry *hi_wh, *parent; ++ struct inode *inode; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = 0 ++ }; ++ ++ if (d_is_dir(dentry)) ++ au_fset_wrdir(wr_dir_args.flags, ISDIR); ++ /* plink or hi_wh() case */ ++ btop = au_dbtop(dentry); ++ inode = d_inode(dentry); ++ ibtop = au_ibtop(inode); ++ if (btop != ibtop && !au_test_ro(inode->i_sb, ibtop, inode)) ++ wr_dir_args.force_btgt = ibtop; ++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); ++ if (unlikely(err < 0)) ++ goto out; ++ a->btgt = err; ++ if (err != btop) ++ au_fset_icpup(a->flags, DID_CPUP); ++ ++ err = 0; ++ a->pin_flags = AuPin_MNT_WRITE; ++ parent = NULL; ++ if (!IS_ROOT(dentry)) { ++ au_fset_pin(a->pin_flags, DI_LOCKED); ++ parent = dget_parent(dentry); ++ di_write_lock_parent(parent); ++ } ++ ++ err = au_pin(&a->pin, dentry, a->btgt, a->udba, a->pin_flags); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ sz = -1; ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ a->h_inode = d_inode(a->h_path.dentry); ++ if (ia && (ia->ia_valid & ATTR_SIZE)) { ++ inode_lock_nested(a->h_inode, AuLsc_I_CHILD); ++ if (ia->ia_size < i_size_read(a->h_inode)) ++ sz = ia->ia_size; ++ inode_unlock(a->h_inode); ++ } ++ ++ hi_wh = NULL; ++ if (au_ftest_icpup(a->flags, DID_CPUP) && d_unlinked(dentry)) { ++ hi_wh = au_hi_wh(inode, a->btgt); ++ if (!hi_wh) { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->btgt, ++ .bsrc = -1, ++ .len = sz, ++ .pin = &a->pin ++ }; ++ err = au_sio_cpup_wh(&cpg, /*file*/NULL); ++ if (unlikely(err)) ++ goto out_unlock; ++ hi_wh = au_hi_wh(inode, a->btgt); ++ /* todo: revalidate hi_wh? */ ++ } ++ } ++ ++ if (parent) { ++ au_pin_set_parent_lflag(&a->pin, /*lflag*/0); ++ di_downgrade_lock(parent, AuLock_IR); ++ dput(parent); ++ parent = NULL; ++ } ++ if (!au_ftest_icpup(a->flags, DID_CPUP)) ++ goto out; /* success */ ++ ++ if (!d_unhashed(dentry)) { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->btgt, ++ .bsrc = btop, ++ .len = sz, ++ .pin = &a->pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ if (!err) ++ a->h_path.dentry = au_h_dptr(dentry, a->btgt); ++ } else if (!hi_wh) ++ a->h_path.dentry = au_h_dptr(dentry, a->btgt); ++ else ++ a->h_path.dentry = hi_wh; /* do not dget here */ ++ ++out_unlock: ++ a->h_inode = d_inode(a->h_path.dentry); ++ if (!err) ++ goto out; /* success */ ++ au_unpin(&a->pin); ++out_parent: ++ if (parent) { ++ di_write_unlock(parent); ++ dput(parent); ++ } ++out: ++ if (!err) ++ inode_lock_nested(a->h_inode, AuLsc_I_CHILD); ++ return err; ++} ++ ++static int aufs_setattr(struct dentry *dentry, struct iattr *ia) ++{ ++ int err; ++ struct inode *inode, *delegated; ++ struct super_block *sb; ++ struct file *file; ++ struct au_icpup_args *a; ++ ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) ++ ia->ia_valid &= ~ATTR_MODE; ++ ++ file = NULL; ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_kfree; ++ ++ if (ia->ia_valid & ATTR_FILE) { ++ /* currently ftruncate(2) only */ ++ AuDebugOn(!d_is_reg(dentry)); ++ file = ia->ia_file; ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); ++ if (unlikely(err)) ++ goto out_si; ++ ia->ia_file = au_hf_top(file); ++ a->udba = AuOpt_UDBA_NONE; ++ } else { ++ /* fchmod() doesn't pass ia_file */ ++ a->udba = au_opt_udba(sb); ++ di_write_lock_child(dentry); ++ /* no d_unlinked(), to set UDBA_NONE for root */ ++ if (d_unhashed(dentry)) ++ a->udba = AuOpt_UDBA_NONE; ++ if (a->udba != AuOpt_UDBA_NONE) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_for_attr(dentry, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out_dentry; ++ } ++ } ++ ++ err = au_pin_and_icpup(dentry, ia, a); ++ if (unlikely(err < 0)) ++ goto out_dentry; ++ if (au_ftest_icpup(a->flags, DID_CPUP)) { ++ ia->ia_file = NULL; ++ ia->ia_valid &= ~ATTR_FILE; ++ } ++ ++ a->h_path.mnt = au_sbr_mnt(sb, a->btgt); ++ if ((ia->ia_valid & (ATTR_MODE | ATTR_CTIME)) ++ == (ATTR_MODE | ATTR_CTIME)) { ++ err = security_path_chmod(&a->h_path, ia->ia_mode); ++ if (unlikely(err)) ++ goto out_unlock; ++ } else if ((ia->ia_valid & (ATTR_UID | ATTR_GID)) ++ && (ia->ia_valid & ATTR_CTIME)) { ++ err = security_path_chown(&a->h_path, ia->ia_uid, ia->ia_gid); ++ if (unlikely(err)) ++ goto out_unlock; ++ } ++ ++ if (ia->ia_valid & ATTR_SIZE) { ++ struct file *f; ++ ++ if (ia->ia_size < i_size_read(inode)) ++ /* unmap only */ ++ truncate_setsize(inode, ia->ia_size); ++ ++ f = NULL; ++ if (ia->ia_valid & ATTR_FILE) ++ f = ia->ia_file; ++ inode_unlock(a->h_inode); ++ err = vfsub_trunc(&a->h_path, ia->ia_size, ia->ia_valid, f); ++ inode_lock_nested(a->h_inode, AuLsc_I_CHILD); ++ } else { ++ delegated = NULL; ++ while (1) { ++ err = vfsub_notify_change(&a->h_path, ia, &delegated); ++ if (delegated) { ++ err = break_deleg_wait(&delegated); ++ if (!err) ++ continue; ++ } ++ break; ++ } ++ } ++ /* ++ * regardless aufs 'acl' option setting. ++ * why don't all acl-aware fs call this func from their ->setattr()? ++ */ ++ if (!err && (ia->ia_valid & ATTR_MODE)) ++ err = vfsub_acl_chmod(a->h_inode, ia->ia_mode); ++ if (!err) ++ au_cpup_attr_changeable(inode); ++ ++out_unlock: ++ inode_unlock(a->h_inode); ++ au_unpin(&a->pin); ++ if (unlikely(err)) ++ au_update_dbtop(dentry); ++out_dentry: ++ di_write_unlock(dentry); ++ if (file) { ++ fi_write_unlock(file); ++ ia->ia_file = file; ++ ia->ia_valid |= ATTR_FILE; ++ } ++out_si: ++ si_read_unlock(sb); ++out_kfree: ++ kfree(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL) ++static int au_h_path_to_set_attr(struct dentry *dentry, ++ struct au_icpup_args *a, struct path *h_path) ++{ ++ int err; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ a->udba = au_opt_udba(sb); ++ /* no d_unlinked(), to set UDBA_NONE for root */ ++ if (d_unhashed(dentry)) ++ a->udba = AuOpt_UDBA_NONE; ++ if (a->udba != AuOpt_UDBA_NONE) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_for_attr(dentry, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out; ++ } ++ err = au_pin_and_icpup(dentry, /*ia*/NULL, a); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ h_path->dentry = a->h_path.dentry; ++ h_path->mnt = au_sbr_mnt(sb, a->btgt); ++ ++out: ++ return err; ++} ++ ++ssize_t au_srxattr(struct dentry *dentry, struct inode *inode, ++ struct au_srxattr *arg) ++{ ++ int err; ++ struct path h_path; ++ struct super_block *sb; ++ struct au_icpup_args *a; ++ struct inode *h_inode; ++ ++ IMustLock(inode); ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_kfree; ++ ++ h_path.dentry = NULL; /* silence gcc */ ++ di_write_lock_child(dentry); ++ err = au_h_path_to_set_attr(dentry, a, &h_path); ++ if (unlikely(err)) ++ goto out_di; ++ ++ inode_unlock(a->h_inode); ++ switch (arg->type) { ++ case AU_XATTR_SET: ++ AuDebugOn(d_is_negative(h_path.dentry)); ++ err = vfsub_setxattr(h_path.dentry, ++ arg->u.set.name, arg->u.set.value, ++ arg->u.set.size, arg->u.set.flags); ++ break; ++ case AU_XATTR_REMOVE: ++ err = vfsub_removexattr(h_path.dentry, arg->u.remove.name); ++ break; ++ case AU_ACL_SET: ++ err = -EOPNOTSUPP; ++ h_inode = d_inode(h_path.dentry); ++ if (h_inode->i_op->set_acl) ++ err = h_inode->i_op->set_acl(h_inode, ++ arg->u.acl_set.acl, ++ arg->u.acl_set.type); ++ break; ++ } ++ if (!err) ++ au_cpup_attr_timesizes(inode); ++ ++ au_unpin(&a->pin); ++ if (unlikely(err)) ++ au_update_dbtop(dentry); ++ ++out_di: ++ di_write_unlock(dentry); ++ si_read_unlock(sb); ++out_kfree: ++ kfree(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++#endif ++ ++static void au_refresh_iattr(struct inode *inode, struct kstat *st, ++ unsigned int nlink) ++{ ++ unsigned int n; ++ ++ inode->i_mode = st->mode; ++ /* don't i_[ug]id_write() here */ ++ inode->i_uid = st->uid; ++ inode->i_gid = st->gid; ++ inode->i_atime = st->atime; ++ inode->i_mtime = st->mtime; ++ inode->i_ctime = st->ctime; ++ ++ au_cpup_attr_nlink(inode, /*force*/0); ++ if (S_ISDIR(inode->i_mode)) { ++ n = inode->i_nlink; ++ n -= nlink; ++ n += st->nlink; ++ smp_mb(); /* for i_nlink */ ++ /* 0 can happen */ ++ set_nlink(inode, n); ++ } ++ ++ spin_lock(&inode->i_lock); ++ inode->i_blocks = st->blocks; ++ i_size_write(inode, st->size); ++ spin_unlock(&inode->i_lock); ++} ++ ++/* ++ * common routine for aufs_getattr() and aufs_getxattr(). ++ * returns zero or negative (an error). ++ * @dentry will be read-locked in success. ++ */ ++int au_h_path_getattr(struct dentry *dentry, int force, struct path *h_path) ++{ ++ int err; ++ unsigned int mnt_flags, sigen; ++ unsigned char udba_none; ++ aufs_bindex_t bindex; ++ struct super_block *sb, *h_sb; ++ struct inode *inode; ++ ++ h_path->mnt = NULL; ++ h_path->dentry = NULL; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ mnt_flags = au_mntflags(sb); ++ udba_none = !!au_opt_test(mnt_flags, UDBA_NONE); ++ ++ /* support fstat(2) */ ++ if (!d_unlinked(dentry) && !udba_none) { ++ sigen = au_sigen(sb); ++ err = au_digen_test(dentry, sigen); ++ if (!err) { ++ di_read_lock_child(dentry, AuLock_IR); ++ err = au_dbrange_test(dentry); ++ if (unlikely(err)) { ++ di_read_unlock(dentry, AuLock_IR); ++ goto out; ++ } ++ } else { ++ AuDebugOn(IS_ROOT(dentry)); ++ di_write_lock_child(dentry); ++ err = au_dbrange_test(dentry); ++ if (!err) ++ err = au_reval_for_attr(dentry, sigen); ++ if (!err) ++ di_downgrade_lock(dentry, AuLock_IR); ++ else { ++ di_write_unlock(dentry); ++ goto out; ++ } ++ } ++ } else ++ di_read_lock_child(dentry, AuLock_IR); ++ ++ inode = d_inode(dentry); ++ bindex = au_ibtop(inode); ++ h_path->mnt = au_sbr_mnt(sb, bindex); ++ h_sb = h_path->mnt->mnt_sb; ++ if (!force ++ && !au_test_fs_bad_iattr(h_sb) ++ && udba_none) ++ goto out; /* success */ ++ ++ if (au_dbtop(dentry) == bindex) ++ h_path->dentry = au_h_dptr(dentry, bindex); ++ else if (au_opt_test(mnt_flags, PLINK) && au_plink_test(inode)) { ++ h_path->dentry = au_plink_lkup(inode, bindex); ++ if (IS_ERR(h_path->dentry)) ++ /* pretending success */ ++ h_path->dentry = NULL; ++ else ++ dput(h_path->dentry); ++ } ++ ++out: ++ return err; ++} ++ ++static int aufs_getattr(struct vfsmount *mnt __maybe_unused, ++ struct dentry *dentry, struct kstat *st) ++{ ++ int err; ++ unsigned char positive; ++ struct path h_path; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ inode = d_inode(dentry); ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ err = au_h_path_getattr(dentry, /*force*/0, &h_path); ++ if (unlikely(err)) ++ goto out_si; ++ if (unlikely(!h_path.dentry)) ++ /* illegally overlapped or something */ ++ goto out_fill; /* pretending success */ ++ ++ positive = d_is_positive(h_path.dentry); ++ if (positive) ++ err = vfs_getattr(&h_path, st); ++ if (!err) { ++ if (positive) ++ au_refresh_iattr(inode, st, ++ d_inode(h_path.dentry)->i_nlink); ++ goto out_fill; /* success */ ++ } ++ AuTraceErr(err); ++ goto out_di; ++ ++out_fill: ++ generic_fillattr(inode, st); ++out_di: ++ di_read_unlock(dentry, AuLock_IR); ++out_si: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const char *aufs_get_link(struct dentry *dentry, struct inode *inode, ++ struct delayed_call *done) ++{ ++ const char *ret; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ int err; ++ aufs_bindex_t bindex; ++ ++ ret = NULL; /* suppress a warning */ ++ err = -ECHILD; ++ if (!dentry) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_d_hashed_positive(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ err = -EINVAL; ++ inode = d_inode(dentry); ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(!h_inode->i_op->get_link)) ++ goto out_unlock; ++ ++ err = -EBUSY; ++ h_dentry = NULL; ++ if (au_dbtop(dentry) <= bindex) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) ++ dget(h_dentry); ++ } ++ if (!h_dentry) { ++ h_dentry = d_find_any_alias(h_inode); ++ if (IS_ERR(h_dentry)) { ++ err = PTR_ERR(h_dentry); ++ goto out_unlock; ++ } ++ } ++ if (unlikely(!h_dentry)) ++ goto out_unlock; ++ ++ err = 0; ++ AuDbg("%pf\n", h_inode->i_op->get_link); ++ AuDbgDentry(h_dentry); ++ ret = h_inode->i_op->get_link(h_dentry, h_inode, done); ++ dput(h_dentry); ++ if (IS_ERR(ret)) ++ err = PTR_ERR(ret); ++ ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_IR); ++out: ++ if (unlikely(err)) ++ ret = ERR_PTR(err); ++ AuTraceErrPtr(ret); ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_update_time(struct inode *inode, struct timespec *ts, int flags) ++{ ++ int err; ++ struct super_block *sb; ++ struct inode *h_inode; ++ ++ sb = inode->i_sb; ++ /* mmap_sem might be acquired already, cf. aufs_mmap() */ ++ lockdep_off(); ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_write_lock_child(inode); ++ lockdep_on(); ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ err = vfsub_update_time(h_inode, ts, flags); ++ lockdep_off(); ++ if (!err) ++ au_cpup_attr_timesizes(inode); ++ ii_write_unlock(inode); ++ si_read_unlock(sb); ++ lockdep_on(); ++ ++ if (!err && (flags & S_VERSION)) ++ inode_inc_iversion(inode); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* no getattr version will be set by module.c:aufs_init() */ ++struct inode_operations aufs_iop_nogetattr[AuIop_Last], ++ aufs_iop[] = { ++ [AuIop_SYMLINK] = { ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, /* unsupport for symlink? */ ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .setxattr = aufs_setxattr, ++ .getxattr = aufs_getxattr, ++ .listxattr = aufs_listxattr, ++ .removexattr = aufs_removexattr, ++#endif ++ ++ .readlink = generic_readlink, ++ .get_link = aufs_get_link, ++ ++ /* .update_time = aufs_update_time */ ++ }, ++ [AuIop_DIR] = { ++ .create = aufs_create, ++ .lookup = aufs_lookup, ++ .link = aufs_link, ++ .unlink = aufs_unlink, ++ .symlink = aufs_symlink, ++ .mkdir = aufs_mkdir, ++ .rmdir = aufs_rmdir, ++ .mknod = aufs_mknod, ++ .rename = aufs_rename, ++ ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .setxattr = aufs_setxattr, ++ .getxattr = aufs_getxattr, ++ .listxattr = aufs_listxattr, ++ .removexattr = aufs_removexattr, ++#endif ++ ++ .update_time = aufs_update_time, ++ .atomic_open = aufs_atomic_open, ++ .tmpfile = aufs_tmpfile ++ }, ++ [AuIop_OTHER] = { ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .setxattr = aufs_setxattr, ++ .getxattr = aufs_getxattr, ++ .listxattr = aufs_listxattr, ++ .removexattr = aufs_removexattr, ++#endif ++ ++ .update_time = aufs_update_time ++ } ++}; +diff --git a/fs/aufs/i_op_add.c b/fs/aufs/i_op_add.c +new file mode 100644 +index 0000000..8e3fb61 +--- /dev/null ++++ b/fs/aufs/i_op_add.c +@@ -0,0 +1,911 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations (add entry) ++ */ ++ ++#include "aufs.h" ++ ++/* ++ * final procedure of adding a new entry, except link(2). ++ * remove whiteout, instantiate, copyup the parent dir's times and size ++ * and update version. ++ * if it failed, re-create the removed whiteout. ++ */ ++static int epilog(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct dentry *dentry) ++{ ++ int err, rerr; ++ aufs_bindex_t bwh; ++ struct path h_path; ++ struct super_block *sb; ++ struct inode *inode, *h_dir; ++ struct dentry *wh; ++ ++ bwh = -1; ++ sb = dir->i_sb; ++ if (wh_dentry) { ++ h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */ ++ IMustLock(h_dir); ++ AuDebugOn(au_h_iptr(dir, bindex) != h_dir); ++ bwh = au_dbwh(dentry); ++ h_path.dentry = wh_dentry; ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, ++ dentry); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ inode = au_new_inode(dentry, /*must_new*/1); ++ if (!IS_ERR(inode)) { ++ d_instantiate(dentry, inode); ++ dir = d_inode(dentry->d_parent); /* dir inode is locked */ ++ IMustLock(dir); ++ au_dir_ts(dir, bindex); ++ dir->i_version++; ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ return 0; /* success */ ++ } ++ ++ err = PTR_ERR(inode); ++ if (!wh_dentry) ++ goto out; ++ ++ /* revert */ ++ /* dir inode is locked */ ++ wh = au_wh_create(dentry, bwh, wh_dentry->d_parent); ++ rerr = PTR_ERR(wh); ++ if (IS_ERR(wh)) { ++ AuIOErr("%pd reverting whiteout failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } else ++ dput(wh); ++ ++out: ++ return err; ++} ++ ++static int au_d_may_add(struct dentry *dentry) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(d_unhashed(dentry))) ++ err = -ENOENT; ++ if (unlikely(d_really_is_positive(dentry))) ++ err = -EEXIST; ++ return err; ++} ++ ++/* ++ * simple tests for the adding inode operations. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir) ++{ ++ int err; ++ umode_t h_mode; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ err = -ENAMETOOLONG; ++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ goto out; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (d_really_is_negative(dentry)) { ++ err = -EEXIST; ++ if (unlikely(d_is_positive(h_dentry))) ++ goto out; ++ } else { ++ /* rename(2) case */ ++ err = -EIO; ++ if (unlikely(d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ if (unlikely(!h_inode->i_nlink)) ++ goto out; ++ ++ h_mode = h_inode->i_mode; ++ if (!isdir) { ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(h_mode))) ++ goto out; ++ } else if (unlikely(!S_ISDIR(h_mode))) { ++ err = -ENOTDIR; ++ goto out; ++ } ++ } ++ ++ err = 0; ++ /* expected parent dir is locked */ ++ if (unlikely(h_parent != h_dentry->d_parent)) ++ err = -EIO; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * initial procedure of adding a new entry. ++ * prepare writable branch and the parent dir, lock it, ++ * and lookup whiteout for the new entry. ++ */ ++static struct dentry* ++lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt, ++ struct dentry *src_dentry, struct au_pin *pin, ++ struct au_wr_dir_args *wr_dir_args) ++{ ++ struct dentry *wh_dentry, *h_parent; ++ struct super_block *sb; ++ struct au_branch *br; ++ int err; ++ unsigned int udba; ++ aufs_bindex_t bcpup; ++ ++ AuDbg("%pd\n", dentry); ++ ++ err = au_wr_dir(dentry, src_dentry, wr_dir_args); ++ bcpup = err; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ udba = au_opt_udba(sb); ++ err = au_pin(pin, dentry, bcpup, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ h_parent = au_pinned_h_parent(pin); ++ if (udba != AuOpt_UDBA_NONE ++ && au_dbtop(dentry) == bcpup) ++ err = au_may_add(dentry, bcpup, h_parent, ++ au_ftest_wrdir(wr_dir_args->flags, ISDIR)); ++ else if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ err = -ENAMETOOLONG; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ br = au_sbr(sb, bcpup); ++ if (dt) { ++ struct path tmp = { ++ .dentry = h_parent, ++ .mnt = au_br_mnt(br) ++ }; ++ au_dtime_store(dt, au_pinned_parent(pin), &tmp); ++ } ++ ++ wh_dentry = NULL; ++ if (bcpup != au_dbwh(dentry)) ++ goto out; /* success */ ++ ++ /* ++ * ENAMETOOLONG here means that if we allowed create such name, then it ++ * would not be able to removed in the future. So we don't allow such ++ * name here and we don't handle ENAMETOOLONG differently here. ++ */ ++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, br); ++ ++out_unpin: ++ if (IS_ERR(wh_dentry)) ++ au_unpin(pin); ++out: ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++enum { Mknod, Symlink, Creat }; ++struct simple_arg { ++ int type; ++ union { ++ struct { ++ umode_t mode; ++ bool want_excl; ++ bool try_aopen; ++ struct vfsub_aopen_args *aopen; ++ } c; ++ struct { ++ const char *symname; ++ } s; ++ struct { ++ umode_t mode; ++ dev_t dev; ++ } m; ++ } u; ++}; ++ ++static int add_simple(struct inode *dir, struct dentry *dentry, ++ struct simple_arg *arg) ++{ ++ int err, rerr; ++ aufs_bindex_t btop; ++ unsigned char created; ++ const unsigned char try_aopen ++ = (arg->type == Creat && arg->u.c.try_aopen); ++ struct dentry *wh_dentry, *parent; ++ struct inode *h_dir; ++ struct super_block *sb; ++ struct au_branch *br; ++ /* to reuduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct path h_path; ++ struct au_wr_dir_args wr_dir_args; ++ } *a; ++ ++ AuDbg("%pd\n", dentry); ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->wr_dir_args.force_btgt = -1; ++ a->wr_dir_args.flags = AuWrDir_ADD_ENTRY; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ if (!try_aopen) { ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ } ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ if (!try_aopen) ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, ++ &a->pin, &a->wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ btop = au_dbtop(dentry); ++ sb = dentry->d_sb; ++ br = au_sbr(sb, btop); ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ a->h_path.mnt = au_br_mnt(br); ++ h_dir = au_pinned_h_dir(&a->pin); ++ switch (arg->type) { ++ case Creat: ++ err = 0; ++ if (!try_aopen || !h_dir->i_op->atomic_open) ++ err = vfsub_create(h_dir, &a->h_path, arg->u.c.mode, ++ arg->u.c.want_excl); ++ else ++ err = vfsub_atomic_open(h_dir, a->h_path.dentry, ++ arg->u.c.aopen, br); ++ break; ++ case Symlink: ++ err = vfsub_symlink(h_dir, &a->h_path, arg->u.s.symname); ++ break; ++ case Mknod: ++ err = vfsub_mknod(h_dir, &a->h_path, arg->u.m.mode, ++ arg->u.m.dev); ++ break; ++ default: ++ BUG(); ++ } ++ created = !err; ++ if (!err) ++ err = epilog(dir, btop, wh_dentry, dentry); ++ ++ /* revert */ ++ if (unlikely(created && err && d_is_positive(a->h_path.dentry))) { ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(h_dir, &a->h_path, /*delegated*/NULL, ++ /*force*/0); ++ if (rerr) { ++ AuIOErr("%pd revert failure(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&a->dt); ++ } ++ ++ if (!err && try_aopen && !h_dir->i_op->atomic_open) ++ *arg->u.c.aopen->opened |= FILE_CREATED; ++ ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ ++out_parent: ++ if (!try_aopen) ++ di_write_unlock(parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ if (!try_aopen) ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ kfree(a); ++out: ++ return err; ++} ++ ++int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, ++ dev_t dev) ++{ ++ struct simple_arg arg = { ++ .type = Mknod, ++ .u.m = { ++ .mode = mode, ++ .dev = dev ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) ++{ ++ struct simple_arg arg = { ++ .type = Symlink, ++ .u.s.symname = symname ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ++ bool want_excl) ++{ ++ struct simple_arg arg = { ++ .type = Creat, ++ .u.c = { ++ .mode = mode, ++ .want_excl = want_excl ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int au_aopen_or_create(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *aopen_args) ++{ ++ struct simple_arg arg = { ++ .type = Creat, ++ .u.c = { ++ .mode = aopen_args->create_mode, ++ .want_excl = aopen_args->open_flag & O_EXCL, ++ .try_aopen = true, ++ .aopen = aopen_args ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent, *h_dentry; ++ struct inode *h_dir, *inode; ++ struct vfsmount *h_mnt; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = AuWrDir_TMPFILE ++ }; ++ ++ /* copy-up may happen */ ++ inode_lock(dir); ++ ++ sb = dir->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_di_init(dentry); ++ if (unlikely(err)) ++ goto out_si; ++ ++ err = -EBUSY; ++ parent = d_find_any_alias(dir); ++ AuDebugOn(!parent); ++ di_write_lock_parent(parent); ++ if (unlikely(d_inode(parent) != dir)) ++ goto out_parent; ++ ++ err = au_digen_test(parent, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ bindex = au_dbtop(parent); ++ au_set_dbtop(dentry, bindex); ++ au_set_dbbot(dentry, bindex); ++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); ++ bindex = err; ++ if (unlikely(err < 0)) ++ goto out_parent; ++ ++ err = -EOPNOTSUPP; ++ h_dir = au_h_iptr(dir, bindex); ++ if (unlikely(!h_dir->i_op->tmpfile)) ++ goto out_parent; ++ ++ h_mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mnt_want_write(h_mnt); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ h_parent = au_h_dptr(parent, bindex); ++ err = inode_permission(d_inode(h_parent), MAY_WRITE | MAY_EXEC); ++ if (unlikely(err)) ++ goto out_mnt; ++ ++ err = -ENOMEM; ++ h_dentry = d_alloc(h_parent, &dentry->d_name); ++ if (unlikely(!h_dentry)) ++ goto out_mnt; ++ ++ err = h_dir->i_op->tmpfile(h_dir, h_dentry, mode); ++ if (unlikely(err)) ++ goto out_dentry; ++ ++ au_set_dbtop(dentry, bindex); ++ au_set_dbbot(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, dget(h_dentry)); ++ inode = au_new_inode(dentry, /*must_new*/1); ++ if (IS_ERR(inode)) { ++ err = PTR_ERR(inode); ++ au_set_h_dptr(dentry, bindex, NULL); ++ au_set_dbtop(dentry, -1); ++ au_set_dbbot(dentry, -1); ++ } else { ++ if (!inode->i_nlink) ++ set_nlink(inode, 1); ++ d_tmpfile(dentry, inode); ++ au_di(dentry)->di_tmpfile = 1; ++ ++ /* update without i_mutex */ ++ if (au_ibtop(dir) == au_dbtop(dentry)) ++ au_cpup_attr_timesizes(dir); ++ } ++ ++out_dentry: ++ dput(h_dentry); ++out_mnt: ++ vfsub_mnt_drop_write(h_mnt); ++out_parent: ++ di_write_unlock(parent); ++ dput(parent); ++ di_write_unlock(dentry); ++ if (unlikely(err)) { ++ au_di_fin(dentry); ++ dentry->d_fsdata = NULL; ++ } ++out_si: ++ si_read_unlock(sb); ++out: ++ inode_unlock(dir); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_link_args { ++ aufs_bindex_t bdst, bsrc; ++ struct au_pin pin; ++ struct path h_path; ++ struct dentry *src_parent, *parent; ++}; ++ ++static int au_cpup_before_link(struct dentry *src_dentry, ++ struct au_link_args *a) ++{ ++ int err; ++ struct dentry *h_src_dentry; ++ struct au_cp_generic cpg = { ++ .dentry = src_dentry, ++ .bdst = a->bdst, ++ .bsrc = a->bsrc, ++ .len = -1, ++ .pin = &a->pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN /* | AuCpup_KEEPLINO */ ++ }; ++ ++ di_read_lock_parent(a->src_parent, AuLock_IR); ++ err = au_test_and_cpup_dirs(src_dentry, a->bdst); ++ if (unlikely(err)) ++ goto out; ++ ++ h_src_dentry = au_h_dptr(src_dentry, a->bsrc); ++ err = au_pin(&a->pin, src_dentry, a->bdst, ++ au_opt_udba(src_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&a->pin); ++ ++out: ++ di_read_unlock(a->src_parent, AuLock_IR); ++ return err; ++} ++ ++static int au_cpup_or_link(struct dentry *src_dentry, struct dentry *dentry, ++ struct au_link_args *a) ++{ ++ int err; ++ unsigned char plink; ++ aufs_bindex_t bbot; ++ struct dentry *h_src_dentry; ++ struct inode *h_inode, *inode, *delegated; ++ struct super_block *sb; ++ struct file *h_file; ++ ++ plink = 0; ++ h_inode = NULL; ++ sb = src_dentry->d_sb; ++ inode = d_inode(src_dentry); ++ if (au_ibtop(inode) <= a->bdst) ++ h_inode = au_h_iptr(inode, a->bdst); ++ if (!h_inode || !h_inode->i_nlink) { ++ /* copyup src_dentry as the name of dentry. */ ++ bbot = au_dbbot(dentry); ++ if (bbot < a->bsrc) ++ au_set_dbbot(dentry, a->bsrc); ++ au_set_h_dptr(dentry, a->bsrc, ++ dget(au_h_dptr(src_dentry, a->bsrc))); ++ dget(a->h_path.dentry); ++ au_set_h_dptr(dentry, a->bdst, NULL); ++ AuDbg("temporary d_inode...\n"); ++ spin_lock(&dentry->d_lock); ++ dentry->d_inode = d_inode(src_dentry); /* tmp */ ++ spin_unlock(&dentry->d_lock); ++ h_file = au_h_open_pre(dentry, a->bsrc, /*force_wr*/0); ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->bdst, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &a->pin, ++ .flags = AuCpup_KEEPLINO ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ au_h_open_post(dentry, a->bsrc, h_file); ++ if (!err) { ++ dput(a->h_path.dentry); ++ a->h_path.dentry = au_h_dptr(dentry, a->bdst); ++ } else ++ au_set_h_dptr(dentry, a->bdst, ++ a->h_path.dentry); ++ } ++ spin_lock(&dentry->d_lock); ++ dentry->d_inode = NULL; /* restore */ ++ spin_unlock(&dentry->d_lock); ++ AuDbg("temporary d_inode...done\n"); ++ au_set_h_dptr(dentry, a->bsrc, NULL); ++ au_set_dbbot(dentry, bbot); ++ } else { ++ /* the inode of src_dentry already exists on a.bdst branch */ ++ h_src_dentry = d_find_alias(h_inode); ++ if (!h_src_dentry && au_plink_test(inode)) { ++ plink = 1; ++ h_src_dentry = au_plink_lkup(inode, a->bdst); ++ err = PTR_ERR(h_src_dentry); ++ if (IS_ERR(h_src_dentry)) ++ goto out; ++ ++ if (unlikely(d_is_negative(h_src_dentry))) { ++ dput(h_src_dentry); ++ h_src_dentry = NULL; ++ } ++ ++ } ++ if (h_src_dentry) { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ dput(h_src_dentry); ++ } else { ++ AuIOErr("no dentry found for hi%lu on b%d\n", ++ h_inode->i_ino, a->bdst); ++ err = -EIO; ++ } ++ } ++ ++ if (!err && !plink) ++ au_plink_append(inode, a->bdst, a->h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry) ++{ ++ int err, rerr; ++ struct au_dtime dt; ++ struct au_link_args *a; ++ struct dentry *wh_dentry, *h_src_dentry; ++ struct inode *inode, *delegated; ++ struct super_block *sb; ++ struct au_wr_dir_args wr_dir_args = { ++ /* .force_btgt = -1, */ ++ .flags = AuWrDir_ADD_ENTRY ++ }; ++ ++ IMustLock(dir); ++ inode = d_inode(src_dentry); ++ IMustLock(inode); ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ a->parent = dentry->d_parent; /* dir inode is locked */ ++ err = aufs_read_and_write_lock2(dentry, src_dentry, ++ AuLock_NOPLM | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_kfree; ++ err = au_d_linkable(src_dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ a->src_parent = dget_parent(src_dentry); ++ wr_dir_args.force_btgt = au_ibtop(inode); ++ ++ di_write_lock_parent(a->parent); ++ wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin, ++ &wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ a->bdst = au_dbtop(dentry); ++ a->h_path.dentry = au_h_dptr(dentry, a->bdst); ++ a->h_path.mnt = au_sbr_mnt(sb, a->bdst); ++ a->bsrc = au_ibtop(inode); ++ h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); ++ if (!h_src_dentry && au_di(src_dentry)->di_tmpfile) ++ h_src_dentry = dget(au_hi_wh(inode, a->bsrc)); ++ if (!h_src_dentry) { ++ a->bsrc = au_dbtop(src_dentry); ++ h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); ++ AuDebugOn(!h_src_dentry); ++ } else if (IS_ERR(h_src_dentry)) { ++ err = PTR_ERR(h_src_dentry); ++ goto out_parent; ++ } ++ ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ if (a->bdst < a->bsrc ++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) ++ err = au_cpup_or_link(src_dentry, dentry, a); ++ else { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ dput(h_src_dentry); ++ } else { ++ /* ++ * copyup src_dentry to the branch we process, ++ * and then link(2) to it. ++ */ ++ dput(h_src_dentry); ++ if (a->bdst < a->bsrc ++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) { ++ au_unpin(&a->pin); ++ di_write_unlock(a->parent); ++ err = au_cpup_before_link(src_dentry, a); ++ di_write_lock_parent(a->parent); ++ if (!err) ++ err = au_pin(&a->pin, dentry, a->bdst, ++ au_opt_udba(sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_wh; ++ } ++ if (!err) { ++ h_src_dentry = au_h_dptr(src_dentry, a->bdst); ++ err = -ENOENT; ++ if (h_src_dentry && d_is_positive(h_src_dentry)) { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, ++ au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry" ++ " for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ } ++ } ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ if (wh_dentry) { ++ a->h_path.dentry = wh_dentry; ++ err = au_wh_unlink_dentry(au_pinned_h_dir(&a->pin), &a->h_path, ++ dentry); ++ if (unlikely(err)) ++ goto out_revert; ++ } ++ ++ au_dir_ts(dir, a->bdst); ++ dir->i_version++; ++ inc_nlink(inode); ++ inode->i_ctime = dir->i_ctime; ++ d_instantiate(dentry, au_igrab(inode)); ++ if (d_unhashed(a->h_path.dentry)) ++ /* some filesystem calls d_drop() */ ++ d_drop(dentry); ++ /* some filesystems consume an inode even hardlink */ ++ au_fhsm_wrote(sb, a->bdst, /*force*/0); ++ goto out_unpin; /* success */ ++ ++out_revert: ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, ++ /*delegated*/NULL, /*force*/0); ++ if (unlikely(rerr)) { ++ AuIOErr("%pd reverting failed(%d, %d)\n", dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&dt); ++out_unpin: ++ au_unpin(&a->pin); ++out_wh: ++ dput(wh_dentry); ++out_parent: ++ di_write_unlock(a->parent); ++ dput(a->src_parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ aufs_read_and_write_unlock2(dentry, src_dentry); ++out_kfree: ++ kfree(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ++{ ++ int err, rerr; ++ aufs_bindex_t bindex; ++ unsigned char diropq; ++ struct path h_path; ++ struct dentry *wh_dentry, *parent, *opq_dentry; ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct { ++ struct au_pin pin; ++ struct au_dtime dt; ++ } *a; /* reduce the stack usage */ ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = AuWrDir_ADD_ENTRY | AuWrDir_ISDIR ++ }; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, ++ &a->pin, &wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ sb = dentry->d_sb; ++ bindex = au_dbtop(dentry); ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode); ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ /* make the dir opaque */ ++ diropq = 0; ++ h_inode = d_inode(h_path.dentry); ++ if (wh_dentry ++ || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) { ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ opq_dentry = au_diropq_create(dentry, bindex); ++ inode_unlock(h_inode); ++ err = PTR_ERR(opq_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out_dir; ++ dput(opq_dentry); ++ diropq = 1; ++ } ++ ++ err = epilog(dir, bindex, wh_dentry, dentry); ++ if (!err) { ++ inc_nlink(dir); ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ if (diropq) { ++ AuLabel(revert opq); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bindex); ++ inode_unlock(h_inode); ++ if (rerr) { ++ AuIOErr("%pd reverting diropq failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ } ++ ++out_dir: ++ AuLabel(revert dir); ++ rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path); ++ if (rerr) { ++ AuIOErr("%pd reverting dir failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&a->dt); ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++out_parent: ++ di_write_unlock(parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ kfree(a); ++out: ++ return err; ++} +diff --git a/fs/aufs/i_op_del.c b/fs/aufs/i_op_del.c +new file mode 100644 +index 0000000..35b923c +--- /dev/null ++++ b/fs/aufs/i_op_del.c +@@ -0,0 +1,498 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations (del entry) ++ */ ++ ++#include "aufs.h" ++ ++/* ++ * decide if a new whiteout for @dentry is necessary or not. ++ * when it is necessary, prepare the parent dir for the upper branch whose ++ * branch index is @bcpup for creation. the actual creation of the whiteout will ++ * be done by caller. ++ * return value: ++ * 0: wh is unnecessary ++ * plus: wh is necessary ++ * minus: error ++ */ ++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup) ++{ ++ int need_wh, err; ++ aufs_bindex_t btop; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ if (*bcpup < 0) { ++ *bcpup = btop; ++ if (au_test_ro(sb, btop, d_inode(dentry))) { ++ err = AuWbrCopyup(au_sbi(sb), dentry); ++ *bcpup = err; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else ++ AuDebugOn(btop < *bcpup ++ || au_test_ro(sb, *bcpup, d_inode(dentry))); ++ AuDbg("bcpup %d, btop %d\n", *bcpup, btop); ++ ++ if (*bcpup != btop) { ++ err = au_cpup_dirs(dentry, *bcpup); ++ if (unlikely(err)) ++ goto out; ++ need_wh = 1; ++ } else { ++ struct au_dinfo *dinfo, *tmp; ++ ++ need_wh = -ENOMEM; ++ dinfo = au_di(dentry); ++ tmp = au_di_alloc(sb, AuLsc_DI_TMP); ++ if (tmp) { ++ au_di_cp(tmp, dinfo); ++ au_di_swap(tmp, dinfo); ++ /* returns the number of positive dentries */ ++ need_wh = au_lkup_dentry(dentry, btop + 1, ++ /* AuLkup_IGNORE_PERM */ 0); ++ au_di_swap(tmp, dinfo); ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ } ++ } ++ AuDbg("need_wh %d\n", need_wh); ++ err = need_wh; ++ ++out: ++ return err; ++} ++ ++/* ++ * simple tests for the del-entry operations. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir) ++{ ++ int err; ++ umode_t h_mode; ++ struct dentry *h_dentry, *h_latest; ++ struct inode *h_inode; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (d_really_is_positive(dentry)) { ++ err = -ENOENT; ++ if (unlikely(d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ if (unlikely(!h_inode->i_nlink)) ++ goto out; ++ ++ h_mode = h_inode->i_mode; ++ if (!isdir) { ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(h_mode))) ++ goto out; ++ } else if (unlikely(!S_ISDIR(h_mode))) { ++ err = -ENOTDIR; ++ goto out; ++ } ++ } else { ++ /* rename(2) case */ ++ err = -EIO; ++ if (unlikely(d_is_positive(h_dentry))) ++ goto out; ++ } ++ ++ err = -ENOENT; ++ /* expected parent dir is locked */ ++ if (unlikely(h_parent != h_dentry->d_parent)) ++ goto out; ++ err = 0; ++ ++ /* ++ * rmdir a dir may break the consistency on some filesystem. ++ * let's try heavy test. ++ */ ++ err = -EACCES; ++ if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1) ++ && au_test_h_perm(d_inode(h_parent), ++ MAY_EXEC | MAY_WRITE))) ++ goto out; ++ ++ h_latest = au_sio_lkup_one(&dentry->d_name, h_parent); ++ err = -EIO; ++ if (IS_ERR(h_latest)) ++ goto out; ++ if (h_latest == h_dentry) ++ err = 0; ++ dput(h_latest); ++ ++out: ++ return err; ++} ++ ++/* ++ * decide the branch where we operate for @dentry. the branch index will be set ++ * @rbcpup. after diciding it, 'pin' it and store the timestamps of the parent ++ * dir for reverting. ++ * when a new whiteout is necessary, create it. ++ */ ++static struct dentry* ++lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup, ++ struct au_dtime *dt, struct au_pin *pin) ++{ ++ struct dentry *wh_dentry; ++ struct super_block *sb; ++ struct path h_path; ++ int err, need_wh; ++ unsigned int udba; ++ aufs_bindex_t bcpup; ++ ++ need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup); ++ wh_dentry = ERR_PTR(need_wh); ++ if (unlikely(need_wh < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ udba = au_opt_udba(sb); ++ bcpup = *rbcpup; ++ err = au_pin(pin, dentry, bcpup, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ h_path.dentry = au_pinned_h_parent(pin); ++ if (udba != AuOpt_UDBA_NONE ++ && au_dbtop(dentry) == bcpup) { ++ err = au_may_del(dentry, bcpup, h_path.dentry, isdir); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_unpin; ++ } ++ ++ h_path.mnt = au_sbr_mnt(sb, bcpup); ++ au_dtime_store(dt, au_pinned_parent(pin), &h_path); ++ wh_dentry = NULL; ++ if (!need_wh) ++ goto out; /* success, no need to create whiteout */ ++ ++ wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_unpin; ++ ++ /* returns with the parent is locked and wh_dentry is dget-ed */ ++ goto out; /* success */ ++ ++out_unpin: ++ au_unpin(pin); ++out: ++ return wh_dentry; ++} ++ ++/* ++ * when removing a dir, rename it to a unique temporary whiteout-ed name first ++ * in order to be revertible and save time for removing many child whiteouts ++ * under the dir. ++ * returns 1 when there are too many child whiteout and caller should remove ++ * them asynchronously. returns 0 when the number of children is enough small to ++ * remove now or the branch fs is a remote fs. ++ * otherwise return an error. ++ */ ++static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex, ++ struct au_nhash *whlist, struct inode *dir) ++{ ++ int rmdir_later, err, dirwh; ++ struct dentry *h_dentry; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ sb = dentry->d_sb; ++ SiMustAnyLock(sb); ++ h_dentry = au_h_dptr(dentry, bindex); ++ err = au_whtmp_ren(h_dentry, au_sbr(sb, bindex)); ++ if (unlikely(err)) ++ goto out; ++ ++ /* stop monitoring */ ++ inode = d_inode(dentry); ++ au_hn_free(au_hi(inode, bindex)); ++ ++ if (!au_test_fs_remote(h_dentry->d_sb)) { ++ dirwh = au_sbi(sb)->si_dirwh; ++ rmdir_later = (dirwh <= 1); ++ if (!rmdir_later) ++ rmdir_later = au_nhash_test_longer_wh(whlist, bindex, ++ dirwh); ++ if (rmdir_later) ++ return rmdir_later; ++ } ++ ++ err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist); ++ if (unlikely(err)) { ++ AuIOErr("rmdir %pd, b%d failed, %d. ignored\n", ++ h_dentry, bindex, err); ++ err = 0; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * final procedure for deleting a entry. ++ * maintain dentry and iattr. ++ */ ++static void epilog(struct inode *dir, struct dentry *dentry, ++ aufs_bindex_t bindex) ++{ ++ struct inode *inode; ++ ++ inode = d_inode(dentry); ++ d_drop(dentry); ++ inode->i_ctime = dir->i_ctime; ++ ++ au_dir_ts(dir, bindex); ++ dir->i_version++; ++} ++ ++/* ++ * when an error happened, remove the created whiteout and revert everything. ++ */ ++static int do_revert(int err, struct inode *dir, aufs_bindex_t bindex, ++ aufs_bindex_t bwh, struct dentry *wh_dentry, ++ struct dentry *dentry, struct au_dtime *dt) ++{ ++ int rerr; ++ struct path h_path = { ++ .dentry = wh_dentry, ++ .mnt = au_sbr_mnt(dir->i_sb, bindex) ++ }; ++ ++ rerr = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, dentry); ++ if (!rerr) { ++ au_set_dbwh(dentry, bwh); ++ au_dtime_revert(dt); ++ return 0; ++ } ++ ++ AuIOErr("%pd reverting whiteout failed(%d, %d)\n", dentry, err, rerr); ++ return -EIO; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_unlink(struct inode *dir, struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bwh, bindex, btop; ++ struct inode *inode, *h_dir, *delegated; ++ struct dentry *parent, *wh_dentry; ++ /* to reuduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct path h_path; ++ } *a; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_d_hashed_positive(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ err = -EISDIR; ++ if (unlikely(d_is_dir(dentry))) ++ goto out_unlock; /* possible? */ ++ ++ btop = au_dbtop(dentry); ++ bwh = au_dbwh(dentry); ++ bindex = -1; ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &a->dt, ++ &a->pin); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ a->h_path.mnt = au_sbr_mnt(dentry->d_sb, btop); ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ dget(a->h_path.dentry); ++ if (bindex == btop) { ++ h_dir = au_pinned_h_dir(&a->pin); ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &a->h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } else { ++ /* dir inode is locked */ ++ h_dir = d_inode(wh_dentry->d_parent); ++ IMustLock(h_dir); ++ err = 0; ++ } ++ ++ if (!err) { ++ vfsub_drop_nlink(inode); ++ epilog(dir, dentry, bindex); ++ ++ /* update target timestamps */ ++ if (bindex == btop) { ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); ++ /*ignore*/ ++ inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ } else ++ /* todo: this timestamp may be reverted later */ ++ inode->i_ctime = h_dir->i_ctime; ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ if (wh_dentry) { ++ int rerr; ++ ++ rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, ++ &a->dt); ++ if (rerr) ++ err = rerr; ++ } ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ dput(a->h_path.dentry); ++out_parent: ++ di_write_unlock(parent); ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ kfree(a); ++out: ++ return err; ++} ++ ++int aufs_rmdir(struct inode *dir, struct dentry *dentry) ++{ ++ int err, rmdir_later; ++ aufs_bindex_t bwh, bindex, btop; ++ struct inode *inode; ++ struct dentry *parent, *wh_dentry, *h_dentry; ++ struct au_whtmp_rmdir *args; ++ /* to reuduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ } *a; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_alive_dir(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ err = -ENOTDIR; ++ if (unlikely(!d_is_dir(dentry))) ++ goto out_unlock; /* possible? */ ++ ++ err = -ENOMEM; ++ args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS); ++ if (unlikely(!args)) ++ goto out_unlock; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ err = au_test_empty(dentry, &args->whlist); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ btop = au_dbtop(dentry); ++ bwh = au_dbwh(dentry); ++ bindex = -1; ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &a->dt, ++ &a->pin); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ h_dentry = au_h_dptr(dentry, btop); ++ dget(h_dentry); ++ rmdir_later = 0; ++ if (bindex == btop) { ++ err = renwh_and_rmdir(dentry, btop, &args->whlist, dir); ++ if (err > 0) { ++ rmdir_later = err; ++ err = 0; ++ } ++ } else { ++ /* stop monitoring */ ++ au_hn_free(au_hi(inode, btop)); ++ ++ /* dir inode is locked */ ++ IMustLock(d_inode(wh_dentry->d_parent)); ++ err = 0; ++ } ++ ++ if (!err) { ++ vfsub_dead_dir(inode); ++ au_set_dbdiropq(dentry, -1); ++ epilog(dir, dentry, bindex); ++ ++ if (rmdir_later) { ++ au_whtmp_kick_rmdir(dir, btop, h_dentry, args); ++ args = NULL; ++ } ++ ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ AuLabel(revert); ++ if (wh_dentry) { ++ int rerr; ++ ++ rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, ++ &a->dt); ++ if (rerr) ++ err = rerr; ++ } ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ dput(h_dentry); ++out_parent: ++ di_write_unlock(parent); ++ if (args) ++ au_whtmp_rmdir_free(args); ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ kfree(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c +new file mode 100644 +index 0000000..df697de +--- /dev/null ++++ b/fs/aufs/i_op_ren.c +@@ -0,0 +1,1002 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operation (rename entry) ++ * todo: this is crazy monster ++ */ ++ ++#include "aufs.h" ++ ++enum { AuSRC, AuDST, AuSrcDst }; ++enum { AuPARENT, AuCHILD, AuParentChild }; ++ ++#define AuRen_ISDIR 1 ++#define AuRen_ISSAMEDIR (1 << 1) ++#define AuRen_WHSRC (1 << 2) ++#define AuRen_WHDST (1 << 3) ++#define AuRen_MNT_WRITE (1 << 4) ++#define AuRen_DT_DSTDIR (1 << 5) ++#define AuRen_DIROPQ (1 << 6) ++#define au_ftest_ren(flags, name) ((flags) & AuRen_##name) ++#define au_fset_ren(flags, name) \ ++ do { (flags) |= AuRen_##name; } while (0) ++#define au_fclr_ren(flags, name) \ ++ do { (flags) &= ~AuRen_##name; } while (0) ++ ++struct au_ren_args { ++ struct { ++ struct dentry *dentry, *h_dentry, *parent, *h_parent, ++ *wh_dentry; ++ struct inode *dir, *inode; ++ struct au_hinode *hdir; ++ struct au_dtime dt[AuParentChild]; ++ aufs_bindex_t btop; ++ } sd[AuSrcDst]; ++ ++#define src_dentry sd[AuSRC].dentry ++#define src_dir sd[AuSRC].dir ++#define src_inode sd[AuSRC].inode ++#define src_h_dentry sd[AuSRC].h_dentry ++#define src_parent sd[AuSRC].parent ++#define src_h_parent sd[AuSRC].h_parent ++#define src_wh_dentry sd[AuSRC].wh_dentry ++#define src_hdir sd[AuSRC].hdir ++#define src_h_dir sd[AuSRC].hdir->hi_inode ++#define src_dt sd[AuSRC].dt ++#define src_btop sd[AuSRC].btop ++ ++#define dst_dentry sd[AuDST].dentry ++#define dst_dir sd[AuDST].dir ++#define dst_inode sd[AuDST].inode ++#define dst_h_dentry sd[AuDST].h_dentry ++#define dst_parent sd[AuDST].parent ++#define dst_h_parent sd[AuDST].h_parent ++#define dst_wh_dentry sd[AuDST].wh_dentry ++#define dst_hdir sd[AuDST].hdir ++#define dst_h_dir sd[AuDST].hdir->hi_inode ++#define dst_dt sd[AuDST].dt ++#define dst_btop sd[AuDST].btop ++ ++ struct dentry *h_trap; ++ struct au_branch *br; ++ struct au_hinode *src_hinode; ++ struct path h_path; ++ struct au_nhash whlist; ++ aufs_bindex_t btgt, src_bwh, src_bdiropq; ++ ++ unsigned int flags; ++ ++ struct au_whtmp_rmdir *thargs; ++ struct dentry *h_dst; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * functions for reverting. ++ * when an error happened in a single rename systemcall, we should revert ++ * everything as if nothing happened. ++ * we don't need to revert the copied-up/down the parent dir since they are ++ * harmless. ++ */ ++ ++#define RevertFailure(fmt, ...) do { \ ++ AuIOErr("revert failure: " fmt " (%d, %d)\n", \ ++ ##__VA_ARGS__, err, rerr); \ ++ err = -EIO; \ ++} while (0) ++ ++static void au_ren_rev_diropq(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ ++ au_hn_inode_lock_nested(a->src_hinode, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(a->src_dentry, a->btgt); ++ au_hn_inode_unlock(a->src_hinode); ++ au_set_dbdiropq(a->src_dentry, a->src_bdiropq); ++ if (rerr) ++ RevertFailure("remove diropq %pd", a->src_dentry); ++} ++ ++static void au_ren_rev_rename(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ struct inode *delegated; ++ ++ a->h_path.dentry = vfsub_lkup_one(&a->src_dentry->d_name, ++ a->src_h_parent); ++ rerr = PTR_ERR(a->h_path.dentry); ++ if (IS_ERR(a->h_path.dentry)) { ++ RevertFailure("lkup one %pd", a->src_dentry); ++ return; ++ } ++ ++ delegated = NULL; ++ rerr = vfsub_rename(a->dst_h_dir, ++ au_h_dptr(a->src_dentry, a->btgt), ++ a->src_h_dir, &a->h_path, &delegated); ++ if (unlikely(rerr == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ /* au_set_h_dptr(a->src_dentry, a->btgt, NULL); */ ++ if (rerr) ++ RevertFailure("rename %pd", a->src_dentry); ++} ++ ++static void au_ren_rev_whtmp(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ struct inode *delegated; ++ ++ a->h_path.dentry = vfsub_lkup_one(&a->dst_dentry->d_name, ++ a->dst_h_parent); ++ rerr = PTR_ERR(a->h_path.dentry); ++ if (IS_ERR(a->h_path.dentry)) { ++ RevertFailure("lkup one %pd", a->dst_dentry); ++ return; ++ } ++ if (d_is_positive(a->h_path.dentry)) { ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ return; ++ } ++ ++ delegated = NULL; ++ rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path, ++ &delegated); ++ if (unlikely(rerr == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ if (!rerr) ++ au_set_h_dptr(a->dst_dentry, a->btgt, dget(a->h_dst)); ++ else ++ RevertFailure("rename %pd", a->h_dst); ++} ++ ++static void au_ren_rev_whsrc(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ ++ a->h_path.dentry = a->src_wh_dentry; ++ rerr = au_wh_unlink_dentry(a->src_h_dir, &a->h_path, a->src_dentry); ++ au_set_dbwh(a->src_dentry, a->src_bwh); ++ if (rerr) ++ RevertFailure("unlink %pd", a->src_wh_dentry); ++} ++#undef RevertFailure ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * when we have to copyup the renaming entry, do it with the rename-target name ++ * in order to minimize the cost (the later actual rename is unnecessary). ++ * otherwise rename it on the target branch. ++ */ ++static int au_ren_or_cpup(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *d; ++ struct inode *delegated; ++ ++ d = a->src_dentry; ++ if (au_dbtop(d) == a->btgt) { ++ a->h_path.dentry = a->dst_h_dentry; ++ if (au_ftest_ren(a->flags, DIROPQ) ++ && au_dbdiropq(d) == a->btgt) ++ au_fclr_ren(a->flags, DIROPQ); ++ AuDebugOn(au_dbtop(d) != a->btgt); ++ delegated = NULL; ++ err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt), ++ a->dst_h_dir, &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ } else ++ BUG(); ++ ++ if (!err && a->h_dst) ++ /* it will be set to dinfo later */ ++ dget(a->h_dst); ++ ++ return err; ++} ++ ++/* cf. aufs_rmdir() */ ++static int au_ren_del_whtmp(struct au_ren_args *a) ++{ ++ int err; ++ struct inode *dir; ++ ++ dir = a->dst_dir; ++ SiMustAnyLock(dir->i_sb); ++ if (!au_nhash_test_longer_wh(&a->whlist, a->btgt, ++ au_sbi(dir->i_sb)->si_dirwh) ++ || au_test_fs_remote(a->h_dst->d_sb)) { ++ err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist); ++ if (unlikely(err)) ++ pr_warn("failed removing whtmp dir %pd (%d), " ++ "ignored.\n", a->h_dst, err); ++ } else { ++ au_nhash_wh_free(&a->thargs->whlist); ++ a->thargs->whlist = a->whlist; ++ a->whlist.nh_num = 0; ++ au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs); ++ dput(a->h_dst); ++ a->thargs = NULL; ++ } ++ ++ return 0; ++} ++ ++/* make it 'opaque' dir. */ ++static int au_ren_diropq(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *diropq; ++ ++ err = 0; ++ a->src_bdiropq = au_dbdiropq(a->src_dentry); ++ a->src_hinode = au_hi(a->src_inode, a->btgt); ++ au_hn_inode_lock_nested(a->src_hinode, AuLsc_I_CHILD); ++ diropq = au_diropq_create(a->src_dentry, a->btgt); ++ au_hn_inode_unlock(a->src_hinode); ++ if (IS_ERR(diropq)) ++ err = PTR_ERR(diropq); ++ else ++ dput(diropq); ++ ++ return err; ++} ++ ++static int do_rename(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *d, *h_d; ++ ++ /* prepare workqueue args for asynchronous rmdir */ ++ h_d = a->dst_h_dentry; ++ if (au_ftest_ren(a->flags, ISDIR) && d_is_positive(h_d)) { ++ err = -ENOMEM; ++ a->thargs = au_whtmp_rmdir_alloc(a->src_dentry->d_sb, GFP_NOFS); ++ if (unlikely(!a->thargs)) ++ goto out; ++ a->h_dst = dget(h_d); ++ } ++ ++ /* create whiteout for src_dentry */ ++ if (au_ftest_ren(a->flags, WHSRC)) { ++ a->src_bwh = au_dbwh(a->src_dentry); ++ AuDebugOn(a->src_bwh >= 0); ++ a->src_wh_dentry ++ = au_wh_create(a->src_dentry, a->btgt, a->src_h_parent); ++ err = PTR_ERR(a->src_wh_dentry); ++ if (IS_ERR(a->src_wh_dentry)) ++ goto out_thargs; ++ } ++ ++ /* lookup whiteout for dentry */ ++ if (au_ftest_ren(a->flags, WHDST)) { ++ h_d = au_wh_lkup(a->dst_h_parent, &a->dst_dentry->d_name, ++ a->br); ++ err = PTR_ERR(h_d); ++ if (IS_ERR(h_d)) ++ goto out_whsrc; ++ if (d_is_negative(h_d)) ++ dput(h_d); ++ else ++ a->dst_wh_dentry = h_d; ++ } ++ ++ /* rename dentry to tmpwh */ ++ if (a->thargs) { ++ err = au_whtmp_ren(a->dst_h_dentry, a->br); ++ if (unlikely(err)) ++ goto out_whdst; ++ ++ d = a->dst_dentry; ++ au_set_h_dptr(d, a->btgt, NULL); ++ err = au_lkup_neg(d, a->btgt, /*wh*/0); ++ if (unlikely(err)) ++ goto out_whtmp; ++ a->dst_h_dentry = au_h_dptr(d, a->btgt); ++ } ++ ++ BUG_ON(d_is_positive(a->dst_h_dentry) && a->src_btop != a->btgt); ++ ++ /* rename by vfs_rename or cpup */ ++ d = a->dst_dentry; ++ if (au_ftest_ren(a->flags, ISDIR) ++ && (a->dst_wh_dentry ++ || au_dbdiropq(d) == a->btgt ++ /* hide the lower to keep xino */ ++ || a->btgt < au_dbbot(d) ++ || au_opt_test(au_mntflags(d->d_sb), ALWAYS_DIROPQ))) ++ au_fset_ren(a->flags, DIROPQ); ++ err = au_ren_or_cpup(a); ++ if (unlikely(err)) ++ /* leave the copied-up one */ ++ goto out_whtmp; ++ ++ /* make dir opaque */ ++ if (au_ftest_ren(a->flags, DIROPQ)) { ++ err = au_ren_diropq(a); ++ if (unlikely(err)) ++ goto out_rename; ++ } ++ ++ /* update target timestamps */ ++ AuDebugOn(au_dbtop(a->src_dentry) != a->btgt); ++ a->h_path.dentry = au_h_dptr(a->src_dentry, a->btgt); ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ ++ a->src_inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ ++ /* remove whiteout for dentry */ ++ if (a->dst_wh_dentry) { ++ a->h_path.dentry = a->dst_wh_dentry; ++ err = au_wh_unlink_dentry(a->dst_h_dir, &a->h_path, ++ a->dst_dentry); ++ if (unlikely(err)) ++ goto out_diropq; ++ } ++ ++ /* remove whtmp */ ++ if (a->thargs) ++ au_ren_del_whtmp(a); /* ignore this error */ ++ ++ au_fhsm_wrote(a->src_dentry->d_sb, a->btgt, /*force*/0); ++ err = 0; ++ goto out_success; ++ ++out_diropq: ++ if (au_ftest_ren(a->flags, DIROPQ)) ++ au_ren_rev_diropq(err, a); ++out_rename: ++ au_ren_rev_rename(err, a); ++ dput(a->h_dst); ++out_whtmp: ++ if (a->thargs) ++ au_ren_rev_whtmp(err, a); ++out_whdst: ++ dput(a->dst_wh_dentry); ++ a->dst_wh_dentry = NULL; ++out_whsrc: ++ if (a->src_wh_dentry) ++ au_ren_rev_whsrc(err, a); ++out_success: ++ dput(a->src_wh_dentry); ++ dput(a->dst_wh_dentry); ++out_thargs: ++ if (a->thargs) { ++ dput(a->h_dst); ++ au_whtmp_rmdir_free(a->thargs); ++ a->thargs = NULL; ++ } ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if @dentry dir can be rename destination or not. ++ * success means, it is a logically empty dir. ++ */ ++static int may_rename_dstdir(struct dentry *dentry, struct au_nhash *whlist) ++{ ++ return au_test_empty(dentry, whlist); ++} ++ ++/* ++ * test if @dentry dir can be rename source or not. ++ * if it can, return 0 and @children is filled. ++ * success means, ++ * - it is a logically empty dir. ++ * - or, it exists on writable branch and has no children including whiteouts ++ * on the lower branch. ++ */ ++static int may_rename_srcdir(struct dentry *dentry, aufs_bindex_t btgt) ++{ ++ int err; ++ unsigned int rdhash; ++ aufs_bindex_t btop; ++ ++ btop = au_dbtop(dentry); ++ if (btop != btgt) { ++ struct au_nhash whlist; ++ ++ SiMustAnyLock(dentry->d_sb); ++ rdhash = au_sbi(dentry->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, ++ dentry)); ++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_test_empty(dentry, &whlist); ++ au_nhash_wh_free(&whlist); ++ goto out; ++ } ++ ++ if (btop == au_dbtaildir(dentry)) ++ return 0; /* success */ ++ ++ err = au_test_empty_lower(dentry); ++ ++out: ++ if (err == -ENOTEMPTY) { ++ AuWarn1("renaming dir who has child(ren) on multiple branches," ++ " is not supported\n"); ++ err = -EXDEV; ++ } ++ return err; ++} ++ ++/* side effect: sets whlist and h_dentry */ ++static int au_ren_may_dir(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int rdhash; ++ struct dentry *d; ++ ++ d = a->dst_dentry; ++ SiMustAnyLock(d->d_sb); ++ ++ err = 0; ++ if (au_ftest_ren(a->flags, ISDIR) && a->dst_inode) { ++ rdhash = au_sbi(d->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, d)); ++ err = au_nhash_alloc(&a->whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ ++ au_set_dbtop(d, a->dst_btop); ++ err = may_rename_dstdir(d, &a->whlist); ++ au_set_dbtop(d, a->btgt); ++ } ++ a->dst_h_dentry = au_h_dptr(d, au_dbtop(d)); ++ if (unlikely(err)) ++ goto out; ++ ++ d = a->src_dentry; ++ a->src_h_dentry = au_h_dptr(d, au_dbtop(d)); ++ if (au_ftest_ren(a->flags, ISDIR)) { ++ err = may_rename_srcdir(d, a->btgt); ++ if (unlikely(err)) { ++ au_nhash_wh_free(&a->whlist); ++ a->whlist.nh_num = 0; ++ } ++ } ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * simple tests for rename. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++static int au_may_ren(struct au_ren_args *a) ++{ ++ int err, isdir; ++ struct inode *h_inode; ++ ++ if (a->src_btop == a->btgt) { ++ err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent, ++ au_ftest_ren(a->flags, ISDIR)); ++ if (unlikely(err)) ++ goto out; ++ err = -EINVAL; ++ if (unlikely(a->src_h_dentry == a->h_trap)) ++ goto out; ++ } ++ ++ err = 0; ++ if (a->dst_btop != a->btgt) ++ goto out; ++ ++ err = -ENOTEMPTY; ++ if (unlikely(a->dst_h_dentry == a->h_trap)) ++ goto out; ++ ++ err = -EIO; ++ isdir = !!au_ftest_ren(a->flags, ISDIR); ++ if (d_really_is_negative(a->dst_dentry)) { ++ if (d_is_negative(a->dst_h_dentry)) ++ err = au_may_add(a->dst_dentry, a->btgt, ++ a->dst_h_parent, isdir); ++ } else { ++ if (unlikely(d_is_negative(a->dst_h_dentry))) ++ goto out; ++ h_inode = d_inode(a->dst_h_dentry); ++ if (h_inode->i_nlink) ++ err = au_may_del(a->dst_dentry, a->btgt, ++ a->dst_h_parent, isdir); ++ } ++ ++out: ++ if (unlikely(err == -ENOENT || err == -EEXIST)) ++ err = -EIO; ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * locking order ++ * (VFS) ++ * - src_dir and dir by lock_rename() ++ * - inode if exitsts ++ * (aufs) ++ * - lock all ++ * + src_dentry and dentry by aufs_read_and_write_lock2() which calls, ++ * + si_read_lock ++ * + di_write_lock2_child() ++ * + di_write_lock_child() ++ * + ii_write_lock_child() ++ * + di_write_lock_child2() ++ * + ii_write_lock_child2() ++ * + src_parent and parent ++ * + di_write_lock_parent() ++ * + ii_write_lock_parent() ++ * + di_write_lock_parent2() ++ * + ii_write_lock_parent2() ++ * + lower src_dir and dir by vfsub_lock_rename() ++ * + verify the every relationships between child and parent. if any ++ * of them failed, unlock all and return -EBUSY. ++ */ ++static void au_ren_unlock(struct au_ren_args *a) ++{ ++ vfsub_unlock_rename(a->src_h_parent, a->src_hdir, ++ a->dst_h_parent, a->dst_hdir); ++ if (au_ftest_ren(a->flags, MNT_WRITE)) ++ vfsub_mnt_drop_write(au_br_mnt(a->br)); ++} ++ ++static int au_ren_lock(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int udba; ++ ++ err = 0; ++ a->src_h_parent = au_h_dptr(a->src_parent, a->btgt); ++ a->src_hdir = au_hi(a->src_dir, a->btgt); ++ a->dst_h_parent = au_h_dptr(a->dst_parent, a->btgt); ++ a->dst_hdir = au_hi(a->dst_dir, a->btgt); ++ ++ err = vfsub_mnt_want_write(au_br_mnt(a->br)); ++ if (unlikely(err)) ++ goto out; ++ au_fset_ren(a->flags, MNT_WRITE); ++ a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir, ++ a->dst_h_parent, a->dst_hdir); ++ udba = au_opt_udba(a->src_dentry->d_sb); ++ if (unlikely(a->src_hdir->hi_inode != d_inode(a->src_h_parent) ++ || a->dst_hdir->hi_inode != d_inode(a->dst_h_parent))) ++ err = au_busy_or_stale(); ++ if (!err && au_dbtop(a->src_dentry) == a->btgt) ++ err = au_h_verify(a->src_h_dentry, udba, ++ d_inode(a->src_h_parent), a->src_h_parent, ++ a->br); ++ if (!err && au_dbtop(a->dst_dentry) == a->btgt) ++ err = au_h_verify(a->dst_h_dentry, udba, ++ d_inode(a->dst_h_parent), a->dst_h_parent, ++ a->br); ++ if (!err) ++ goto out; /* success */ ++ ++ err = au_busy_or_stale(); ++ au_ren_unlock(a); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_ren_refresh_dir(struct au_ren_args *a) ++{ ++ struct inode *dir; ++ ++ dir = a->dst_dir; ++ dir->i_version++; ++ if (au_ftest_ren(a->flags, ISDIR)) { ++ /* is this updating defined in POSIX? */ ++ au_cpup_attr_timesizes(a->src_inode); ++ au_cpup_attr_nlink(dir, /*force*/1); ++ } ++ ++ au_dir_ts(dir, a->btgt); ++ ++ if (au_ftest_ren(a->flags, ISSAMEDIR)) ++ return; ++ ++ dir = a->src_dir; ++ dir->i_version++; ++ if (au_ftest_ren(a->flags, ISDIR)) ++ au_cpup_attr_nlink(dir, /*force*/1); ++ au_dir_ts(dir, a->btgt); ++} ++ ++static void au_ren_refresh(struct au_ren_args *a) ++{ ++ aufs_bindex_t bbot, bindex; ++ struct dentry *d, *h_d; ++ struct inode *i, *h_i; ++ struct super_block *sb; ++ ++ d = a->dst_dentry; ++ d_drop(d); ++ if (a->h_dst) ++ /* already dget-ed by au_ren_or_cpup() */ ++ au_set_h_dptr(d, a->btgt, a->h_dst); ++ ++ i = a->dst_inode; ++ if (i) { ++ if (!au_ftest_ren(a->flags, ISDIR)) ++ vfsub_drop_nlink(i); ++ else { ++ vfsub_dead_dir(i); ++ au_cpup_attr_timesizes(i); ++ } ++ au_update_dbrange(d, /*do_put_zero*/1); ++ } else { ++ bbot = a->btgt; ++ for (bindex = au_dbtop(d); bindex < bbot; bindex++) ++ au_set_h_dptr(d, bindex, NULL); ++ bbot = au_dbbot(d); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) ++ au_set_h_dptr(d, bindex, NULL); ++ au_update_dbrange(d, /*do_put_zero*/0); ++ } ++ ++ d = a->src_dentry; ++ au_set_dbwh(d, -1); ++ bbot = au_dbbot(d); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) { ++ h_d = au_h_dptr(d, bindex); ++ if (h_d) ++ au_set_h_dptr(d, bindex, NULL); ++ } ++ au_set_dbbot(d, a->btgt); ++ ++ sb = d->d_sb; ++ i = a->src_inode; ++ if (au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(i)) ++ return; /* success */ ++ ++ bbot = au_ibbot(i); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) { ++ h_i = au_h_iptr(i, bindex); ++ if (h_i) { ++ au_xino_write(sb, bindex, h_i->i_ino, /*ino*/0); ++ /* ignore this error */ ++ au_set_h_iptr(i, bindex, NULL, 0); ++ } ++ } ++ au_set_ibbot(i, a->btgt); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* mainly for link(2) and rename(2) */ ++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt) ++{ ++ aufs_bindex_t bdiropq, bwh; ++ struct dentry *parent; ++ struct au_branch *br; ++ ++ parent = dentry->d_parent; ++ IMustLock(d_inode(parent)); /* dir is locked */ ++ ++ bdiropq = au_dbdiropq(parent); ++ bwh = au_dbwh(dentry); ++ br = au_sbr(dentry->d_sb, btgt); ++ if (au_br_rdonly(br) ++ || (0 <= bdiropq && bdiropq < btgt) ++ || (0 <= bwh && bwh < btgt)) ++ btgt = -1; ++ ++ AuDbg("btgt %d\n", btgt); ++ return btgt; ++} ++ ++/* sets src_btop, dst_btop and btgt */ ++static int au_ren_wbr(struct au_ren_args *a) ++{ ++ int err; ++ struct au_wr_dir_args wr_dir_args = { ++ /* .force_btgt = -1, */ ++ .flags = AuWrDir_ADD_ENTRY ++ }; ++ ++ a->src_btop = au_dbtop(a->src_dentry); ++ a->dst_btop = au_dbtop(a->dst_dentry); ++ if (au_ftest_ren(a->flags, ISDIR)) ++ au_fset_wrdir(wr_dir_args.flags, ISDIR); ++ wr_dir_args.force_btgt = a->src_btop; ++ if (a->dst_inode && a->dst_btop < a->src_btop) ++ wr_dir_args.force_btgt = a->dst_btop; ++ wr_dir_args.force_btgt = au_wbr(a->dst_dentry, wr_dir_args.force_btgt); ++ err = au_wr_dir(a->dst_dentry, a->src_dentry, &wr_dir_args); ++ a->btgt = err; ++ ++ return err; ++} ++ ++static void au_ren_dt(struct au_ren_args *a) ++{ ++ a->h_path.dentry = a->src_h_parent; ++ au_dtime_store(a->src_dt + AuPARENT, a->src_parent, &a->h_path); ++ if (!au_ftest_ren(a->flags, ISSAMEDIR)) { ++ a->h_path.dentry = a->dst_h_parent; ++ au_dtime_store(a->dst_dt + AuPARENT, a->dst_parent, &a->h_path); ++ } ++ ++ au_fclr_ren(a->flags, DT_DSTDIR); ++ if (!au_ftest_ren(a->flags, ISDIR)) ++ return; ++ ++ a->h_path.dentry = a->src_h_dentry; ++ au_dtime_store(a->src_dt + AuCHILD, a->src_dentry, &a->h_path); ++ if (d_is_positive(a->dst_h_dentry)) { ++ au_fset_ren(a->flags, DT_DSTDIR); ++ a->h_path.dentry = a->dst_h_dentry; ++ au_dtime_store(a->dst_dt + AuCHILD, a->dst_dentry, &a->h_path); ++ } ++} ++ ++static void au_ren_rev_dt(int err, struct au_ren_args *a) ++{ ++ struct dentry *h_d; ++ struct inode *h_inode; ++ ++ au_dtime_revert(a->src_dt + AuPARENT); ++ if (!au_ftest_ren(a->flags, ISSAMEDIR)) ++ au_dtime_revert(a->dst_dt + AuPARENT); ++ ++ if (au_ftest_ren(a->flags, ISDIR) && err != -EIO) { ++ h_d = a->src_dt[AuCHILD].dt_h_path.dentry; ++ h_inode = d_inode(h_d); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ au_dtime_revert(a->src_dt + AuCHILD); ++ inode_unlock(h_inode); ++ ++ if (au_ftest_ren(a->flags, DT_DSTDIR)) { ++ h_d = a->dst_dt[AuCHILD].dt_h_path.dentry; ++ h_inode = d_inode(h_d); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ au_dtime_revert(a->dst_dt + AuCHILD); ++ inode_unlock(h_inode); ++ } ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry, ++ struct inode *_dst_dir, struct dentry *_dst_dentry) ++{ ++ int err, flags; ++ /* reduce stack space */ ++ struct au_ren_args *a; ++ ++ AuDbg("%pd, %pd\n", _src_dentry, _dst_dentry); ++ IMustLock(_src_dir); ++ IMustLock(_dst_dir); ++ ++ err = -ENOMEM; ++ BUILD_BUG_ON(sizeof(*a) > PAGE_SIZE); ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ a->src_dir = _src_dir; ++ a->src_dentry = _src_dentry; ++ a->src_inode = NULL; ++ if (d_really_is_positive(a->src_dentry)) ++ a->src_inode = d_inode(a->src_dentry); ++ a->src_parent = a->src_dentry->d_parent; /* dir inode is locked */ ++ a->dst_dir = _dst_dir; ++ a->dst_dentry = _dst_dentry; ++ a->dst_inode = NULL; ++ if (d_really_is_positive(a->dst_dentry)) ++ a->dst_inode = d_inode(a->dst_dentry); ++ a->dst_parent = a->dst_dentry->d_parent; /* dir inode is locked */ ++ if (a->dst_inode) { ++ IMustLock(a->dst_inode); ++ au_igrab(a->dst_inode); ++ } ++ ++ err = -ENOTDIR; ++ flags = AuLock_FLUSH | AuLock_NOPLM | AuLock_GEN; ++ if (d_is_dir(a->src_dentry)) { ++ au_fset_ren(a->flags, ISDIR); ++ if (unlikely(d_really_is_positive(a->dst_dentry) ++ && !d_is_dir(a->dst_dentry))) ++ goto out_free; ++ flags |= AuLock_DIRS; ++ } ++ err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, flags); ++ if (unlikely(err)) ++ goto out_free; ++ ++ err = au_d_hashed_positive(a->src_dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ err = -ENOENT; ++ if (a->dst_inode) { ++ /* ++ * If it is a dir, VFS unhash dst_dentry before this ++ * function. It means we cannot rely upon d_unhashed(). ++ */ ++ if (unlikely(!a->dst_inode->i_nlink)) ++ goto out_unlock; ++ if (!S_ISDIR(a->dst_inode->i_mode)) { ++ err = au_d_hashed_positive(a->dst_dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ } else if (unlikely(IS_DEADDIR(a->dst_inode))) ++ goto out_unlock; ++ } else if (unlikely(d_unhashed(a->dst_dentry))) ++ goto out_unlock; ++ ++ /* ++ * is it possible? ++ * yes, it happened (in linux-3.3-rcN) but I don't know why. ++ * there may exist a problem somewhere else. ++ */ ++ err = -EINVAL; ++ if (unlikely(d_inode(a->dst_parent) == d_inode(a->src_dentry))) ++ goto out_unlock; ++ ++ au_fset_ren(a->flags, ISSAMEDIR); /* temporary */ ++ di_write_lock_parent(a->dst_parent); ++ ++ /* which branch we process */ ++ err = au_ren_wbr(a); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ a->br = au_sbr(a->dst_dentry->d_sb, a->btgt); ++ a->h_path.mnt = au_br_mnt(a->br); ++ ++ /* are they available to be renamed */ ++ err = au_ren_may_dir(a); ++ if (unlikely(err)) ++ goto out_children; ++ ++ /* prepare the writable parent dir on the same branch */ ++ if (a->dst_btop == a->btgt) { ++ au_fset_ren(a->flags, WHDST); ++ } else { ++ err = au_cpup_dirs(a->dst_dentry, a->btgt); ++ if (unlikely(err)) ++ goto out_children; ++ } ++ ++ if (a->src_dir != a->dst_dir) { ++ /* ++ * this temporary unlock is safe, ++ * because both dir->i_mutex are locked. ++ */ ++ di_write_unlock(a->dst_parent); ++ di_write_lock_parent(a->src_parent); ++ err = au_wr_dir_need_wh(a->src_dentry, ++ au_ftest_ren(a->flags, ISDIR), ++ &a->btgt); ++ di_write_unlock(a->src_parent); ++ di_write_lock2_parent(a->src_parent, a->dst_parent, /*isdir*/1); ++ au_fclr_ren(a->flags, ISSAMEDIR); ++ } else ++ err = au_wr_dir_need_wh(a->src_dentry, ++ au_ftest_ren(a->flags, ISDIR), ++ &a->btgt); ++ if (unlikely(err < 0)) ++ goto out_children; ++ if (err) ++ au_fset_ren(a->flags, WHSRC); ++ ++ /* cpup src */ ++ if (a->src_btop != a->btgt) { ++ struct au_pin pin; ++ ++ err = au_pin(&pin, a->src_dentry, a->btgt, ++ au_opt_udba(a->src_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ struct au_cp_generic cpg = { ++ .dentry = a->src_dentry, ++ .bdst = a->btgt, ++ .bsrc = a->src_btop, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ AuDebugOn(au_dbtop(a->src_dentry) != a->src_btop); ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ if (unlikely(err)) ++ goto out_children; ++ a->src_btop = a->btgt; ++ a->src_h_dentry = au_h_dptr(a->src_dentry, a->btgt); ++ au_fset_ren(a->flags, WHSRC); ++ } ++ ++ /* lock them all */ ++ err = au_ren_lock(a); ++ if (unlikely(err)) ++ /* leave the copied-up one */ ++ goto out_children; ++ ++ if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE)) ++ err = au_may_ren(a); ++ else if (unlikely(a->dst_dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ err = -ENAMETOOLONG; ++ if (unlikely(err)) ++ goto out_hdir; ++ ++ /* store timestamps to be revertible */ ++ au_ren_dt(a); ++ ++ /* here we go */ ++ err = do_rename(a); ++ if (unlikely(err)) ++ goto out_dt; ++ ++ /* update dir attributes */ ++ au_ren_refresh_dir(a); ++ ++ /* dput/iput all lower dentries */ ++ au_ren_refresh(a); ++ ++ goto out_hdir; /* success */ ++ ++out_dt: ++ au_ren_rev_dt(err, a); ++out_hdir: ++ au_ren_unlock(a); ++out_children: ++ au_nhash_wh_free(&a->whlist); ++ if (err && a->dst_inode && a->dst_btop != a->btgt) { ++ AuDbg("btop %d, btgt %d\n", a->dst_btop, a->btgt); ++ au_set_h_dptr(a->dst_dentry, a->btgt, NULL); ++ au_set_dbtop(a->dst_dentry, a->dst_btop); ++ } ++out_parent: ++ if (!err) ++ d_move(a->src_dentry, a->dst_dentry); ++ else { ++ au_update_dbtop(a->dst_dentry); ++ if (!a->dst_inode) ++ d_drop(a->dst_dentry); ++ } ++ if (au_ftest_ren(a->flags, ISSAMEDIR)) ++ di_write_unlock(a->dst_parent); ++ else ++ di_write_unlock2(a->src_parent, a->dst_parent); ++out_unlock: ++ aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry); ++out_free: ++ iput(a->dst_inode); ++ if (a->thargs) ++ au_whtmp_rmdir_free(a->thargs); ++ kfree(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/iinfo.c b/fs/aufs/iinfo.c +new file mode 100644 +index 0000000..fae4c27 +--- /dev/null ++++ b/fs/aufs/iinfo.c +@@ -0,0 +1,271 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode private data ++ */ ++ ++#include "aufs.h" ++ ++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct inode *h_inode; ++ struct au_hinode *hinode; ++ ++ IiMustAnyLock(inode); ++ ++ hinode = au_hinode(au_ii(inode), bindex); ++ h_inode = hinode->hi_inode; ++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); ++ return h_inode; ++} ++ ++/* todo: hard/soft set? */ ++void au_hiput(struct au_hinode *hinode) ++{ ++ au_hn_free(hinode); ++ dput(hinode->hi_whdentry); ++ iput(hinode->hi_inode); ++} ++ ++unsigned int au_hi_flags(struct inode *inode, int isdir) ++{ ++ unsigned int flags; ++ const unsigned int mnt_flags = au_mntflags(inode->i_sb); ++ ++ flags = 0; ++ if (au_opt_test(mnt_flags, XINO)) ++ au_fset_hi(flags, XINO); ++ if (isdir && au_opt_test(mnt_flags, UDBA_HNOTIFY)) ++ au_fset_hi(flags, HNOTIFY); ++ return flags; ++} ++ ++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags) ++{ ++ struct au_hinode *hinode; ++ struct inode *hi; ++ struct au_iinfo *iinfo = au_ii(inode); ++ ++ IiMustWriteLock(inode); ++ ++ hinode = au_hinode(iinfo, bindex); ++ hi = hinode->hi_inode; ++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); ++ ++ if (hi) ++ au_hiput(hinode); ++ hinode->hi_inode = h_inode; ++ if (h_inode) { ++ int err; ++ struct super_block *sb = inode->i_sb; ++ struct au_branch *br; ++ ++ AuDebugOn(inode->i_mode ++ && (h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT)); ++ if (bindex == iinfo->ii_btop) ++ au_cpup_igen(inode, h_inode); ++ br = au_sbr(sb, bindex); ++ hinode->hi_id = br->br_id; ++ if (au_ftest_hi(flags, XINO)) { ++ err = au_xino_write(sb, bindex, h_inode->i_ino, ++ inode->i_ino); ++ if (unlikely(err)) ++ AuIOErr1("failed au_xino_write() %d\n", err); ++ } ++ ++ if (au_ftest_hi(flags, HNOTIFY) ++ && au_br_hnotifyable(br->br_perm)) { ++ err = au_hn_alloc(hinode, inode); ++ if (unlikely(err)) ++ AuIOErr1("au_hn_alloc() %d\n", err); ++ } ++ } ++} ++ ++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_wh) ++{ ++ struct au_hinode *hinode; ++ ++ IiMustWriteLock(inode); ++ ++ hinode = au_hinode(au_ii(inode), bindex); ++ AuDebugOn(hinode->hi_whdentry); ++ hinode->hi_whdentry = h_wh; ++} ++ ++void au_update_iigen(struct inode *inode, int half) ++{ ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ unsigned int sigen; ++ ++ sigen = au_sigen(inode->i_sb); ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ iigen->ig_generation = sigen; ++ if (half) ++ au_ig_fset(iigen->ig_flags, HALF_REFRESHED); ++ else ++ au_ig_fclr(iigen->ig_flags, HALF_REFRESHED); ++ spin_unlock(&iigen->ig_spin); ++} ++ ++/* it may be called at remount time, too */ ++void au_update_ibrange(struct inode *inode, int do_put_zero) ++{ ++ struct au_iinfo *iinfo; ++ aufs_bindex_t bindex, bbot; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ IiMustWriteLock(inode); ++ ++ iinfo = au_ii(inode); ++ if (do_put_zero && iinfo->ii_btop >= 0) { ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; ++ bindex++) { ++ struct inode *h_i; ++ ++ h_i = au_hinode(iinfo, bindex)->hi_inode; ++ if (h_i ++ && !h_i->i_nlink ++ && !(h_i->i_state & I_LINKABLE)) ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ } ++ } ++ ++ iinfo->ii_btop = -1; ++ iinfo->ii_bbot = -1; ++ bbot = au_sbbot(inode->i_sb); ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (au_hinode(iinfo, bindex)->hi_inode) { ++ iinfo->ii_btop = bindex; ++ break; ++ } ++ if (iinfo->ii_btop >= 0) ++ for (bindex = bbot; bindex >= iinfo->ii_btop; bindex--) ++ if (au_hinode(iinfo, bindex)->hi_inode) { ++ iinfo->ii_bbot = bindex; ++ break; ++ } ++ AuDebugOn(iinfo->ii_btop > iinfo->ii_bbot); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_icntnr_init_once(void *_c) ++{ ++ struct au_icntnr *c = _c; ++ struct au_iinfo *iinfo = &c->iinfo; ++ ++ spin_lock_init(&iinfo->ii_generation.ig_spin); ++ au_rw_init(&iinfo->ii_rwsem); ++ inode_init_once(&c->vfs_inode); ++} ++ ++void au_hinode_init(struct au_hinode *hinode) ++{ ++ hinode->hi_inode = NULL; ++ hinode->hi_id = -1; ++ au_hn_init(hinode); ++ hinode->hi_whdentry = NULL; ++} ++ ++int au_iinfo_init(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct super_block *sb; ++ struct au_hinode *hi; ++ int nbr, i; ++ ++ sb = inode->i_sb; ++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++ nbr = au_sbbot(sb) + 1; ++ if (unlikely(nbr <= 0)) ++ nbr = 1; ++ hi = kmalloc_array(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS); ++ if (hi) { ++ au_ninodes_inc(sb); ++ ++ iinfo->ii_hinode = hi; ++ for (i = 0; i < nbr; i++, hi++) ++ au_hinode_init(hi); ++ ++ iinfo->ii_generation.ig_generation = au_sigen(sb); ++ iinfo->ii_btop = -1; ++ iinfo->ii_bbot = -1; ++ iinfo->ii_vdir = NULL; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++int au_hinode_realloc(struct au_iinfo *iinfo, int nbr) ++{ ++ int err, i; ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ err = -ENOMEM; ++ hip = krealloc(iinfo->ii_hinode, sizeof(*hip) * nbr, GFP_NOFS); ++ if (hip) { ++ iinfo->ii_hinode = hip; ++ i = iinfo->ii_bbot + 1; ++ hip += i; ++ for (; i < nbr; i++, hip++) ++ au_hinode_init(hip); ++ err = 0; ++ } ++ ++ return err; ++} ++ ++void au_iinfo_fin(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ const unsigned char unlinked = !inode->i_nlink; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ ++ sb = inode->i_sb; ++ au_ninodes_dec(sb); ++ if (si_pid_test(sb)) ++ au_xino_delete_inode(inode, unlinked); ++ else { ++ /* ++ * it is safe to hide the dependency between sbinfo and ++ * sb->s_umount. ++ */ ++ lockdep_off(); ++ si_noflush_read_lock(sb); ++ au_xino_delete_inode(inode, unlinked); ++ si_read_unlock(sb); ++ lockdep_on(); ++ } ++ ++ iinfo = au_ii(inode); ++ if (iinfo->ii_vdir) ++ au_vdir_free(iinfo->ii_vdir); ++ ++ bindex = iinfo->ii_btop; ++ if (bindex >= 0) { ++ hi = au_hinode(iinfo, bindex); ++ bbot = iinfo->ii_bbot; ++ while (bindex++ <= bbot) { ++ if (hi->hi_inode) ++ au_hiput(hi); ++ hi++; ++ } ++ } ++ kfree(iinfo->ii_hinode); ++ AuRwDestroy(&iinfo->ii_rwsem); ++} +diff --git a/fs/aufs/inode.c b/fs/aufs/inode.c +new file mode 100644 +index 0000000..a4b994e +--- /dev/null ++++ b/fs/aufs/inode.c +@@ -0,0 +1,504 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode functions ++ */ ++ ++#include "aufs.h" ++ ++struct inode *au_igrab(struct inode *inode) ++{ ++ if (inode) { ++ AuDebugOn(!atomic_read(&inode->i_count)); ++ ihold(inode); ++ } ++ return inode; ++} ++ ++static void au_refresh_hinode_attr(struct inode *inode, int do_version) ++{ ++ au_cpup_attr_all(inode, /*force*/0); ++ au_update_iigen(inode, /*half*/1); ++ if (do_version) ++ inode->i_version++; ++} ++ ++static int au_ii_refresh(struct inode *inode, int *update) ++{ ++ int err, e; ++ umode_t type; ++ aufs_bindex_t bindex, new_bindex; ++ struct super_block *sb; ++ struct au_iinfo *iinfo; ++ struct au_hinode *p, *q, tmp; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ IiMustWriteLock(inode); ++ ++ *update = 0; ++ sb = inode->i_sb; ++ type = inode->i_mode & S_IFMT; ++ iinfo = au_ii(inode); ++ err = au_hinode_realloc(iinfo, au_sbbot(sb) + 1); ++ if (unlikely(err)) ++ goto out; ++ ++ AuDebugOn(iinfo->ii_btop < 0); ++ p = au_hinode(iinfo, iinfo->ii_btop); ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; ++ bindex++, p++) { ++ if (!p->hi_inode) ++ continue; ++ ++ AuDebugOn(type != (p->hi_inode->i_mode & S_IFMT)); ++ new_bindex = au_br_index(sb, p->hi_id); ++ if (new_bindex == bindex) ++ continue; ++ ++ if (new_bindex < 0) { ++ *update = 1; ++ au_hiput(p); ++ p->hi_inode = NULL; ++ continue; ++ } ++ ++ if (new_bindex < iinfo->ii_btop) ++ iinfo->ii_btop = new_bindex; ++ if (iinfo->ii_bbot < new_bindex) ++ iinfo->ii_bbot = new_bindex; ++ /* swap two lower inode, and loop again */ ++ q = au_hinode(iinfo, new_bindex); ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hi_inode) { ++ bindex--; ++ p--; ++ } ++ } ++ au_update_ibrange(inode, /*do_put_zero*/0); ++ e = au_dy_irefresh(inode); ++ if (unlikely(e && !err)) ++ err = e; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_refresh_iop(struct inode *inode, int force_getattr) ++{ ++ int type; ++ struct au_sbinfo *sbi = au_sbi(inode->i_sb); ++ const struct inode_operations *iop ++ = force_getattr ? aufs_iop : sbi->si_iop_array; ++ ++ if (inode->i_op == iop) ++ return; ++ ++ switch (inode->i_mode & S_IFMT) { ++ case S_IFDIR: ++ type = AuIop_DIR; ++ break; ++ case S_IFLNK: ++ type = AuIop_SYMLINK; ++ break; ++ default: ++ type = AuIop_OTHER; ++ break; ++ } ++ ++ inode->i_op = iop + type; ++ /* unnecessary smp_wmb() */ ++} ++ ++int au_refresh_hinode_self(struct inode *inode) ++{ ++ int err, update; ++ ++ err = au_ii_refresh(inode, &update); ++ if (!err) ++ au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode)); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry) ++{ ++ int err, e, update; ++ unsigned int flags; ++ umode_t mode; ++ aufs_bindex_t bindex, bbot; ++ unsigned char isdir; ++ struct au_hinode *p; ++ struct au_iinfo *iinfo; ++ ++ err = au_ii_refresh(inode, &update); ++ if (unlikely(err)) ++ goto out; ++ ++ update = 0; ++ iinfo = au_ii(inode); ++ p = au_hinode(iinfo, iinfo->ii_btop); ++ mode = (inode->i_mode & S_IFMT); ++ isdir = S_ISDIR(mode); ++ flags = au_hi_flags(inode, isdir); ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) { ++ struct inode *h_i, *h_inode; ++ struct dentry *h_d; ++ ++ h_d = au_h_dptr(dentry, bindex); ++ if (!h_d || d_is_negative(h_d)) ++ continue; ++ ++ h_inode = d_inode(h_d); ++ AuDebugOn(mode != (h_inode->i_mode & S_IFMT)); ++ if (iinfo->ii_btop <= bindex && bindex <= iinfo->ii_bbot) { ++ h_i = au_h_iptr(inode, bindex); ++ if (h_i) { ++ if (h_i == h_inode) ++ continue; ++ err = -EIO; ++ break; ++ } ++ } ++ if (bindex < iinfo->ii_btop) ++ iinfo->ii_btop = bindex; ++ if (iinfo->ii_bbot < bindex) ++ iinfo->ii_bbot = bindex; ++ au_set_h_iptr(inode, bindex, au_igrab(h_inode), flags); ++ update = 1; ++ } ++ au_update_ibrange(inode, /*do_put_zero*/0); ++ e = au_dy_irefresh(inode); ++ if (unlikely(e && !err)) ++ err = e; ++ if (!err) ++ au_refresh_hinode_attr(inode, update && isdir); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int set_inode(struct inode *inode, struct dentry *dentry) ++{ ++ int err; ++ unsigned int flags; ++ umode_t mode; ++ aufs_bindex_t bindex, btop, btail; ++ unsigned char isdir; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_iinfo *iinfo; ++ struct inode_operations *iop; ++ ++ IiMustWriteLock(inode); ++ ++ err = 0; ++ isdir = 0; ++ iop = au_sbi(inode->i_sb)->si_iop_array; ++ btop = au_dbtop(dentry); ++ h_dentry = au_h_dptr(dentry, btop); ++ h_inode = d_inode(h_dentry); ++ mode = h_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_OTHER; ++ inode->i_fop = &aufs_file_fop; ++ err = au_dy_iaop(inode, btop, h_inode); ++ if (unlikely(err)) ++ goto out; ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ btail = au_dbtaildir(dentry); ++ inode->i_op = iop + AuIop_DIR; ++ inode->i_fop = &aufs_dir_fop; ++ break; ++ case S_IFLNK: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_SYMLINK; ++ break; ++ case S_IFBLK: ++ case S_IFCHR: ++ case S_IFIFO: ++ case S_IFSOCK: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_OTHER; ++ init_special_inode(inode, mode, h_inode->i_rdev); ++ break; ++ default: ++ AuIOErr("Unknown file type 0%o\n", mode); ++ err = -EIO; ++ goto out; ++ } ++ ++ /* do not set hnotify for whiteouted dirs (SHWH mode) */ ++ flags = au_hi_flags(inode, isdir); ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH) ++ && au_ftest_hi(flags, HNOTIFY) ++ && dentry->d_name.len > AUFS_WH_PFX_LEN ++ && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) ++ au_fclr_hi(flags, HNOTIFY); ++ iinfo = au_ii(inode); ++ iinfo->ii_btop = btop; ++ iinfo->ii_bbot = btail; ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) ++ au_set_h_iptr(inode, bindex, ++ au_igrab(d_inode(h_dentry)), flags); ++ } ++ au_cpup_attr_all(inode, /*force*/1); ++ /* ++ * to force calling aufs_get_acl() every time, ++ * do not call cache_no_acl() for aufs inode. ++ */ ++ ++out: ++ return err; ++} ++ ++/* ++ * successful returns with iinfo write_locked ++ * minus: errno ++ * zero: success, matched ++ * plus: no error, but unmatched ++ */ ++static int reval_inode(struct inode *inode, struct dentry *dentry) ++{ ++ int err; ++ unsigned int gen, igflags; ++ aufs_bindex_t bindex, bbot; ++ struct inode *h_inode, *h_dinode; ++ struct dentry *h_dentry; ++ ++ /* ++ * before this function, if aufs got any iinfo lock, it must be only ++ * one, the parent dir. ++ * it can happen by UDBA and the obsoleted inode number. ++ */ ++ err = -EIO; ++ if (unlikely(inode->i_ino == parent_ino(dentry))) ++ goto out; ++ ++ err = 1; ++ ii_write_lock_new_child(inode); ++ h_dentry = au_h_dptr(dentry, au_dbtop(dentry)); ++ h_dinode = d_inode(h_dentry); ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); bindex <= bbot; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (!h_inode || h_inode != h_dinode) ++ continue; ++ ++ err = 0; ++ gen = au_iigen(inode, &igflags); ++ if (gen == au_digen(dentry) ++ && !au_ig_ftest(igflags, HALF_REFRESHED)) ++ break; ++ ++ /* fully refresh inode using dentry */ ++ err = au_refresh_hinode(inode, dentry); ++ if (!err) ++ au_update_iigen(inode, /*half*/0); ++ break; ++ } ++ ++ if (unlikely(err)) ++ ii_write_unlock(inode); ++out: ++ return err; ++} ++ ++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ unsigned int d_type, ino_t *ino) ++{ ++ int err; ++ struct mutex *mtx; ++ ++ /* prevent hardlinked inode number from race condition */ ++ mtx = NULL; ++ if (d_type != DT_DIR) { ++ mtx = &au_sbr(sb, bindex)->br_xino.xi_nondir_mtx; ++ mutex_lock(mtx); ++ } ++ err = au_xino_read(sb, bindex, h_ino, ino); ++ if (unlikely(err)) ++ goto out; ++ ++ if (!*ino) { ++ err = -EIO; ++ *ino = au_xino_new_ino(sb); ++ if (unlikely(!*ino)) ++ goto out; ++ err = au_xino_write(sb, bindex, h_ino, *ino); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++out: ++ if (mtx) ++ mutex_unlock(mtx); ++ return err; ++} ++ ++/* successful returns with iinfo write_locked */ ++/* todo: return with unlocked? */ ++struct inode *au_new_inode(struct dentry *dentry, int must_new) ++{ ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry; ++ struct super_block *sb; ++ struct mutex *mtx; ++ ino_t h_ino, ino; ++ int err; ++ aufs_bindex_t btop; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ h_dentry = au_h_dptr(dentry, btop); ++ h_inode = d_inode(h_dentry); ++ h_ino = h_inode->i_ino; ++ ++ /* ++ * stop 'race'-ing between hardlinks under different ++ * parents. ++ */ ++ mtx = NULL; ++ if (!d_is_dir(h_dentry)) ++ mtx = &au_sbr(sb, btop)->br_xino.xi_nondir_mtx; ++ ++new_ino: ++ if (mtx) ++ mutex_lock(mtx); ++ err = au_xino_read(sb, btop, h_ino, &ino); ++ inode = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ if (!ino) { ++ ino = au_xino_new_ino(sb); ++ if (unlikely(!ino)) { ++ inode = ERR_PTR(-EIO); ++ goto out; ++ } ++ } ++ ++ AuDbg("i%lu\n", (unsigned long)ino); ++ inode = au_iget_locked(sb, ino); ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out; ++ ++ AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); ++ if (inode->i_state & I_NEW) { ++ ii_write_lock_new_child(inode); ++ err = set_inode(inode, dentry); ++ if (!err) { ++ unlock_new_inode(inode); ++ goto out; /* success */ ++ } ++ ++ /* ++ * iget_failed() calls iput(), but we need to call ++ * ii_write_unlock() after iget_failed(). so dirty hack for ++ * i_count. ++ */ ++ atomic_inc(&inode->i_count); ++ iget_failed(inode); ++ ii_write_unlock(inode); ++ au_xino_write(sb, btop, h_ino, /*ino*/0); ++ /* ignore this error */ ++ goto out_iput; ++ } else if (!must_new && !IS_DEADDIR(inode) && inode->i_nlink) { ++ /* ++ * horrible race condition between lookup, readdir and copyup ++ * (or something). ++ */ ++ if (mtx) ++ mutex_unlock(mtx); ++ err = reval_inode(inode, dentry); ++ if (unlikely(err < 0)) { ++ mtx = NULL; ++ goto out_iput; ++ } ++ ++ if (!err) { ++ mtx = NULL; ++ goto out; /* success */ ++ } else if (mtx) ++ mutex_lock(mtx); ++ } ++ ++ if (unlikely(au_test_fs_unique_ino(h_inode))) ++ AuWarn1("Warning: Un-notified UDBA or repeatedly renamed dir," ++ " b%d, %s, %pd, hi%lu, i%lu.\n", ++ btop, au_sbtype(h_dentry->d_sb), dentry, ++ (unsigned long)h_ino, (unsigned long)ino); ++ ino = 0; ++ err = au_xino_write(sb, btop, h_ino, /*ino*/0); ++ if (!err) { ++ iput(inode); ++ if (mtx) ++ mutex_unlock(mtx); ++ goto new_ino; ++ } ++ ++out_iput: ++ iput(inode); ++ inode = ERR_PTR(err); ++out: ++ if (mtx) ++ mutex_unlock(mtx); ++ return inode; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode) ++{ ++ int err; ++ struct inode *hi; ++ ++ err = au_br_rdonly(au_sbr(sb, bindex)); ++ ++ /* pseudo-link after flushed may happen out of bounds */ ++ if (!err ++ && inode ++ && au_ibtop(inode) <= bindex ++ && bindex <= au_ibbot(inode)) { ++ /* ++ * permission check is unnecessary since vfsub routine ++ * will be called later ++ */ ++ hi = au_h_iptr(inode, bindex); ++ if (hi) ++ err = IS_IMMUTABLE(hi) ? -EROFS : 0; ++ } ++ ++ return err; ++} ++ ++int au_test_h_perm(struct inode *h_inode, int mask) ++{ ++ if (uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) ++ return 0; ++ return inode_permission(h_inode, mask); ++} ++ ++int au_test_h_perm_sio(struct inode *h_inode, int mask) ++{ ++ if (au_test_nfs(h_inode->i_sb) ++ && (mask & MAY_WRITE) ++ && S_ISDIR(h_inode->i_mode)) ++ mask |= MAY_READ; /* force permission check */ ++ return au_test_h_perm(h_inode, mask); ++} +diff --git a/fs/aufs/inode.h b/fs/aufs/inode.h +new file mode 100644 +index 0000000..3fc5a58 +--- /dev/null ++++ b/fs/aufs/inode.h +@@ -0,0 +1,681 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations ++ */ ++ ++#ifndef __AUFS_INODE_H__ ++#define __AUFS_INODE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "rwsem.h" ++ ++struct vfsmount; ++ ++struct au_hnotify { ++#ifdef CONFIG_AUFS_HNOTIFY ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ /* never use fsnotify_add_vfsmount_mark() */ ++ struct fsnotify_mark hn_mark; ++#endif ++ struct inode *hn_aufs_inode; /* no get/put */ ++#endif ++} ____cacheline_aligned_in_smp; ++ ++struct au_hinode { ++ struct inode *hi_inode; ++ aufs_bindex_t hi_id; ++#ifdef CONFIG_AUFS_HNOTIFY ++ struct au_hnotify *hi_notify; ++#endif ++ ++ /* reference to the copied-up whiteout with get/put */ ++ struct dentry *hi_whdentry; ++}; ++ ++/* ig_flags */ ++#define AuIG_HALF_REFRESHED 1 ++#define au_ig_ftest(flags, name) ((flags) & AuIG_##name) ++#define au_ig_fset(flags, name) \ ++ do { (flags) |= AuIG_##name; } while (0) ++#define au_ig_fclr(flags, name) \ ++ do { (flags) &= ~AuIG_##name; } while (0) ++ ++struct au_iigen { ++ spinlock_t ig_spin; ++ __u32 ig_generation, ig_flags; ++}; ++ ++struct au_vdir; ++struct au_iinfo { ++ struct au_iigen ii_generation; ++ struct super_block *ii_hsb1; /* no get/put */ ++ ++ struct au_rwsem ii_rwsem; ++ aufs_bindex_t ii_btop, ii_bbot; ++ __u32 ii_higen; ++ struct au_hinode *ii_hinode; ++ struct au_vdir *ii_vdir; ++}; ++ ++struct au_icntnr { ++ struct au_iinfo iinfo; ++ struct inode vfs_inode; ++ struct hlist_node plink; ++} ____cacheline_aligned_in_smp; ++ ++/* au_pin flags */ ++#define AuPin_DI_LOCKED 1 ++#define AuPin_MNT_WRITE (1 << 1) ++#define au_ftest_pin(flags, name) ((flags) & AuPin_##name) ++#define au_fset_pin(flags, name) \ ++ do { (flags) |= AuPin_##name; } while (0) ++#define au_fclr_pin(flags, name) \ ++ do { (flags) &= ~AuPin_##name; } while (0) ++ ++struct au_pin { ++ /* input */ ++ struct dentry *dentry; ++ unsigned int udba; ++ unsigned char lsc_di, lsc_hi, flags; ++ aufs_bindex_t bindex; ++ ++ /* output */ ++ struct dentry *parent; ++ struct au_hinode *hdir; ++ struct vfsmount *h_mnt; ++ ++ /* temporary unlock/relock for copyup */ ++ struct dentry *h_dentry, *h_parent; ++ struct au_branch *br; ++ struct task_struct *task; ++}; ++ ++void au_pin_hdir_unlock(struct au_pin *p); ++int au_pin_hdir_lock(struct au_pin *p); ++int au_pin_hdir_relock(struct au_pin *p); ++void au_pin_hdir_acquire_nest(struct au_pin *p); ++void au_pin_hdir_release(struct au_pin *p); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_iinfo *au_ii(struct inode *inode) ++{ ++ BUG_ON(is_bad_inode(inode)); ++ return &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* inode.c */ ++struct inode *au_igrab(struct inode *inode); ++void au_refresh_iop(struct inode *inode, int force_getattr); ++int au_refresh_hinode_self(struct inode *inode); ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry); ++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ unsigned int d_type, ino_t *ino); ++struct inode *au_new_inode(struct dentry *dentry, int must_new); ++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode); ++int au_test_h_perm(struct inode *h_inode, int mask); ++int au_test_h_perm_sio(struct inode *h_inode, int mask); ++ ++static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex, ++ ino_t h_ino, unsigned int d_type, ino_t *ino) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ return au_ino(sb, bindex, h_ino, d_type, ino); ++#else ++ return 0; ++#endif ++} ++ ++/* i_op.c */ ++enum { ++ AuIop_SYMLINK, ++ AuIop_DIR, ++ AuIop_OTHER, ++ AuIop_Last ++}; ++extern struct inode_operations aufs_iop[AuIop_Last], ++ aufs_iop_nogetattr[AuIop_Last]; ++ ++/* au_wr_dir flags */ ++#define AuWrDir_ADD_ENTRY 1 ++#define AuWrDir_ISDIR (1 << 1) ++#define AuWrDir_TMPFILE (1 << 2) ++#define au_ftest_wrdir(flags, name) ((flags) & AuWrDir_##name) ++#define au_fset_wrdir(flags, name) \ ++ do { (flags) |= AuWrDir_##name; } while (0) ++#define au_fclr_wrdir(flags, name) \ ++ do { (flags) &= ~AuWrDir_##name; } while (0) ++ ++struct au_wr_dir_args { ++ aufs_bindex_t force_btgt; ++ unsigned char flags; ++}; ++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, ++ struct au_wr_dir_args *args); ++ ++struct dentry *au_pinned_h_parent(struct au_pin *pin); ++void au_pin_init(struct au_pin *pin, struct dentry *dentry, ++ aufs_bindex_t bindex, int lsc_di, int lsc_hi, ++ unsigned int udba, unsigned char flags); ++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int udba, unsigned char flags) __must_check; ++int au_do_pin(struct au_pin *pin) __must_check; ++void au_unpin(struct au_pin *pin); ++int au_reval_for_attr(struct dentry *dentry, unsigned int sigen); ++ ++#define AuIcpup_DID_CPUP 1 ++#define au_ftest_icpup(flags, name) ((flags) & AuIcpup_##name) ++#define au_fset_icpup(flags, name) \ ++ do { (flags) |= AuIcpup_##name; } while (0) ++#define au_fclr_icpup(flags, name) \ ++ do { (flags) &= ~AuIcpup_##name; } while (0) ++ ++struct au_icpup_args { ++ unsigned char flags; ++ unsigned char pin_flags; ++ aufs_bindex_t btgt; ++ unsigned int udba; ++ struct au_pin pin; ++ struct path h_path; ++ struct inode *h_inode; ++}; ++ ++int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, ++ struct au_icpup_args *a); ++ ++int au_h_path_getattr(struct dentry *dentry, int force, struct path *h_path); ++ ++/* i_op_add.c */ ++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir); ++int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, ++ dev_t dev); ++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); ++int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ++ bool want_excl); ++struct vfsub_aopen_args; ++int au_aopen_or_create(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args); ++int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode); ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry); ++int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode); ++ ++/* i_op_del.c */ ++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup); ++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir); ++int aufs_unlink(struct inode *dir, struct dentry *dentry); ++int aufs_rmdir(struct inode *dir, struct dentry *dentry); ++ ++/* i_op_ren.c */ ++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt); ++int aufs_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry); ++ ++/* iinfo.c */ ++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex); ++void au_hiput(struct au_hinode *hinode); ++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_wh); ++unsigned int au_hi_flags(struct inode *inode, int isdir); ++ ++/* hinode flags */ ++#define AuHi_XINO 1 ++#define AuHi_HNOTIFY (1 << 1) ++#define au_ftest_hi(flags, name) ((flags) & AuHi_##name) ++#define au_fset_hi(flags, name) \ ++ do { (flags) |= AuHi_##name; } while (0) ++#define au_fclr_hi(flags, name) \ ++ do { (flags) &= ~AuHi_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_HNOTIFY ++#undef AuHi_HNOTIFY ++#define AuHi_HNOTIFY 0 ++#endif ++ ++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags); ++ ++void au_update_iigen(struct inode *inode, int half); ++void au_update_ibrange(struct inode *inode, int do_put_zero); ++ ++void au_icntnr_init_once(void *_c); ++void au_hinode_init(struct au_hinode *hinode); ++int au_iinfo_init(struct inode *inode); ++void au_iinfo_fin(struct inode *inode); ++int au_hinode_realloc(struct au_iinfo *iinfo, int nbr); ++ ++#ifdef CONFIG_PROC_FS ++/* plink.c */ ++int au_plink_maint(struct super_block *sb, int flags); ++struct au_sbinfo; ++void au_plink_maint_leave(struct au_sbinfo *sbinfo); ++int au_plink_maint_enter(struct super_block *sb); ++#ifdef CONFIG_AUFS_DEBUG ++void au_plink_list(struct super_block *sb); ++#else ++AuStubVoid(au_plink_list, struct super_block *sb) ++#endif ++int au_plink_test(struct inode *inode); ++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex); ++void au_plink_append(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++void au_plink_put(struct super_block *sb, int verbose); ++void au_plink_clean(struct super_block *sb, int verbose); ++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id); ++#else ++AuStubInt0(au_plink_maint, struct super_block *sb, int flags); ++AuStubVoid(au_plink_maint_leave, struct au_sbinfo *sbinfo); ++AuStubInt0(au_plink_maint_enter, struct super_block *sb); ++AuStubVoid(au_plink_list, struct super_block *sb); ++AuStubInt0(au_plink_test, struct inode *inode); ++AuStub(struct dentry *, au_plink_lkup, return NULL, ++ struct inode *inode, aufs_bindex_t bindex); ++AuStubVoid(au_plink_append, struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++AuStubVoid(au_plink_put, struct super_block *sb, int verbose); ++AuStubVoid(au_plink_clean, struct super_block *sb, int verbose); ++AuStubVoid(au_plink_half_refresh, struct super_block *sb, aufs_bindex_t br_id); ++#endif /* CONFIG_PROC_FS */ ++ ++#ifdef CONFIG_AUFS_XATTR ++/* xattr.c */ ++int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags, ++ unsigned int verbose); ++ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size); ++ssize_t aufs_getxattr(struct dentry *dentry, struct inode *inode, ++ const char *name, void *value, size_t size); ++int aufs_setxattr(struct dentry *dentry, struct inode *inode, const char *name, ++ const void *value, size_t size, int flags); ++int aufs_removexattr(struct dentry *dentry, const char *name); ++ ++/* void au_xattr_init(struct super_block *sb); */ ++#else ++AuStubInt0(au_cpup_xattr, struct dentry *h_dst, struct dentry *h_src, ++ int ignore_flags, unsigned int verbose); ++/* AuStubVoid(au_xattr_init, struct super_block *sb); */ ++#endif ++ ++#ifdef CONFIG_FS_POSIX_ACL ++struct posix_acl *aufs_get_acl(struct inode *inode, int type); ++int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type); ++#endif ++ ++#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL) ++enum { ++ AU_XATTR_SET, ++ AU_XATTR_REMOVE, ++ AU_ACL_SET ++}; ++ ++struct au_srxattr { ++ int type; ++ union { ++ struct { ++ const char *name; ++ const void *value; ++ size_t size; ++ int flags; ++ } set; ++ struct { ++ const char *name; ++ } remove; ++ struct { ++ struct posix_acl *acl; ++ int type; ++ } acl_set; ++ } u; ++}; ++ssize_t au_srxattr(struct dentry *dentry, struct inode *inode, ++ struct au_srxattr *arg); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for iinfo */ ++enum { ++ AuLsc_II_CHILD, /* child first */ ++ AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hnotify */ ++ AuLsc_II_CHILD3, /* copyup dirs */ ++ AuLsc_II_PARENT, /* see AuLsc_I_PARENT in vfsub.h */ ++ AuLsc_II_PARENT2, ++ AuLsc_II_PARENT3, /* copyup dirs */ ++ AuLsc_II_NEW_CHILD ++}; ++ ++/* ++ * ii_read_lock_child, ii_write_lock_child, ++ * ii_read_lock_child2, ii_write_lock_child2, ++ * ii_read_lock_child3, ii_write_lock_child3, ++ * ii_read_lock_parent, ii_write_lock_parent, ++ * ii_read_lock_parent2, ii_write_lock_parent2, ++ * ii_read_lock_parent3, ii_write_lock_parent3, ++ * ii_read_lock_new_child, ii_write_lock_new_child, ++ */ ++#define AuReadLockFunc(name, lsc) \ ++static inline void ii_read_lock_##name(struct inode *i) \ ++{ \ ++ au_rw_read_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ ++} ++ ++#define AuWriteLockFunc(name, lsc) \ ++static inline void ii_write_lock_##name(struct inode *i) \ ++{ \ ++ au_rw_write_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ ++} ++ ++#define AuRWLockFuncs(name, lsc) \ ++ AuReadLockFunc(name, lsc) \ ++ AuWriteLockFunc(name, lsc) ++ ++AuRWLockFuncs(child, CHILD); ++AuRWLockFuncs(child2, CHILD2); ++AuRWLockFuncs(child3, CHILD3); ++AuRWLockFuncs(parent, PARENT); ++AuRWLockFuncs(parent2, PARENT2); ++AuRWLockFuncs(parent3, PARENT3); ++AuRWLockFuncs(new_child, NEW_CHILD); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++/* ++ * ii_read_unlock, ii_write_unlock, ii_downgrade_lock ++ */ ++AuSimpleUnlockRwsemFuncs(ii, struct inode *i, &au_ii(i)->ii_rwsem); ++ ++#define IiMustNoWaiters(i) AuRwMustNoWaiters(&au_ii(i)->ii_rwsem) ++#define IiMustAnyLock(i) AuRwMustAnyLock(&au_ii(i)->ii_rwsem) ++#define IiMustWriteLock(i) AuRwMustWriteLock(&au_ii(i)->ii_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void au_icntnr_init(struct au_icntnr *c) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++ c->vfs_inode.i_mode = 0; ++#endif ++} ++ ++static inline unsigned int au_iigen(struct inode *inode, unsigned int *igflags) ++{ ++ unsigned int gen; ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ if (igflags) ++ *igflags = iigen->ig_flags; ++ gen = iigen->ig_generation; ++ spin_unlock(&iigen->ig_spin); ++ ++ return gen; ++} ++ ++/* tiny test for inode number */ ++/* tmpfs generation is too rough */ ++static inline int au_test_higen(struct inode *inode, struct inode *h_inode) ++{ ++ struct au_iinfo *iinfo; ++ ++ iinfo = au_ii(inode); ++ AuRwMustAnyLock(&iinfo->ii_rwsem); ++ return !(iinfo->ii_hsb1 == h_inode->i_sb ++ && iinfo->ii_higen == h_inode->i_generation); ++} ++ ++static inline void au_iigen_dec(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ iigen->ig_generation--; ++ spin_unlock(&iigen->ig_spin); ++} ++ ++static inline int au_iigen_test(struct inode *inode, unsigned int sigen) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(inode && au_iigen(inode, NULL) != sigen)) ++ err = -EIO; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_hinode *au_hinode(struct au_iinfo *iinfo, ++ aufs_bindex_t bindex) ++{ ++ return iinfo->ii_hinode + bindex; ++} ++ ++static inline int au_is_bad_inode(struct inode *inode) ++{ ++ return !!(is_bad_inode(inode) || !au_hinode(au_ii(inode), 0)); ++} ++ ++static inline aufs_bindex_t au_ii_br_id(struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_hinode(au_ii(inode), bindex)->hi_id; ++} ++ ++static inline aufs_bindex_t au_ibtop(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_btop; ++} ++ ++static inline aufs_bindex_t au_ibbot(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_bbot; ++} ++ ++static inline struct au_vdir *au_ivdir(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_vdir; ++} ++ ++static inline struct dentry *au_hi_wh(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_hinode(au_ii(inode), bindex)->hi_whdentry; ++} ++ ++static inline void au_set_ibtop(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_btop = bindex; ++} ++ ++static inline void au_set_ibbot(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_bbot = bindex; ++} ++ ++static inline void au_set_ivdir(struct inode *inode, struct au_vdir *vdir) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_vdir = vdir; ++} ++ ++static inline struct au_hinode *au_hi(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_hinode(au_ii(inode), bindex); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct dentry *au_pinned_parent(struct au_pin *pin) ++{ ++ if (pin) ++ return pin->parent; ++ return NULL; ++} ++ ++static inline struct inode *au_pinned_h_dir(struct au_pin *pin) ++{ ++ if (pin && pin->hdir) ++ return pin->hdir->hi_inode; ++ return NULL; ++} ++ ++static inline struct au_hinode *au_pinned_hdir(struct au_pin *pin) ++{ ++ if (pin) ++ return pin->hdir; ++ return NULL; ++} ++ ++static inline void au_pin_set_dentry(struct au_pin *pin, struct dentry *dentry) ++{ ++ if (pin) ++ pin->dentry = dentry; ++} ++ ++static inline void au_pin_set_parent_lflag(struct au_pin *pin, ++ unsigned char lflag) ++{ ++ if (pin) { ++ if (lflag) ++ au_fset_pin(pin->flags, DI_LOCKED); ++ else ++ au_fclr_pin(pin->flags, DI_LOCKED); ++ } ++} ++ ++#if 0 /* reserved */ ++static inline void au_pin_set_parent(struct au_pin *pin, struct dentry *parent) ++{ ++ if (pin) { ++ dput(pin->parent); ++ pin->parent = dget(parent); ++ } ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_branch; ++#ifdef CONFIG_AUFS_HNOTIFY ++struct au_hnotify_op { ++ void (*ctl)(struct au_hinode *hinode, int do_set); ++ int (*alloc)(struct au_hinode *hinode); ++ ++ /* ++ * if it returns true, the the caller should free hinode->hi_notify, ++ * otherwise ->free() frees it. ++ */ ++ int (*free)(struct au_hinode *hinode, ++ struct au_hnotify *hn) __must_check; ++ ++ void (*fin)(void); ++ int (*init)(void); ++ ++ int (*reset_br)(unsigned int udba, struct au_branch *br, int perm); ++ void (*fin_br)(struct au_branch *br); ++ int (*init_br)(struct au_branch *br, int perm); ++}; ++ ++/* hnotify.c */ ++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode); ++void au_hn_free(struct au_hinode *hinode); ++void au_hn_ctl(struct au_hinode *hinode, int do_set); ++void au_hn_reset(struct inode *inode, unsigned int flags); ++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, ++ struct qstr *h_child_qstr, struct inode *h_child_inode); ++int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm); ++int au_hnotify_init_br(struct au_branch *br, int perm); ++void au_hnotify_fin_br(struct au_branch *br); ++int __init au_hnotify_init(void); ++void au_hnotify_fin(void); ++ ++/* hfsnotify.c */ ++extern const struct au_hnotify_op au_hnotify_op; ++ ++static inline ++void au_hn_init(struct au_hinode *hinode) ++{ ++ hinode->hi_notify = NULL; ++} ++ ++static inline struct au_hnotify *au_hn(struct au_hinode *hinode) ++{ ++ return hinode->hi_notify; ++} ++ ++#else ++AuStub(int, au_hn_alloc, return -EOPNOTSUPP, ++ struct au_hinode *hinode __maybe_unused, ++ struct inode *inode __maybe_unused) ++AuStub(struct au_hnotify *, au_hn, return NULL, struct au_hinode *hinode) ++AuStubVoid(au_hn_free, struct au_hinode *hinode __maybe_unused) ++AuStubVoid(au_hn_ctl, struct au_hinode *hinode __maybe_unused, ++ int do_set __maybe_unused) ++AuStubVoid(au_hn_reset, struct inode *inode __maybe_unused, ++ unsigned int flags __maybe_unused) ++AuStubInt0(au_hnotify_reset_br, unsigned int udba __maybe_unused, ++ struct au_branch *br __maybe_unused, ++ int perm __maybe_unused) ++AuStubInt0(au_hnotify_init_br, struct au_branch *br __maybe_unused, ++ int perm __maybe_unused) ++AuStubVoid(au_hnotify_fin_br, struct au_branch *br __maybe_unused) ++AuStubInt0(__init au_hnotify_init, void) ++AuStubVoid(au_hnotify_fin, void) ++AuStubVoid(au_hn_init, struct au_hinode *hinode __maybe_unused) ++#endif /* CONFIG_AUFS_HNOTIFY */ ++ ++static inline void au_hn_suspend(struct au_hinode *hdir) ++{ ++ au_hn_ctl(hdir, /*do_set*/0); ++} ++ ++static inline void au_hn_resume(struct au_hinode *hdir) ++{ ++ au_hn_ctl(hdir, /*do_set*/1); ++} ++ ++static inline void au_hn_inode_lock(struct au_hinode *hdir) ++{ ++ inode_lock(hdir->hi_inode); ++ au_hn_suspend(hdir); ++} ++ ++static inline void au_hn_inode_lock_nested(struct au_hinode *hdir, ++ unsigned int sc __maybe_unused) ++{ ++ inode_lock_nested(hdir->hi_inode, sc); ++ au_hn_suspend(hdir); ++} ++ ++static inline void au_hn_inode_unlock(struct au_hinode *hdir) ++{ ++ au_hn_resume(hdir); ++ inode_unlock(hdir->hi_inode); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_INODE_H__ */ +diff --git a/fs/aufs/ioctl.c b/fs/aufs/ioctl.c +new file mode 100644 +index 0000000..2ebfdc4 +--- /dev/null ++++ b/fs/aufs/ioctl.c +@@ -0,0 +1,206 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * ioctl ++ * plink-management and readdir in userspace. ++ * assist the pathconf(3) wrapper library. ++ * move-down ++ * File-based Hierarchical Storage Management. ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++static int au_wbr_fd(struct path *path, struct aufs_wbr_fd __user *arg) ++{ ++ int err, fd; ++ aufs_bindex_t wbi, bindex, bbot; ++ struct file *h_file; ++ struct super_block *sb; ++ struct dentry *root; ++ struct au_branch *br; ++ struct aufs_wbr_fd wbrfd = { ++ .oflags = au_dir_roflags, ++ .brid = -1 ++ }; ++ const int valid = O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_DIRECTORY ++ | O_NOATIME | O_CLOEXEC; ++ ++ AuDebugOn(wbrfd.oflags & ~valid); ++ ++ if (arg) { ++ err = copy_from_user(&wbrfd, arg, sizeof(wbrfd)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ goto out; ++ } ++ ++ err = -EINVAL; ++ AuDbg("wbrfd{0%o, %d}\n", wbrfd.oflags, wbrfd.brid); ++ wbrfd.oflags |= au_dir_roflags; ++ AuDbg("0%o\n", wbrfd.oflags); ++ if (unlikely(wbrfd.oflags & ~valid)) ++ goto out; ++ } ++ ++ fd = get_unused_fd_flags(0); ++ err = fd; ++ if (unlikely(fd < 0)) ++ goto out; ++ ++ h_file = ERR_PTR(-EINVAL); ++ wbi = 0; ++ br = NULL; ++ sb = path->dentry->d_sb; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_IR); ++ bbot = au_sbbot(sb); ++ if (wbrfd.brid >= 0) { ++ wbi = au_br_index(sb, wbrfd.brid); ++ if (unlikely(wbi < 0 || wbi > bbot)) ++ goto out_unlock; ++ } ++ ++ h_file = ERR_PTR(-ENOENT); ++ br = au_sbr(sb, wbi); ++ if (!au_br_writable(br->br_perm)) { ++ if (arg) ++ goto out_unlock; ++ ++ bindex = wbi + 1; ++ wbi = -1; ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm)) { ++ wbi = bindex; ++ br = au_sbr(sb, wbi); ++ break; ++ } ++ } ++ } ++ AuDbg("wbi %d\n", wbi); ++ if (wbi >= 0) ++ h_file = au_h_open(root, wbi, wbrfd.oflags, NULL, ++ /*force_wr*/0); ++ ++out_unlock: ++ aufs_read_unlock(root, AuLock_IR); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out_fd; ++ ++ au_br_put(br); /* cf. au_h_open() */ ++ fd_install(fd, h_file); ++ err = fd; ++ goto out; /* success */ ++ ++out_fd: ++ put_unused_fd(fd); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err; ++ struct dentry *dentry; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ioctl(file, cmd, arg); ++ break; ++ ++ case AUFS_CTL_WBR_FD: ++ err = au_wbr_fd(&file->f_path, (void __user *)arg); ++ break; ++ ++ case AUFS_CTL_IBUSY: ++ err = au_ibusy_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_BRINFO: ++ err = au_brinfo_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_FHSM_FD: ++ dentry = file->f_path.dentry; ++ if (IS_ROOT(dentry)) ++ err = au_fhsm_fd(dentry->d_sb, arg); ++ else ++ err = -ENOTTY; ++ break; ++ ++ default: ++ /* do not call the lower */ ++ AuDbg("0x%x\n", cmd); ++ err = -ENOTTY; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err; ++ ++ switch (cmd) { ++ case AUFS_CTL_MVDOWN: ++ err = au_mvdown(file->f_path.dentry, (void __user *)arg); ++ break; ++ ++ case AUFS_CTL_WBR_FD: ++ err = au_wbr_fd(&file->f_path, (void __user *)arg); ++ break; ++ ++ default: ++ /* do not call the lower */ ++ AuDbg("0x%x\n", cmd); ++ err = -ENOTTY; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++#ifdef CONFIG_COMPAT ++long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ long err; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_compat_ioctl(file, cmd, arg); ++ break; ++ ++ case AUFS_CTL_IBUSY: ++ err = au_ibusy_compat_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_BRINFO: ++ err = au_brinfo_compat_ioctl(file, arg); ++ break; ++ ++ default: ++ err = aufs_ioctl_dir(file, cmd, arg); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ return aufs_ioctl_nondir(file, cmd, (unsigned long)compat_ptr(arg)); ++} ++#endif +diff --git a/fs/aufs/loop.c b/fs/aufs/loop.c +new file mode 100644 +index 0000000..5711e7a +--- /dev/null ++++ b/fs/aufs/loop.c +@@ -0,0 +1,133 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * support for loopback block device as a branch ++ */ ++ ++#include "aufs.h" ++ ++/* added into drivers/block/loop.c */ ++static struct file *(*backing_file_func)(struct super_block *sb); ++ ++/* ++ * test if two lower dentries have overlapping branches. ++ */ ++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding) ++{ ++ struct super_block *h_sb; ++ struct file *backing_file; ++ ++ if (unlikely(!backing_file_func)) { ++ /* don't load "loop" module here */ ++ backing_file_func = symbol_get(loop_backing_file); ++ if (unlikely(!backing_file_func)) ++ /* "loop" module is not loaded */ ++ return 0; ++ } ++ ++ h_sb = h_adding->d_sb; ++ backing_file = backing_file_func(h_sb); ++ if (!backing_file) ++ return 0; ++ ++ h_adding = backing_file->f_path.dentry; ++ /* ++ * h_adding can be local NFS. ++ * in this case aufs cannot detect the loop. ++ */ ++ if (unlikely(h_adding->d_sb == sb)) ++ return 1; ++ return !!au_test_subdir(h_adding, sb->s_root); ++} ++ ++/* true if a kernel thread named 'loop[0-9].*' accesses a file */ ++int au_test_loopback_kthread(void) ++{ ++ int ret; ++ struct task_struct *tsk = current; ++ char c, comm[sizeof(tsk->comm)]; ++ ++ ret = 0; ++ if (tsk->flags & PF_KTHREAD) { ++ get_task_comm(comm, tsk); ++ c = comm[4]; ++ ret = ('0' <= c && c <= '9' ++ && !strncmp(comm, "loop", 4)); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define au_warn_loopback_step 16 ++static int au_warn_loopback_nelem = au_warn_loopback_step; ++static unsigned long *au_warn_loopback_array; ++ ++void au_warn_loopback(struct super_block *h_sb) ++{ ++ int i, new_nelem; ++ unsigned long *a, magic; ++ static DEFINE_SPINLOCK(spin); ++ ++ magic = h_sb->s_magic; ++ spin_lock(&spin); ++ a = au_warn_loopback_array; ++ for (i = 0; i < au_warn_loopback_nelem && *a; i++) ++ if (a[i] == magic) { ++ spin_unlock(&spin); ++ return; ++ } ++ ++ /* h_sb is new to us, print it */ ++ if (i < au_warn_loopback_nelem) { ++ a[i] = magic; ++ goto pr; ++ } ++ ++ /* expand the array */ ++ new_nelem = au_warn_loopback_nelem + au_warn_loopback_step; ++ a = au_kzrealloc(au_warn_loopback_array, ++ au_warn_loopback_nelem * sizeof(unsigned long), ++ new_nelem * sizeof(unsigned long), GFP_ATOMIC); ++ if (a) { ++ au_warn_loopback_nelem = new_nelem; ++ au_warn_loopback_array = a; ++ a[i] = magic; ++ goto pr; ++ } ++ ++ spin_unlock(&spin); ++ AuWarn1("realloc failed, ignored\n"); ++ return; ++ ++pr: ++ spin_unlock(&spin); ++ pr_warn("you may want to try another patch for loopback file " ++ "on %s(0x%lx) branch\n", au_sbtype(h_sb), magic); ++} ++ ++int au_loopback_init(void) ++{ ++ int err; ++ struct super_block *sb __maybe_unused; ++ ++ BUILD_BUG_ON(sizeof(sb->s_magic) != sizeof(unsigned long)); ++ ++ err = 0; ++ au_warn_loopback_array = kcalloc(au_warn_loopback_step, ++ sizeof(unsigned long), GFP_NOFS); ++ if (unlikely(!au_warn_loopback_array)) ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++void au_loopback_fin(void) ++{ ++ if (backing_file_func) ++ symbol_put(loop_backing_file); ++ kfree(au_warn_loopback_array); ++} +diff --git a/fs/aufs/loop.h b/fs/aufs/loop.h +new file mode 100644 +index 0000000..48bf070 +--- /dev/null ++++ b/fs/aufs/loop.h +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * support for loopback mount as a branch ++ */ ++ ++#ifndef __AUFS_LOOP_H__ ++#define __AUFS_LOOP_H__ ++ ++#ifdef __KERNEL__ ++ ++struct dentry; ++struct super_block; ++ ++#ifdef CONFIG_AUFS_BDEV_LOOP ++/* drivers/block/loop.c */ ++struct file *loop_backing_file(struct super_block *sb); ++ ++/* loop.c */ ++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding); ++int au_test_loopback_kthread(void); ++void au_warn_loopback(struct super_block *h_sb); ++ ++int au_loopback_init(void); ++void au_loopback_fin(void); ++#else ++AuStubInt0(au_test_loopback_overlap, struct super_block *sb, ++ struct dentry *h_adding) ++AuStubInt0(au_test_loopback_kthread, void) ++AuStubVoid(au_warn_loopback, struct super_block *h_sb) ++ ++AuStubInt0(au_loopback_init, void) ++AuStubVoid(au_loopback_fin, void) ++#endif /* BLK_DEV_LOOP */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_LOOP_H__ */ +diff --git a/fs/aufs/magic.mk b/fs/aufs/magic.mk +new file mode 100644 +index 0000000..4f83bdf +--- /dev/null ++++ b/fs/aufs/magic.mk +@@ -0,0 +1,30 @@ ++ ++# defined in ${srctree}/fs/fuse/inode.c ++# tristate ++ifdef CONFIG_FUSE_FS ++ccflags-y += -DFUSE_SUPER_MAGIC=0x65735546 ++endif ++ ++# defined in ${srctree}/fs/xfs/xfs_sb.h ++# tristate ++ifdef CONFIG_XFS_FS ++ccflags-y += -DXFS_SB_MAGIC=0x58465342 ++endif ++ ++# defined in ${srctree}/fs/configfs/mount.c ++# tristate ++ifdef CONFIG_CONFIGFS_FS ++ccflags-y += -DCONFIGFS_MAGIC=0x62656570 ++endif ++ ++# defined in ${srctree}/fs/ubifs/ubifs.h ++# tristate ++ifdef CONFIG_UBIFS_FS ++ccflags-y += -DUBIFS_SUPER_MAGIC=0x24051905 ++endif ++ ++# defined in ${srctree}/fs/hfsplus/hfsplus_raw.h ++# tristate ++ifdef CONFIG_HFSPLUS_FS ++ccflags-y += -DHFSPLUS_SUPER_MAGIC=0x482b ++endif +diff --git a/fs/aufs/module.c b/fs/aufs/module.c +new file mode 100644 +index 0000000..88f8f41 +--- /dev/null ++++ b/fs/aufs/module.c +@@ -0,0 +1,209 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * module global variables and operations ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp) ++{ ++ if (new_sz <= nused) ++ return p; ++ ++ p = krealloc(p, new_sz, gfp); ++ if (p) ++ memset(p + nused, 0, new_sz - nused); ++ return p; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * aufs caches ++ */ ++struct kmem_cache *au_cachep[AuCache_Last] = { ++ [0] = NULL ++}; ++ ++static void au_cache_fin(void) ++{ ++ int i; ++ ++ /* ++ * Make sure all delayed rcu free inodes are flushed before we ++ * destroy cache. ++ */ ++ rcu_barrier(); ++ ++ /* excluding AuCache_HNOTIFY */ ++ BUILD_BUG_ON(AuCache_HNOTIFY + 1 != AuCache_Last); ++ for (i = 0; i < AuCache_HNOTIFY; i++) { ++ kmem_cache_destroy(au_cachep[i]); ++ au_cachep[i] = NULL; ++ } ++} ++ ++static int __init au_cache_init(void) ++{ ++ au_cachep[AuCache_DINFO] = AuCacheCtor(au_dinfo, au_di_init_once); ++ if (au_cachep[AuCache_DINFO]) ++ /* SLAB_DESTROY_BY_RCU */ ++ au_cachep[AuCache_ICNTNR] = AuCacheCtor(au_icntnr, ++ au_icntnr_init_once); ++ if (au_cachep[AuCache_ICNTNR]) ++ au_cachep[AuCache_FINFO] = AuCacheCtor(au_finfo, ++ au_fi_init_once); ++ if (au_cachep[AuCache_FINFO]) ++ au_cachep[AuCache_VDIR] = AuCache(au_vdir); ++ if (au_cachep[AuCache_VDIR]) ++ au_cachep[AuCache_DEHSTR] = AuCache(au_vdir_dehstr); ++ if (au_cachep[AuCache_DEHSTR]) ++ return 0; ++ ++ au_cache_fin(); ++ return -ENOMEM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dir_roflags; ++ ++#ifdef CONFIG_AUFS_SBILIST ++/* ++ * iterate_supers_type() doesn't protect us from ++ * remounting (branch management) ++ */ ++struct au_sphlhead au_sbilist; ++#endif ++ ++/* ++ * functions for module interface. ++ */ ++MODULE_LICENSE("GPL"); ++/* MODULE_LICENSE("GPL v2"); */ ++MODULE_AUTHOR("Junjiro R. Okajima "); ++MODULE_DESCRIPTION(AUFS_NAME ++ " -- Advanced multi layered unification filesystem"); ++MODULE_VERSION(AUFS_VERSION); ++ ++/* this module parameter has no meaning when SYSFS is disabled */ ++int sysaufs_brs = 1; ++MODULE_PARM_DESC(brs, "use /fs/aufs/si_*/brN"); ++module_param_named(brs, sysaufs_brs, int, S_IRUGO); ++ ++/* this module parameter has no meaning when USER_NS is disabled */ ++bool au_userns; ++MODULE_PARM_DESC(allow_userns, "allow unprivileged to mount under userns"); ++module_param_named(allow_userns, au_userns, bool, S_IRUGO); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */ ++ ++int au_seq_path(struct seq_file *seq, struct path *path) ++{ ++ int err; ++ ++ err = seq_path(seq, path, au_esc_chars); ++ if (err > 0) ++ err = 0; ++ else if (err < 0) ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int __init aufs_init(void) ++{ ++ int err, i; ++ char *p; ++ ++ p = au_esc_chars; ++ for (i = 1; i <= ' '; i++) ++ *p++ = i; ++ *p++ = '\\'; ++ *p++ = '\x7f'; ++ *p = 0; ++ ++ au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE); ++ ++ memcpy(aufs_iop_nogetattr, aufs_iop, sizeof(aufs_iop)); ++ for (i = 0; i < AuIop_Last; i++) ++ aufs_iop_nogetattr[i].getattr = NULL; ++ ++ au_sbilist_init(); ++ sysaufs_brs_init(); ++ au_debug_init(); ++ au_dy_init(); ++ err = sysaufs_init(); ++ if (unlikely(err)) ++ goto out; ++ err = au_procfs_init(); ++ if (unlikely(err)) ++ goto out_sysaufs; ++ err = au_wkq_init(); ++ if (unlikely(err)) ++ goto out_procfs; ++ err = au_loopback_init(); ++ if (unlikely(err)) ++ goto out_wkq; ++ err = au_hnotify_init(); ++ if (unlikely(err)) ++ goto out_loopback; ++ err = au_sysrq_init(); ++ if (unlikely(err)) ++ goto out_hin; ++ err = au_cache_init(); ++ if (unlikely(err)) ++ goto out_sysrq; ++ ++ aufs_fs_type.fs_flags |= au_userns ? FS_USERNS_MOUNT : 0; ++ err = register_filesystem(&aufs_fs_type); ++ if (unlikely(err)) ++ goto out_cache; ++ ++ /* since we define pr_fmt, call printk directly */ ++ printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n"); ++ goto out; /* success */ ++ ++out_cache: ++ au_cache_fin(); ++out_sysrq: ++ au_sysrq_fin(); ++out_hin: ++ au_hnotify_fin(); ++out_loopback: ++ au_loopback_fin(); ++out_wkq: ++ au_wkq_fin(); ++out_procfs: ++ au_procfs_fin(); ++out_sysaufs: ++ sysaufs_fin(); ++ au_dy_fin(); ++out: ++ return err; ++} ++ ++static void __exit aufs_exit(void) ++{ ++ unregister_filesystem(&aufs_fs_type); ++ au_cache_fin(); ++ au_sysrq_fin(); ++ au_hnotify_fin(); ++ au_loopback_fin(); ++ au_wkq_fin(); ++ au_procfs_fin(); ++ sysaufs_fin(); ++ au_dy_fin(); ++} ++ ++module_init(aufs_init); ++module_exit(aufs_exit); +diff --git a/fs/aufs/module.h b/fs/aufs/module.h +new file mode 100644 +index 0000000..1383e3d +--- /dev/null ++++ b/fs/aufs/module.h +@@ -0,0 +1,76 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * module initialization and module-global ++ */ ++ ++#ifndef __AUFS_MODULE_H__ ++#define __AUFS_MODULE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct path; ++struct seq_file; ++ ++/* module parameters */ ++extern int sysaufs_brs; ++extern bool au_userns; ++ ++/* ---------------------------------------------------------------------- */ ++ ++extern int au_dir_roflags; ++ ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp); ++int au_seq_path(struct seq_file *seq, struct path *path); ++ ++#ifdef CONFIG_PROC_FS ++/* procfs.c */ ++int __init au_procfs_init(void); ++void au_procfs_fin(void); ++#else ++AuStubInt0(au_procfs_init, void); ++AuStubVoid(au_procfs_fin, void); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* kmem cache */ ++enum { ++ AuCache_DINFO, ++ AuCache_ICNTNR, ++ AuCache_FINFO, ++ AuCache_VDIR, ++ AuCache_DEHSTR, ++ AuCache_HNOTIFY, /* must be last */ ++ AuCache_Last ++}; ++ ++#define AuCacheFlags (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD) ++#define AuCache(type) KMEM_CACHE(type, AuCacheFlags) ++#define AuCacheCtor(type, ctor) \ ++ kmem_cache_create(#type, sizeof(struct type), \ ++ __alignof__(struct type), AuCacheFlags, ctor) ++ ++extern struct kmem_cache *au_cachep[]; ++ ++#define AuCacheFuncs(name, index) \ ++static inline struct au_##name *au_cache_alloc_##name(void) \ ++{ return kmem_cache_alloc(au_cachep[AuCache_##index], GFP_NOFS); } \ ++static inline void au_cache_free_##name(struct au_##name *p) \ ++{ kmem_cache_free(au_cachep[AuCache_##index], p); } ++ ++AuCacheFuncs(dinfo, DINFO); ++AuCacheFuncs(icntnr, ICNTNR); ++AuCacheFuncs(finfo, FINFO); ++AuCacheFuncs(vdir, VDIR); ++AuCacheFuncs(vdir_dehstr, DEHSTR); ++#ifdef CONFIG_AUFS_HNOTIFY ++AuCacheFuncs(hnotify, HNOTIFY); ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_MODULE_H__ */ +diff --git a/fs/aufs/mvdown.c b/fs/aufs/mvdown.c +new file mode 100644 +index 0000000..a48aa1c +--- /dev/null ++++ b/fs/aufs/mvdown.c +@@ -0,0 +1,691 @@ ++/* ++ * Copyright (C) 2011-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * move-down, opposite of copy-up ++ */ ++ ++#include "aufs.h" ++ ++struct au_mvd_args { ++ struct { ++ struct super_block *h_sb; ++ struct dentry *h_parent; ++ struct au_hinode *hdir; ++ struct inode *h_dir, *h_inode; ++ struct au_pin pin; ++ } info[AUFS_MVDOWN_NARRAY]; ++ ++ struct aufs_mvdown mvdown; ++ struct dentry *dentry, *parent; ++ struct inode *inode, *dir; ++ struct super_block *sb; ++ aufs_bindex_t bopq, bwh, bfound; ++ unsigned char rename_lock; ++}; ++ ++#define mvd_errno mvdown.au_errno ++#define mvd_bsrc mvdown.stbr[AUFS_MVDOWN_UPPER].bindex ++#define mvd_src_brid mvdown.stbr[AUFS_MVDOWN_UPPER].brid ++#define mvd_bdst mvdown.stbr[AUFS_MVDOWN_LOWER].bindex ++#define mvd_dst_brid mvdown.stbr[AUFS_MVDOWN_LOWER].brid ++ ++#define mvd_h_src_sb info[AUFS_MVDOWN_UPPER].h_sb ++#define mvd_h_src_parent info[AUFS_MVDOWN_UPPER].h_parent ++#define mvd_hdir_src info[AUFS_MVDOWN_UPPER].hdir ++#define mvd_h_src_dir info[AUFS_MVDOWN_UPPER].h_dir ++#define mvd_h_src_inode info[AUFS_MVDOWN_UPPER].h_inode ++#define mvd_pin_src info[AUFS_MVDOWN_UPPER].pin ++ ++#define mvd_h_dst_sb info[AUFS_MVDOWN_LOWER].h_sb ++#define mvd_h_dst_parent info[AUFS_MVDOWN_LOWER].h_parent ++#define mvd_hdir_dst info[AUFS_MVDOWN_LOWER].hdir ++#define mvd_h_dst_dir info[AUFS_MVDOWN_LOWER].h_dir ++#define mvd_h_dst_inode info[AUFS_MVDOWN_LOWER].h_inode ++#define mvd_pin_dst info[AUFS_MVDOWN_LOWER].pin ++ ++#define AU_MVD_PR(flag, ...) do { \ ++ if (flag) \ ++ pr_err(__VA_ARGS__); \ ++ } while (0) ++ ++static int find_lower_writable(struct au_mvd_args *a) ++{ ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ sb = a->sb; ++ bindex = a->mvd_bsrc; ++ bbot = au_sbbot(sb); ++ if (a->mvdown.flags & AUFS_MVDOWN_FHSM_LOWER) ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm) ++ && (!(au_br_sb(br)->s_flags & MS_RDONLY))) ++ return bindex; ++ } ++ else if (!(a->mvdown.flags & AUFS_MVDOWN_ROLOWER)) ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_rdonly(br)) ++ return bindex; ++ } ++ else ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!(au_br_sb(br)->s_flags & MS_RDONLY)) { ++ if (au_br_rdonly(br)) ++ a->mvdown.flags ++ |= AUFS_MVDOWN_ROLOWER_R; ++ return bindex; ++ } ++ } ++ ++ return -1; ++} ++ ++/* make the parent dir on bdst */ ++static int au_do_mkdir(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = 0; ++ a->mvd_hdir_src = au_hi(a->dir, a->mvd_bsrc); ++ a->mvd_hdir_dst = au_hi(a->dir, a->mvd_bdst); ++ a->mvd_h_src_parent = au_h_dptr(a->parent, a->mvd_bsrc); ++ a->mvd_h_dst_parent = NULL; ++ if (au_dbbot(a->parent) >= a->mvd_bdst) ++ a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); ++ if (!a->mvd_h_dst_parent) { ++ err = au_cpdown_dirs(a->dentry, a->mvd_bdst); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "cpdown_dirs failed\n"); ++ goto out; ++ } ++ a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* lock them all */ ++static int au_do_lock(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct dentry *h_trap; ++ ++ a->mvd_h_src_sb = au_sbr_sb(a->sb, a->mvd_bsrc); ++ a->mvd_h_dst_sb = au_sbr_sb(a->sb, a->mvd_bdst); ++ err = au_pin(&a->mvd_pin_dst, a->dentry, a->mvd_bdst, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ AuTraceErr(err); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_dst failed\n"); ++ goto out; ++ } ++ ++ if (a->mvd_h_src_sb != a->mvd_h_dst_sb) { ++ a->rename_lock = 0; ++ au_pin_init(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, ++ AuLsc_DI_PARENT, AuLsc_I_PARENT3, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ err = au_do_pin(&a->mvd_pin_src); ++ AuTraceErr(err); ++ a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_src failed\n"); ++ goto out_dst; ++ } ++ goto out; /* success */ ++ } ++ ++ a->rename_lock = 1; ++ au_pin_hdir_unlock(&a->mvd_pin_dst); ++ err = au_pin(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ AuTraceErr(err); ++ a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_src failed\n"); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ goto out_dst; ++ } ++ au_pin_hdir_unlock(&a->mvd_pin_src); ++ h_trap = vfsub_lock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ if (h_trap) { ++ err = (h_trap != a->mvd_h_src_parent); ++ if (err) ++ err = (h_trap != a->mvd_h_dst_parent); ++ } ++ BUG_ON(err); /* it should never happen */ ++ if (unlikely(a->mvd_h_src_dir != au_pinned_h_dir(&a->mvd_pin_src))) { ++ err = -EBUSY; ++ AuTraceErr(err); ++ vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ au_pin_hdir_lock(&a->mvd_pin_src); ++ au_unpin(&a->mvd_pin_src); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ goto out_dst; ++ } ++ goto out; /* success */ ++ ++out_dst: ++ au_unpin(&a->mvd_pin_dst); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static void au_do_unlock(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ if (!a->rename_lock) ++ au_unpin(&a->mvd_pin_src); ++ else { ++ vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ au_pin_hdir_lock(&a->mvd_pin_src); ++ au_unpin(&a->mvd_pin_src); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ } ++ au_unpin(&a->mvd_pin_dst); ++} ++ ++/* copy-down the file */ ++static int au_do_cpdown(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_cp_generic cpg = { ++ .dentry = a->dentry, ++ .bdst = a->mvd_bdst, ++ .bsrc = a->mvd_bsrc, ++ .len = -1, ++ .pin = &a->mvd_pin_dst, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ ++ AuDbg("b%d, b%d\n", cpg.bsrc, cpg.bdst); ++ if (a->mvdown.flags & AUFS_MVDOWN_OWLOWER) ++ au_fset_cpup(cpg.flags, OVERWRITE); ++ if (a->mvdown.flags & AUFS_MVDOWN_ROLOWER) ++ au_fset_cpup(cpg.flags, RWDST); ++ err = au_sio_cpdown_simple(&cpg); ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "cpdown failed\n"); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * unlink the whiteout on bdst if exist which may be created by UDBA while we ++ * were sleeping ++ */ ++static int au_do_unlink_wh(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct path h_path; ++ struct au_branch *br; ++ struct inode *delegated; ++ ++ br = au_sbr(a->sb, a->mvd_bdst); ++ h_path.dentry = au_wh_lkup(a->mvd_h_dst_parent, &a->dentry->d_name, br); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) { ++ AU_MVD_PR(dmsg, "wh_lkup failed\n"); ++ goto out; ++ } ++ ++ err = 0; ++ if (d_is_positive(h_path.dentry)) { ++ h_path.mnt = au_br_mnt(br); ++ delegated = NULL; ++ err = vfsub_unlink(d_inode(a->mvd_h_dst_parent), &h_path, ++ &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "wh_unlink failed\n"); ++ } ++ dput(h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * unlink the topmost h_dentry ++ */ ++static int au_do_unlink(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct path h_path; ++ struct inode *delegated; ++ ++ h_path.mnt = au_sbr_mnt(a->sb, a->mvd_bsrc); ++ h_path.dentry = au_h_dptr(a->dentry, a->mvd_bsrc); ++ delegated = NULL; ++ err = vfsub_unlink(a->mvd_h_src_dir, &h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "unlink failed\n"); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* Since mvdown succeeded, we ignore an error of this function */ ++static void au_do_stfs(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_branch *br; ++ ++ a->mvdown.flags |= AUFS_MVDOWN_STFS_FAILED; ++ br = au_sbr(a->sb, a->mvd_bsrc); ++ err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_UPPER].stfs); ++ if (!err) { ++ br = au_sbr(a->sb, a->mvd_bdst); ++ a->mvdown.stbr[AUFS_MVDOWN_LOWER].brid = br->br_id; ++ err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_LOWER].stfs); ++ } ++ if (!err) ++ a->mvdown.flags &= ~AUFS_MVDOWN_STFS_FAILED; ++ else ++ AU_MVD_PR(dmsg, "statfs failed (%d), ignored\n", err); ++} ++ ++/* ++ * copy-down the file and unlink the bsrc file. ++ * - unlink the bdst whout if exist ++ * - copy-down the file (with whtmp name and rename) ++ * - unlink the bsrc file ++ */ ++static int au_do_mvdown(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = au_do_mkdir(dmsg, a); ++ if (!err) ++ err = au_do_lock(dmsg, a); ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * do not revert the activities we made on bdst since they should be ++ * harmless in aufs. ++ */ ++ ++ err = au_do_cpdown(dmsg, a); ++ if (!err) ++ err = au_do_unlink_wh(dmsg, a); ++ if (!err && !(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) ++ err = au_do_unlink(dmsg, a); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ AuDbg("%pd2, 0x%x, %d --> %d\n", ++ a->dentry, a->mvdown.flags, a->mvd_bsrc, a->mvd_bdst); ++ if (find_lower_writable(a) < 0) ++ a->mvdown.flags |= AUFS_MVDOWN_BOTTOM; ++ ++ if (a->mvdown.flags & AUFS_MVDOWN_STFS) ++ au_do_stfs(dmsg, a); ++ ++ /* maintain internal array */ ++ if (!(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) { ++ au_set_h_dptr(a->dentry, a->mvd_bsrc, NULL); ++ au_set_dbtop(a->dentry, a->mvd_bdst); ++ au_set_h_iptr(a->inode, a->mvd_bsrc, NULL, /*flags*/0); ++ au_set_ibtop(a->inode, a->mvd_bdst); ++ } else { ++ /* hide the lower */ ++ au_set_h_dptr(a->dentry, a->mvd_bdst, NULL); ++ au_set_dbbot(a->dentry, a->mvd_bsrc); ++ au_set_h_iptr(a->inode, a->mvd_bdst, NULL, /*flags*/0); ++ au_set_ibbot(a->inode, a->mvd_bsrc); ++ } ++ if (au_dbbot(a->dentry) < a->mvd_bdst) ++ au_set_dbbot(a->dentry, a->mvd_bdst); ++ if (au_ibbot(a->inode) < a->mvd_bdst) ++ au_set_ibbot(a->inode, a->mvd_bdst); ++ ++out_unlock: ++ au_do_unlock(dmsg, a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* make sure the file is idle */ ++static int au_mvd_args_busy(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err, plinked; ++ ++ err = 0; ++ plinked = !!au_opt_test(au_mntflags(a->sb), PLINK); ++ if (au_dbtop(a->dentry) == a->mvd_bsrc ++ && au_dcount(a->dentry) == 1 ++ && atomic_read(&a->inode->i_count) == 1 ++ /* && a->mvd_h_src_inode->i_nlink == 1 */ ++ && (!plinked || !au_plink_test(a->inode)) ++ && a->inode->i_nlink == 1) ++ goto out; ++ ++ err = -EBUSY; ++ AU_MVD_PR(dmsg, ++ "b%d, d{b%d, c%d?}, i{c%d?, l%u}, hi{l%u}, p{%d, %d}\n", ++ a->mvd_bsrc, au_dbtop(a->dentry), au_dcount(a->dentry), ++ atomic_read(&a->inode->i_count), a->inode->i_nlink, ++ a->mvd_h_src_inode->i_nlink, ++ plinked, plinked ? au_plink_test(a->inode) : 0); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* make sure the parent dir is fine */ ++static int au_mvd_args_parent(const unsigned char dmsg, ++ struct au_mvd_args *a) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ ++ err = 0; ++ if (unlikely(au_alive_dir(a->parent))) { ++ err = -ENOENT; ++ AU_MVD_PR(dmsg, "parent dir is dead\n"); ++ goto out; ++ } ++ ++ a->bopq = au_dbdiropq(a->parent); ++ bindex = au_wbr_nonopq(a->dentry, a->mvd_bdst); ++ AuDbg("b%d\n", bindex); ++ if (unlikely((bindex >= 0 && bindex < a->mvd_bdst) ++ || (a->bopq != -1 && a->bopq < a->mvd_bdst))) { ++ err = -EINVAL; ++ a->mvd_errno = EAU_MVDOWN_OPAQUE; ++ AU_MVD_PR(dmsg, "ancestor is opaque b%d, b%d\n", ++ a->bopq, a->mvd_bdst); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args_intermediate(const unsigned char dmsg, ++ struct au_mvd_args *a) ++{ ++ int err; ++ struct au_dinfo *dinfo, *tmp; ++ ++ /* lookup the next lower positive entry */ ++ err = -ENOMEM; ++ tmp = au_di_alloc(a->sb, AuLsc_DI_TMP); ++ if (unlikely(!tmp)) ++ goto out; ++ ++ a->bfound = -1; ++ a->bwh = -1; ++ dinfo = au_di(a->dentry); ++ au_di_cp(tmp, dinfo); ++ au_di_swap(tmp, dinfo); ++ ++ /* returns the number of positive dentries */ ++ err = au_lkup_dentry(a->dentry, a->mvd_bsrc + 1, ++ /* AuLkup_IGNORE_PERM */ 0); ++ if (!err) ++ a->bwh = au_dbwh(a->dentry); ++ else if (err > 0) ++ a->bfound = au_dbtop(a->dentry); ++ ++ au_di_swap(tmp, dinfo); ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ if (unlikely(err < 0)) ++ AU_MVD_PR(dmsg, "failed look-up lower\n"); ++ ++ /* ++ * here, we have these cases. ++ * bfound == -1 ++ * no positive dentry under bsrc. there are more sub-cases. ++ * bwh < 0 ++ * there no whiteout, we can safely move-down. ++ * bwh <= bsrc ++ * impossible ++ * bsrc < bwh && bwh < bdst ++ * there is a whiteout on RO branch. cannot proceed. ++ * bwh == bdst ++ * there is a whiteout on the RW target branch. it should ++ * be removed. ++ * bdst < bwh ++ * there is a whiteout somewhere unrelated branch. ++ * -1 < bfound && bfound <= bsrc ++ * impossible. ++ * bfound < bdst ++ * found, but it is on RO branch between bsrc and bdst. cannot ++ * proceed. ++ * bfound == bdst ++ * found, replace it if AUFS_MVDOWN_FORCE is set. otherwise return ++ * error. ++ * bdst < bfound ++ * found, after we create the file on bdst, it will be hidden. ++ */ ++ ++ AuDebugOn(a->bfound == -1 ++ && a->bwh != -1 ++ && a->bwh <= a->mvd_bsrc); ++ AuDebugOn(-1 < a->bfound ++ && a->bfound <= a->mvd_bsrc); ++ ++ err = -EINVAL; ++ if (a->bfound == -1 ++ && a->mvd_bsrc < a->bwh ++ && a->bwh != -1 ++ && a->bwh < a->mvd_bdst) { ++ a->mvd_errno = EAU_MVDOWN_WHITEOUT; ++ AU_MVD_PR(dmsg, "bsrc %d, bdst %d, bfound %d, bwh %d\n", ++ a->mvd_bsrc, a->mvd_bdst, a->bfound, a->bwh); ++ goto out; ++ } else if (a->bfound != -1 && a->bfound < a->mvd_bdst) { ++ a->mvd_errno = EAU_MVDOWN_UPPER; ++ AU_MVD_PR(dmsg, "bdst %d, bfound %d\n", ++ a->mvd_bdst, a->bfound); ++ goto out; ++ } ++ ++ err = 0; /* success */ ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args_exist(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = 0; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_OWLOWER) ++ && a->bfound == a->mvd_bdst) ++ err = -EEXIST; ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_branch *br; ++ ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(a->inode->i_mode))) ++ goto out; ++ ++ err = -EINVAL; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_UPPER)) ++ a->mvd_bsrc = au_ibtop(a->inode); ++ else { ++ a->mvd_bsrc = au_br_index(a->sb, a->mvd_src_brid); ++ if (unlikely(a->mvd_bsrc < 0 ++ || (a->mvd_bsrc < au_dbtop(a->dentry) ++ || au_dbbot(a->dentry) < a->mvd_bsrc ++ || !au_h_dptr(a->dentry, a->mvd_bsrc)) ++ || (a->mvd_bsrc < au_ibtop(a->inode) ++ || au_ibbot(a->inode) < a->mvd_bsrc ++ || !au_h_iptr(a->inode, a->mvd_bsrc)))) { ++ a->mvd_errno = EAU_MVDOWN_NOUPPER; ++ AU_MVD_PR(dmsg, "no upper\n"); ++ goto out; ++ } ++ } ++ if (unlikely(a->mvd_bsrc == au_sbbot(a->sb))) { ++ a->mvd_errno = EAU_MVDOWN_BOTTOM; ++ AU_MVD_PR(dmsg, "on the bottom\n"); ++ goto out; ++ } ++ a->mvd_h_src_inode = au_h_iptr(a->inode, a->mvd_bsrc); ++ br = au_sbr(a->sb, a->mvd_bsrc); ++ err = au_br_rdonly(br); ++ if (!(a->mvdown.flags & AUFS_MVDOWN_ROUPPER)) { ++ if (unlikely(err)) ++ goto out; ++ } else if (!(vfsub_native_ro(a->mvd_h_src_inode) ++ || IS_APPEND(a->mvd_h_src_inode))) { ++ if (err) ++ a->mvdown.flags |= AUFS_MVDOWN_ROUPPER_R; ++ /* go on */ ++ } else ++ goto out; ++ ++ err = -EINVAL; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_LOWER)) { ++ a->mvd_bdst = find_lower_writable(a); ++ if (unlikely(a->mvd_bdst < 0)) { ++ a->mvd_errno = EAU_MVDOWN_BOTTOM; ++ AU_MVD_PR(dmsg, "no writable lower branch\n"); ++ goto out; ++ } ++ } else { ++ a->mvd_bdst = au_br_index(a->sb, a->mvd_dst_brid); ++ if (unlikely(a->mvd_bdst < 0 ++ || au_sbbot(a->sb) < a->mvd_bdst)) { ++ a->mvd_errno = EAU_MVDOWN_NOLOWERBR; ++ AU_MVD_PR(dmsg, "no lower brid\n"); ++ goto out; ++ } ++ } ++ ++ err = au_mvd_args_busy(dmsg, a); ++ if (!err) ++ err = au_mvd_args_parent(dmsg, a); ++ if (!err) ++ err = au_mvd_args_intermediate(dmsg, a); ++ if (!err) ++ err = au_mvd_args_exist(dmsg, a); ++ if (!err) ++ AuDbg("b%d, b%d\n", a->mvd_bsrc, a->mvd_bdst); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg) ++{ ++ int err, e; ++ unsigned char dmsg; ++ struct au_mvd_args *args; ++ struct inode *inode; ++ ++ inode = d_inode(dentry); ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -ENOMEM; ++ args = kmalloc(sizeof(*args), GFP_NOFS); ++ if (unlikely(!args)) ++ goto out; ++ ++ err = copy_from_user(&args->mvdown, uarg, sizeof(args->mvdown)); ++ if (!err) ++ err = !access_ok(VERIFY_WRITE, uarg, sizeof(*uarg)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out_free; ++ } ++ AuDbg("flags 0x%x\n", args->mvdown.flags); ++ args->mvdown.flags &= ~(AUFS_MVDOWN_ROLOWER_R | AUFS_MVDOWN_ROUPPER_R); ++ args->mvdown.au_errno = 0; ++ args->dentry = dentry; ++ args->inode = inode; ++ args->sb = dentry->d_sb; ++ ++ err = -ENOENT; ++ dmsg = !!(args->mvdown.flags & AUFS_MVDOWN_DMSG); ++ args->parent = dget_parent(dentry); ++ args->dir = d_inode(args->parent); ++ inode_lock_nested(args->dir, I_MUTEX_PARENT); ++ dput(args->parent); ++ if (unlikely(args->parent != dentry->d_parent)) { ++ AU_MVD_PR(dmsg, "parent dir is moved\n"); ++ goto out_dir; ++ } ++ ++ inode_lock_nested(inode, I_MUTEX_CHILD); ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_NOPLMW); ++ if (unlikely(err)) ++ goto out_inode; ++ ++ di_write_lock_parent(args->parent); ++ err = au_mvd_args(dmsg, args); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ err = au_do_mvdown(dmsg, args); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ au_cpup_attr_timesizes(args->dir); ++ au_cpup_attr_timesizes(inode); ++ if (!(args->mvdown.flags & AUFS_MVDOWN_KUPPER)) ++ au_cpup_igen(inode, au_h_iptr(inode, args->mvd_bdst)); ++ /* au_digen_dec(dentry); */ ++ ++out_parent: ++ di_write_unlock(args->parent); ++ aufs_read_unlock(dentry, AuLock_DW); ++out_inode: ++ inode_unlock(inode); ++out_dir: ++ inode_unlock(args->dir); ++out_free: ++ e = copy_to_user(uarg, &args->mvdown, sizeof(args->mvdown)); ++ if (unlikely(e)) ++ err = -EFAULT; ++ kfree(args); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/opts.c b/fs/aufs/opts.c +new file mode 100644 +index 0000000..79c7d71 +--- /dev/null ++++ b/fs/aufs/opts.c +@@ -0,0 +1,1846 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * mount options/flags ++ */ ++ ++#include ++#include /* a distribution requires */ ++#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++enum { ++ Opt_br, ++ Opt_add, Opt_del, Opt_mod, Opt_append, Opt_prepend, ++ Opt_idel, Opt_imod, ++ Opt_dirwh, Opt_rdcache, Opt_rdblk, Opt_rdhash, ++ Opt_rdblk_def, Opt_rdhash_def, ++ Opt_xino, Opt_noxino, ++ Opt_trunc_xino, Opt_trunc_xino_v, Opt_notrunc_xino, ++ Opt_trunc_xino_path, Opt_itrunc_xino, ++ Opt_trunc_xib, Opt_notrunc_xib, ++ Opt_shwh, Opt_noshwh, ++ Opt_plink, Opt_noplink, Opt_list_plink, ++ Opt_udba, ++ Opt_dio, Opt_nodio, ++ Opt_diropq_a, Opt_diropq_w, ++ Opt_warn_perm, Opt_nowarn_perm, ++ Opt_wbr_copyup, Opt_wbr_create, ++ Opt_fhsm_sec, ++ Opt_verbose, Opt_noverbose, ++ Opt_sum, Opt_nosum, Opt_wsum, ++ Opt_dirperm1, Opt_nodirperm1, ++ Opt_acl, Opt_noacl, ++ Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err ++}; ++ ++static match_table_t options = { ++ {Opt_br, "br=%s"}, ++ {Opt_br, "br:%s"}, ++ ++ {Opt_add, "add=%d:%s"}, ++ {Opt_add, "add:%d:%s"}, ++ {Opt_add, "ins=%d:%s"}, ++ {Opt_add, "ins:%d:%s"}, ++ {Opt_append, "append=%s"}, ++ {Opt_append, "append:%s"}, ++ {Opt_prepend, "prepend=%s"}, ++ {Opt_prepend, "prepend:%s"}, ++ ++ {Opt_del, "del=%s"}, ++ {Opt_del, "del:%s"}, ++ /* {Opt_idel, "idel:%d"}, */ ++ {Opt_mod, "mod=%s"}, ++ {Opt_mod, "mod:%s"}, ++ /* {Opt_imod, "imod:%d:%s"}, */ ++ ++ {Opt_dirwh, "dirwh=%d"}, ++ ++ {Opt_xino, "xino=%s"}, ++ {Opt_noxino, "noxino"}, ++ {Opt_trunc_xino, "trunc_xino"}, ++ {Opt_trunc_xino_v, "trunc_xino_v=%d:%d"}, ++ {Opt_notrunc_xino, "notrunc_xino"}, ++ {Opt_trunc_xino_path, "trunc_xino=%s"}, ++ {Opt_itrunc_xino, "itrunc_xino=%d"}, ++ /* {Opt_zxino, "zxino=%s"}, */ ++ {Opt_trunc_xib, "trunc_xib"}, ++ {Opt_notrunc_xib, "notrunc_xib"}, ++ ++#ifdef CONFIG_PROC_FS ++ {Opt_plink, "plink"}, ++#else ++ {Opt_ignore_silent, "plink"}, ++#endif ++ ++ {Opt_noplink, "noplink"}, ++ ++#ifdef CONFIG_AUFS_DEBUG ++ {Opt_list_plink, "list_plink"}, ++#endif ++ ++ {Opt_udba, "udba=%s"}, ++ ++ {Opt_dio, "dio"}, ++ {Opt_nodio, "nodio"}, ++ ++#ifdef CONFIG_AUFS_FHSM ++ {Opt_fhsm_sec, "fhsm_sec=%d"}, ++#else ++ {Opt_ignore_silent, "fhsm_sec=%d"}, ++#endif ++ ++ {Opt_diropq_a, "diropq=always"}, ++ {Opt_diropq_a, "diropq=a"}, ++ {Opt_diropq_w, "diropq=whiteouted"}, ++ {Opt_diropq_w, "diropq=w"}, ++ ++ {Opt_warn_perm, "warn_perm"}, ++ {Opt_nowarn_perm, "nowarn_perm"}, ++ ++ /* keep them temporary */ ++ {Opt_ignore_silent, "nodlgt"}, ++ {Opt_ignore_silent, "clean_plink"}, ++ ++#ifdef CONFIG_AUFS_SHWH ++ {Opt_shwh, "shwh"}, ++#endif ++ {Opt_noshwh, "noshwh"}, ++ ++ {Opt_dirperm1, "dirperm1"}, ++ {Opt_nodirperm1, "nodirperm1"}, ++ ++ {Opt_verbose, "verbose"}, ++ {Opt_verbose, "v"}, ++ {Opt_noverbose, "noverbose"}, ++ {Opt_noverbose, "quiet"}, ++ {Opt_noverbose, "q"}, ++ {Opt_noverbose, "silent"}, ++ ++ {Opt_sum, "sum"}, ++ {Opt_nosum, "nosum"}, ++ {Opt_wsum, "wsum"}, ++ ++ {Opt_rdcache, "rdcache=%d"}, ++ {Opt_rdblk, "rdblk=%d"}, ++ {Opt_rdblk_def, "rdblk=def"}, ++ {Opt_rdhash, "rdhash=%d"}, ++ {Opt_rdhash_def, "rdhash=def"}, ++ ++ {Opt_wbr_create, "create=%s"}, ++ {Opt_wbr_create, "create_policy=%s"}, ++ {Opt_wbr_copyup, "cpup=%s"}, ++ {Opt_wbr_copyup, "copyup=%s"}, ++ {Opt_wbr_copyup, "copyup_policy=%s"}, ++ ++ /* generic VFS flag */ ++#ifdef CONFIG_FS_POSIX_ACL ++ {Opt_acl, "acl"}, ++ {Opt_noacl, "noacl"}, ++#else ++ {Opt_ignore_silent, "acl"}, ++ {Opt_ignore_silent, "noacl"}, ++#endif ++ ++ /* internal use for the scripts */ ++ {Opt_ignore_silent, "si=%s"}, ++ ++ {Opt_br, "dirs=%s"}, ++ {Opt_ignore, "debug=%d"}, ++ {Opt_ignore, "delete=whiteout"}, ++ {Opt_ignore, "delete=all"}, ++ {Opt_ignore, "imap=%s"}, ++ ++ /* temporary workaround, due to old mount(8)? */ ++ {Opt_ignore_silent, "relatime"}, ++ ++ {Opt_err, NULL} ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const char *au_parser_pattern(int val, match_table_t tbl) ++{ ++ struct match_token *p; ++ ++ p = tbl; ++ while (p->pattern) { ++ if (p->token == val) ++ return p->pattern; ++ p++; ++ } ++ BUG(); ++ return "??"; ++} ++ ++static const char *au_optstr(int *val, match_table_t tbl) ++{ ++ struct match_token *p; ++ int v; ++ ++ v = *val; ++ if (!v) ++ goto out; ++ p = tbl; ++ while (p->pattern) { ++ if (p->token ++ && (v & p->token) == p->token) { ++ *val &= ~p->token; ++ return p->pattern; ++ } ++ p++; ++ } ++ ++out: ++ return NULL; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t brperm = { ++ {AuBrPerm_RO, AUFS_BRPERM_RO}, ++ {AuBrPerm_RR, AUFS_BRPERM_RR}, ++ {AuBrPerm_RW, AUFS_BRPERM_RW}, ++ {0, NULL} ++}; ++ ++static match_table_t brattr = { ++ /* general */ ++ {AuBrAttr_COO_REG, AUFS_BRATTR_COO_REG}, ++ {AuBrAttr_COO_ALL, AUFS_BRATTR_COO_ALL}, ++ /* 'unpin' attrib is meaningless since linux-3.18-rc1 */ ++ {AuBrAttr_UNPIN, AUFS_BRATTR_UNPIN}, ++#ifdef CONFIG_AUFS_FHSM ++ {AuBrAttr_FHSM, AUFS_BRATTR_FHSM}, ++#endif ++#ifdef CONFIG_AUFS_XATTR ++ {AuBrAttr_ICEX, AUFS_BRATTR_ICEX}, ++ {AuBrAttr_ICEX_SEC, AUFS_BRATTR_ICEX_SEC}, ++ {AuBrAttr_ICEX_SYS, AUFS_BRATTR_ICEX_SYS}, ++ {AuBrAttr_ICEX_TR, AUFS_BRATTR_ICEX_TR}, ++ {AuBrAttr_ICEX_USR, AUFS_BRATTR_ICEX_USR}, ++ {AuBrAttr_ICEX_OTH, AUFS_BRATTR_ICEX_OTH}, ++#endif ++ ++ /* ro/rr branch */ ++ {AuBrRAttr_WH, AUFS_BRRATTR_WH}, ++ ++ /* rw branch */ ++ {AuBrWAttr_MOO, AUFS_BRWATTR_MOO}, ++ {AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH}, ++ ++ {0, NULL} ++}; ++ ++static int br_attr_val(char *str, match_table_t table, substring_t args[]) ++{ ++ int attr, v; ++ char *p; ++ ++ attr = 0; ++ do { ++ p = strchr(str, '+'); ++ if (p) ++ *p = 0; ++ v = match_token(str, table, args); ++ if (v) { ++ if (v & AuBrAttr_CMOO_Mask) ++ attr &= ~AuBrAttr_CMOO_Mask; ++ attr |= v; ++ } else { ++ if (p) ++ *p = '+'; ++ pr_warn("ignored branch attribute %s\n", str); ++ break; ++ } ++ if (p) ++ str = p + 1; ++ } while (p); ++ ++ return attr; ++} ++ ++static int au_do_optstr_br_attr(au_br_perm_str_t *str, int perm) ++{ ++ int sz; ++ const char *p; ++ char *q; ++ ++ q = str->a; ++ *q = 0; ++ p = au_optstr(&perm, brattr); ++ if (p) { ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ } else ++ goto out; ++ ++ do { ++ p = au_optstr(&perm, brattr); ++ if (p) { ++ *q++ = '+'; ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ } ++ } while (p); ++ ++out: ++ return q - str->a; ++} ++ ++static int noinline_for_stack br_perm_val(char *perm) ++{ ++ int val, bad, sz; ++ char *p; ++ substring_t args[MAX_OPT_ARGS]; ++ au_br_perm_str_t attr; ++ ++ p = strchr(perm, '+'); ++ if (p) ++ *p = 0; ++ val = match_token(perm, brperm, args); ++ if (!val) { ++ if (p) ++ *p = '+'; ++ pr_warn("ignored branch permission %s\n", perm); ++ val = AuBrPerm_RO; ++ goto out; ++ } ++ if (!p) ++ goto out; ++ ++ val |= br_attr_val(p + 1, brattr, args); ++ ++ bad = 0; ++ switch (val & AuBrPerm_Mask) { ++ case AuBrPerm_RO: ++ case AuBrPerm_RR: ++ bad = val & AuBrWAttr_Mask; ++ val &= ~AuBrWAttr_Mask; ++ break; ++ case AuBrPerm_RW: ++ bad = val & AuBrRAttr_Mask; ++ val &= ~AuBrRAttr_Mask; ++ break; ++ } ++ ++ /* ++ * 'unpin' attrib becomes meaningless since linux-3.18-rc1, but aufs ++ * does not treat it as an error, just warning. ++ * this is a tiny guard for the user operation. ++ */ ++ if (val & AuBrAttr_UNPIN) { ++ bad |= AuBrAttr_UNPIN; ++ val &= ~AuBrAttr_UNPIN; ++ } ++ ++ if (unlikely(bad)) { ++ sz = au_do_optstr_br_attr(&attr, bad); ++ AuDebugOn(!sz); ++ pr_warn("ignored branch attribute %s\n", attr.a); ++ } ++ ++out: ++ return val; ++} ++ ++void au_optstr_br_perm(au_br_perm_str_t *str, int perm) ++{ ++ au_br_perm_str_t attr; ++ const char *p; ++ char *q; ++ int sz; ++ ++ q = str->a; ++ p = au_optstr(&perm, brperm); ++ AuDebugOn(!p || !*p); ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ ++ sz = au_do_optstr_br_attr(&attr, perm); ++ if (sz) { ++ *q++ = '+'; ++ memcpy(q, attr.a, sz + 1); ++ } ++ ++ AuDebugOn(strlen(str->a) >= sizeof(str->a)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t udbalevel = { ++ {AuOpt_UDBA_REVAL, "reval"}, ++ {AuOpt_UDBA_NONE, "none"}, ++#ifdef CONFIG_AUFS_HNOTIFY ++ {AuOpt_UDBA_HNOTIFY, "notify"}, /* abstraction */ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ {AuOpt_UDBA_HNOTIFY, "fsnotify"}, ++#endif ++#endif ++ {-1, NULL} ++}; ++ ++static int noinline_for_stack udba_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ ++ return match_token(str, udbalevel, args); ++} ++ ++const char *au_optstr_udba(int udba) ++{ ++ return au_parser_pattern(udba, udbalevel); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t au_wbr_create_policy = { ++ {AuWbrCreate_TDP, "tdp"}, ++ {AuWbrCreate_TDP, "top-down-parent"}, ++ {AuWbrCreate_RR, "rr"}, ++ {AuWbrCreate_RR, "round-robin"}, ++ {AuWbrCreate_MFS, "mfs"}, ++ {AuWbrCreate_MFS, "most-free-space"}, ++ {AuWbrCreate_MFSV, "mfs:%d"}, ++ {AuWbrCreate_MFSV, "most-free-space:%d"}, ++ ++ {AuWbrCreate_MFSRR, "mfsrr:%d"}, ++ {AuWbrCreate_MFSRRV, "mfsrr:%d:%d"}, ++ {AuWbrCreate_PMFS, "pmfs"}, ++ {AuWbrCreate_PMFSV, "pmfs:%d"}, ++ {AuWbrCreate_PMFSRR, "pmfsrr:%d"}, ++ {AuWbrCreate_PMFSRRV, "pmfsrr:%d:%d"}, ++ ++ {-1, NULL} ++}; ++ ++/* ++ * cf. linux/lib/parser.c and cmdline.c ++ * gave up calling memparse() since it uses simple_strtoull() instead of ++ * kstrto...(). ++ */ ++static int noinline_for_stack ++au_match_ull(substring_t *s, unsigned long long *result) ++{ ++ int err; ++ unsigned int len; ++ char a[32]; ++ ++ err = -ERANGE; ++ len = s->to - s->from; ++ if (len + 1 <= sizeof(a)) { ++ memcpy(a, s->from, len); ++ a[len] = '\0'; ++ err = kstrtoull(a, 0, result); ++ } ++ return err; ++} ++ ++static int au_wbr_mfs_wmark(substring_t *arg, char *str, ++ struct au_opt_wbr_create *create) ++{ ++ int err; ++ unsigned long long ull; ++ ++ err = 0; ++ if (!au_match_ull(arg, &ull)) ++ create->mfsrr_watermark = ull; ++ else { ++ pr_err("bad integer in %s\n", str); ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++static int au_wbr_mfs_sec(substring_t *arg, char *str, ++ struct au_opt_wbr_create *create) ++{ ++ int n, err; ++ ++ err = 0; ++ if (!match_int(arg, &n) && 0 <= n && n <= AUFS_MFS_MAX_SEC) ++ create->mfs_second = n; ++ else { ++ pr_err("bad integer in %s\n", str); ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++static int noinline_for_stack ++au_wbr_create_val(char *str, struct au_opt_wbr_create *create) ++{ ++ int err, e; ++ substring_t args[MAX_OPT_ARGS]; ++ ++ err = match_token(str, au_wbr_create_policy, args); ++ create->wbr_create = err; ++ switch (err) { ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_PMFSRRV: ++ e = au_wbr_mfs_wmark(&args[0], str, create); ++ if (!e) ++ e = au_wbr_mfs_sec(&args[1], str, create); ++ if (unlikely(e)) ++ err = e; ++ break; ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_PMFSRR: ++ e = au_wbr_mfs_wmark(&args[0], str, create); ++ if (unlikely(e)) { ++ err = e; ++ break; ++ } ++ /*FALLTHROUGH*/ ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_PMFS: ++ create->mfs_second = AUFS_MFS_DEF_SEC; ++ break; ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ e = au_wbr_mfs_sec(&args[0], str, create); ++ if (unlikely(e)) ++ err = e; ++ break; ++ } ++ ++ return err; ++} ++ ++const char *au_optstr_wbr_create(int wbr_create) ++{ ++ return au_parser_pattern(wbr_create, au_wbr_create_policy); ++} ++ ++static match_table_t au_wbr_copyup_policy = { ++ {AuWbrCopyup_TDP, "tdp"}, ++ {AuWbrCopyup_TDP, "top-down-parent"}, ++ {AuWbrCopyup_BUP, "bup"}, ++ {AuWbrCopyup_BUP, "bottom-up-parent"}, ++ {AuWbrCopyup_BU, "bu"}, ++ {AuWbrCopyup_BU, "bottom-up"}, ++ {-1, NULL} ++}; ++ ++static int noinline_for_stack au_wbr_copyup_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ ++ return match_token(str, au_wbr_copyup_policy, args); ++} ++ ++const char *au_optstr_wbr_copyup(int wbr_copyup) ++{ ++ return au_parser_pattern(wbr_copyup, au_wbr_copyup_policy); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const int lkup_dirflags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; ++ ++static void dump_opts(struct au_opts *opts) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++ /* reduce stack space */ ++ union { ++ struct au_opt_add *add; ++ struct au_opt_del *del; ++ struct au_opt_mod *mod; ++ struct au_opt_xino *xino; ++ struct au_opt_xino_itrunc *xino_itrunc; ++ struct au_opt_wbr_create *create; ++ } u; ++ struct au_opt *opt; ++ ++ opt = opts->opt; ++ while (opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ u.add = &opt->add; ++ AuDbg("add {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_del: ++ case Opt_idel: ++ u.del = &opt->del; ++ AuDbg("del {%s, %p}\n", ++ u.del->pathname, u.del->h_path.dentry); ++ break; ++ case Opt_mod: ++ case Opt_imod: ++ u.mod = &opt->mod; ++ AuDbg("mod {%s, 0x%x, %p}\n", ++ u.mod->path, u.mod->perm, u.mod->h_root); ++ break; ++ case Opt_append: ++ u.add = &opt->add; ++ AuDbg("append {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_prepend: ++ u.add = &opt->add; ++ AuDbg("prepend {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_dirwh: ++ AuDbg("dirwh %d\n", opt->dirwh); ++ break; ++ case Opt_rdcache: ++ AuDbg("rdcache %d\n", opt->rdcache); ++ break; ++ case Opt_rdblk: ++ AuDbg("rdblk %u\n", opt->rdblk); ++ break; ++ case Opt_rdblk_def: ++ AuDbg("rdblk_def\n"); ++ break; ++ case Opt_rdhash: ++ AuDbg("rdhash %u\n", opt->rdhash); ++ break; ++ case Opt_rdhash_def: ++ AuDbg("rdhash_def\n"); ++ break; ++ case Opt_xino: ++ u.xino = &opt->xino; ++ AuDbg("xino {%s %pD}\n", u.xino->path, u.xino->file); ++ break; ++ case Opt_trunc_xino: ++ AuLabel(trunc_xino); ++ break; ++ case Opt_notrunc_xino: ++ AuLabel(notrunc_xino); ++ break; ++ case Opt_trunc_xino_path: ++ case Opt_itrunc_xino: ++ u.xino_itrunc = &opt->xino_itrunc; ++ AuDbg("trunc_xino %d\n", u.xino_itrunc->bindex); ++ break; ++ case Opt_noxino: ++ AuLabel(noxino); ++ break; ++ case Opt_trunc_xib: ++ AuLabel(trunc_xib); ++ break; ++ case Opt_notrunc_xib: ++ AuLabel(notrunc_xib); ++ break; ++ case Opt_shwh: ++ AuLabel(shwh); ++ break; ++ case Opt_noshwh: ++ AuLabel(noshwh); ++ break; ++ case Opt_dirperm1: ++ AuLabel(dirperm1); ++ break; ++ case Opt_nodirperm1: ++ AuLabel(nodirperm1); ++ break; ++ case Opt_plink: ++ AuLabel(plink); ++ break; ++ case Opt_noplink: ++ AuLabel(noplink); ++ break; ++ case Opt_list_plink: ++ AuLabel(list_plink); ++ break; ++ case Opt_udba: ++ AuDbg("udba %d, %s\n", ++ opt->udba, au_optstr_udba(opt->udba)); ++ break; ++ case Opt_dio: ++ AuLabel(dio); ++ break; ++ case Opt_nodio: ++ AuLabel(nodio); ++ break; ++ case Opt_diropq_a: ++ AuLabel(diropq_a); ++ break; ++ case Opt_diropq_w: ++ AuLabel(diropq_w); ++ break; ++ case Opt_warn_perm: ++ AuLabel(warn_perm); ++ break; ++ case Opt_nowarn_perm: ++ AuLabel(nowarn_perm); ++ break; ++ case Opt_verbose: ++ AuLabel(verbose); ++ break; ++ case Opt_noverbose: ++ AuLabel(noverbose); ++ break; ++ case Opt_sum: ++ AuLabel(sum); ++ break; ++ case Opt_nosum: ++ AuLabel(nosum); ++ break; ++ case Opt_wsum: ++ AuLabel(wsum); ++ break; ++ case Opt_wbr_create: ++ u.create = &opt->wbr_create; ++ AuDbg("create %d, %s\n", u.create->wbr_create, ++ au_optstr_wbr_create(u.create->wbr_create)); ++ switch (u.create->wbr_create) { ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ AuDbg("%d sec\n", u.create->mfs_second); ++ break; ++ case AuWbrCreate_MFSRR: ++ AuDbg("%llu watermark\n", ++ u.create->mfsrr_watermark); ++ break; ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_PMFSRRV: ++ AuDbg("%llu watermark, %d sec\n", ++ u.create->mfsrr_watermark, ++ u.create->mfs_second); ++ break; ++ } ++ break; ++ case Opt_wbr_copyup: ++ AuDbg("copyup %d, %s\n", opt->wbr_copyup, ++ au_optstr_wbr_copyup(opt->wbr_copyup)); ++ break; ++ case Opt_fhsm_sec: ++ AuDbg("fhsm_sec %u\n", opt->fhsm_second); ++ break; ++ case Opt_acl: ++ AuLabel(acl); ++ break; ++ case Opt_noacl: ++ AuLabel(noacl); ++ break; ++ default: ++ BUG(); ++ } ++ opt++; ++ } ++#endif ++} ++ ++void au_opts_free(struct au_opts *opts) ++{ ++ struct au_opt *opt; ++ ++ opt = opts->opt; ++ while (opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ case Opt_append: ++ case Opt_prepend: ++ path_put(&opt->add.path); ++ break; ++ case Opt_del: ++ case Opt_idel: ++ path_put(&opt->del.h_path); ++ break; ++ case Opt_mod: ++ case Opt_imod: ++ dput(opt->mod.h_root); ++ break; ++ case Opt_xino: ++ fput(opt->xino.file); ++ break; ++ } ++ opt++; ++ } ++} ++ ++static int opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ struct au_opt_add *add = &opt->add; ++ char *p; ++ ++ add->bindex = bindex; ++ add->perm = AuBrPerm_RO; ++ add->pathname = opt_str; ++ p = strchr(opt_str, '='); ++ if (p) { ++ *p++ = 0; ++ if (*p) ++ add->perm = br_perm_val(p); ++ } ++ ++ err = vfsub_kern_path(add->pathname, lkup_dirflags, &add->path); ++ if (!err) { ++ if (!p) { ++ add->perm = AuBrPerm_RO; ++ if (au_test_fs_rr(add->path.dentry->d_sb)) ++ add->perm = AuBrPerm_RR; ++ else if (!bindex && !(sb_flags & MS_RDONLY)) ++ add->perm = AuBrPerm_RW; ++ } ++ opt->type = Opt_add; ++ goto out; ++ } ++ pr_err("lookup failed %s (%d)\n", add->pathname, err); ++ err = -EINVAL; ++ ++out: ++ return err; ++} ++ ++static int au_opts_parse_del(struct au_opt_del *del, substring_t args[]) ++{ ++ int err; ++ ++ del->pathname = args[0].from; ++ AuDbg("del path %s\n", del->pathname); ++ ++ err = vfsub_kern_path(del->pathname, lkup_dirflags, &del->h_path); ++ if (unlikely(err)) ++ pr_err("lookup failed %s (%d)\n", del->pathname, err); ++ ++ return err; ++} ++ ++#if 0 /* reserved for future use */ ++static int au_opts_parse_idel(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_opt_del *del, substring_t args[]) ++{ ++ int err; ++ struct dentry *root; ++ ++ err = -EINVAL; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (bindex < 0 || au_sbbot(sb) < bindex) { ++ pr_err("out of bounds, %d\n", bindex); ++ goto out; ++ } ++ ++ err = 0; ++ del->h_path.dentry = dget(au_h_dptr(root, bindex)); ++ del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex)); ++ ++out: ++ aufs_read_unlock(root, !AuLock_IR); ++ return err; ++} ++#endif ++ ++static int noinline_for_stack ++au_opts_parse_mod(struct au_opt_mod *mod, substring_t args[]) ++{ ++ int err; ++ struct path path; ++ char *p; ++ ++ err = -EINVAL; ++ mod->path = args[0].from; ++ p = strchr(mod->path, '='); ++ if (unlikely(!p)) { ++ pr_err("no permssion %s\n", args[0].from); ++ goto out; ++ } ++ ++ *p++ = 0; ++ err = vfsub_kern_path(mod->path, lkup_dirflags, &path); ++ if (unlikely(err)) { ++ pr_err("lookup failed %s (%d)\n", mod->path, err); ++ goto out; ++ } ++ ++ mod->perm = br_perm_val(p); ++ AuDbg("mod path %s, perm 0x%x, %s\n", mod->path, mod->perm, p); ++ mod->h_root = dget(path.dentry); ++ path_put(&path); ++ ++out: ++ return err; ++} ++ ++#if 0 /* reserved for future use */ ++static int au_opts_parse_imod(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_opt_mod *mod, substring_t args[]) ++{ ++ int err; ++ struct dentry *root; ++ ++ err = -EINVAL; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (bindex < 0 || au_sbbot(sb) < bindex) { ++ pr_err("out of bounds, %d\n", bindex); ++ goto out; ++ } ++ ++ err = 0; ++ mod->perm = br_perm_val(args[1].from); ++ AuDbg("mod path %s, perm 0x%x, %s\n", ++ mod->path, mod->perm, args[1].from); ++ mod->h_root = dget(au_h_dptr(root, bindex)); ++ ++out: ++ aufs_read_unlock(root, !AuLock_IR); ++ return err; ++} ++#endif ++ ++static int au_opts_parse_xino(struct super_block *sb, struct au_opt_xino *xino, ++ substring_t args[]) ++{ ++ int err; ++ struct file *file; ++ ++ file = au_xino_create(sb, args[0].from, /*silent*/0); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(file->f_path.dentry->d_sb == sb)) { ++ fput(file); ++ pr_err("%s must be outside\n", args[0].from); ++ goto out; ++ } ++ ++ err = 0; ++ xino->file = file; ++ xino->path = args[0].from; ++ ++out: ++ return err; ++} ++ ++static int noinline_for_stack ++au_opts_parse_xino_itrunc_path(struct super_block *sb, ++ struct au_opt_xino_itrunc *xino_itrunc, ++ substring_t args[]) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct path path; ++ struct dentry *root; ++ ++ err = vfsub_kern_path(args[0].from, lkup_dirflags, &path); ++ if (unlikely(err)) { ++ pr_err("lookup failed %s (%d)\n", args[0].from, err); ++ goto out; ++ } ++ ++ xino_itrunc->bindex = -1; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ if (au_h_dptr(root, bindex) == path.dentry) { ++ xino_itrunc->bindex = bindex; ++ break; ++ } ++ } ++ aufs_read_unlock(root, !AuLock_IR); ++ path_put(&path); ++ ++ if (unlikely(xino_itrunc->bindex < 0)) { ++ pr_err("no such branch %s\n", args[0].from); ++ err = -EINVAL; ++ } ++ ++out: ++ return err; ++} ++ ++/* called without aufs lock */ ++int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts) ++{ ++ int err, n, token; ++ aufs_bindex_t bindex; ++ unsigned char skipped; ++ struct dentry *root; ++ struct au_opt *opt, *opt_tail; ++ char *opt_str; ++ /* reduce the stack space */ ++ union { ++ struct au_opt_xino_itrunc *xino_itrunc; ++ struct au_opt_wbr_create *create; ++ } u; ++ struct { ++ substring_t args[MAX_OPT_ARGS]; ++ } *a; ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ root = sb->s_root; ++ err = 0; ++ bindex = 0; ++ opt = opts->opt; ++ opt_tail = opt + opts->max_opt - 1; ++ opt->type = Opt_tail; ++ while (!err && (opt_str = strsep(&str, ",")) && *opt_str) { ++ err = -EINVAL; ++ skipped = 0; ++ token = match_token(opt_str, options, a->args); ++ switch (token) { ++ case Opt_br: ++ err = 0; ++ while (!err && (opt_str = strsep(&a->args[0].from, ":")) ++ && *opt_str) { ++ err = opt_add(opt, opt_str, opts->sb_flags, ++ bindex++); ++ if (unlikely(!err && ++opt > opt_tail)) { ++ err = -E2BIG; ++ break; ++ } ++ opt->type = Opt_tail; ++ skipped = 1; ++ } ++ break; ++ case Opt_add: ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ bindex = n; ++ err = opt_add(opt, a->args[1].from, opts->sb_flags, ++ bindex); ++ if (!err) ++ opt->type = token; ++ break; ++ case Opt_append: ++ err = opt_add(opt, a->args[0].from, opts->sb_flags, ++ /*dummy bindex*/1); ++ if (!err) ++ opt->type = token; ++ break; ++ case Opt_prepend: ++ err = opt_add(opt, a->args[0].from, opts->sb_flags, ++ /*bindex*/0); ++ if (!err) ++ opt->type = token; ++ break; ++ case Opt_del: ++ err = au_opts_parse_del(&opt->del, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#if 0 /* reserved for future use */ ++ case Opt_idel: ++ del->pathname = "(indexed)"; ++ if (unlikely(match_int(&args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ err = au_opts_parse_idel(sb, n, &opt->del, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#endif ++ case Opt_mod: ++ err = au_opts_parse_mod(&opt->mod, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#ifdef IMOD /* reserved for future use */ ++ case Opt_imod: ++ u.mod->path = "(indexed)"; ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ err = au_opts_parse_imod(sb, n, &opt->mod, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#endif ++ case Opt_xino: ++ err = au_opts_parse_xino(sb, &opt->xino, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++ ++ case Opt_trunc_xino_path: ++ err = au_opts_parse_xino_itrunc_path ++ (sb, &opt->xino_itrunc, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++ ++ case Opt_itrunc_xino: ++ u.xino_itrunc = &opt->xino_itrunc; ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ u.xino_itrunc->bindex = n; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (n < 0 || au_sbbot(sb) < n) { ++ pr_err("out of bounds, %d\n", n); ++ aufs_read_unlock(root, !AuLock_IR); ++ break; ++ } ++ aufs_read_unlock(root, !AuLock_IR); ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_dirwh: ++ if (unlikely(match_int(&a->args[0], &opt->dirwh))) ++ break; ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_rdcache: ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ if (unlikely(n > AUFS_RDCACHE_MAX)) { ++ pr_err("rdcache must be smaller than %d\n", ++ AUFS_RDCACHE_MAX); ++ break; ++ } ++ opt->rdcache = n; ++ err = 0; ++ opt->type = token; ++ break; ++ case Opt_rdblk: ++ if (unlikely(match_int(&a->args[0], &n) ++ || n < 0 ++ || n > KMALLOC_MAX_SIZE)) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ if (unlikely(n && n < NAME_MAX)) { ++ pr_err("rdblk must be larger than %d\n", ++ NAME_MAX); ++ break; ++ } ++ opt->rdblk = n; ++ err = 0; ++ opt->type = token; ++ break; ++ case Opt_rdhash: ++ if (unlikely(match_int(&a->args[0], &n) ++ || n < 0 ++ || n * sizeof(struct hlist_head) ++ > KMALLOC_MAX_SIZE)) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ opt->rdhash = n; ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_trunc_xino: ++ case Opt_notrunc_xino: ++ case Opt_noxino: ++ case Opt_trunc_xib: ++ case Opt_notrunc_xib: ++ case Opt_shwh: ++ case Opt_noshwh: ++ case Opt_dirperm1: ++ case Opt_nodirperm1: ++ case Opt_plink: ++ case Opt_noplink: ++ case Opt_list_plink: ++ case Opt_dio: ++ case Opt_nodio: ++ case Opt_diropq_a: ++ case Opt_diropq_w: ++ case Opt_warn_perm: ++ case Opt_nowarn_perm: ++ case Opt_verbose: ++ case Opt_noverbose: ++ case Opt_sum: ++ case Opt_nosum: ++ case Opt_wsum: ++ case Opt_rdblk_def: ++ case Opt_rdhash_def: ++ case Opt_acl: ++ case Opt_noacl: ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_udba: ++ opt->udba = udba_val(a->args[0].from); ++ if (opt->udba >= 0) { ++ err = 0; ++ opt->type = token; ++ } else ++ pr_err("wrong value, %s\n", opt_str); ++ break; ++ ++ case Opt_wbr_create: ++ u.create = &opt->wbr_create; ++ u.create->wbr_create ++ = au_wbr_create_val(a->args[0].from, u.create); ++ if (u.create->wbr_create >= 0) { ++ err = 0; ++ opt->type = token; ++ } else ++ pr_err("wrong value, %s\n", opt_str); ++ break; ++ case Opt_wbr_copyup: ++ opt->wbr_copyup = au_wbr_copyup_val(a->args[0].from); ++ if (opt->wbr_copyup >= 0) { ++ err = 0; ++ opt->type = token; ++ } else ++ pr_err("wrong value, %s\n", opt_str); ++ break; ++ ++ case Opt_fhsm_sec: ++ if (unlikely(match_int(&a->args[0], &n) ++ || n < 0)) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ if (sysaufs_brs) { ++ opt->fhsm_second = n; ++ opt->type = token; ++ } else ++ pr_warn("ignored %s\n", opt_str); ++ err = 0; ++ break; ++ ++ case Opt_ignore: ++ pr_warn("ignored %s\n", opt_str); ++ /*FALLTHROUGH*/ ++ case Opt_ignore_silent: ++ skipped = 1; ++ err = 0; ++ break; ++ case Opt_err: ++ pr_err("unknown option %s\n", opt_str); ++ break; ++ } ++ ++ if (!err && !skipped) { ++ if (unlikely(++opt > opt_tail)) { ++ err = -E2BIG; ++ opt--; ++ opt->type = Opt_tail; ++ break; ++ } ++ opt->type = Opt_tail; ++ } ++ } ++ ++ kfree(a); ++ dump_opts(opts); ++ if (unlikely(err)) ++ au_opts_free(opts); ++ ++out: ++ return err; ++} ++ ++static int au_opt_wbr_create(struct super_block *sb, ++ struct au_opt_wbr_create *create) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 1; /* handled */ ++ sbinfo = au_sbi(sb); ++ if (sbinfo->si_wbr_create_ops->fin) { ++ err = sbinfo->si_wbr_create_ops->fin(sb); ++ if (!err) ++ err = 1; ++ } ++ ++ sbinfo->si_wbr_create = create->wbr_create; ++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create; ++ switch (create->wbr_create) { ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_PMFSRR: ++ case AuWbrCreate_PMFSRRV: ++ sbinfo->si_wbr_mfs.mfsrr_watermark = create->mfsrr_watermark; ++ /*FALLTHROUGH*/ ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFS: ++ case AuWbrCreate_PMFSV: ++ sbinfo->si_wbr_mfs.mfs_expire ++ = msecs_to_jiffies(create->mfs_second * MSEC_PER_SEC); ++ break; ++ } ++ ++ if (sbinfo->si_wbr_create_ops->init) ++ sbinfo->si_wbr_create_ops->init(sb); /* ignore */ ++ ++ return err; ++} ++ ++/* ++ * returns, ++ * plus: processed without an error ++ * zero: unprocessed ++ */ ++static int au_opt_simple(struct super_block *sb, struct au_opt *opt, ++ struct au_opts *opts) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 1; /* handled */ ++ sbinfo = au_sbi(sb); ++ switch (opt->type) { ++ case Opt_udba: ++ sbinfo->si_mntflags &= ~AuOptMask_UDBA; ++ sbinfo->si_mntflags |= opt->udba; ++ opts->given_udba |= opt->udba; ++ break; ++ ++ case Opt_plink: ++ au_opt_set(sbinfo->si_mntflags, PLINK); ++ break; ++ case Opt_noplink: ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_put(sb, /*verbose*/1); ++ au_opt_clr(sbinfo->si_mntflags, PLINK); ++ break; ++ case Opt_list_plink: ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_list(sb); ++ break; ++ ++ case Opt_dio: ++ au_opt_set(sbinfo->si_mntflags, DIO); ++ au_fset_opts(opts->flags, REFRESH_DYAOP); ++ break; ++ case Opt_nodio: ++ au_opt_clr(sbinfo->si_mntflags, DIO); ++ au_fset_opts(opts->flags, REFRESH_DYAOP); ++ break; ++ ++ case Opt_fhsm_sec: ++ au_fhsm_set(sbinfo, opt->fhsm_second); ++ break; ++ ++ case Opt_diropq_a: ++ au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ); ++ break; ++ case Opt_diropq_w: ++ au_opt_clr(sbinfo->si_mntflags, ALWAYS_DIROPQ); ++ break; ++ ++ case Opt_warn_perm: ++ au_opt_set(sbinfo->si_mntflags, WARN_PERM); ++ break; ++ case Opt_nowarn_perm: ++ au_opt_clr(sbinfo->si_mntflags, WARN_PERM); ++ break; ++ ++ case Opt_verbose: ++ au_opt_set(sbinfo->si_mntflags, VERBOSE); ++ break; ++ case Opt_noverbose: ++ au_opt_clr(sbinfo->si_mntflags, VERBOSE); ++ break; ++ ++ case Opt_sum: ++ au_opt_set(sbinfo->si_mntflags, SUM); ++ break; ++ case Opt_wsum: ++ au_opt_clr(sbinfo->si_mntflags, SUM); ++ au_opt_set(sbinfo->si_mntflags, SUM_W); ++ case Opt_nosum: ++ au_opt_clr(sbinfo->si_mntflags, SUM); ++ au_opt_clr(sbinfo->si_mntflags, SUM_W); ++ break; ++ ++ case Opt_wbr_create: ++ err = au_opt_wbr_create(sb, &opt->wbr_create); ++ break; ++ case Opt_wbr_copyup: ++ sbinfo->si_wbr_copyup = opt->wbr_copyup; ++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup; ++ break; ++ ++ case Opt_dirwh: ++ sbinfo->si_dirwh = opt->dirwh; ++ break; ++ ++ case Opt_rdcache: ++ sbinfo->si_rdcache ++ = msecs_to_jiffies(opt->rdcache * MSEC_PER_SEC); ++ break; ++ case Opt_rdblk: ++ sbinfo->si_rdblk = opt->rdblk; ++ break; ++ case Opt_rdblk_def: ++ sbinfo->si_rdblk = AUFS_RDBLK_DEF; ++ break; ++ case Opt_rdhash: ++ sbinfo->si_rdhash = opt->rdhash; ++ break; ++ case Opt_rdhash_def: ++ sbinfo->si_rdhash = AUFS_RDHASH_DEF; ++ break; ++ ++ case Opt_shwh: ++ au_opt_set(sbinfo->si_mntflags, SHWH); ++ break; ++ case Opt_noshwh: ++ au_opt_clr(sbinfo->si_mntflags, SHWH); ++ break; ++ ++ case Opt_dirperm1: ++ au_opt_set(sbinfo->si_mntflags, DIRPERM1); ++ break; ++ case Opt_nodirperm1: ++ au_opt_clr(sbinfo->si_mntflags, DIRPERM1); ++ break; ++ ++ case Opt_trunc_xino: ++ au_opt_set(sbinfo->si_mntflags, TRUNC_XINO); ++ break; ++ case Opt_notrunc_xino: ++ au_opt_clr(sbinfo->si_mntflags, TRUNC_XINO); ++ break; ++ ++ case Opt_trunc_xino_path: ++ case Opt_itrunc_xino: ++ err = au_xino_trunc(sb, opt->xino_itrunc.bindex); ++ if (!err) ++ err = 1; ++ break; ++ ++ case Opt_trunc_xib: ++ au_fset_opts(opts->flags, TRUNC_XIB); ++ break; ++ case Opt_notrunc_xib: ++ au_fclr_opts(opts->flags, TRUNC_XIB); ++ break; ++ ++ case Opt_acl: ++ sb->s_flags |= MS_POSIXACL; ++ break; ++ case Opt_noacl: ++ sb->s_flags &= ~MS_POSIXACL; ++ break; ++ ++ default: ++ err = 0; ++ break; ++ } ++ ++ return err; ++} ++ ++/* ++ * returns tri-state. ++ * plus: processed without an error ++ * zero: unprocessed ++ * minus: error ++ */ ++static int au_opt_br(struct super_block *sb, struct au_opt *opt, ++ struct au_opts *opts) ++{ ++ int err, do_refresh; ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_append: ++ opt->add.bindex = au_sbbot(sb) + 1; ++ if (opt->add.bindex < 0) ++ opt->add.bindex = 0; ++ goto add; ++ case Opt_prepend: ++ opt->add.bindex = 0; ++ add: /* indented label */ ++ case Opt_add: ++ err = au_br_add(sb, &opt->add, ++ au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) { ++ err = 1; ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ ++ case Opt_del: ++ case Opt_idel: ++ err = au_br_del(sb, &opt->del, ++ au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) { ++ err = 1; ++ au_fset_opts(opts->flags, TRUNC_XIB); ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ ++ case Opt_mod: ++ case Opt_imod: ++ err = au_br_mod(sb, &opt->mod, ++ au_ftest_opts(opts->flags, REMOUNT), ++ &do_refresh); ++ if (!err) { ++ err = 1; ++ if (do_refresh) ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ } ++ ++ return err; ++} ++ ++static int au_opt_xino(struct super_block *sb, struct au_opt *opt, ++ struct au_opt_xino **opt_xino, ++ struct au_opts *opts) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct dentry *root, *parent, *h_root; ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_xino: ++ err = au_xino_set(sb, &opt->xino, ++ !!au_ftest_opts(opts->flags, REMOUNT)); ++ if (unlikely(err)) ++ break; ++ ++ *opt_xino = &opt->xino; ++ au_xino_brid_set(sb, -1); ++ ++ /* safe d_parent access */ ++ parent = opt->xino.file->f_path.dentry->d_parent; ++ root = sb->s_root; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ h_root = au_h_dptr(root, bindex); ++ if (h_root == parent) { ++ au_xino_brid_set(sb, au_sbr_id(sb, bindex)); ++ break; ++ } ++ } ++ break; ++ ++ case Opt_noxino: ++ au_xino_clr(sb); ++ au_xino_brid_set(sb, -1); ++ *opt_xino = (void *)-1; ++ break; ++ } ++ ++ return err; ++} ++ ++int au_opts_verify(struct super_block *sb, unsigned long sb_flags, ++ unsigned int pending) ++{ ++ int err, fhsm; ++ aufs_bindex_t bindex, bbot; ++ unsigned char do_plink, skip, do_free, can_no_dreval; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *root, *dentry; ++ struct inode *dir, *h_dir; ++ struct au_sbinfo *sbinfo; ++ struct au_hinode *hdir; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA)); ++ ++ if (!(sb_flags & MS_RDONLY)) { ++ if (unlikely(!au_br_writable(au_sbr_perm(sb, 0)))) ++ pr_warn("first branch should be rw\n"); ++ if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH))) ++ pr_warn_once("shwh should be used with ro\n"); ++ } ++ ++ if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HNOTIFY) ++ && !au_opt_test(sbinfo->si_mntflags, XINO)) ++ pr_warn_once("udba=*notify requires xino\n"); ++ ++ if (au_opt_test(sbinfo->si_mntflags, DIRPERM1)) ++ pr_warn_once("dirperm1 breaks the protection" ++ " by the permission bits on the lower branch\n"); ++ ++ err = 0; ++ fhsm = 0; ++ root = sb->s_root; ++ dir = d_inode(root); ++ do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK); ++ can_no_dreval = !!au_opt_test((sbinfo->si_mntflags | pending), ++ UDBA_NONE); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) { ++ skip = 0; ++ h_dir = au_h_iptr(dir, bindex); ++ br = au_sbr(sb, bindex); ++ ++ if ((br->br_perm & AuBrAttr_ICEX) ++ && !h_dir->i_op->listxattr) ++ br->br_perm &= ~AuBrAttr_ICEX; ++#if 0 ++ if ((br->br_perm & AuBrAttr_ICEX_SEC) ++ && (au_br_sb(br)->s_flags & MS_NOSEC)) ++ br->br_perm &= ~AuBrAttr_ICEX_SEC; ++#endif ++ ++ do_free = 0; ++ wbr = br->br_wbr; ++ if (wbr) ++ wbr_wh_read_lock(wbr); ++ ++ if (!au_br_writable(br->br_perm)) { ++ do_free = !!wbr; ++ skip = (!wbr ++ || (!wbr->wbr_whbase ++ && !wbr->wbr_plink ++ && !wbr->wbr_orph)); ++ } else if (!au_br_wh_linkable(br->br_perm)) { ++ /* skip = (!br->br_whbase && !br->br_orph); */ ++ skip = (!wbr || !wbr->wbr_whbase); ++ if (skip && wbr) { ++ if (do_plink) ++ skip = !!wbr->wbr_plink; ++ else ++ skip = !wbr->wbr_plink; ++ } ++ } else { ++ /* skip = (br->br_whbase && br->br_ohph); */ ++ skip = (wbr && wbr->wbr_whbase); ++ if (skip) { ++ if (do_plink) ++ skip = !!wbr->wbr_plink; ++ else ++ skip = !wbr->wbr_plink; ++ } ++ } ++ if (wbr) ++ wbr_wh_read_unlock(wbr); ++ ++ if (can_no_dreval) { ++ dentry = br->br_path.dentry; ++ spin_lock(&dentry->d_lock); ++ if (dentry->d_flags & ++ (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE)) ++ can_no_dreval = 0; ++ spin_unlock(&dentry->d_lock); ++ } ++ ++ if (au_br_fhsm(br->br_perm)) { ++ fhsm++; ++ AuDebugOn(!br->br_fhsm); ++ } ++ ++ if (skip) ++ continue; ++ ++ hdir = au_hi(dir, bindex); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ if (wbr) ++ wbr_wh_write_lock(wbr); ++ err = au_wh_init(br, sb); ++ if (wbr) ++ wbr_wh_write_unlock(wbr); ++ au_hn_inode_unlock(hdir); ++ ++ if (!err && do_free) { ++ kfree(wbr); ++ br->br_wbr = NULL; ++ } ++ } ++ ++ if (can_no_dreval) ++ au_fset_si(sbinfo, NO_DREVAL); ++ else ++ au_fclr_si(sbinfo, NO_DREVAL); ++ ++ if (fhsm >= 2) { ++ au_fset_si(sbinfo, FHSM); ++ for (bindex = bbot; bindex >= 0; bindex--) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) { ++ au_fhsm_set_bottom(sb, bindex); ++ break; ++ } ++ } ++ } else { ++ au_fclr_si(sbinfo, FHSM); ++ au_fhsm_set_bottom(sb, -1); ++ } ++ ++ return err; ++} ++ ++int au_opts_mount(struct super_block *sb, struct au_opts *opts) ++{ ++ int err; ++ unsigned int tmp; ++ aufs_bindex_t bindex, bbot; ++ struct au_opt *opt; ++ struct au_opt_xino *opt_xino, xino; ++ struct au_sbinfo *sbinfo; ++ struct au_branch *br; ++ struct inode *dir; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_opt_simple(sb, opt++, opts); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ /* disable xino and udba temporary */ ++ sbinfo = au_sbi(sb); ++ tmp = sbinfo->si_mntflags; ++ au_opt_clr(sbinfo->si_mntflags, XINO); ++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL); ++ ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_opt_br(sb, opt++, opts); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ bbot = au_sbbot(sb); ++ if (unlikely(bbot < 0)) { ++ err = -EINVAL; ++ pr_err("no branches\n"); ++ goto out; ++ } ++ ++ if (au_opt_test(tmp, XINO)) ++ au_opt_set(sbinfo->si_mntflags, XINO); ++ opt = opts->opt; ++ while (!err && opt->type != Opt_tail) ++ err = au_opt_xino(sb, opt++, &opt_xino, opts); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_opts_verify(sb, sb->s_flags, tmp); ++ if (unlikely(err)) ++ goto out; ++ ++ /* restore xino */ ++ if (au_opt_test(tmp, XINO) && !opt_xino) { ++ xino.file = au_xino_def(sb); ++ err = PTR_ERR(xino.file); ++ if (IS_ERR(xino.file)) ++ goto out; ++ ++ err = au_xino_set(sb, &xino, /*remount*/0); ++ fput(xino.file); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ /* restore udba */ ++ tmp &= AuOptMask_UDBA; ++ sbinfo->si_mntflags &= ~AuOptMask_UDBA; ++ sbinfo->si_mntflags |= tmp; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_hnotify_reset_br(tmp, br, br->br_perm); ++ if (unlikely(err)) ++ AuIOErr("hnotify failed on br %d, %d, ignored\n", ++ bindex, err); ++ /* go on even if err */ ++ } ++ if (au_opt_test(tmp, UDBA_HNOTIFY)) { ++ dir = d_inode(sb->s_root); ++ au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO); ++ } ++ ++out: ++ return err; ++} ++ ++int au_opts_remount(struct super_block *sb, struct au_opts *opts) ++{ ++ int err, rerr; ++ unsigned char no_dreval; ++ struct inode *dir; ++ struct au_opt_xino *opt_xino; ++ struct au_opt *opt; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ dir = d_inode(sb->s_root); ++ sbinfo = au_sbi(sb); ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) { ++ err = au_opt_simple(sb, opt, opts); ++ if (!err) ++ err = au_opt_br(sb, opt, opts); ++ if (!err) ++ err = au_opt_xino(sb, opt, &opt_xino, opts); ++ opt++; ++ } ++ if (err > 0) ++ err = 0; ++ AuTraceErr(err); ++ /* go on even err */ ++ ++ no_dreval = !!au_ftest_si(sbinfo, NO_DREVAL); ++ rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0); ++ if (unlikely(rerr && !err)) ++ err = rerr; ++ ++ if (no_dreval != !!au_ftest_si(sbinfo, NO_DREVAL)) ++ au_fset_opts(opts->flags, REFRESH_IDOP); ++ ++ if (au_ftest_opts(opts->flags, TRUNC_XIB)) { ++ rerr = au_xib_trunc(sb); ++ if (unlikely(rerr && !err)) ++ err = rerr; ++ } ++ ++ /* will be handled by the caller */ ++ if (!au_ftest_opts(opts->flags, REFRESH) ++ && (opts->given_udba ++ || au_opt_test(sbinfo->si_mntflags, XINO) ++ || au_ftest_opts(opts->flags, REFRESH_IDOP) ++ )) ++ au_fset_opts(opts->flags, REFRESH); ++ ++ AuDbg("status 0x%x\n", opts->flags); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++unsigned int au_opt_udba(struct super_block *sb) ++{ ++ return au_mntflags(sb) & AuOptMask_UDBA; ++} +diff --git a/fs/aufs/opts.h b/fs/aufs/opts.h +new file mode 100644 +index 0000000..0d6c2e1 +--- /dev/null ++++ b/fs/aufs/opts.h +@@ -0,0 +1,198 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * mount options/flags ++ */ ++ ++#ifndef __AUFS_OPTS_H__ ++#define __AUFS_OPTS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct file; ++struct super_block; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* mount flags */ ++#define AuOpt_XINO 1 /* external inode number bitmap ++ and translation table */ ++#define AuOpt_TRUNC_XINO (1 << 1) /* truncate xino files */ ++#define AuOpt_UDBA_NONE (1 << 2) /* users direct branch access */ ++#define AuOpt_UDBA_REVAL (1 << 3) ++#define AuOpt_UDBA_HNOTIFY (1 << 4) ++#define AuOpt_SHWH (1 << 5) /* show whiteout */ ++#define AuOpt_PLINK (1 << 6) /* pseudo-link */ ++#define AuOpt_DIRPERM1 (1 << 7) /* ignore the lower dir's perm ++ bits */ ++#define AuOpt_ALWAYS_DIROPQ (1 << 9) /* policy to creating diropq */ ++#define AuOpt_SUM (1 << 10) /* summation for statfs(2) */ ++#define AuOpt_SUM_W (1 << 11) /* unimplemented */ ++#define AuOpt_WARN_PERM (1 << 12) /* warn when add-branch */ ++#define AuOpt_VERBOSE (1 << 13) /* busy inode when del-branch */ ++#define AuOpt_DIO (1 << 14) /* direct io */ ++ ++#ifndef CONFIG_AUFS_HNOTIFY ++#undef AuOpt_UDBA_HNOTIFY ++#define AuOpt_UDBA_HNOTIFY 0 ++#endif ++#ifndef CONFIG_AUFS_SHWH ++#undef AuOpt_SHWH ++#define AuOpt_SHWH 0 ++#endif ++ ++#define AuOpt_Def (AuOpt_XINO \ ++ | AuOpt_UDBA_REVAL \ ++ | AuOpt_PLINK \ ++ /* | AuOpt_DIRPERM1 */ \ ++ | AuOpt_WARN_PERM) ++#define AuOptMask_UDBA (AuOpt_UDBA_NONE \ ++ | AuOpt_UDBA_REVAL \ ++ | AuOpt_UDBA_HNOTIFY) ++ ++#define au_opt_test(flags, name) (flags & AuOpt_##name) ++#define au_opt_set(flags, name) do { \ ++ BUILD_BUG_ON(AuOpt_##name & AuOptMask_UDBA); \ ++ ((flags) |= AuOpt_##name); \ ++} while (0) ++#define au_opt_set_udba(flags, name) do { \ ++ (flags) &= ~AuOptMask_UDBA; \ ++ ((flags) |= AuOpt_##name); \ ++} while (0) ++#define au_opt_clr(flags, name) do { \ ++ ((flags) &= ~AuOpt_##name); \ ++} while (0) ++ ++static inline unsigned int au_opts_plink(unsigned int mntflags) ++{ ++#ifdef CONFIG_PROC_FS ++ return mntflags; ++#else ++ return mntflags & ~AuOpt_PLINK; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies to select one among multiple writable branches */ ++enum { ++ AuWbrCreate_TDP, /* top down parent */ ++ AuWbrCreate_RR, /* round robin */ ++ AuWbrCreate_MFS, /* most free space */ ++ AuWbrCreate_MFSV, /* mfs with seconds */ ++ AuWbrCreate_MFSRR, /* mfs then rr */ ++ AuWbrCreate_MFSRRV, /* mfs then rr with seconds */ ++ AuWbrCreate_PMFS, /* parent and mfs */ ++ AuWbrCreate_PMFSV, /* parent and mfs with seconds */ ++ AuWbrCreate_PMFSRR, /* parent, mfs and round-robin */ ++ AuWbrCreate_PMFSRRV, /* plus seconds */ ++ ++ AuWbrCreate_Def = AuWbrCreate_TDP ++}; ++ ++enum { ++ AuWbrCopyup_TDP, /* top down parent */ ++ AuWbrCopyup_BUP, /* bottom up parent */ ++ AuWbrCopyup_BU, /* bottom up */ ++ ++ AuWbrCopyup_Def = AuWbrCopyup_TDP ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_opt_add { ++ aufs_bindex_t bindex; ++ char *pathname; ++ int perm; ++ struct path path; ++}; ++ ++struct au_opt_del { ++ char *pathname; ++ struct path h_path; ++}; ++ ++struct au_opt_mod { ++ char *path; ++ int perm; ++ struct dentry *h_root; ++}; ++ ++struct au_opt_xino { ++ char *path; ++ struct file *file; ++}; ++ ++struct au_opt_xino_itrunc { ++ aufs_bindex_t bindex; ++}; ++ ++struct au_opt_wbr_create { ++ int wbr_create; ++ int mfs_second; ++ unsigned long long mfsrr_watermark; ++}; ++ ++struct au_opt { ++ int type; ++ union { ++ struct au_opt_xino xino; ++ struct au_opt_xino_itrunc xino_itrunc; ++ struct au_opt_add add; ++ struct au_opt_del del; ++ struct au_opt_mod mod; ++ int dirwh; ++ int rdcache; ++ unsigned int rdblk; ++ unsigned int rdhash; ++ int udba; ++ struct au_opt_wbr_create wbr_create; ++ int wbr_copyup; ++ unsigned int fhsm_second; ++ }; ++}; ++ ++/* opts flags */ ++#define AuOpts_REMOUNT 1 ++#define AuOpts_REFRESH (1 << 1) ++#define AuOpts_TRUNC_XIB (1 << 2) ++#define AuOpts_REFRESH_DYAOP (1 << 3) ++#define AuOpts_REFRESH_IDOP (1 << 4) ++#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name) ++#define au_fset_opts(flags, name) \ ++ do { (flags) |= AuOpts_##name; } while (0) ++#define au_fclr_opts(flags, name) \ ++ do { (flags) &= ~AuOpts_##name; } while (0) ++ ++struct au_opts { ++ struct au_opt *opt; ++ int max_opt; ++ ++ unsigned int given_udba; ++ unsigned int flags; ++ unsigned long sb_flags; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* opts.c */ ++void au_optstr_br_perm(au_br_perm_str_t *str, int perm); ++const char *au_optstr_udba(int udba); ++const char *au_optstr_wbr_copyup(int wbr_copyup); ++const char *au_optstr_wbr_create(int wbr_create); ++ ++void au_opts_free(struct au_opts *opts); ++int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts); ++int au_opts_verify(struct super_block *sb, unsigned long sb_flags, ++ unsigned int pending); ++int au_opts_mount(struct super_block *sb, struct au_opts *opts); ++int au_opts_remount(struct super_block *sb, struct au_opts *opts); ++ ++unsigned int au_opt_udba(struct super_block *sb); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_OPTS_H__ */ +diff --git a/fs/aufs/plink.c b/fs/aufs/plink.c +new file mode 100644 +index 0000000..c42734d +--- /dev/null ++++ b/fs/aufs/plink.c +@@ -0,0 +1,489 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * pseudo-link ++ */ ++ ++#include "aufs.h" ++ ++/* ++ * the pseudo-link maintenance mode. ++ * during a user process maintains the pseudo-links, ++ * prohibit adding a new plink and branch manipulation. ++ * ++ * Flags ++ * NOPLM: ++ * For entry functions which will handle plink, and i_mutex is already held ++ * in VFS. ++ * They cannot wait and should return an error at once. ++ * Callers has to check the error. ++ * NOPLMW: ++ * For entry functions which will handle plink, but i_mutex is not held ++ * in VFS. ++ * They can wait the plink maintenance mode to finish. ++ * ++ * They behave like F_SETLK and F_SETLKW. ++ * If the caller never handle plink, then both flags are unnecessary. ++ */ ++ ++int au_plink_maint(struct super_block *sb, int flags) ++{ ++ int err; ++ pid_t pid, ppid; ++ struct au_sbinfo *sbi; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (!au_opt_test(au_mntflags(sb), PLINK)) ++ goto out; ++ ++ sbi = au_sbi(sb); ++ pid = sbi->si_plink_maint_pid; ++ if (!pid || pid == current->pid) ++ goto out; ++ ++ /* todo: it highly depends upon /sbin/mount.aufs */ ++ rcu_read_lock(); ++ ppid = task_pid_vnr(rcu_dereference(current->real_parent)); ++ rcu_read_unlock(); ++ if (pid == ppid) ++ goto out; ++ ++ if (au_ftest_lock(flags, NOPLMW)) { ++ /* if there is no i_mutex lock in VFS, we don't need to wait */ ++ /* AuDebugOn(!lockdep_depth(current)); */ ++ while (sbi->si_plink_maint_pid) { ++ si_read_unlock(sb); ++ /* gave up wake_up_bit() */ ++ wait_event(sbi->si_plink_wq, !sbi->si_plink_maint_pid); ++ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&sbi->si_nowait); ++ si_noflush_read_lock(sb); ++ } ++ } else if (au_ftest_lock(flags, NOPLM)) { ++ AuDbg("ppid %d, pid %d\n", ppid, pid); ++ err = -EAGAIN; ++ } ++ ++out: ++ return err; ++} ++ ++void au_plink_maint_leave(struct au_sbinfo *sbinfo) ++{ ++ spin_lock(&sbinfo->si_plink_maint_lock); ++ sbinfo->si_plink_maint_pid = 0; ++ spin_unlock(&sbinfo->si_plink_maint_lock); ++ wake_up_all(&sbinfo->si_plink_wq); ++} ++ ++int au_plink_maint_enter(struct super_block *sb) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ /* make sure i am the only one in this fs */ ++ si_write_lock(sb, AuLock_FLUSH); ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ spin_lock(&sbinfo->si_plink_maint_lock); ++ if (!sbinfo->si_plink_maint_pid) ++ sbinfo->si_plink_maint_pid = current->pid; ++ else ++ err = -EBUSY; ++ spin_unlock(&sbinfo->si_plink_maint_lock); ++ } ++ si_write_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DEBUG ++void au_plink_list(struct super_block *sb) ++{ ++ int i; ++ struct au_sbinfo *sbinfo; ++ struct hlist_head *plink_hlist; ++ struct au_icntnr *icntnr; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ plink_hlist = &sbinfo->si_plink[i].head; ++ rcu_read_lock(); ++ hlist_for_each_entry_rcu(icntnr, plink_hlist, plink) ++ AuDbg("%lu\n", icntnr->vfs_inode.i_ino); ++ rcu_read_unlock(); ++ } ++} ++#endif ++ ++/* is the inode pseudo-linked? */ ++int au_plink_test(struct inode *inode) ++{ ++ int found, i; ++ struct au_sbinfo *sbinfo; ++ struct hlist_head *plink_hlist; ++ struct au_icntnr *icntnr; ++ ++ sbinfo = au_sbi(inode->i_sb); ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ AuDebugOn(!au_opt_test(au_mntflags(inode->i_sb), PLINK)); ++ AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM)); ++ ++ found = 0; ++ i = au_plink_hash(inode->i_ino); ++ plink_hlist = &sbinfo->si_plink[i].head; ++ rcu_read_lock(); ++ hlist_for_each_entry_rcu(icntnr, plink_hlist, plink) ++ if (&icntnr->vfs_inode == inode) { ++ found = 1; ++ break; ++ } ++ rcu_read_unlock(); ++ return found; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * generate a name for plink. ++ * the file will be stored under AUFS_WH_PLINKDIR. ++ */ ++/* 20 is max digits length of ulong 64 */ ++#define PLINK_NAME_LEN ((20 + 1) * 2) ++ ++static int plink_name(char *name, int len, struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ int rlen; ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, bindex); ++ rlen = snprintf(name, len, "%lu.%lu", inode->i_ino, h_inode->i_ino); ++ return rlen; ++} ++ ++struct au_do_plink_lkup_args { ++ struct dentry **errp; ++ struct qstr *tgtname; ++ struct dentry *h_parent; ++ struct au_branch *br; ++}; ++ ++static struct dentry *au_do_plink_lkup(struct qstr *tgtname, ++ struct dentry *h_parent, ++ struct au_branch *br) ++{ ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ h_inode = d_inode(h_parent); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD2); ++ h_dentry = vfsub_lkup_one(tgtname, h_parent); ++ inode_unlock(h_inode); ++ return h_dentry; ++} ++ ++static void au_call_do_plink_lkup(void *args) ++{ ++ struct au_do_plink_lkup_args *a = args; ++ *a->errp = au_do_plink_lkup(a->tgtname, a->h_parent, a->br); ++} ++ ++/* lookup the plink-ed @inode under the branch at @bindex */ ++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct dentry *h_dentry, *h_parent; ++ struct au_branch *br; ++ int wkq_err; ++ char a[PLINK_NAME_LEN]; ++ struct qstr tgtname = QSTR_INIT(a, 0); ++ ++ AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM)); ++ ++ br = au_sbr(inode->i_sb, bindex); ++ h_parent = br->br_wbr->wbr_plink; ++ tgtname.len = plink_name(a, sizeof(a), inode, bindex); ++ ++ if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { ++ struct au_do_plink_lkup_args args = { ++ .errp = &h_dentry, ++ .tgtname = &tgtname, ++ .h_parent = h_parent, ++ .br = br ++ }; ++ ++ wkq_err = au_wkq_wait(au_call_do_plink_lkup, &args); ++ if (unlikely(wkq_err)) ++ h_dentry = ERR_PTR(wkq_err); ++ } else ++ h_dentry = au_do_plink_lkup(&tgtname, h_parent, br); ++ ++ return h_dentry; ++} ++ ++/* create a pseudo-link */ ++static int do_whplink(struct qstr *tgt, struct dentry *h_parent, ++ struct dentry *h_dentry, struct au_branch *br) ++{ ++ int err; ++ struct path h_path = { ++ .mnt = au_br_mnt(br) ++ }; ++ struct inode *h_dir, *delegated; ++ ++ h_dir = d_inode(h_parent); ++ inode_lock_nested(h_dir, AuLsc_I_CHILD2); ++again: ++ h_path.dentry = vfsub_lkup_one(tgt, h_parent); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ err = 0; ++ /* wh.plink dir is not monitored */ ++ /* todo: is it really safe? */ ++ if (d_is_positive(h_path.dentry) ++ && d_inode(h_path.dentry) != d_inode(h_dentry)) { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ dput(h_path.dentry); ++ h_path.dentry = NULL; ++ if (!err) ++ goto again; ++ } ++ if (!err && d_is_negative(h_path.dentry)) { ++ delegated = NULL; ++ err = vfsub_link(h_dentry, h_dir, &h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ dput(h_path.dentry); ++ ++out: ++ inode_unlock(h_dir); ++ return err; ++} ++ ++struct do_whplink_args { ++ int *errp; ++ struct qstr *tgt; ++ struct dentry *h_parent; ++ struct dentry *h_dentry; ++ struct au_branch *br; ++}; ++ ++static void call_do_whplink(void *args) ++{ ++ struct do_whplink_args *a = args; ++ *a->errp = do_whplink(a->tgt, a->h_parent, a->h_dentry, a->br); ++} ++ ++static int whplink(struct dentry *h_dentry, struct inode *inode, ++ aufs_bindex_t bindex, struct au_branch *br) ++{ ++ int err, wkq_err; ++ struct au_wbr *wbr; ++ struct dentry *h_parent; ++ char a[PLINK_NAME_LEN]; ++ struct qstr tgtname = QSTR_INIT(a, 0); ++ ++ wbr = au_sbr(inode->i_sb, bindex)->br_wbr; ++ h_parent = wbr->wbr_plink; ++ tgtname.len = plink_name(a, sizeof(a), inode, bindex); ++ ++ /* always superio. */ ++ if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { ++ struct do_whplink_args args = { ++ .errp = &err, ++ .tgt = &tgtname, ++ .h_parent = h_parent, ++ .h_dentry = h_dentry, ++ .br = br ++ }; ++ wkq_err = au_wkq_wait(call_do_whplink, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } else ++ err = do_whplink(&tgtname, h_parent, h_dentry, br); ++ ++ return err; ++} ++ ++/* ++ * create a new pseudo-link for @h_dentry on @bindex. ++ * the linked inode is held in aufs @inode. ++ */ ++void au_plink_append(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry) ++{ ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct hlist_head *plink_hlist; ++ struct au_icntnr *icntnr; ++ struct au_sphlhead *sphl; ++ int found, err, cnt, i; ++ ++ sb = inode->i_sb; ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ found = au_plink_test(inode); ++ if (found) ++ return; ++ ++ i = au_plink_hash(inode->i_ino); ++ sphl = sbinfo->si_plink + i; ++ plink_hlist = &sphl->head; ++ au_igrab(inode); ++ ++ spin_lock(&sphl->spin); ++ hlist_for_each_entry(icntnr, plink_hlist, plink) { ++ if (&icntnr->vfs_inode == inode) { ++ found = 1; ++ break; ++ } ++ } ++ if (!found) { ++ icntnr = container_of(inode, struct au_icntnr, vfs_inode); ++ hlist_add_head_rcu(&icntnr->plink, plink_hlist); ++ } ++ spin_unlock(&sphl->spin); ++ if (!found) { ++ cnt = au_sphl_count(sphl); ++#define msg "unexpectedly unblanced or too many pseudo-links" ++ if (cnt > AUFS_PLINK_WARN) ++ AuWarn1(msg ", %d\n", cnt); ++#undef msg ++ err = whplink(h_dentry, inode, bindex, au_sbr(sb, bindex)); ++ if (unlikely(err)) { ++ pr_warn("err %d, damaged pseudo link.\n", err); ++ au_sphl_del_rcu(&icntnr->plink, sphl); ++ iput(&icntnr->vfs_inode); ++ } ++ } else ++ iput(&icntnr->vfs_inode); ++} ++ ++/* free all plinks */ ++void au_plink_put(struct super_block *sb, int verbose) ++{ ++ int i, warned; ++ struct au_sbinfo *sbinfo; ++ struct hlist_head *plink_hlist; ++ struct hlist_node *tmp; ++ struct au_icntnr *icntnr; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ /* no spin_lock since sbinfo is write-locked */ ++ warned = 0; ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ plink_hlist = &sbinfo->si_plink[i].head; ++ if (!warned && verbose && !hlist_empty(plink_hlist)) { ++ pr_warn("pseudo-link is not flushed"); ++ warned = 1; ++ } ++ hlist_for_each_entry_safe(icntnr, tmp, plink_hlist, plink) ++ iput(&icntnr->vfs_inode); ++ INIT_HLIST_HEAD(plink_hlist); ++ } ++} ++ ++void au_plink_clean(struct super_block *sb, int verbose) ++{ ++ struct dentry *root; ++ ++ root = sb->s_root; ++ aufs_write_lock(root); ++ if (au_opt_test(au_mntflags(sb), PLINK)) ++ au_plink_put(sb, verbose); ++ aufs_write_unlock(root); ++} ++ ++static int au_plink_do_half_refresh(struct inode *inode, aufs_bindex_t br_id) ++{ ++ int do_put; ++ aufs_bindex_t btop, bbot, bindex; ++ ++ do_put = 0; ++ btop = au_ibtop(inode); ++ bbot = au_ibbot(inode); ++ if (btop >= 0) { ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ if (!au_h_iptr(inode, bindex) ++ || au_ii_br_id(inode, bindex) != br_id) ++ continue; ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ do_put = 1; ++ break; ++ } ++ if (do_put) ++ for (bindex = btop; bindex <= bbot; bindex++) ++ if (au_h_iptr(inode, bindex)) { ++ do_put = 0; ++ break; ++ } ++ } else ++ do_put = 1; ++ ++ return do_put; ++} ++ ++/* free the plinks on a branch specified by @br_id */ ++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ struct au_sbinfo *sbinfo; ++ struct hlist_head *plink_hlist; ++ struct hlist_node *tmp; ++ struct au_icntnr *icntnr; ++ struct inode *inode; ++ int i, do_put; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ /* no spin_lock since sbinfo is write-locked */ ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ plink_hlist = &sbinfo->si_plink[i].head; ++ hlist_for_each_entry_safe(icntnr, tmp, plink_hlist, plink) { ++ inode = au_igrab(&icntnr->vfs_inode); ++ ii_write_lock_child(inode); ++ do_put = au_plink_do_half_refresh(inode, br_id); ++ if (do_put) { ++ hlist_del(&icntnr->plink); ++ iput(inode); ++ } ++ ii_write_unlock(inode); ++ iput(inode); ++ } ++ } ++} +diff --git a/fs/aufs/poll.c b/fs/aufs/poll.c +new file mode 100644 +index 0000000..dd2baf5 +--- /dev/null ++++ b/fs/aufs/poll.c +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * poll operation ++ * There is only one filesystem which implements ->poll operation, currently. ++ */ ++ ++#include "aufs.h" ++ ++unsigned int aufs_poll(struct file *file, poll_table *wait) ++{ ++ unsigned int mask; ++ int err; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ /* We should pretend an error happened. */ ++ mask = POLLERR /* | POLLIN | POLLOUT */; ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ /* it is not an error if h_file has no operation */ ++ mask = DEFAULT_POLLMASK; ++ if (h_file->f_op->poll) ++ mask = h_file->f_op->poll(h_file, wait); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ AuTraceErr((int)mask); ++ return mask; ++} +diff --git a/fs/aufs/posix_acl.c b/fs/aufs/posix_acl.c +new file mode 100644 +index 0000000..1ee17ee +--- /dev/null ++++ b/fs/aufs/posix_acl.c +@@ -0,0 +1,85 @@ ++/* ++ * Copyright (C) 2014-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * posix acl operations ++ */ ++ ++#include ++#include "aufs.h" ++ ++struct posix_acl *aufs_get_acl(struct inode *inode, int type) ++{ ++ struct posix_acl *acl; ++ int err; ++ aufs_bindex_t bindex; ++ struct inode *h_inode; ++ struct super_block *sb; ++ ++ acl = NULL; ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_read_lock_child(inode); ++ if (!(sb->s_flags & MS_POSIXACL)) ++ goto out; ++ ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(!h_inode ++ || ((h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT)))) { ++ err = au_busy_or_stale(); ++ acl = ERR_PTR(err); ++ goto out; ++ } ++ ++ /* always topmost only */ ++ acl = get_acl(h_inode, type); ++ ++out: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ ++ AuTraceErrPtr(acl); ++ return acl; ++} ++ ++int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type) ++{ ++ int err; ++ ssize_t ssz; ++ struct dentry *dentry; ++ struct au_srxattr arg = { ++ .type = AU_ACL_SET, ++ .u.acl_set = { ++ .acl = acl, ++ .type = type ++ }, ++ }; ++ ++ IMustLock(inode); ++ ++ if (inode->i_ino == AUFS_ROOT_INO) ++ dentry = dget(inode->i_sb->s_root); ++ else { ++ dentry = d_find_alias(inode); ++ if (!dentry) ++ dentry = d_find_any_alias(inode); ++ if (!dentry) { ++ pr_warn("cannot handle this inode, " ++ "please report to aufs-users ML\n"); ++ err = -ENOENT; ++ goto out; ++ } ++ } ++ ++ ssz = au_srxattr(dentry, inode, &arg); ++ dput(dentry); ++ err = ssz; ++ if (ssz >= 0) ++ err = 0; ++ ++out: ++ return err; ++} +diff --git a/fs/aufs/procfs.c b/fs/aufs/procfs.c +new file mode 100644 +index 0000000..e5a4e37 +--- /dev/null ++++ b/fs/aufs/procfs.c +@@ -0,0 +1,156 @@ ++/* ++ * Copyright (C) 2010-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * procfs interfaces ++ */ ++ ++#include ++#include "aufs.h" ++ ++static int au_procfs_plm_release(struct inode *inode, struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = file->private_data; ++ if (sbinfo) { ++ au_plink_maint_leave(sbinfo); ++ kobject_put(&sbinfo->si_kobj); ++ } ++ ++ return 0; ++} ++ ++static void au_procfs_plm_write_clean(struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = file->private_data; ++ if (sbinfo) ++ au_plink_clean(sbinfo->si_sb, /*verbose*/0); ++} ++ ++static int au_procfs_plm_write_si(struct file *file, unsigned long id) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ err = -EBUSY; ++ if (unlikely(file->private_data)) ++ goto out; ++ ++ sb = NULL; ++ /* don't use au_sbilist_lock() here */ ++ spin_lock(&au_sbilist.spin); ++ hlist_for_each_entry(sbinfo, &au_sbilist.head, si_list) ++ if (id == sysaufs_si_id(sbinfo)) { ++ kobject_get(&sbinfo->si_kobj); ++ sb = sbinfo->si_sb; ++ break; ++ } ++ spin_unlock(&au_sbilist.spin); ++ ++ err = -EINVAL; ++ if (unlikely(!sb)) ++ goto out; ++ ++ err = au_plink_maint_enter(sb); ++ if (!err) ++ /* keep kobject_get() */ ++ file->private_data = sbinfo; ++ else ++ kobject_put(&sbinfo->si_kobj); ++out: ++ return err; ++} ++ ++/* ++ * Accept a valid "si=xxxx" only. ++ * Once it is accepted successfully, accept "clean" too. ++ */ ++static ssize_t au_procfs_plm_write(struct file *file, const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ unsigned long id; ++ /* last newline is allowed */ ++ char buf[3 + sizeof(unsigned long) * 2 + 1]; ++ ++ err = -EACCES; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(count > sizeof(buf))) ++ goto out; ++ ++ err = copy_from_user(buf, ubuf, count); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ goto out; ++ } ++ buf[count] = 0; ++ ++ err = -EINVAL; ++ if (!strcmp("clean", buf)) { ++ au_procfs_plm_write_clean(file); ++ goto out_success; ++ } else if (unlikely(strncmp("si=", buf, 3))) ++ goto out; ++ ++ err = kstrtoul(buf + 3, 16, &id); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_procfs_plm_write_si(file, id); ++ if (unlikely(err)) ++ goto out; ++ ++out_success: ++ err = count; /* success */ ++out: ++ return err; ++} ++ ++static const struct file_operations au_procfs_plm_fop = { ++ .write = au_procfs_plm_write, ++ .release = au_procfs_plm_release, ++ .owner = THIS_MODULE ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct proc_dir_entry *au_procfs_dir; ++ ++void au_procfs_fin(void) ++{ ++ remove_proc_entry(AUFS_PLINK_MAINT_NAME, au_procfs_dir); ++ remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); ++} ++ ++int __init au_procfs_init(void) ++{ ++ int err; ++ struct proc_dir_entry *entry; ++ ++ err = -ENOMEM; ++ au_procfs_dir = proc_mkdir(AUFS_PLINK_MAINT_DIR, NULL); ++ if (unlikely(!au_procfs_dir)) ++ goto out; ++ ++ entry = proc_create(AUFS_PLINK_MAINT_NAME, S_IFREG | S_IWUSR, ++ au_procfs_dir, &au_procfs_plm_fop); ++ if (unlikely(!entry)) ++ goto out_dir; ++ ++ err = 0; ++ goto out; /* success */ ++ ++ ++out_dir: ++ remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); ++out: ++ return err; ++} +diff --git a/fs/aufs/rdu.c b/fs/aufs/rdu.c +new file mode 100644 +index 0000000..54abc14 +--- /dev/null ++++ b/fs/aufs/rdu.c +@@ -0,0 +1,368 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * readdir in userspace. ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* bits for struct aufs_rdu.flags */ ++#define AuRdu_CALLED 1 ++#define AuRdu_CONT (1 << 1) ++#define AuRdu_FULL (1 << 2) ++#define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name) ++#define au_fset_rdu(flags, name) \ ++ do { (flags) |= AuRdu_##name; } while (0) ++#define au_fclr_rdu(flags, name) \ ++ do { (flags) &= ~AuRdu_##name; } while (0) ++ ++struct au_rdu_arg { ++ struct dir_context ctx; ++ struct aufs_rdu *rdu; ++ union au_rdu_ent_ul ent; ++ unsigned long end; ++ ++ struct super_block *sb; ++ int err; ++}; ++ ++static int au_rdu_fill(struct dir_context *ctx, const char *name, int nlen, ++ loff_t offset, u64 h_ino, unsigned int d_type) ++{ ++ int err, len; ++ struct au_rdu_arg *arg = container_of(ctx, struct au_rdu_arg, ctx); ++ struct aufs_rdu *rdu = arg->rdu; ++ struct au_rdu_ent ent; ++ ++ err = 0; ++ arg->err = 0; ++ au_fset_rdu(rdu->cookie.flags, CALLED); ++ len = au_rdu_len(nlen); ++ if (arg->ent.ul + len < arg->end) { ++ ent.ino = h_ino; ++ ent.bindex = rdu->cookie.bindex; ++ ent.type = d_type; ++ ent.nlen = nlen; ++ if (unlikely(nlen > AUFS_MAX_NAMELEN)) ++ ent.type = DT_UNKNOWN; ++ ++ /* unnecessary to support mmap_sem since this is a dir */ ++ err = -EFAULT; ++ if (copy_to_user(arg->ent.e, &ent, sizeof(ent))) ++ goto out; ++ if (copy_to_user(arg->ent.e->name, name, nlen)) ++ goto out; ++ /* the terminating NULL */ ++ if (__put_user(0, arg->ent.e->name + nlen)) ++ goto out; ++ err = 0; ++ /* AuDbg("%p, %.*s\n", arg->ent.p, nlen, name); */ ++ arg->ent.ul += len; ++ rdu->rent++; ++ } else { ++ err = -EFAULT; ++ au_fset_rdu(rdu->cookie.flags, FULL); ++ rdu->full = 1; ++ rdu->tail = arg->ent; ++ } ++ ++out: ++ /* AuTraceErr(err); */ ++ return err; ++} ++ ++static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg) ++{ ++ int err; ++ loff_t offset; ++ struct au_rdu_cookie *cookie = &arg->rdu->cookie; ++ ++ /* we don't have to care (FMODE_32BITHASH | FMODE_64BITHASH) for ext4 */ ++ offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET); ++ err = offset; ++ if (unlikely(offset != cookie->h_pos)) ++ goto out; ++ ++ err = 0; ++ do { ++ arg->err = 0; ++ au_fclr_rdu(cookie->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(h_file, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err ++ && au_ftest_rdu(cookie->flags, CALLED) ++ && !au_ftest_rdu(cookie->flags, FULL)); ++ cookie->h_pos = h_file->f_pos; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_rdu(struct file *file, struct aufs_rdu *rdu) ++{ ++ int err; ++ aufs_bindex_t bbot; ++ struct au_rdu_arg arg = { ++ .ctx = { ++ .actor = au_rdu_fill ++ } ++ }; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct file *h_file; ++ struct au_rdu_cookie *cookie = &rdu->cookie; ++ ++ err = !access_ok(VERIFY_WRITE, rdu->ent.e, rdu->sz); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ rdu->rent = 0; ++ rdu->tail = rdu->ent; ++ rdu->full = 0; ++ arg.rdu = rdu; ++ arg.ent = rdu->ent; ++ arg.end = arg.ent.ul; ++ arg.end += rdu->sz; ++ ++ err = -ENOTDIR; ++ if (unlikely(!file->f_op->iterate && !file->f_op->iterate_shared)) ++ goto out; ++ ++ err = security_file_permission(file, MAY_READ); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ inode_lock_shared(inode); ++ ++ arg.sb = inode->i_sb; ++ err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_mtx; ++ err = au_alive_dir(dentry); ++ if (unlikely(err)) ++ goto out_si; ++ /* todo: reval? */ ++ fi_read_lock(file); ++ ++ err = -EAGAIN; ++ if (unlikely(au_ftest_rdu(cookie->flags, CONT) ++ && cookie->generation != au_figen(file))) ++ goto out_unlock; ++ ++ err = 0; ++ if (!rdu->blk) { ++ rdu->blk = au_sbi(arg.sb)->si_rdblk; ++ if (!rdu->blk) ++ rdu->blk = au_dir_size(file, /*dentry*/NULL); ++ } ++ bbot = au_fbtop(file); ++ if (cookie->bindex < bbot) ++ cookie->bindex = bbot; ++ bbot = au_fbbot_dir(file); ++ /* AuDbg("b%d, b%d\n", cookie->bindex, bbot); */ ++ for (; !err && cookie->bindex <= bbot; ++ cookie->bindex++, cookie->h_pos = 0) { ++ h_file = au_hf_dir(file, cookie->bindex); ++ if (!h_file) ++ continue; ++ ++ au_fclr_rdu(cookie->flags, FULL); ++ err = au_rdu_do(h_file, &arg); ++ AuTraceErr(err); ++ if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err)) ++ break; ++ } ++ AuDbg("rent %llu\n", rdu->rent); ++ ++ if (!err && !au_ftest_rdu(cookie->flags, CONT)) { ++ rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH); ++ au_fset_rdu(cookie->flags, CONT); ++ cookie->generation = au_figen(file); ++ } ++ ++ ii_read_lock_child(inode); ++ fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibtop(inode))); ++ ii_read_unlock(inode); ++ ++out_unlock: ++ fi_read_unlock(file); ++out_si: ++ si_read_unlock(arg.sb); ++out_mtx: ++ inode_unlock_shared(inode); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu) ++{ ++ int err; ++ ino_t ino; ++ unsigned long long nent; ++ union au_rdu_ent_ul *u; ++ struct au_rdu_ent ent; ++ struct super_block *sb; ++ ++ err = 0; ++ nent = rdu->nent; ++ u = &rdu->ent; ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ while (nent-- > 0) { ++ /* unnecessary to support mmap_sem since this is a dir */ ++ err = copy_from_user(&ent, u->e, sizeof(ent)); ++ if (!err) ++ err = !access_ok(VERIFY_WRITE, &u->e->ino, sizeof(ino)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ break; ++ } ++ ++ /* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */ ++ if (!ent.wh) ++ err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino); ++ else ++ err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type, ++ &ino); ++ if (unlikely(err)) { ++ AuTraceErr(err); ++ break; ++ } ++ ++ err = __put_user(ino, &u->e->ino); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ break; ++ } ++ u->ul += au_rdu_len(ent.nlen); ++ } ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_rdu_verify(struct aufs_rdu *rdu) ++{ ++ AuDbg("rdu{%llu, %p, %u | %u | %llu, %u, %u | " ++ "%llu, b%d, 0x%x, g%u}\n", ++ rdu->sz, rdu->ent.e, rdu->verify[AufsCtlRduV_SZ], ++ rdu->blk, ++ rdu->rent, rdu->shwh, rdu->full, ++ rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags, ++ rdu->cookie.generation); ++ ++ if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu)) ++ return 0; ++ ++ AuDbg("%u:%u\n", ++ rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu)); ++ return -EINVAL; ++} ++ ++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err, e; ++ struct aufs_rdu rdu; ++ void __user *p = (void __user *)arg; ++ ++ err = copy_from_user(&rdu, p, sizeof(rdu)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ err = au_rdu_verify(&rdu); ++ if (unlikely(err)) ++ goto out; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ err = au_rdu(file, &rdu); ++ if (unlikely(err)) ++ break; ++ ++ e = copy_to_user(p, &rdu, sizeof(rdu)); ++ if (unlikely(e)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ break; ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ino(file, &rdu); ++ break; ++ ++ default: ++ /* err = -ENOTTY; */ ++ err = -EINVAL; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#ifdef CONFIG_COMPAT ++long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err, e; ++ struct aufs_rdu rdu; ++ void __user *p = compat_ptr(arg); ++ ++ /* todo: get_user()? */ ++ err = copy_from_user(&rdu, p, sizeof(rdu)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ rdu.ent.e = compat_ptr(rdu.ent.ul); ++ err = au_rdu_verify(&rdu); ++ if (unlikely(err)) ++ goto out; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ err = au_rdu(file, &rdu); ++ if (unlikely(err)) ++ break; ++ ++ rdu.ent.ul = ptr_to_compat(rdu.ent.e); ++ rdu.tail.ul = ptr_to_compat(rdu.tail.e); ++ e = copy_to_user(p, &rdu, sizeof(rdu)); ++ if (unlikely(e)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ break; ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ino(file, &rdu); ++ break; ++ ++ default: ++ /* err = -ENOTTY; */ ++ err = -EINVAL; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++#endif +diff --git a/fs/aufs/rwsem.h b/fs/aufs/rwsem.h +new file mode 100644 +index 0000000..6c0d5a9 +--- /dev/null ++++ b/fs/aufs/rwsem.h +@@ -0,0 +1,185 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * simple read-write semaphore wrappers ++ */ ++ ++#ifndef __AUFS_RWSEM_H__ ++#define __AUFS_RWSEM_H__ ++ ++#ifdef __KERNEL__ ++ ++#include "debug.h" ++ ++struct au_rwsem { ++ struct rw_semaphore rwsem; ++#ifdef CONFIG_AUFS_DEBUG ++ /* just for debugging, not almighty counter */ ++ atomic_t rcnt, wcnt; ++#endif ++}; ++ ++#ifdef CONFIG_LOCKDEP ++#define au_lockdep_set_name(rw) \ ++ lockdep_set_class_and_name(&(rw)->rwsem, \ ++ /*original key*/(rw)->rwsem.dep_map.key, \ ++ /*name*/#rw) ++#else ++#define au_lockdep_set_name(rw) do {} while (0) ++#endif ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define AuDbgCntInit(rw) do { \ ++ atomic_set(&(rw)->rcnt, 0); \ ++ atomic_set(&(rw)->wcnt, 0); \ ++ smp_mb(); /* atomic set */ \ ++} while (0) ++ ++#define AuDbgCnt(rw, cnt) atomic_read(&(rw)->cnt) ++#define AuDbgCntInc(rw, cnt) atomic_inc(&(rw)->cnt) ++#define AuDbgCntDec(rw, cnt) WARN_ON(atomic_dec_return(&(rw)->cnt) < 0) ++#define AuDbgRcntInc(rw) AuDbgCntInc(rw, rcnt) ++#define AuDbgRcntDec(rw) AuDbgCntDec(rw, rcnt) ++#define AuDbgWcntInc(rw) AuDbgCntInc(rw, wcnt) ++#define AuDbgWcntDec(rw) AuDbgCntDec(rw, wcnt) ++#else ++#define AuDbgCnt(rw, cnt) 0 ++#define AuDbgCntInit(rw) do {} while (0) ++#define AuDbgRcntInc(rw) do {} while (0) ++#define AuDbgRcntDec(rw) do {} while (0) ++#define AuDbgWcntInc(rw) do {} while (0) ++#define AuDbgWcntDec(rw) do {} while (0) ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++/* to debug easier, do not make them inlined functions */ ++#define AuRwMustNoWaiters(rw) AuDebugOn(rwsem_is_contended(&(rw)->rwsem)) ++/* rwsem_is_locked() is unusable */ ++#define AuRwMustReadLock(rw) AuDebugOn(AuDbgCnt(rw, rcnt) <= 0) ++#define AuRwMustWriteLock(rw) AuDebugOn(AuDbgCnt(rw, wcnt) <= 0) ++#define AuRwMustAnyLock(rw) AuDebugOn(AuDbgCnt(rw, rcnt) <= 0 \ ++ && AuDbgCnt(rw, wcnt) <= 0) ++#define AuRwDestroy(rw) AuDebugOn(AuDbgCnt(rw, rcnt) \ ++ || AuDbgCnt(rw, wcnt)) ++ ++#define au_rw_init(rw) do { \ ++ AuDbgCntInit(rw); \ ++ init_rwsem(&(rw)->rwsem); \ ++ au_lockdep_set_name(rw); \ ++ } while (0) ++ ++#define au_rw_init_wlock(rw) do { \ ++ au_rw_init(rw); \ ++ down_write(&(rw)->rwsem); \ ++ AuDbgWcntInc(rw); \ ++ } while (0) ++ ++#define au_rw_init_wlock_nested(rw, lsc) do { \ ++ au_rw_init(rw); \ ++ down_write_nested(&(rw)->rwsem, lsc); \ ++ AuDbgWcntInc(rw); \ ++ } while (0) ++ ++static inline void au_rw_read_lock(struct au_rwsem *rw) ++{ ++ down_read(&rw->rwsem); ++ AuDbgRcntInc(rw); ++} ++ ++static inline void au_rw_read_lock_nested(struct au_rwsem *rw, unsigned int lsc) ++{ ++ down_read_nested(&rw->rwsem, lsc); ++ AuDbgRcntInc(rw); ++} ++ ++static inline void au_rw_read_unlock(struct au_rwsem *rw) ++{ ++ AuRwMustReadLock(rw); ++ AuDbgRcntDec(rw); ++ up_read(&rw->rwsem); ++} ++ ++static inline void au_rw_dgrade_lock(struct au_rwsem *rw) ++{ ++ AuRwMustWriteLock(rw); ++ AuDbgRcntInc(rw); ++ AuDbgWcntDec(rw); ++ downgrade_write(&rw->rwsem); ++} ++ ++static inline void au_rw_write_lock(struct au_rwsem *rw) ++{ ++ down_write(&rw->rwsem); ++ AuDbgWcntInc(rw); ++} ++ ++static inline void au_rw_write_lock_nested(struct au_rwsem *rw, ++ unsigned int lsc) ++{ ++ down_write_nested(&rw->rwsem, lsc); ++ AuDbgWcntInc(rw); ++} ++ ++static inline void au_rw_write_unlock(struct au_rwsem *rw) ++{ ++ AuRwMustWriteLock(rw); ++ AuDbgWcntDec(rw); ++ up_write(&rw->rwsem); ++} ++ ++/* why is not _nested version defined */ ++static inline int au_rw_read_trylock(struct au_rwsem *rw) ++{ ++ int ret; ++ ++ ret = down_read_trylock(&rw->rwsem); ++ if (ret) ++ AuDbgRcntInc(rw); ++ return ret; ++} ++ ++static inline int au_rw_write_trylock(struct au_rwsem *rw) ++{ ++ int ret; ++ ++ ret = down_write_trylock(&rw->rwsem); ++ if (ret) ++ AuDbgWcntInc(rw); ++ return ret; ++} ++ ++#undef AuDbgCntDec ++#undef AuDbgRcntInc ++#undef AuDbgRcntDec ++#undef AuDbgWcntDec ++ ++#define AuSimpleLockRwsemFuncs(prefix, param, rwsem) \ ++static inline void prefix##_read_lock(param) \ ++{ au_rw_read_lock(rwsem); } \ ++static inline void prefix##_write_lock(param) \ ++{ au_rw_write_lock(rwsem); } \ ++static inline int prefix##_read_trylock(param) \ ++{ return au_rw_read_trylock(rwsem); } \ ++static inline int prefix##_write_trylock(param) \ ++{ return au_rw_write_trylock(rwsem); } ++/* why is not _nested version defined */ ++/* static inline void prefix##_read_trylock_nested(param, lsc) ++{ au_rw_read_trylock_nested(rwsem, lsc)); } ++static inline void prefix##_write_trylock_nestd(param, lsc) ++{ au_rw_write_trylock_nested(rwsem, lsc); } */ ++ ++#define AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) \ ++static inline void prefix##_read_unlock(param) \ ++{ au_rw_read_unlock(rwsem); } \ ++static inline void prefix##_write_unlock(param) \ ++{ au_rw_write_unlock(rwsem); } \ ++static inline void prefix##_downgrade_lock(param) \ ++{ au_rw_dgrade_lock(rwsem); } ++ ++#define AuSimpleRwsemFuncs(prefix, param, rwsem) \ ++ AuSimpleLockRwsemFuncs(prefix, param, rwsem) \ ++ AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_RWSEM_H__ */ +diff --git a/fs/aufs/sbinfo.c b/fs/aufs/sbinfo.c +new file mode 100644 +index 0000000..aa97059 +--- /dev/null ++++ b/fs/aufs/sbinfo.c +@@ -0,0 +1,340 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * superblock private data ++ */ ++ ++#include "aufs.h" ++ ++/* ++ * they are necessary regardless sysfs is disabled. ++ */ ++void au_si_free(struct kobject *kobj) ++{ ++ int i; ++ struct au_sbinfo *sbinfo; ++ char *locked __maybe_unused; /* debug only */ ++ ++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); ++ for (i = 0; i < AuPlink_NHASH; i++) ++ AuDebugOn(!hlist_empty(&sbinfo->si_plink[i].head)); ++ au_nwt_fin(&sbinfo->si_nowait); ++ ++ AuDebugOn(percpu_counter_sum(&sbinfo->si_ninodes)); ++ percpu_counter_destroy(&sbinfo->si_ninodes); ++ AuDebugOn(percpu_counter_sum(&sbinfo->si_nfiles)); ++ percpu_counter_destroy(&sbinfo->si_nfiles); ++ ++ au_rw_write_lock(&sbinfo->si_rwsem); ++ au_br_free(sbinfo); ++ au_rw_write_unlock(&sbinfo->si_rwsem); ++ ++ kfree(sbinfo->si_branch); ++ for (i = 0; i < AU_NPIDMAP; i++) ++ kfree(sbinfo->au_si_pid.pid_bitmap[i]); ++ mutex_destroy(&sbinfo->au_si_pid.pid_mtx); ++ mutex_destroy(&sbinfo->si_xib_mtx); ++ AuRwDestroy(&sbinfo->si_rwsem); ++ ++ kfree(sbinfo); ++} ++ ++int au_si_alloc(struct super_block *sb) ++{ ++ int err, i; ++ struct au_sbinfo *sbinfo; ++ ++ err = -ENOMEM; ++ sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS); ++ if (unlikely(!sbinfo)) ++ goto out; ++ ++ /* will be reallocated separately */ ++ sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS); ++ if (unlikely(!sbinfo->si_branch)) ++ goto out_sbinfo; ++ ++ err = sysaufs_si_init(sbinfo); ++ if (unlikely(err)) ++ goto out_br; ++ ++ au_nwt_init(&sbinfo->si_nowait); ++ au_rw_init_wlock(&sbinfo->si_rwsem); ++ mutex_init(&sbinfo->au_si_pid.pid_mtx); ++ ++ percpu_counter_init(&sbinfo->si_ninodes, 0, GFP_NOFS); ++ percpu_counter_init(&sbinfo->si_nfiles, 0, GFP_NOFS); ++ ++ sbinfo->si_bbot = -1; ++ sbinfo->si_last_br_id = AUFS_BRANCH_MAX / 2; ++ ++ sbinfo->si_wbr_copyup = AuWbrCopyup_Def; ++ sbinfo->si_wbr_create = AuWbrCreate_Def; ++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup; ++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create; ++ ++ au_fhsm_init(sbinfo); ++ ++ sbinfo->si_mntflags = au_opts_plink(AuOpt_Def); ++ ++ sbinfo->si_xino_jiffy = jiffies; ++ sbinfo->si_xino_expire ++ = msecs_to_jiffies(AUFS_XINO_DEF_SEC * MSEC_PER_SEC); ++ mutex_init(&sbinfo->si_xib_mtx); ++ sbinfo->si_xino_brid = -1; ++ /* leave si_xib_last_pindex and si_xib_next_bit */ ++ ++ au_sphl_init(&sbinfo->si_aopen); ++ ++ sbinfo->si_rdcache = msecs_to_jiffies(AUFS_RDCACHE_DEF * MSEC_PER_SEC); ++ sbinfo->si_rdblk = AUFS_RDBLK_DEF; ++ sbinfo->si_rdhash = AUFS_RDHASH_DEF; ++ sbinfo->si_dirwh = AUFS_DIRWH_DEF; ++ ++ for (i = 0; i < AuPlink_NHASH; i++) ++ au_sphl_init(sbinfo->si_plink + i); ++ init_waitqueue_head(&sbinfo->si_plink_wq); ++ spin_lock_init(&sbinfo->si_plink_maint_lock); ++ ++ au_sphl_init(&sbinfo->si_files); ++ ++ /* with getattr by default */ ++ sbinfo->si_iop_array = aufs_iop; ++ ++ /* leave other members for sysaufs and si_mnt. */ ++ sbinfo->si_sb = sb; ++ sb->s_fs_info = sbinfo; ++ si_pid_set(sb); ++ return 0; /* success */ ++ ++out_br: ++ kfree(sbinfo->si_branch); ++out_sbinfo: ++ kfree(sbinfo); ++out: ++ return err; ++} ++ ++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr) ++{ ++ int err, sz; ++ struct au_branch **brp; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*brp) * (sbinfo->si_bbot + 1); ++ if (unlikely(!sz)) ++ sz = sizeof(*brp); ++ brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS); ++ if (brp) { ++ sbinfo->si_branch = brp; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++unsigned int au_sigen_inc(struct super_block *sb) ++{ ++ unsigned int gen; ++ struct inode *inode; ++ ++ SiMustWriteLock(sb); ++ ++ gen = ++au_sbi(sb)->si_generation; ++ au_update_digen(sb->s_root); ++ inode = d_inode(sb->s_root); ++ au_update_iigen(inode, /*half*/0); ++ inode->i_version++; ++ return gen; ++} ++ ++aufs_bindex_t au_new_br_id(struct super_block *sb) ++{ ++ aufs_bindex_t br_id; ++ int i; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ for (i = 0; i <= AUFS_BRANCH_MAX; i++) { ++ br_id = ++sbinfo->si_last_br_id; ++ AuDebugOn(br_id < 0); ++ if (br_id && au_br_index(sb, br_id) < 0) ++ return br_id; ++ } ++ ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* it is ok that new 'nwt' tasks are appended while we are sleeping */ ++int si_read_lock(struct super_block *sb, int flags) ++{ ++ int err; ++ ++ err = 0; ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ ++ si_noflush_read_lock(sb); ++ err = au_plink_maint(sb, flags); ++ if (unlikely(err)) ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++int si_write_lock(struct super_block *sb, int flags) ++{ ++ int err; ++ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ ++ si_noflush_write_lock(sb); ++ err = au_plink_maint(sb, flags); ++ if (unlikely(err)) ++ si_write_unlock(sb); ++ ++ return err; ++} ++ ++/* dentry and super_block lock. call at entry point */ ++int aufs_read_lock(struct dentry *dentry, int flags) ++{ ++ int err; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, flags); ++ if (unlikely(err)) ++ goto out; ++ ++ if (au_ftest_lock(flags, DW)) ++ di_write_lock_child(dentry); ++ else ++ di_read_lock_child(dentry, flags); ++ ++ if (au_ftest_lock(flags, GEN)) { ++ err = au_digen_test(dentry, au_sigen(sb)); ++ if (!au_opt_test(au_mntflags(sb), UDBA_NONE)) ++ AuDebugOn(!err && au_dbrange_test(dentry)); ++ else if (!err) ++ err = au_dbrange_test(dentry); ++ if (unlikely(err)) ++ aufs_read_unlock(dentry, flags); ++ } ++ ++out: ++ return err; ++} ++ ++void aufs_read_unlock(struct dentry *dentry, int flags) ++{ ++ if (au_ftest_lock(flags, DW)) ++ di_write_unlock(dentry); ++ else ++ di_read_unlock(dentry, flags); ++ si_read_unlock(dentry->d_sb); ++} ++ ++void aufs_write_lock(struct dentry *dentry) ++{ ++ si_write_lock(dentry->d_sb, AuLock_FLUSH | AuLock_NOPLMW); ++ di_write_lock_child(dentry); ++} ++ ++void aufs_write_unlock(struct dentry *dentry) ++{ ++ di_write_unlock(dentry); ++ si_write_unlock(dentry->d_sb); ++} ++ ++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags) ++{ ++ int err; ++ unsigned int sigen; ++ struct super_block *sb; ++ ++ sb = d1->d_sb; ++ err = si_read_lock(sb, flags); ++ if (unlikely(err)) ++ goto out; ++ ++ di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIRS)); ++ ++ if (au_ftest_lock(flags, GEN)) { ++ sigen = au_sigen(sb); ++ err = au_digen_test(d1, sigen); ++ AuDebugOn(!err && au_dbrange_test(d1)); ++ if (!err) { ++ err = au_digen_test(d2, sigen); ++ AuDebugOn(!err && au_dbrange_test(d2)); ++ } ++ if (unlikely(err)) ++ aufs_read_and_write_unlock2(d1, d2); ++ } ++ ++out: ++ return err; ++} ++ ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ di_write_unlock2(d1, d2); ++ si_read_unlock(d1->d_sb); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void si_pid_alloc(struct au_si_pid *au_si_pid, int idx) ++{ ++ unsigned long *p; ++ ++ BUILD_BUG_ON(sizeof(unsigned long) != ++ sizeof(*au_si_pid->pid_bitmap)); ++ ++ mutex_lock(&au_si_pid->pid_mtx); ++ p = au_si_pid->pid_bitmap[idx]; ++ while (!p) { ++ /* ++ * bad approach. ++ * but keeping 'si_pid_set()' void is more important. ++ */ ++ p = kcalloc(BITS_TO_LONGS(AU_PIDSTEP), ++ sizeof(*au_si_pid->pid_bitmap), ++ GFP_NOFS); ++ if (p) ++ break; ++ cond_resched(); ++ } ++ au_si_pid->pid_bitmap[idx] = p; ++ mutex_unlock(&au_si_pid->pid_mtx); ++} ++ ++void si_pid_set(struct super_block *sb) ++{ ++ pid_t bit; ++ int idx; ++ unsigned long *bitmap; ++ struct au_si_pid *au_si_pid; ++ ++ si_pid_idx_bit(&idx, &bit); ++ au_si_pid = &au_sbi(sb)->au_si_pid; ++ bitmap = au_si_pid->pid_bitmap[idx]; ++ if (!bitmap) { ++ si_pid_alloc(au_si_pid, idx); ++ bitmap = au_si_pid->pid_bitmap[idx]; ++ } ++ AuDebugOn(test_bit(bit, bitmap)); ++ set_bit(bit, bitmap); ++ /* smp_mb(); */ ++} +diff --git a/fs/aufs/spl.h b/fs/aufs/spl.h +new file mode 100644 +index 0000000..f9b5288 +--- /dev/null ++++ b/fs/aufs/spl.h +@@ -0,0 +1,98 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * simple list protected by a spinlock ++ */ ++ ++#ifndef __AUFS_SPL_H__ ++#define __AUFS_SPL_H__ ++ ++#ifdef __KERNEL__ ++ ++struct au_splhead { ++ spinlock_t spin; ++ struct list_head head; ++}; ++ ++static inline void au_spl_init(struct au_splhead *spl) ++{ ++ spin_lock_init(&spl->spin); ++ INIT_LIST_HEAD(&spl->head); ++} ++ ++static inline void au_spl_add(struct list_head *list, struct au_splhead *spl) ++{ ++ spin_lock(&spl->spin); ++ list_add(list, &spl->head); ++ spin_unlock(&spl->spin); ++} ++ ++static inline void au_spl_del(struct list_head *list, struct au_splhead *spl) ++{ ++ spin_lock(&spl->spin); ++ list_del(list); ++ spin_unlock(&spl->spin); ++} ++ ++static inline void au_spl_del_rcu(struct list_head *list, ++ struct au_splhead *spl) ++{ ++ spin_lock(&spl->spin); ++ list_del_rcu(list); ++ spin_unlock(&spl->spin); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_sphlhead { ++ spinlock_t spin; ++ struct hlist_head head; ++}; ++ ++static inline void au_sphl_init(struct au_sphlhead *sphl) ++{ ++ spin_lock_init(&sphl->spin); ++ INIT_HLIST_HEAD(&sphl->head); ++} ++ ++static inline void au_sphl_add(struct hlist_node *hlist, ++ struct au_sphlhead *sphl) ++{ ++ spin_lock(&sphl->spin); ++ hlist_add_head(hlist, &sphl->head); ++ spin_unlock(&sphl->spin); ++} ++ ++static inline void au_sphl_del(struct hlist_node *hlist, ++ struct au_sphlhead *sphl) ++{ ++ spin_lock(&sphl->spin); ++ hlist_del(hlist); ++ spin_unlock(&sphl->spin); ++} ++ ++static inline void au_sphl_del_rcu(struct hlist_node *hlist, ++ struct au_sphlhead *sphl) ++{ ++ spin_lock(&sphl->spin); ++ hlist_del_rcu(hlist); ++ spin_unlock(&sphl->spin); ++} ++ ++static inline unsigned long au_sphl_count(struct au_sphlhead *sphl) ++{ ++ unsigned long cnt; ++ struct hlist_node *pos; ++ ++ cnt = 0; ++ spin_lock(&sphl->spin); ++ hlist_for_each(pos, &sphl->head) ++ cnt++; ++ spin_unlock(&sphl->spin); ++ return cnt; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_SPL_H__ */ +diff --git a/fs/aufs/super.c b/fs/aufs/super.c +new file mode 100644 +index 0000000..8bd2d9c +--- /dev/null ++++ b/fs/aufs/super.c +@@ -0,0 +1,1026 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * mount and super_block operations ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * super_operations ++ */ ++static struct inode *aufs_alloc_inode(struct super_block *sb __maybe_unused) ++{ ++ struct au_icntnr *c; ++ ++ c = au_cache_alloc_icntnr(); ++ if (c) { ++ au_icntnr_init(c); ++ c->vfs_inode.i_version = 1; /* sigen(sb); */ ++ c->iinfo.ii_hinode = NULL; ++ return &c->vfs_inode; ++ } ++ return NULL; ++} ++ ++static void aufs_destroy_inode_cb(struct rcu_head *head) ++{ ++ struct inode *inode = container_of(head, struct inode, i_rcu); ++ ++ INIT_HLIST_HEAD(&inode->i_dentry); ++ au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode)); ++} ++ ++static void aufs_destroy_inode(struct inode *inode) ++{ ++ if (!au_is_bad_inode(inode)) ++ au_iinfo_fin(inode); ++ call_rcu(&inode->i_rcu, aufs_destroy_inode_cb); ++} ++ ++struct inode *au_iget_locked(struct super_block *sb, ino_t ino) ++{ ++ struct inode *inode; ++ int err; ++ ++ inode = iget_locked(sb, ino); ++ if (unlikely(!inode)) { ++ inode = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ if (!(inode->i_state & I_NEW)) ++ goto out; ++ ++ err = au_xigen_new(inode); ++ if (!err) ++ err = au_iinfo_init(inode); ++ if (!err) ++ inode->i_version++; ++ else { ++ iget_failed(inode); ++ inode = ERR_PTR(err); ++ } ++ ++out: ++ /* never return NULL */ ++ AuDebugOn(!inode); ++ AuTraceErrPtr(inode); ++ return inode; ++} ++ ++/* lock free root dinfo */ ++static int au_show_brs(struct seq_file *seq, struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct path path; ++ struct au_hdentry *hdp; ++ struct au_branch *br; ++ au_br_perm_str_t perm; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ bindex = 0; ++ hdp = au_hdentry(au_di(sb->s_root), bindex); ++ for (; !err && bindex <= bbot; bindex++, hdp++) { ++ br = au_sbr(sb, bindex); ++ path.mnt = au_br_mnt(br); ++ path.dentry = hdp->hd_dentry; ++ err = au_seq_path(seq, &path); ++ if (!err) { ++ au_optstr_br_perm(&perm, br->br_perm); ++ seq_printf(seq, "=%s", perm.a); ++ if (bindex != bbot) ++ seq_putc(seq, ':'); ++ } ++ } ++ if (unlikely(err || seq_has_overflowed(seq))) ++ err = -E2BIG; ++ ++ return err; ++} ++ ++static void au_show_wbr_create(struct seq_file *m, int v, ++ struct au_sbinfo *sbinfo) ++{ ++ const char *pat; ++ ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ ++ seq_puts(m, ",create="); ++ pat = au_optstr_wbr_create(v); ++ switch (v) { ++ case AuWbrCreate_TDP: ++ case AuWbrCreate_RR: ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_PMFS: ++ seq_puts(m, pat); ++ break; ++ case AuWbrCreate_MFSV: ++ seq_printf(m, /*pat*/"mfs:%lu", ++ jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire) ++ / MSEC_PER_SEC); ++ break; ++ case AuWbrCreate_PMFSV: ++ seq_printf(m, /*pat*/"pmfs:%lu", ++ jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire) ++ / MSEC_PER_SEC); ++ break; ++ case AuWbrCreate_MFSRR: ++ seq_printf(m, /*pat*/"mfsrr:%llu", ++ sbinfo->si_wbr_mfs.mfsrr_watermark); ++ break; ++ case AuWbrCreate_MFSRRV: ++ seq_printf(m, /*pat*/"mfsrr:%llu:%lu", ++ sbinfo->si_wbr_mfs.mfsrr_watermark, ++ jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire) ++ / MSEC_PER_SEC); ++ break; ++ case AuWbrCreate_PMFSRR: ++ seq_printf(m, /*pat*/"pmfsrr:%llu", ++ sbinfo->si_wbr_mfs.mfsrr_watermark); ++ break; ++ case AuWbrCreate_PMFSRRV: ++ seq_printf(m, /*pat*/"pmfsrr:%llu:%lu", ++ sbinfo->si_wbr_mfs.mfsrr_watermark, ++ jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire) ++ / MSEC_PER_SEC); ++ break; ++ } ++} ++ ++static int au_show_xino(struct seq_file *seq, struct super_block *sb) ++{ ++#ifdef CONFIG_SYSFS ++ return 0; ++#else ++ int err; ++ const int len = sizeof(AUFS_XINO_FNAME) - 1; ++ aufs_bindex_t bindex, brid; ++ struct qstr *name; ++ struct file *f; ++ struct dentry *d, *h_root; ++ ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ ++ err = 0; ++ f = au_sbi(sb)->si_xib; ++ if (!f) ++ goto out; ++ ++ /* stop printing the default xino path on the first writable branch */ ++ h_root = NULL; ++ brid = au_xino_brid(sb); ++ if (brid >= 0) { ++ bindex = au_br_index(sb, brid); ++ h_root = au_hdentry(au_di(sb->s_root), bindex)->hd_dentry; ++ } ++ d = f->f_path.dentry; ++ name = &d->d_name; ++ /* safe ->d_parent because the file is unlinked */ ++ if (d->d_parent == h_root ++ && name->len == len ++ && !memcmp(name->name, AUFS_XINO_FNAME, len)) ++ goto out; ++ ++ seq_puts(seq, ",xino="); ++ err = au_xino_path(seq, f); ++ ++out: ++ return err; ++#endif ++} ++ ++/* seq_file will re-call me in case of too long string */ ++static int aufs_show_options(struct seq_file *m, struct dentry *dentry) ++{ ++ int err; ++ unsigned int mnt_flags, v; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++#define AuBool(name, str) do { \ ++ v = au_opt_test(mnt_flags, name); \ ++ if (v != au_opt_test(AuOpt_Def, name)) \ ++ seq_printf(m, ",%s" #str, v ? "" : "no"); \ ++} while (0) ++ ++#define AuStr(name, str) do { \ ++ v = mnt_flags & AuOptMask_##name; \ ++ if (v != (AuOpt_Def & AuOptMask_##name)) \ ++ seq_printf(m, "," #str "=%s", au_optstr_##str(v)); \ ++} while (0) ++ ++#define AuUInt(name, str, val) do { \ ++ if (val != AUFS_##name##_DEF) \ ++ seq_printf(m, "," #str "=%u", val); \ ++} while (0) ++ ++ sb = dentry->d_sb; ++ if (sb->s_flags & MS_POSIXACL) ++ seq_puts(m, ",acl"); ++ ++ /* lock free root dinfo */ ++ si_noflush_read_lock(sb); ++ sbinfo = au_sbi(sb); ++ seq_printf(m, ",si=%lx", sysaufs_si_id(sbinfo)); ++ ++ mnt_flags = au_mntflags(sb); ++ if (au_opt_test(mnt_flags, XINO)) { ++ err = au_show_xino(m, sb); ++ if (unlikely(err)) ++ goto out; ++ } else ++ seq_puts(m, ",noxino"); ++ ++ AuBool(TRUNC_XINO, trunc_xino); ++ AuStr(UDBA, udba); ++ AuBool(SHWH, shwh); ++ AuBool(PLINK, plink); ++ AuBool(DIO, dio); ++ AuBool(DIRPERM1, dirperm1); ++ ++ v = sbinfo->si_wbr_create; ++ if (v != AuWbrCreate_Def) ++ au_show_wbr_create(m, v, sbinfo); ++ ++ v = sbinfo->si_wbr_copyup; ++ if (v != AuWbrCopyup_Def) ++ seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v)); ++ ++ v = au_opt_test(mnt_flags, ALWAYS_DIROPQ); ++ if (v != au_opt_test(AuOpt_Def, ALWAYS_DIROPQ)) ++ seq_printf(m, ",diropq=%c", v ? 'a' : 'w'); ++ ++ AuUInt(DIRWH, dirwh, sbinfo->si_dirwh); ++ ++ v = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC; ++ AuUInt(RDCACHE, rdcache, v); ++ ++ AuUInt(RDBLK, rdblk, sbinfo->si_rdblk); ++ AuUInt(RDHASH, rdhash, sbinfo->si_rdhash); ++ ++ au_fhsm_show(m, sbinfo); ++ ++ AuBool(SUM, sum); ++ /* AuBool(SUM_W, wsum); */ ++ AuBool(WARN_PERM, warn_perm); ++ AuBool(VERBOSE, verbose); ++ ++out: ++ /* be sure to print "br:" last */ ++ if (!sysaufs_brs) { ++ seq_puts(m, ",br:"); ++ au_show_brs(m, sb); ++ } ++ si_read_unlock(sb); ++ return 0; ++ ++#undef AuBool ++#undef AuStr ++#undef AuUInt ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* sum mode which returns the summation for statfs(2) */ ++ ++static u64 au_add_till_max(u64 a, u64 b) ++{ ++ u64 old; ++ ++ old = a; ++ a += b; ++ if (old <= a) ++ return a; ++ return ULLONG_MAX; ++} ++ ++static u64 au_mul_till_max(u64 a, long mul) ++{ ++ u64 old; ++ ++ old = a; ++ a *= mul; ++ if (old <= a) ++ return a; ++ return ULLONG_MAX; ++} ++ ++static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf) ++{ ++ int err; ++ long bsize, factor; ++ u64 blocks, bfree, bavail, files, ffree; ++ aufs_bindex_t bbot, bindex, i; ++ unsigned char shared; ++ struct path h_path; ++ struct super_block *h_sb; ++ ++ err = 0; ++ bsize = LONG_MAX; ++ files = 0; ++ ffree = 0; ++ blocks = 0; ++ bfree = 0; ++ bavail = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ h_sb = h_path.mnt->mnt_sb; ++ shared = 0; ++ for (i = 0; !shared && i < bindex; i++) ++ shared = (au_sbr_sb(sb, i) == h_sb); ++ if (shared) ++ continue; ++ ++ /* sb->s_root for NFS is unreliable */ ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, buf); ++ if (unlikely(err)) ++ goto out; ++ ++ if (bsize > buf->f_bsize) { ++ /* ++ * we will reduce bsize, so we have to expand blocks ++ * etc. to match them again ++ */ ++ factor = (bsize / buf->f_bsize); ++ blocks = au_mul_till_max(blocks, factor); ++ bfree = au_mul_till_max(bfree, factor); ++ bavail = au_mul_till_max(bavail, factor); ++ bsize = buf->f_bsize; ++ } ++ ++ factor = (buf->f_bsize / bsize); ++ blocks = au_add_till_max(blocks, ++ au_mul_till_max(buf->f_blocks, factor)); ++ bfree = au_add_till_max(bfree, ++ au_mul_till_max(buf->f_bfree, factor)); ++ bavail = au_add_till_max(bavail, ++ au_mul_till_max(buf->f_bavail, factor)); ++ files = au_add_till_max(files, buf->f_files); ++ ffree = au_add_till_max(ffree, buf->f_ffree); ++ } ++ ++ buf->f_bsize = bsize; ++ buf->f_blocks = blocks; ++ buf->f_bfree = bfree; ++ buf->f_bavail = bavail; ++ buf->f_files = files; ++ buf->f_ffree = ffree; ++ buf->f_frsize = 0; ++ ++out: ++ return err; ++} ++ ++static int aufs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ int err; ++ struct path h_path; ++ struct super_block *sb; ++ ++ /* lock free root dinfo */ ++ sb = dentry->d_sb; ++ si_noflush_read_lock(sb); ++ if (!au_opt_test(au_mntflags(sb), SUM)) { ++ /* sb->s_root for NFS is unreliable */ ++ h_path.mnt = au_sbr_mnt(sb, 0); ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, buf); ++ } else ++ err = au_statfs_sum(sb, buf); ++ si_read_unlock(sb); ++ ++ if (!err) { ++ buf->f_type = AUFS_SUPER_MAGIC; ++ buf->f_namelen = AUFS_MAX_NAMELEN; ++ memset(&buf->f_fsid, 0, sizeof(buf->f_fsid)); ++ } ++ /* buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; */ ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_sync_fs(struct super_block *sb, int wait) ++{ ++ int err, e; ++ aufs_bindex_t bbot, bindex; ++ struct au_branch *br; ++ struct super_block *h_sb; ++ ++ err = 0; ++ si_noflush_read_lock(sb); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_writable(br->br_perm)) ++ continue; ++ ++ h_sb = au_sbr_sb(sb, bindex); ++ if (h_sb->s_op->sync_fs) { ++ e = h_sb->s_op->sync_fs(h_sb, wait); ++ if (unlikely(e && !err)) ++ err = e; ++ /* go on even if an error happens */ ++ } ++ } ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* final actions when unmounting a file system */ ++static void aufs_put_super(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = au_sbi(sb); ++ if (!sbinfo) ++ return; ++ ++ dbgaufs_si_fin(sbinfo); ++ kobject_put(&sbinfo->si_kobj); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, ++ struct super_block *sb, void *arg) ++{ ++ void *array; ++ unsigned long long n, sz; ++ ++ array = NULL; ++ n = 0; ++ if (!*hint) ++ goto out; ++ ++ if (*hint > ULLONG_MAX / sizeof(array)) { ++ array = ERR_PTR(-EMFILE); ++ pr_err("hint %llu\n", *hint); ++ goto out; ++ } ++ ++ sz = sizeof(array) * *hint; ++ array = kzalloc(sz, GFP_NOFS); ++ if (unlikely(!array)) ++ array = vzalloc(sz); ++ if (unlikely(!array)) { ++ array = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ n = cb(sb, array, *hint, arg); ++ AuDebugOn(n > *hint); ++ ++out: ++ *hint = n; ++ return array; ++} ++ ++static unsigned long long au_iarray_cb(struct super_block *sb, void *a, ++ unsigned long long max __maybe_unused, ++ void *arg) ++{ ++ unsigned long long n; ++ struct inode **p, *inode; ++ struct list_head *head; ++ ++ n = 0; ++ p = a; ++ head = arg; ++ spin_lock(&sb->s_inode_list_lock); ++ list_for_each_entry(inode, head, i_sb_list) { ++ if (!au_is_bad_inode(inode) ++ && au_ii(inode)->ii_btop >= 0) { ++ spin_lock(&inode->i_lock); ++ if (atomic_read(&inode->i_count)) { ++ au_igrab(inode); ++ *p++ = inode; ++ n++; ++ AuDebugOn(n > max); ++ } ++ spin_unlock(&inode->i_lock); ++ } ++ } ++ spin_unlock(&sb->s_inode_list_lock); ++ ++ return n; ++} ++ ++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max) ++{ ++ *max = au_ninodes(sb); ++ return au_array_alloc(max, au_iarray_cb, sb, &sb->s_inodes); ++} ++ ++void au_iarray_free(struct inode **a, unsigned long long max) ++{ ++ unsigned long long ull; ++ ++ for (ull = 0; ull < max; ull++) ++ iput(a[ull]); ++ kvfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * refresh dentry and inode at remount time. ++ */ ++/* todo: consolidate with simple_reval_dpath() and au_reval_for_attr() */ ++static int au_do_refresh(struct dentry *dentry, unsigned int dir_flags, ++ struct dentry *parent) ++{ ++ int err; ++ ++ di_write_lock_child(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(dentry, parent); ++ if (!err && dir_flags) ++ au_hn_reset(d_inode(dentry), dir_flags); ++ di_read_unlock(parent, AuLock_IR); ++ di_write_unlock(dentry); ++ ++ return err; ++} ++ ++static int au_do_refresh_d(struct dentry *dentry, unsigned int sigen, ++ struct au_sbinfo *sbinfo, ++ const unsigned int dir_flags, unsigned int do_idop) ++{ ++ int err; ++ struct dentry *parent; ++ ++ err = 0; ++ parent = dget_parent(dentry); ++ if (!au_digen_test(parent, sigen) && au_digen_test(dentry, sigen)) { ++ if (d_really_is_positive(dentry)) { ++ if (!d_is_dir(dentry)) ++ err = au_do_refresh(dentry, /*dir_flags*/0, ++ parent); ++ else { ++ err = au_do_refresh(dentry, dir_flags, parent); ++ if (unlikely(err)) ++ au_fset_si(sbinfo, FAILED_REFRESH_DIR); ++ } ++ } else ++ err = au_do_refresh(dentry, /*dir_flags*/0, parent); ++ AuDbgDentry(dentry); ++ } ++ dput(parent); ++ ++ if (!err) { ++ if (do_idop) ++ au_refresh_dop(dentry, /*force_reval*/0); ++ } else ++ au_refresh_dop(dentry, /*force_reval*/1); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_refresh_d(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, i, j, ndentry, e; ++ unsigned int sigen; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries, *d; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root = sb->s_root; ++ const unsigned int dir_flags = au_hi_flags(d_inode(root), /*isdir*/1); ++ ++ if (do_idop) ++ au_refresh_dop(root, /*force_reval*/0); ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ sigen = au_sigen(sb); ++ sbinfo = au_sbi(sb); ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ d = dentries[j]; ++ e = au_do_refresh_d(d, sigen, sbinfo, dir_flags, ++ do_idop); ++ if (unlikely(e && !err)) ++ err = e; ++ /* go on even err */ ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int au_refresh_i(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, e; ++ unsigned int sigen; ++ unsigned long long max, ull; ++ struct inode *inode, **array; ++ ++ array = au_iarray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ sigen = au_sigen(sb); ++ for (ull = 0; ull < max; ull++) { ++ inode = array[ull]; ++ if (unlikely(!inode)) ++ break; ++ ++ e = 0; ++ ii_write_lock_child(inode); ++ if (au_iigen(inode, NULL) != sigen) { ++ e = au_refresh_hinode_self(inode); ++ if (unlikely(e)) { ++ au_refresh_iop(inode, /*force_getattr*/1); ++ pr_err("error %d, i%lu\n", e, inode->i_ino); ++ if (!err) ++ err = e; ++ /* go on even if err */ ++ } ++ } ++ if (!e && do_idop) ++ au_refresh_iop(inode, /*force_getattr*/0); ++ ii_write_unlock(inode); ++ } ++ ++ au_iarray_free(array, max); ++ ++out: ++ return err; ++} ++ ++static void au_remount_refresh(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, e; ++ unsigned int udba; ++ aufs_bindex_t bindex, bbot; ++ struct dentry *root; ++ struct inode *inode; ++ struct au_branch *br; ++ struct au_sbinfo *sbi; ++ ++ au_sigen_inc(sb); ++ sbi = au_sbi(sb); ++ au_fclr_si(sbi, FAILED_REFRESH_DIR); ++ ++ root = sb->s_root; ++ DiMustNoWaiters(root); ++ inode = d_inode(root); ++ IiMustNoWaiters(inode); ++ ++ udba = au_opt_udba(sb); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_hnotify_reset_br(udba, br, br->br_perm); ++ if (unlikely(err)) ++ AuIOErr("hnotify failed on br %d, %d, ignored\n", ++ bindex, err); ++ /* go on even if err */ ++ } ++ au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1)); ++ ++ if (do_idop) { ++ if (au_ftest_si(sbi, NO_DREVAL)) { ++ AuDebugOn(sb->s_d_op == &aufs_dop_noreval); ++ sb->s_d_op = &aufs_dop_noreval; ++ AuDebugOn(sbi->si_iop_array == aufs_iop_nogetattr); ++ sbi->si_iop_array = aufs_iop_nogetattr; ++ } else { ++ AuDebugOn(sb->s_d_op == &aufs_dop); ++ sb->s_d_op = &aufs_dop; ++ AuDebugOn(sbi->si_iop_array == aufs_iop); ++ sbi->si_iop_array = aufs_iop; ++ } ++ pr_info("reset to %pf and %pf\n", ++ sb->s_d_op, sbi->si_iop_array); ++ } ++ ++ di_write_unlock(root); ++ err = au_refresh_d(sb, do_idop); ++ e = au_refresh_i(sb, do_idop); ++ if (unlikely(e && !err)) ++ err = e; ++ /* aufs_write_lock() calls ..._child() */ ++ di_write_lock_child(root); ++ ++ au_cpup_attr_all(inode, /*force*/1); ++ ++ if (unlikely(err)) ++ AuIOErr("refresh failed, ignored, %d\n", err); ++} ++ ++/* stop extra interpretation of errno in mount(8), and strange error messages */ ++static int cvt_err(int err) ++{ ++ AuTraceErr(err); ++ ++ switch (err) { ++ case -ENOENT: ++ case -ENOTDIR: ++ case -EEXIST: ++ case -EIO: ++ err = -EINVAL; ++ } ++ return err; ++} ++ ++static int aufs_remount_fs(struct super_block *sb, int *flags, char *data) ++{ ++ int err, do_dx; ++ unsigned int mntflags; ++ struct au_opts opts = { ++ .opt = NULL ++ }; ++ struct dentry *root; ++ struct inode *inode; ++ struct au_sbinfo *sbinfo; ++ ++ err = 0; ++ root = sb->s_root; ++ if (!data || !*data) { ++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (!err) { ++ di_write_lock_child(root); ++ err = au_opts_verify(sb, *flags, /*pending*/0); ++ aufs_write_unlock(root); ++ } ++ goto out; ++ } ++ ++ err = -ENOMEM; ++ opts.opt = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!opts.opt)) ++ goto out; ++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); ++ opts.flags = AuOpts_REMOUNT; ++ opts.sb_flags = *flags; ++ ++ /* parse it before aufs lock */ ++ err = au_opts_parse(sb, data, &opts); ++ if (unlikely(err)) ++ goto out_opts; ++ ++ sbinfo = au_sbi(sb); ++ inode = d_inode(root); ++ inode_lock(inode); ++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_mtx; ++ di_write_lock_child(root); ++ ++ /* au_opts_remount() may return an error */ ++ err = au_opts_remount(sb, &opts); ++ au_opts_free(&opts); ++ ++ if (au_ftest_opts(opts.flags, REFRESH)) ++ au_remount_refresh(sb, au_ftest_opts(opts.flags, REFRESH_IDOP)); ++ ++ if (au_ftest_opts(opts.flags, REFRESH_DYAOP)) { ++ mntflags = au_mntflags(sb); ++ do_dx = !!au_opt_test(mntflags, DIO); ++ au_dy_arefresh(do_dx); ++ } ++ ++ au_fhsm_wrote_all(sb, /*force*/1); /* ?? */ ++ aufs_write_unlock(root); ++ ++out_mtx: ++ inode_unlock(inode); ++out_opts: ++ free_page((unsigned long)opts.opt); ++out: ++ err = cvt_err(err); ++ AuTraceErr(err); ++ return err; ++} ++ ++static const struct super_operations aufs_sop = { ++ .alloc_inode = aufs_alloc_inode, ++ .destroy_inode = aufs_destroy_inode, ++ /* always deleting, no clearing */ ++ .drop_inode = generic_delete_inode, ++ .show_options = aufs_show_options, ++ .statfs = aufs_statfs, ++ .put_super = aufs_put_super, ++ .sync_fs = aufs_sync_fs, ++ .remount_fs = aufs_remount_fs ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int alloc_root(struct super_block *sb) ++{ ++ int err; ++ struct inode *inode; ++ struct dentry *root; ++ ++ err = -ENOMEM; ++ inode = au_iget_locked(sb, AUFS_ROOT_INO); ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out; ++ ++ inode->i_op = aufs_iop + AuIop_DIR; /* with getattr by default */ ++ inode->i_fop = &aufs_dir_fop; ++ inode->i_mode = S_IFDIR; ++ set_nlink(inode, 2); ++ unlock_new_inode(inode); ++ ++ root = d_make_root(inode); ++ if (unlikely(!root)) ++ goto out; ++ err = PTR_ERR(root); ++ if (IS_ERR(root)) ++ goto out; ++ ++ err = au_di_init(root); ++ if (!err) { ++ sb->s_root = root; ++ return 0; /* success */ ++ } ++ dput(root); ++ ++out: ++ return err; ++} ++ ++static int aufs_fill_super(struct super_block *sb, void *raw_data, ++ int silent __maybe_unused) ++{ ++ int err; ++ struct au_opts opts = { ++ .opt = NULL ++ }; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root; ++ struct inode *inode; ++ char *arg = raw_data; ++ ++ if (unlikely(!arg || !*arg)) { ++ err = -EINVAL; ++ pr_err("no arg\n"); ++ goto out; ++ } ++ ++ err = -ENOMEM; ++ opts.opt = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!opts.opt)) ++ goto out; ++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); ++ opts.sb_flags = sb->s_flags; ++ ++ err = au_si_alloc(sb); ++ if (unlikely(err)) ++ goto out_opts; ++ sbinfo = au_sbi(sb); ++ ++ /* all timestamps always follow the ones on the branch */ ++ sb->s_flags |= MS_NOATIME | MS_NODIRATIME; ++ sb->s_op = &aufs_sop; ++ sb->s_d_op = &aufs_dop; ++ sb->s_magic = AUFS_SUPER_MAGIC; ++ sb->s_maxbytes = 0; ++ sb->s_stack_depth = 1; ++ au_export_init(sb); ++ /* au_xattr_init(sb); */ ++ ++ err = alloc_root(sb); ++ if (unlikely(err)) { ++ si_write_unlock(sb); ++ goto out_info; ++ } ++ root = sb->s_root; ++ inode = d_inode(root); ++ ++ /* ++ * actually we can parse options regardless aufs lock here. ++ * but at remount time, parsing must be done before aufs lock. ++ * so we follow the same rule. ++ */ ++ ii_write_lock_parent(inode); ++ aufs_write_unlock(root); ++ err = au_opts_parse(sb, arg, &opts); ++ if (unlikely(err)) ++ goto out_root; ++ ++ /* lock vfs_inode first, then aufs. */ ++ inode_lock(inode); ++ aufs_write_lock(root); ++ err = au_opts_mount(sb, &opts); ++ au_opts_free(&opts); ++ if (!err && au_ftest_si(sbinfo, NO_DREVAL)) { ++ sb->s_d_op = &aufs_dop_noreval; ++ pr_info("%pf\n", sb->s_d_op); ++ au_refresh_dop(root, /*force_reval*/0); ++ sbinfo->si_iop_array = aufs_iop_nogetattr; ++ au_refresh_iop(inode, /*force_getattr*/0); ++ } ++ aufs_write_unlock(root); ++ inode_unlock(inode); ++ if (!err) ++ goto out_opts; /* success */ ++ ++out_root: ++ dput(root); ++ sb->s_root = NULL; ++out_info: ++ dbgaufs_si_fin(sbinfo); ++ kobject_put(&sbinfo->si_kobj); ++ sb->s_fs_info = NULL; ++out_opts: ++ free_page((unsigned long)opts.opt); ++out: ++ AuTraceErr(err); ++ err = cvt_err(err); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *aufs_mount(struct file_system_type *fs_type, int flags, ++ const char *dev_name __maybe_unused, ++ void *raw_data) ++{ ++ struct dentry *root; ++ struct super_block *sb; ++ ++ /* all timestamps always follow the ones on the branch */ ++ /* mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; */ ++ root = mount_nodev(fs_type, flags, raw_data, aufs_fill_super); ++ if (IS_ERR(root)) ++ goto out; ++ ++ sb = root->d_sb; ++ si_write_lock(sb, !AuLock_FLUSH); ++ sysaufs_brs_add(sb, 0); ++ si_write_unlock(sb); ++ au_sbilist_add(sb); ++ ++out: ++ return root; ++} ++ ++static void aufs_kill_sb(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo) { ++ au_sbilist_del(sb); ++ aufs_write_lock(sb->s_root); ++ au_fhsm_fin(sb); ++ if (sbinfo->si_wbr_create_ops->fin) ++ sbinfo->si_wbr_create_ops->fin(sb); ++ if (au_opt_test(sbinfo->si_mntflags, UDBA_HNOTIFY)) { ++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_NONE); ++ au_remount_refresh(sb, /*do_idop*/0); ++ } ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_put(sb, /*verbose*/1); ++ au_xino_clr(sb); ++ sbinfo->si_sb = NULL; ++ aufs_write_unlock(sb->s_root); ++ au_nwt_flush(&sbinfo->si_nowait); ++ } ++ kill_anon_super(sb); ++} ++ ++struct file_system_type aufs_fs_type = { ++ .name = AUFS_FSTYPE, ++ /* a race between rename and others */ ++ .fs_flags = FS_RENAME_DOES_D_MOVE, ++ .mount = aufs_mount, ++ .kill_sb = aufs_kill_sb, ++ /* no need to __module_get() and module_put(). */ ++ .owner = THIS_MODULE, ++}; +diff --git a/fs/aufs/super.h b/fs/aufs/super.h +new file mode 100644 +index 0000000..b8ca149 +--- /dev/null ++++ b/fs/aufs/super.h +@@ -0,0 +1,625 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * super_block operations ++ */ ++ ++#ifndef __AUFS_SUPER_H__ ++#define __AUFS_SUPER_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include "rwsem.h" ++#include "spl.h" ++#include "wkq.h" ++ ++/* policies to select one among multiple writable branches */ ++struct au_wbr_copyup_operations { ++ int (*copyup)(struct dentry *dentry); ++}; ++ ++#define AuWbr_DIR 1 /* target is a dir */ ++#define AuWbr_PARENT (1 << 1) /* always require a parent */ ++ ++#define au_ftest_wbr(flags, name) ((flags) & AuWbr_##name) ++#define au_fset_wbr(flags, name) { (flags) |= AuWbr_##name; } ++#define au_fclr_wbr(flags, name) { (flags) &= ~AuWbr_##name; } ++ ++struct au_wbr_create_operations { ++ int (*create)(struct dentry *dentry, unsigned int flags); ++ int (*init)(struct super_block *sb); ++ int (*fin)(struct super_block *sb); ++}; ++ ++struct au_wbr_mfs { ++ struct mutex mfs_lock; /* protect this structure */ ++ unsigned long mfs_jiffy; ++ unsigned long mfs_expire; ++ aufs_bindex_t mfs_bindex; ++ ++ unsigned long long mfsrr_bytes; ++ unsigned long long mfsrr_watermark; ++}; ++ ++#define AuPlink_NHASH 100 ++static inline int au_plink_hash(ino_t ino) ++{ ++ return ino % AuPlink_NHASH; ++} ++ ++/* File-based Hierarchical Storage Management */ ++struct au_fhsm { ++#ifdef CONFIG_AUFS_FHSM ++ /* allow only one process who can receive the notification */ ++ spinlock_t fhsm_spin; ++ pid_t fhsm_pid; ++ wait_queue_head_t fhsm_wqh; ++ atomic_t fhsm_readable; ++ ++ /* these are protected by si_rwsem */ ++ unsigned long fhsm_expire; ++ aufs_bindex_t fhsm_bottom; ++#endif ++}; ++ ++#define AU_PIDSTEP (int)(BITS_TO_LONGS(PID_MAX_DEFAULT) * BITS_PER_LONG) ++#define AU_NPIDMAP (int)DIV_ROUND_UP(PID_MAX_LIMIT, AU_PIDSTEP) ++struct au_si_pid { ++ unsigned long *pid_bitmap[AU_NPIDMAP]; ++ struct mutex pid_mtx; ++}; ++ ++struct au_branch; ++struct au_sbinfo { ++ /* nowait tasks in the system-wide workqueue */ ++ struct au_nowait_tasks si_nowait; ++ ++ /* ++ * tried sb->s_umount, but failed due to the dependecy between i_mutex. ++ * rwsem for au_sbinfo is necessary. ++ */ ++ struct au_rwsem si_rwsem; ++ ++ /* prevent recursive locking in deleting inode */ ++ struct au_si_pid au_si_pid; ++ ++ /* ++ * dirty approach to protect sb->sb_inodes and ->s_files (gone) from ++ * remount. ++ */ ++ struct percpu_counter si_ninodes, si_nfiles; ++ ++ /* branch management */ ++ unsigned int si_generation; ++ ++ /* see AuSi_ flags */ ++ unsigned char au_si_status; ++ ++ aufs_bindex_t si_bbot; ++ ++ /* dirty trick to keep br_id plus */ ++ unsigned int si_last_br_id : ++ sizeof(aufs_bindex_t) * BITS_PER_BYTE - 1; ++ struct au_branch **si_branch; ++ ++ /* policy to select a writable branch */ ++ unsigned char si_wbr_copyup; ++ unsigned char si_wbr_create; ++ struct au_wbr_copyup_operations *si_wbr_copyup_ops; ++ struct au_wbr_create_operations *si_wbr_create_ops; ++ ++ /* round robin */ ++ atomic_t si_wbr_rr_next; ++ ++ /* most free space */ ++ struct au_wbr_mfs si_wbr_mfs; ++ ++ /* File-based Hierarchical Storage Management */ ++ struct au_fhsm si_fhsm; ++ ++ /* mount flags */ ++ /* include/asm-ia64/siginfo.h defines a macro named si_flags */ ++ unsigned int si_mntflags; ++ ++ /* external inode number (bitmap and translation table) */ ++ vfs_readf_t si_xread; ++ vfs_writef_t si_xwrite; ++ struct file *si_xib; ++ struct mutex si_xib_mtx; /* protect xib members */ ++ unsigned long *si_xib_buf; ++ unsigned long si_xib_last_pindex; ++ int si_xib_next_bit; ++ aufs_bindex_t si_xino_brid; ++ unsigned long si_xino_jiffy; ++ unsigned long si_xino_expire; ++ /* reserved for future use */ ++ /* unsigned long long si_xib_limit; */ /* Max xib file size */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++ /* i_generation */ ++ struct file *si_xigen; ++ atomic_t si_xigen_next; ++#endif ++ ++ /* dirty trick to suppoer atomic_open */ ++ struct au_sphlhead si_aopen; ++ ++ /* vdir parameters */ ++ unsigned long si_rdcache; /* max cache time in jiffies */ ++ unsigned int si_rdblk; /* deblk size */ ++ unsigned int si_rdhash; /* hash size */ ++ ++ /* ++ * If the number of whiteouts are larger than si_dirwh, leave all of ++ * them after au_whtmp_ren to reduce the cost of rmdir(2). ++ * future fsck.aufs or kernel thread will remove them later. ++ * Otherwise, remove all whiteouts and the dir in rmdir(2). ++ */ ++ unsigned int si_dirwh; ++ ++ /* pseudo_link list */ ++ struct au_sphlhead si_plink[AuPlink_NHASH]; ++ wait_queue_head_t si_plink_wq; ++ spinlock_t si_plink_maint_lock; ++ pid_t si_plink_maint_pid; ++ ++ /* file list */ ++ struct au_sphlhead si_files; ++ ++ /* with/without getattr, brother of sb->s_d_op */ ++ struct inode_operations *si_iop_array; ++ ++ /* ++ * sysfs and lifetime management. ++ * this is not a small structure and it may be a waste of memory in case ++ * of sysfs is disabled, particulary when many aufs-es are mounted. ++ * but using sysfs is majority. ++ */ ++ struct kobject si_kobj; ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *si_dbgaufs; ++ struct dentry *si_dbgaufs_plink; ++ struct dentry *si_dbgaufs_xib; ++#ifdef CONFIG_AUFS_EXPORT ++ struct dentry *si_dbgaufs_xigen; ++#endif ++#endif ++ ++#ifdef CONFIG_AUFS_SBILIST ++ struct hlist_node si_list; ++#endif ++ ++ /* dirty, necessary for unmounting, sysfs and sysrq */ ++ struct super_block *si_sb; ++}; ++ ++/* sbinfo status flags */ ++/* ++ * set true when refresh_dirs() failed at remount time. ++ * then try refreshing dirs at access time again. ++ * if it is false, refreshing dirs at access time is unnecesary ++ */ ++#define AuSi_FAILED_REFRESH_DIR 1 ++#define AuSi_FHSM (1 << 1) /* fhsm is active now */ ++#define AuSi_NO_DREVAL (1 << 2) /* disable all d_revalidate */ ++ ++#ifndef CONFIG_AUFS_FHSM ++#undef AuSi_FHSM ++#define AuSi_FHSM 0 ++#endif ++ ++static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi, ++ unsigned int flag) ++{ ++ AuRwMustAnyLock(&sbi->si_rwsem); ++ return sbi->au_si_status & flag; ++} ++#define au_ftest_si(sbinfo, name) au_do_ftest_si(sbinfo, AuSi_##name) ++#define au_fset_si(sbinfo, name) do { \ ++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ ++ (sbinfo)->au_si_status |= AuSi_##name; \ ++} while (0) ++#define au_fclr_si(sbinfo, name) do { \ ++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ ++ (sbinfo)->au_si_status &= ~AuSi_##name; \ ++} while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policy to select one among writable branches */ ++#define AuWbrCopyup(sbinfo, ...) \ ++ ((sbinfo)->si_wbr_copyup_ops->copyup(__VA_ARGS__)) ++#define AuWbrCreate(sbinfo, ...) \ ++ ((sbinfo)->si_wbr_create_ops->create(__VA_ARGS__)) ++ ++/* flags for si_read_lock()/aufs_read_lock()/di_read_lock() */ ++#define AuLock_DW 1 /* write-lock dentry */ ++#define AuLock_IR (1 << 1) /* read-lock inode */ ++#define AuLock_IW (1 << 2) /* write-lock inode */ ++#define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */ ++#define AuLock_DIRS (1 << 4) /* target is a pair of dirs */ ++#define AuLock_NOPLM (1 << 5) /* return err in plm mode */ ++#define AuLock_NOPLMW (1 << 6) /* wait for plm mode ends */ ++#define AuLock_GEN (1 << 7) /* test digen/iigen */ ++#define au_ftest_lock(flags, name) ((flags) & AuLock_##name) ++#define au_fset_lock(flags, name) \ ++ do { (flags) |= AuLock_##name; } while (0) ++#define au_fclr_lock(flags, name) \ ++ do { (flags) &= ~AuLock_##name; } while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* super.c */ ++extern struct file_system_type aufs_fs_type; ++struct inode *au_iget_locked(struct super_block *sb, ino_t ino); ++typedef unsigned long long (*au_arraycb_t)(struct super_block *sb, void *array, ++ unsigned long long max, void *arg); ++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, ++ struct super_block *sb, void *arg); ++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max); ++void au_iarray_free(struct inode **a, unsigned long long max); ++ ++/* sbinfo.c */ ++void au_si_free(struct kobject *kobj); ++int au_si_alloc(struct super_block *sb); ++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr); ++ ++unsigned int au_sigen_inc(struct super_block *sb); ++aufs_bindex_t au_new_br_id(struct super_block *sb); ++ ++int si_read_lock(struct super_block *sb, int flags); ++int si_write_lock(struct super_block *sb, int flags); ++int aufs_read_lock(struct dentry *dentry, int flags); ++void aufs_read_unlock(struct dentry *dentry, int flags); ++void aufs_write_lock(struct dentry *dentry); ++void aufs_write_unlock(struct dentry *dentry); ++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags); ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++/* wbr_policy.c */ ++extern struct au_wbr_copyup_operations au_wbr_copyup_ops[]; ++extern struct au_wbr_create_operations au_wbr_create_ops[]; ++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex); ++int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t btop); ++ ++/* mvdown.c */ ++int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *arg); ++ ++#ifdef CONFIG_AUFS_FHSM ++/* fhsm.c */ ++ ++static inline pid_t au_fhsm_pid(struct au_fhsm *fhsm) ++{ ++ pid_t pid; ++ ++ spin_lock(&fhsm->fhsm_spin); ++ pid = fhsm->fhsm_pid; ++ spin_unlock(&fhsm->fhsm_spin); ++ ++ return pid; ++} ++ ++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force); ++void au_fhsm_wrote_all(struct super_block *sb, int force); ++int au_fhsm_fd(struct super_block *sb, int oflags); ++int au_fhsm_br_alloc(struct au_branch *br); ++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex); ++void au_fhsm_fin(struct super_block *sb); ++void au_fhsm_init(struct au_sbinfo *sbinfo); ++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec); ++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo); ++#else ++AuStubVoid(au_fhsm_wrote, struct super_block *sb, aufs_bindex_t bindex, ++ int force) ++AuStubVoid(au_fhsm_wrote_all, struct super_block *sb, int force) ++AuStub(int, au_fhsm_fd, return -EOPNOTSUPP, struct super_block *sb, int oflags) ++AuStub(pid_t, au_fhsm_pid, return 0, struct au_fhsm *fhsm) ++AuStubInt0(au_fhsm_br_alloc, struct au_branch *br) ++AuStubVoid(au_fhsm_set_bottom, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(au_fhsm_fin, struct super_block *sb) ++AuStubVoid(au_fhsm_init, struct au_sbinfo *sbinfo) ++AuStubVoid(au_fhsm_set, struct au_sbinfo *sbinfo, unsigned int sec) ++AuStubVoid(au_fhsm_show, struct seq_file *seq, struct au_sbinfo *sbinfo) ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_sbinfo *au_sbi(struct super_block *sb) ++{ ++ return sb->s_fs_info; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++int au_test_nfsd(void); ++void au_export_init(struct super_block *sb); ++void au_xigen_inc(struct inode *inode); ++int au_xigen_new(struct inode *inode); ++int au_xigen_set(struct super_block *sb, struct file *base); ++void au_xigen_clr(struct super_block *sb); ++ ++static inline int au_busy_or_stale(void) ++{ ++ if (!au_test_nfsd()) ++ return -EBUSY; ++ return -ESTALE; ++} ++#else ++AuStubInt0(au_test_nfsd, void) ++AuStubVoid(au_export_init, struct super_block *sb) ++AuStubVoid(au_xigen_inc, struct inode *inode) ++AuStubInt0(au_xigen_new, struct inode *inode) ++AuStubInt0(au_xigen_set, struct super_block *sb, struct file *base) ++AuStubVoid(au_xigen_clr, struct super_block *sb) ++AuStub(int, au_busy_or_stale, return -EBUSY, void) ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_SBILIST ++/* module.c */ ++extern struct au_sphlhead au_sbilist; ++ ++static inline void au_sbilist_init(void) ++{ ++ au_sphl_init(&au_sbilist); ++} ++ ++static inline void au_sbilist_add(struct super_block *sb) ++{ ++ au_sphl_add(&au_sbi(sb)->si_list, &au_sbilist); ++} ++ ++static inline void au_sbilist_del(struct super_block *sb) ++{ ++ au_sphl_del(&au_sbi(sb)->si_list, &au_sbilist); ++} ++ ++#ifdef CONFIG_AUFS_MAGIC_SYSRQ ++static inline void au_sbilist_lock(void) ++{ ++ spin_lock(&au_sbilist.spin); ++} ++ ++static inline void au_sbilist_unlock(void) ++{ ++ spin_unlock(&au_sbilist.spin); ++} ++#define AuGFP_SBILIST GFP_ATOMIC ++#else ++AuStubVoid(au_sbilist_lock, void) ++AuStubVoid(au_sbilist_unlock, void) ++#define AuGFP_SBILIST GFP_NOFS ++#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ ++#else ++AuStubVoid(au_sbilist_init, void) ++AuStubVoid(au_sbilist_add, struct super_block *sb) ++AuStubVoid(au_sbilist_del, struct super_block *sb) ++AuStubVoid(au_sbilist_lock, void) ++AuStubVoid(au_sbilist_unlock, void) ++#define AuGFP_SBILIST GFP_NOFS ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void dbgaufs_si_null(struct au_sbinfo *sbinfo) ++{ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++#ifdef CONFIG_DEBUG_FS ++ sbinfo->si_dbgaufs = NULL; ++ sbinfo->si_dbgaufs_plink = NULL; ++ sbinfo->si_dbgaufs_xib = NULL; ++#ifdef CONFIG_AUFS_EXPORT ++ sbinfo->si_dbgaufs_xigen = NULL; ++#endif ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void si_pid_idx_bit(int *idx, pid_t *bit) ++{ ++ /* the origin of pid is 1, but the bitmap's is 0 */ ++ *bit = current->pid - 1; ++ *idx = *bit / AU_PIDSTEP; ++ *bit %= AU_PIDSTEP; ++} ++ ++static inline int si_pid_test(struct super_block *sb) ++{ ++ pid_t bit; ++ int idx; ++ unsigned long *bitmap; ++ ++ si_pid_idx_bit(&idx, &bit); ++ bitmap = au_sbi(sb)->au_si_pid.pid_bitmap[idx]; ++ if (bitmap) ++ return test_bit(bit, bitmap); ++ return 0; ++} ++ ++static inline void si_pid_clr(struct super_block *sb) ++{ ++ pid_t bit; ++ int idx; ++ unsigned long *bitmap; ++ ++ si_pid_idx_bit(&idx, &bit); ++ bitmap = au_sbi(sb)->au_si_pid.pid_bitmap[idx]; ++ BUG_ON(!bitmap); ++ AuDebugOn(!test_bit(bit, bitmap)); ++ clear_bit(bit, bitmap); ++ /* smp_mb(); */ ++} ++ ++void si_pid_set(struct super_block *sb); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock superblock. mainly for entry point functions */ ++/* ++ * __si_read_lock, __si_write_lock, ++ * __si_read_unlock, __si_write_unlock, __si_downgrade_lock ++ */ ++AuSimpleRwsemFuncs(__si, struct super_block *sb, &au_sbi(sb)->si_rwsem); ++ ++#define SiMustNoWaiters(sb) AuRwMustNoWaiters(&au_sbi(sb)->si_rwsem) ++#define SiMustAnyLock(sb) AuRwMustAnyLock(&au_sbi(sb)->si_rwsem) ++#define SiMustWriteLock(sb) AuRwMustWriteLock(&au_sbi(sb)->si_rwsem) ++ ++static inline void si_noflush_read_lock(struct super_block *sb) ++{ ++ __si_read_lock(sb); ++ si_pid_set(sb); ++} ++ ++static inline int si_noflush_read_trylock(struct super_block *sb) ++{ ++ int locked; ++ ++ locked = __si_read_trylock(sb); ++ if (locked) ++ si_pid_set(sb); ++ return locked; ++} ++ ++static inline void si_noflush_write_lock(struct super_block *sb) ++{ ++ __si_write_lock(sb); ++ si_pid_set(sb); ++} ++ ++static inline int si_noflush_write_trylock(struct super_block *sb) ++{ ++ int locked; ++ ++ locked = __si_write_trylock(sb); ++ if (locked) ++ si_pid_set(sb); ++ return locked; ++} ++ ++#if 0 /* reserved */ ++static inline int si_read_trylock(struct super_block *sb, int flags) ++{ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ return si_noflush_read_trylock(sb); ++} ++#endif ++ ++static inline void si_read_unlock(struct super_block *sb) ++{ ++ si_pid_clr(sb); ++ __si_read_unlock(sb); ++} ++ ++#if 0 /* reserved */ ++static inline int si_write_trylock(struct super_block *sb, int flags) ++{ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ return si_noflush_write_trylock(sb); ++} ++#endif ++ ++static inline void si_write_unlock(struct super_block *sb) ++{ ++ si_pid_clr(sb); ++ __si_write_unlock(sb); ++} ++ ++#if 0 /* reserved */ ++static inline void si_downgrade_lock(struct super_block *sb) ++{ ++ __si_downgrade_lock(sb); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline aufs_bindex_t au_sbbot(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_bbot; ++} ++ ++static inline unsigned int au_mntflags(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_mntflags; ++} ++ ++static inline unsigned int au_sigen(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_generation; ++} ++ ++static inline unsigned long long au_ninodes(struct super_block *sb) ++{ ++ s64 n = percpu_counter_sum(&au_sbi(sb)->si_ninodes); ++ ++ BUG_ON(n < 0); ++ return n; ++} ++ ++static inline void au_ninodes_inc(struct super_block *sb) ++{ ++ percpu_counter_inc(&au_sbi(sb)->si_ninodes); ++} ++ ++static inline void au_ninodes_dec(struct super_block *sb) ++{ ++ percpu_counter_dec(&au_sbi(sb)->si_ninodes); ++} ++ ++static inline unsigned long long au_nfiles(struct super_block *sb) ++{ ++ s64 n = percpu_counter_sum(&au_sbi(sb)->si_nfiles); ++ ++ BUG_ON(n < 0); ++ return n; ++} ++ ++static inline void au_nfiles_inc(struct super_block *sb) ++{ ++ percpu_counter_inc(&au_sbi(sb)->si_nfiles); ++} ++ ++static inline void au_nfiles_dec(struct super_block *sb) ++{ ++ percpu_counter_dec(&au_sbi(sb)->si_nfiles); ++} ++ ++static inline struct au_branch *au_sbr(struct super_block *sb, ++ aufs_bindex_t bindex) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_branch[0 + bindex]; ++} ++ ++static inline void au_xino_brid_set(struct super_block *sb, aufs_bindex_t brid) ++{ ++ SiMustWriteLock(sb); ++ au_sbi(sb)->si_xino_brid = brid; ++} ++ ++static inline aufs_bindex_t au_xino_brid(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_xino_brid; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_SUPER_H__ */ +diff --git a/fs/aufs/sysaufs.c b/fs/aufs/sysaufs.c +new file mode 100644 +index 0000000..8ec10fb3 +--- /dev/null ++++ b/fs/aufs/sysaufs.c +@@ -0,0 +1,91 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * sysfs interface and lifetime management ++ * they are necessary regardless sysfs is disabled. ++ */ ++ ++#include ++#include "aufs.h" ++ ++unsigned long sysaufs_si_mask; ++struct kset *sysaufs_kset; ++ ++#define AuSiAttr(_name) { \ ++ .attr = { .name = __stringify(_name), .mode = 0444 }, \ ++ .show = sysaufs_si_##_name, \ ++} ++ ++static struct sysaufs_si_attr sysaufs_si_attr_xi_path = AuSiAttr(xi_path); ++struct attribute *sysaufs_si_attrs[] = { ++ &sysaufs_si_attr_xi_path.attr, ++ NULL, ++}; ++ ++static const struct sysfs_ops au_sbi_ops = { ++ .show = sysaufs_si_show ++}; ++ ++static struct kobj_type au_sbi_ktype = { ++ .release = au_si_free, ++ .sysfs_ops = &au_sbi_ops, ++ .default_attrs = sysaufs_si_attrs ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int sysaufs_si_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ ++ sbinfo->si_kobj.kset = sysaufs_kset; ++ /* cf. sysaufs_name() */ ++ err = kobject_init_and_add ++ (&sbinfo->si_kobj, &au_sbi_ktype, /*&sysaufs_kset->kobj*/NULL, ++ SysaufsSiNamePrefix "%lx", sysaufs_si_id(sbinfo)); ++ ++ dbgaufs_si_null(sbinfo); ++ if (!err) { ++ err = dbgaufs_si_init(sbinfo); ++ if (unlikely(err)) ++ kobject_put(&sbinfo->si_kobj); ++ } ++ return err; ++} ++ ++void sysaufs_fin(void) ++{ ++ dbgaufs_fin(); ++ sysfs_remove_group(&sysaufs_kset->kobj, sysaufs_attr_group); ++ kset_unregister(sysaufs_kset); ++} ++ ++int __init sysaufs_init(void) ++{ ++ int err; ++ ++ do { ++ get_random_bytes(&sysaufs_si_mask, sizeof(sysaufs_si_mask)); ++ } while (!sysaufs_si_mask); ++ ++ err = -EINVAL; ++ sysaufs_kset = kset_create_and_add(AUFS_NAME, NULL, fs_kobj); ++ if (unlikely(!sysaufs_kset)) ++ goto out; ++ err = PTR_ERR(sysaufs_kset); ++ if (IS_ERR(sysaufs_kset)) ++ goto out; ++ err = sysfs_create_group(&sysaufs_kset->kobj, sysaufs_attr_group); ++ if (unlikely(err)) { ++ kset_unregister(sysaufs_kset); ++ goto out; ++ } ++ ++ err = dbgaufs_init(); ++ if (unlikely(err)) ++ sysaufs_fin(); ++out: ++ return err; ++} +diff --git a/fs/aufs/sysaufs.h b/fs/aufs/sysaufs.h +new file mode 100644 +index 0000000..1f79983 +--- /dev/null ++++ b/fs/aufs/sysaufs.h +@@ -0,0 +1,88 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * sysfs interface and mount lifetime management ++ */ ++ ++#ifndef __SYSAUFS_H__ ++#define __SYSAUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "module.h" ++ ++struct super_block; ++struct au_sbinfo; ++ ++struct sysaufs_si_attr { ++ struct attribute attr; ++ int (*show)(struct seq_file *seq, struct super_block *sb); ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* sysaufs.c */ ++extern unsigned long sysaufs_si_mask; ++extern struct kset *sysaufs_kset; ++extern struct attribute *sysaufs_si_attrs[]; ++int sysaufs_si_init(struct au_sbinfo *sbinfo); ++int __init sysaufs_init(void); ++void sysaufs_fin(void); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* some people doesn't like to show a pointer in kernel */ ++static inline unsigned long sysaufs_si_id(struct au_sbinfo *sbinfo) ++{ ++ return sysaufs_si_mask ^ (unsigned long)sbinfo; ++} ++ ++#define SysaufsSiNamePrefix "si_" ++#define SysaufsSiNameLen (sizeof(SysaufsSiNamePrefix) + 16) ++static inline void sysaufs_name(struct au_sbinfo *sbinfo, char *name) ++{ ++ snprintf(name, SysaufsSiNameLen, SysaufsSiNamePrefix "%lx", ++ sysaufs_si_id(sbinfo)); ++} ++ ++struct au_branch; ++#ifdef CONFIG_SYSFS ++/* sysfs.c */ ++extern struct attribute_group *sysaufs_attr_group; ++ ++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb); ++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, ++ char *buf); ++long au_brinfo_ioctl(struct file *file, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg); ++#endif ++ ++void sysaufs_br_init(struct au_branch *br); ++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); ++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); ++ ++#define sysaufs_brs_init() do {} while (0) ++ ++#else ++#define sysaufs_attr_group NULL ++ ++AuStubInt0(sysaufs_si_xi_path, struct seq_file *seq, struct super_block *sb) ++AuStub(ssize_t, sysaufs_si_show, return 0, struct kobject *kobj, ++ struct attribute *attr, char *buf) ++AuStubVoid(sysaufs_br_init, struct au_branch *br) ++AuStubVoid(sysaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(sysaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) ++ ++static inline void sysaufs_brs_init(void) ++{ ++ sysaufs_brs = 0; ++} ++ ++#endif /* CONFIG_SYSFS */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __SYSAUFS_H__ */ +diff --git a/fs/aufs/sysfs.c b/fs/aufs/sysfs.c +new file mode 100644 +index 0000000..0efb77a +--- /dev/null ++++ b/fs/aufs/sysfs.c +@@ -0,0 +1,340 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * sysfs interface ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++static struct attribute *au_attr[] = { ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct attribute_group sysaufs_attr_group_body = { ++ .attrs = au_attr ++}; ++ ++struct attribute_group *sysaufs_attr_group = &sysaufs_attr_group_body; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb) ++{ ++ int err; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (au_opt_test(au_mntflags(sb), XINO)) { ++ err = au_xino_path(seq, au_sbi(sb)->si_xib); ++ seq_putc(seq, '\n'); ++ } ++ return err; ++} ++ ++/* ++ * the lifetime of branch is independent from the entry under sysfs. ++ * sysfs handles the lifetime of the entry, and never call ->show() after it is ++ * unlinked. ++ */ ++static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb, ++ aufs_bindex_t bindex, int idx) ++{ ++ int err; ++ struct path path; ++ struct dentry *root; ++ struct au_branch *br; ++ au_br_perm_str_t perm; ++ ++ AuDbg("b%d\n", bindex); ++ ++ err = 0; ++ root = sb->s_root; ++ di_read_lock_parent(root, !AuLock_IR); ++ br = au_sbr(sb, bindex); ++ ++ switch (idx) { ++ case AuBrSysfs_BR: ++ path.mnt = au_br_mnt(br); ++ path.dentry = au_h_dptr(root, bindex); ++ err = au_seq_path(seq, &path); ++ if (!err) { ++ au_optstr_br_perm(&perm, br->br_perm); ++ seq_printf(seq, "=%s\n", perm.a); ++ } ++ break; ++ case AuBrSysfs_BRID: ++ seq_printf(seq, "%d\n", br->br_id); ++ break; ++ } ++ di_read_unlock(root, !AuLock_IR); ++ if (unlikely(err || seq_has_overflowed(seq))) ++ err = -E2BIG; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct seq_file *au_seq(char *p, ssize_t len) ++{ ++ struct seq_file *seq; ++ ++ seq = kzalloc(sizeof(*seq), GFP_NOFS); ++ if (seq) { ++ /* mutex_init(&seq.lock); */ ++ seq->buf = p; ++ seq->size = len; ++ return seq; /* success */ ++ } ++ ++ seq = ERR_PTR(-ENOMEM); ++ return seq; ++} ++ ++#define SysaufsBr_PREFIX "br" ++#define SysaufsBrid_PREFIX "brid" ++ ++/* todo: file size may exceed PAGE_SIZE */ ++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, ++ char *buf) ++{ ++ ssize_t err; ++ int idx; ++ long l; ++ aufs_bindex_t bbot; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct seq_file *seq; ++ char *name; ++ struct attribute **cattr; ++ ++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); ++ sb = sbinfo->si_sb; ++ ++ /* ++ * prevent a race condition between sysfs and aufs. ++ * for instance, sysfs_file_read() calls sysfs_get_active_two() which ++ * prohibits maintaining the sysfs entries. ++ * hew we acquire read lock after sysfs_get_active_two(). ++ * on the other hand, the remount process may maintain the sysfs/aufs ++ * entries after acquiring write lock. ++ * it can cause a deadlock. ++ * simply we gave up processing read here. ++ */ ++ err = -EBUSY; ++ if (unlikely(!si_noflush_read_trylock(sb))) ++ goto out; ++ ++ seq = au_seq(buf, PAGE_SIZE); ++ err = PTR_ERR(seq); ++ if (IS_ERR(seq)) ++ goto out_unlock; ++ ++ name = (void *)attr->name; ++ cattr = sysaufs_si_attrs; ++ while (*cattr) { ++ if (!strcmp(name, (*cattr)->name)) { ++ err = container_of(*cattr, struct sysaufs_si_attr, attr) ++ ->show(seq, sb); ++ goto out_seq; ++ } ++ cattr++; ++ } ++ ++ if (!strncmp(name, SysaufsBrid_PREFIX, ++ sizeof(SysaufsBrid_PREFIX) - 1)) { ++ idx = AuBrSysfs_BRID; ++ name += sizeof(SysaufsBrid_PREFIX) - 1; ++ } else if (!strncmp(name, SysaufsBr_PREFIX, ++ sizeof(SysaufsBr_PREFIX) - 1)) { ++ idx = AuBrSysfs_BR; ++ name += sizeof(SysaufsBr_PREFIX) - 1; ++ } else ++ BUG(); ++ ++ err = kstrtol(name, 10, &l); ++ if (!err) { ++ bbot = au_sbbot(sb); ++ if (l <= bbot) ++ err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l, idx); ++ else ++ err = -ENOENT; ++ } ++ ++out_seq: ++ if (!err) { ++ err = seq->count; ++ /* sysfs limit */ ++ if (unlikely(err == PAGE_SIZE)) ++ err = -EFBIG; ++ } ++ kfree(seq); ++out_unlock: ++ si_read_unlock(sb); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_brinfo(struct super_block *sb, union aufs_brinfo __user *arg) ++{ ++ int err; ++ int16_t brid; ++ aufs_bindex_t bindex, bbot; ++ size_t sz; ++ char *buf; ++ struct seq_file *seq; ++ struct au_branch *br; ++ ++ si_read_lock(sb, AuLock_FLUSH); ++ bbot = au_sbbot(sb); ++ err = bbot + 1; ++ if (!arg) ++ goto out; ++ ++ err = -ENOMEM; ++ buf = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!buf)) ++ goto out; ++ ++ seq = au_seq(buf, PAGE_SIZE); ++ err = PTR_ERR(seq); ++ if (IS_ERR(seq)) ++ goto out_buf; ++ ++ sz = sizeof(*arg) - offsetof(union aufs_brinfo, path); ++ for (bindex = 0; bindex <= bbot; bindex++, arg++) { ++ err = !access_ok(VERIFY_WRITE, arg, sizeof(*arg)); ++ if (unlikely(err)) ++ break; ++ ++ br = au_sbr(sb, bindex); ++ brid = br->br_id; ++ BUILD_BUG_ON(sizeof(brid) != sizeof(arg->id)); ++ err = __put_user(brid, &arg->id); ++ if (unlikely(err)) ++ break; ++ ++ BUILD_BUG_ON(sizeof(br->br_perm) != sizeof(arg->perm)); ++ err = __put_user(br->br_perm, &arg->perm); ++ if (unlikely(err)) ++ break; ++ ++ err = au_seq_path(seq, &br->br_path); ++ if (unlikely(err)) ++ break; ++ seq_putc(seq, '\0'); ++ if (!seq_has_overflowed(seq)) { ++ err = copy_to_user(arg->path, seq->buf, seq->count); ++ seq->count = 0; ++ if (unlikely(err)) ++ break; ++ } else { ++ err = -E2BIG; ++ goto out_seq; ++ } ++ } ++ if (unlikely(err)) ++ err = -EFAULT; ++ ++out_seq: ++ kfree(seq); ++out_buf: ++ free_page((unsigned long)buf); ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++long au_brinfo_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_brinfo(file->f_path.dentry->d_sb, (void __user *)arg); ++} ++ ++#ifdef CONFIG_COMPAT ++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_brinfo(file->f_path.dentry->d_sb, compat_ptr(arg)); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++void sysaufs_br_init(struct au_branch *br) ++{ ++ int i; ++ struct au_brsysfs *br_sysfs; ++ struct attribute *attr; ++ ++ br_sysfs = br->br_sysfs; ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ attr = &br_sysfs->attr; ++ sysfs_attr_init(attr); ++ attr->name = br_sysfs->name; ++ attr->mode = S_IRUGO; ++ br_sysfs++; ++ } ++} ++ ++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_branch *br; ++ struct kobject *kobj; ++ struct au_brsysfs *br_sysfs; ++ int i; ++ aufs_bindex_t bbot; ++ ++ dbgaufs_brs_del(sb, bindex); ++ ++ if (!sysaufs_brs) ++ return; ++ ++ kobj = &au_sbi(sb)->si_kobj; ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ br_sysfs = br->br_sysfs; ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ sysfs_remove_file(kobj, &br_sysfs->attr); ++ br_sysfs++; ++ } ++ } ++} ++ ++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err, i; ++ aufs_bindex_t bbot; ++ struct kobject *kobj; ++ struct au_branch *br; ++ struct au_brsysfs *br_sysfs; ++ ++ dbgaufs_brs_add(sb, bindex); ++ ++ if (!sysaufs_brs) ++ return; ++ ++ kobj = &au_sbi(sb)->si_kobj; ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ br_sysfs = br->br_sysfs; ++ snprintf(br_sysfs[AuBrSysfs_BR].name, sizeof(br_sysfs->name), ++ SysaufsBr_PREFIX "%d", bindex); ++ snprintf(br_sysfs[AuBrSysfs_BRID].name, sizeof(br_sysfs->name), ++ SysaufsBrid_PREFIX "%d", bindex); ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ err = sysfs_create_file(kobj, &br_sysfs->attr); ++ if (unlikely(err)) ++ pr_warn("failed %s under sysfs(%d)\n", ++ br_sysfs->name, err); ++ br_sysfs++; ++ } ++ } ++} +diff --git a/fs/aufs/sysrq.c b/fs/aufs/sysrq.c +new file mode 100644 +index 0000000..7d22979 +--- /dev/null ++++ b/fs/aufs/sysrq.c +@@ -0,0 +1,144 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * magic sysrq hanlder ++ */ ++ ++/* #include */ ++#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void sysrq_sb(struct super_block *sb) ++{ ++ char *plevel; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ struct au_sphlhead *files; ++ struct au_finfo *finfo; ++ ++ plevel = au_plevel; ++ au_plevel = KERN_WARNING; ++ ++ /* since we define pr_fmt, call printk directly */ ++#define pr(str) printk(KERN_WARNING AUFS_NAME ": " str) ++ ++ sbinfo = au_sbi(sb); ++ printk(KERN_WARNING "si=%lx\n", sysaufs_si_id(sbinfo)); ++ pr("superblock\n"); ++ au_dpri_sb(sb); ++ ++#if 0 ++ pr("root dentry\n"); ++ au_dpri_dentry(sb->s_root); ++ pr("root inode\n"); ++ au_dpri_inode(d_inode(sb->s_root)); ++#endif ++ ++#if 0 ++ do { ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ ++ err = au_dpages_init(&dpages, GFP_ATOMIC); ++ if (unlikely(err)) ++ break; ++ err = au_dcsub_pages(&dpages, sb->s_root, NULL, NULL); ++ if (!err) ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) ++ au_dpri_dentry(dpage->dentries[j]); ++ } ++ au_dpages_free(&dpages); ++ } while (0); ++#endif ++ ++#if 1 ++ { ++ struct inode *i; ++ ++ pr("isolated inode\n"); ++ spin_lock(&sb->s_inode_list_lock); ++ list_for_each_entry(i, &sb->s_inodes, i_sb_list) { ++ spin_lock(&i->i_lock); ++ if (1 || hlist_empty(&i->i_dentry)) ++ au_dpri_inode(i); ++ spin_unlock(&i->i_lock); ++ } ++ spin_unlock(&sb->s_inode_list_lock); ++ } ++#endif ++ pr("files\n"); ++ files = &au_sbi(sb)->si_files; ++ spin_lock(&files->spin); ++ hlist_for_each_entry(finfo, &files->head, fi_hlist) { ++ umode_t mode; ++ ++ file = finfo->fi_file; ++ mode = file_inode(file)->i_mode; ++ if (!special_file(mode)) ++ au_dpri_file(file); ++ } ++ spin_unlock(&files->spin); ++ pr("done\n"); ++ ++#undef pr ++ au_plevel = plevel; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* module parameter */ ++static char *aufs_sysrq_key = "a"; ++module_param_named(sysrq, aufs_sysrq_key, charp, S_IRUGO); ++MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME); ++ ++static void au_sysrq(int key __maybe_unused) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ lockdep_off(); ++ au_sbilist_lock(); ++ hlist_for_each_entry(sbinfo, &au_sbilist.head, si_list) ++ sysrq_sb(sbinfo->si_sb); ++ au_sbilist_unlock(); ++ lockdep_on(); ++} ++ ++static struct sysrq_key_op au_sysrq_op = { ++ .handler = au_sysrq, ++ .help_msg = "Aufs", ++ .action_msg = "Aufs", ++ .enable_mask = SYSRQ_ENABLE_DUMP ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int __init au_sysrq_init(void) ++{ ++ int err; ++ char key; ++ ++ err = -1; ++ key = *aufs_sysrq_key; ++ if ('a' <= key && key <= 'z') ++ err = register_sysrq_key(key, &au_sysrq_op); ++ if (unlikely(err)) ++ pr_err("err %d, sysrq=%c\n", err, key); ++ return err; ++} ++ ++void au_sysrq_fin(void) ++{ ++ int err; ++ ++ err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op); ++ if (unlikely(err)) ++ pr_err("err %d (ignored)\n", err); ++} +diff --git a/fs/aufs/vdir.c b/fs/aufs/vdir.c +new file mode 100644 +index 0000000..0a9ff00 +--- /dev/null ++++ b/fs/aufs/vdir.c +@@ -0,0 +1,876 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * virtual or vertical directory ++ */ ++ ++#include "aufs.h" ++ ++static unsigned int calc_size(int nlen) ++{ ++ return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t)); ++} ++ ++static int set_deblk_end(union au_vdir_deblk_p *p, ++ union au_vdir_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->deblk - p->deblk) { ++ p->de->de_str.len = 0; ++ /* smp_mb(); */ ++ return 0; ++ } ++ return -1; /* error */ ++} ++ ++/* returns true or false */ ++static int is_deblk_end(union au_vdir_deblk_p *p, ++ union au_vdir_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->deblk - p->deblk) ++ return !p->de->de_str.len; ++ return 1; ++} ++ ++static unsigned char *last_deblk(struct au_vdir *vdir) ++{ ++ return vdir->vd_deblk[vdir->vd_nblk - 1]; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* estimate the appropriate size for name hash table */ ++unsigned int au_rdhash_est(loff_t sz) ++{ ++ unsigned int n; ++ ++ n = UINT_MAX; ++ sz >>= 10; ++ if (sz < n) ++ n = sz; ++ if (sz < AUFS_RDHASH_DEF) ++ n = AUFS_RDHASH_DEF; ++ /* pr_info("n %u\n", n); */ ++ return n; ++} ++ ++/* ++ * the allocated memory has to be freed by ++ * au_nhash_wh_free() or au_nhash_de_free(). ++ */ ++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp) ++{ ++ struct hlist_head *head; ++ unsigned int u; ++ size_t sz; ++ ++ sz = sizeof(*nhash->nh_head) * num_hash; ++ head = kmalloc(sz, gfp); ++ if (head) { ++ nhash->nh_num = num_hash; ++ nhash->nh_head = head; ++ for (u = 0; u < num_hash; u++) ++ INIT_HLIST_HEAD(head++); ++ return 0; /* success */ ++ } ++ ++ return -ENOMEM; ++} ++ ++static void nhash_count(struct hlist_head *head) ++{ ++#if 0 ++ unsigned long n; ++ struct hlist_node *pos; ++ ++ n = 0; ++ hlist_for_each(pos, head) ++ n++; ++ pr_info("%lu\n", n); ++#endif ++} ++ ++static void au_nhash_wh_do_free(struct hlist_head *head) ++{ ++ struct au_vdir_wh *pos; ++ struct hlist_node *node; ++ ++ hlist_for_each_entry_safe(pos, node, head, wh_hash) ++ kfree(pos); ++} ++ ++static void au_nhash_de_do_free(struct hlist_head *head) ++{ ++ struct au_vdir_dehstr *pos; ++ struct hlist_node *node; ++ ++ hlist_for_each_entry_safe(pos, node, head, hash) ++ au_cache_free_vdir_dehstr(pos); ++} ++ ++static void au_nhash_do_free(struct au_nhash *nhash, ++ void (*free)(struct hlist_head *head)) ++{ ++ unsigned int n; ++ struct hlist_head *head; ++ ++ n = nhash->nh_num; ++ if (!n) ++ return; ++ ++ head = nhash->nh_head; ++ while (n-- > 0) { ++ nhash_count(head); ++ free(head++); ++ } ++ kfree(nhash->nh_head); ++} ++ ++void au_nhash_wh_free(struct au_nhash *whlist) ++{ ++ au_nhash_do_free(whlist, au_nhash_wh_do_free); ++} ++ ++static void au_nhash_de_free(struct au_nhash *delist) ++{ ++ au_nhash_do_free(delist, au_nhash_de_do_free); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, ++ int limit) ++{ ++ int num; ++ unsigned int u, n; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ ++ num = 0; ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (u = 0; u < n; u++, head++) ++ hlist_for_each_entry(pos, head, wh_hash) ++ if (pos->wh_bindex == btgt && ++num > limit) ++ return 1; ++ return 0; ++} ++ ++static struct hlist_head *au_name_hash(struct au_nhash *nhash, ++ unsigned char *name, ++ unsigned int len) ++{ ++ unsigned int v; ++ /* const unsigned int magic_bit = 12; */ ++ ++ AuDebugOn(!nhash->nh_num || !nhash->nh_head); ++ ++ v = 0; ++ while (len--) ++ v += *name++; ++ /* v = hash_long(v, magic_bit); */ ++ v %= nhash->nh_num; ++ return nhash->nh_head + v; ++} ++ ++static int au_nhash_test_name(struct au_vdir_destr *str, const char *name, ++ int nlen) ++{ ++ return str->len == nlen && !memcmp(str->name, name, nlen); ++} ++ ++/* returns found or not */ ++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen) ++{ ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct au_vdir_destr *str; ++ ++ head = au_name_hash(whlist, name, nlen); ++ hlist_for_each_entry(pos, head, wh_hash) { ++ str = &pos->wh_str; ++ AuDbg("%.*s\n", str->len, str->name); ++ if (au_nhash_test_name(str, name, nlen)) ++ return 1; ++ } ++ return 0; ++} ++ ++/* returns found(true) or not */ ++static int test_known(struct au_nhash *delist, char *name, int nlen) ++{ ++ struct hlist_head *head; ++ struct au_vdir_dehstr *pos; ++ struct au_vdir_destr *str; ++ ++ head = au_name_hash(delist, name, nlen); ++ hlist_for_each_entry(pos, head, hash) { ++ str = pos->str; ++ AuDbg("%.*s\n", str->len, str->name); ++ if (au_nhash_test_name(str, name, nlen)) ++ return 1; ++ } ++ return 0; ++} ++ ++static void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino, ++ unsigned char d_type) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ wh->wh_ino = ino; ++ wh->wh_type = d_type; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, ++ unsigned int d_type, aufs_bindex_t bindex, ++ unsigned char shwh) ++{ ++ int err; ++ struct au_vdir_destr *str; ++ struct au_vdir_wh *wh; ++ ++ AuDbg("%.*s\n", nlen, name); ++ AuDebugOn(!whlist->nh_num || !whlist->nh_head); ++ ++ err = -ENOMEM; ++ wh = kmalloc(sizeof(*wh) + nlen, GFP_NOFS); ++ if (unlikely(!wh)) ++ goto out; ++ ++ err = 0; ++ wh->wh_bindex = bindex; ++ if (shwh) ++ au_shwh_init_wh(wh, ino, d_type); ++ str = &wh->wh_str; ++ str->len = nlen; ++ memcpy(str->name, name, nlen); ++ hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen)); ++ /* smp_mb(); */ ++ ++out: ++ return err; ++} ++ ++static int append_deblk(struct au_vdir *vdir) ++{ ++ int err; ++ unsigned long ul; ++ const unsigned int deblk_sz = vdir->vd_deblk_sz; ++ union au_vdir_deblk_p p, deblk_end; ++ unsigned char **o; ++ ++ err = -ENOMEM; ++ o = krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1), ++ GFP_NOFS); ++ if (unlikely(!o)) ++ goto out; ++ ++ vdir->vd_deblk = o; ++ p.deblk = kmalloc(deblk_sz, GFP_NOFS); ++ if (p.deblk) { ++ ul = vdir->vd_nblk++; ++ vdir->vd_deblk[ul] = p.deblk; ++ vdir->vd_last.ul = ul; ++ vdir->vd_last.p.deblk = p.deblk; ++ deblk_end.deblk = p.deblk + deblk_sz; ++ err = set_deblk_end(&p, &deblk_end); ++ } ++ ++out: ++ return err; ++} ++ ++static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino, ++ unsigned int d_type, struct au_nhash *delist) ++{ ++ int err; ++ unsigned int sz; ++ const unsigned int deblk_sz = vdir->vd_deblk_sz; ++ union au_vdir_deblk_p p, *room, deblk_end; ++ struct au_vdir_dehstr *dehstr; ++ ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + deblk_sz; ++ room = &vdir->vd_last.p; ++ AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk ++ || !is_deblk_end(room, &deblk_end)); ++ ++ sz = calc_size(nlen); ++ if (unlikely(sz > deblk_end.deblk - room->deblk)) { ++ err = append_deblk(vdir); ++ if (unlikely(err)) ++ goto out; ++ ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + deblk_sz; ++ /* smp_mb(); */ ++ AuDebugOn(room->deblk != p.deblk); ++ } ++ ++ err = -ENOMEM; ++ dehstr = au_cache_alloc_vdir_dehstr(); ++ if (unlikely(!dehstr)) ++ goto out; ++ ++ dehstr->str = &room->de->de_str; ++ hlist_add_head(&dehstr->hash, au_name_hash(delist, name, nlen)); ++ room->de->de_ino = ino; ++ room->de->de_type = d_type; ++ room->de->de_str.len = nlen; ++ memcpy(room->de->de_str.name, name, nlen); ++ ++ err = 0; ++ room->deblk += sz; ++ if (unlikely(set_deblk_end(room, &deblk_end))) ++ err = append_deblk(vdir); ++ /* smp_mb(); */ ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_vdir_free(struct au_vdir *vdir) ++{ ++ unsigned char **deblk; ++ ++ deblk = vdir->vd_deblk; ++ while (vdir->vd_nblk--) ++ kfree(*deblk++); ++ kfree(vdir->vd_deblk); ++ au_cache_free_vdir(vdir); ++} ++ ++static struct au_vdir *alloc_vdir(struct file *file) ++{ ++ struct au_vdir *vdir; ++ struct super_block *sb; ++ int err; ++ ++ sb = file->f_path.dentry->d_sb; ++ SiMustAnyLock(sb); ++ ++ err = -ENOMEM; ++ vdir = au_cache_alloc_vdir(); ++ if (unlikely(!vdir)) ++ goto out; ++ ++ vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS); ++ if (unlikely(!vdir->vd_deblk)) ++ goto out_free; ++ ++ vdir->vd_deblk_sz = au_sbi(sb)->si_rdblk; ++ if (!vdir->vd_deblk_sz) { ++ /* estimate the appropriate size for deblk */ ++ vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL); ++ /* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */ ++ } ++ vdir->vd_nblk = 0; ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ err = append_deblk(vdir); ++ if (!err) ++ return vdir; /* success */ ++ ++ kfree(vdir->vd_deblk); ++ ++out_free: ++ au_cache_free_vdir(vdir); ++out: ++ vdir = ERR_PTR(err); ++ return vdir; ++} ++ ++static int reinit_vdir(struct au_vdir *vdir) ++{ ++ int err; ++ union au_vdir_deblk_p p, deblk_end; ++ ++ while (vdir->vd_nblk > 1) { ++ kfree(vdir->vd_deblk[vdir->vd_nblk - 1]); ++ /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */ ++ vdir->vd_nblk--; ++ } ++ p.deblk = vdir->vd_deblk[0]; ++ deblk_end.deblk = p.deblk + vdir->vd_deblk_sz; ++ err = set_deblk_end(&p, &deblk_end); ++ /* keep vd_dblk_sz */ ++ vdir->vd_last.ul = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ /* smp_mb(); */ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuFillVdir_CALLED 1 ++#define AuFillVdir_WHABLE (1 << 1) ++#define AuFillVdir_SHWH (1 << 2) ++#define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name) ++#define au_fset_fillvdir(flags, name) \ ++ do { (flags) |= AuFillVdir_##name; } while (0) ++#define au_fclr_fillvdir(flags, name) \ ++ do { (flags) &= ~AuFillVdir_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_SHWH ++#undef AuFillVdir_SHWH ++#define AuFillVdir_SHWH 0 ++#endif ++ ++struct fillvdir_arg { ++ struct dir_context ctx; ++ struct file *file; ++ struct au_vdir *vdir; ++ struct au_nhash delist; ++ struct au_nhash whlist; ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ int err; ++}; ++ ++static int fillvdir(struct dir_context *ctx, const char *__name, int nlen, ++ loff_t offset __maybe_unused, u64 h_ino, ++ unsigned int d_type) ++{ ++ struct fillvdir_arg *arg = container_of(ctx, struct fillvdir_arg, ctx); ++ char *name = (void *)__name; ++ struct super_block *sb; ++ ino_t ino; ++ const unsigned char shwh = !!au_ftest_fillvdir(arg->flags, SHWH); ++ ++ arg->err = 0; ++ sb = arg->file->f_path.dentry->d_sb; ++ au_fset_fillvdir(arg->flags, CALLED); ++ /* smp_mb(); */ ++ if (nlen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ if (test_known(&arg->delist, name, nlen) ++ || au_nhash_test_known_wh(&arg->whlist, name, nlen)) ++ goto out; /* already exists or whiteouted */ ++ ++ arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino); ++ if (!arg->err) { ++ if (unlikely(nlen > AUFS_MAX_NAMELEN)) ++ d_type = DT_UNKNOWN; ++ arg->err = append_de(arg->vdir, name, nlen, ino, ++ d_type, &arg->delist); ++ } ++ } else if (au_ftest_fillvdir(arg->flags, WHABLE)) { ++ name += AUFS_WH_PFX_LEN; ++ nlen -= AUFS_WH_PFX_LEN; ++ if (au_nhash_test_known_wh(&arg->whlist, name, nlen)) ++ goto out; /* already whiteouted */ ++ ++ if (shwh) ++ arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type, ++ &ino); ++ if (!arg->err) { ++ if (nlen <= AUFS_MAX_NAMELEN + AUFS_WH_PFX_LEN) ++ d_type = DT_UNKNOWN; ++ arg->err = au_nhash_append_wh ++ (&arg->whlist, name, nlen, ino, d_type, ++ arg->bindex, shwh); ++ } ++ } ++ ++out: ++ if (!arg->err) ++ arg->vdir->vd_jiffy = jiffies; ++ /* smp_mb(); */ ++ AuTraceErr(arg->err); ++ return arg->err; ++} ++ ++static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir, ++ struct au_nhash *whlist, struct au_nhash *delist) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ int err; ++ unsigned int nh, u; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct hlist_node *n; ++ char *p, *o; ++ struct au_vdir_destr *destr; ++ ++ AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH)); ++ ++ err = -ENOMEM; ++ o = p = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = 0; ++ nh = whlist->nh_num; ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ p += AUFS_WH_PFX_LEN; ++ for (u = 0; u < nh; u++) { ++ head = whlist->nh_head + u; ++ hlist_for_each_entry_safe(pos, n, head, wh_hash) { ++ destr = &pos->wh_str; ++ memcpy(p, destr->name, destr->len); ++ err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN, ++ pos->wh_ino, pos->wh_type, delist); ++ if (unlikely(err)) ++ break; ++ } ++ } ++ ++ free_page((unsigned long)o); ++ ++out: ++ AuTraceErr(err); ++ return err; ++#else ++ return 0; ++#endif ++} ++ ++static int au_do_read_vdir(struct fillvdir_arg *arg) ++{ ++ int err; ++ unsigned int rdhash; ++ loff_t offset; ++ aufs_bindex_t bbot, bindex, btop; ++ unsigned char shwh; ++ struct file *hf, *file; ++ struct super_block *sb; ++ ++ file = arg->file; ++ sb = file->f_path.dentry->d_sb; ++ SiMustAnyLock(sb); ++ ++ rdhash = au_sbi(sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL)); ++ err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out_delist; ++ ++ err = 0; ++ arg->flags = 0; ++ shwh = 0; ++ if (au_opt_test(au_mntflags(sb), SHWH)) { ++ shwh = 1; ++ au_fset_fillvdir(arg->flags, SHWH); ++ } ++ btop = au_fbtop(file); ++ bbot = au_fbbot_dir(file); ++ for (bindex = btop; !err && bindex <= bbot; bindex++) { ++ hf = au_hf_dir(file, bindex); ++ if (!hf) ++ continue; ++ ++ offset = vfsub_llseek(hf, 0, SEEK_SET); ++ err = offset; ++ if (unlikely(offset)) ++ break; ++ ++ arg->bindex = bindex; ++ au_fclr_fillvdir(arg->flags, WHABLE); ++ if (shwh ++ || (bindex != bbot ++ && au_br_whable(au_sbr_perm(sb, bindex)))) ++ au_fset_fillvdir(arg->flags, WHABLE); ++ do { ++ arg->err = 0; ++ au_fclr_fillvdir(arg->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(hf, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && au_ftest_fillvdir(arg->flags, CALLED)); ++ ++ /* ++ * dir_relax() may be good for concurrency, but aufs should not ++ * use it since it will cause a lockdep problem. ++ */ ++ } ++ ++ if (!err && shwh) ++ err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist); ++ ++ au_nhash_wh_free(&arg->whlist); ++ ++out_delist: ++ au_nhash_de_free(&arg->delist); ++out: ++ return err; ++} ++ ++static int read_vdir(struct file *file, int may_read) ++{ ++ int err; ++ unsigned long expire; ++ unsigned char do_read; ++ struct fillvdir_arg arg = { ++ .ctx = { ++ .actor = fillvdir ++ } ++ }; ++ struct inode *inode; ++ struct au_vdir *vdir, *allocated; ++ ++ err = 0; ++ inode = file_inode(file); ++ IMustLock(inode); ++ IiMustWriteLock(inode); ++ SiMustAnyLock(inode->i_sb); ++ ++ allocated = NULL; ++ do_read = 0; ++ expire = au_sbi(inode->i_sb)->si_rdcache; ++ vdir = au_ivdir(inode); ++ if (!vdir) { ++ do_read = 1; ++ vdir = alloc_vdir(file); ++ err = PTR_ERR(vdir); ++ if (IS_ERR(vdir)) ++ goto out; ++ err = 0; ++ allocated = vdir; ++ } else if (may_read ++ && (inode->i_version != vdir->vd_version ++ || time_after(jiffies, vdir->vd_jiffy + expire))) { ++ do_read = 1; ++ err = reinit_vdir(vdir); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ if (!do_read) ++ return 0; /* success */ ++ ++ arg.file = file; ++ arg.vdir = vdir; ++ err = au_do_read_vdir(&arg); ++ if (!err) { ++ /* file->f_pos = 0; */ /* todo: ctx->pos? */ ++ vdir->vd_version = inode->i_version; ++ vdir->vd_last.ul = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ if (allocated) ++ au_set_ivdir(inode, allocated); ++ } else if (allocated) ++ au_vdir_free(allocated); ++ ++out: ++ return err; ++} ++ ++static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src) ++{ ++ int err, rerr; ++ unsigned long ul, n; ++ const unsigned int deblk_sz = src->vd_deblk_sz; ++ ++ AuDebugOn(tgt->vd_nblk != 1); ++ ++ err = -ENOMEM; ++ if (tgt->vd_nblk < src->vd_nblk) { ++ unsigned char **p; ++ ++ p = krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk, ++ GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ tgt->vd_deblk = p; ++ } ++ ++ if (tgt->vd_deblk_sz != deblk_sz) { ++ unsigned char *p; ++ ++ tgt->vd_deblk_sz = deblk_sz; ++ p = krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ tgt->vd_deblk[0] = p; ++ } ++ memcpy(tgt->vd_deblk[0], src->vd_deblk[0], deblk_sz); ++ tgt->vd_version = src->vd_version; ++ tgt->vd_jiffy = src->vd_jiffy; ++ ++ n = src->vd_nblk; ++ for (ul = 1; ul < n; ul++) { ++ tgt->vd_deblk[ul] = kmemdup(src->vd_deblk[ul], deblk_sz, ++ GFP_NOFS); ++ if (unlikely(!tgt->vd_deblk[ul])) ++ goto out; ++ tgt->vd_nblk++; ++ } ++ tgt->vd_nblk = n; ++ tgt->vd_last.ul = tgt->vd_last.ul; ++ tgt->vd_last.p.deblk = tgt->vd_deblk[tgt->vd_last.ul]; ++ tgt->vd_last.p.deblk += src->vd_last.p.deblk ++ - src->vd_deblk[src->vd_last.ul]; ++ /* smp_mb(); */ ++ return 0; /* success */ ++ ++out: ++ rerr = reinit_vdir(tgt); ++ BUG_ON(rerr); ++ return err; ++} ++ ++int au_vdir_init(struct file *file) ++{ ++ int err; ++ struct inode *inode; ++ struct au_vdir *vdir_cache, *allocated; ++ ++ /* test file->f_pos here instead of ctx->pos */ ++ err = read_vdir(file, !file->f_pos); ++ if (unlikely(err)) ++ goto out; ++ ++ allocated = NULL; ++ vdir_cache = au_fvdir_cache(file); ++ if (!vdir_cache) { ++ vdir_cache = alloc_vdir(file); ++ err = PTR_ERR(vdir_cache); ++ if (IS_ERR(vdir_cache)) ++ goto out; ++ allocated = vdir_cache; ++ } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) { ++ /* test file->f_pos here instead of ctx->pos */ ++ err = reinit_vdir(vdir_cache); ++ if (unlikely(err)) ++ goto out; ++ } else ++ return 0; /* success */ ++ ++ inode = file_inode(file); ++ err = copy_vdir(vdir_cache, au_ivdir(inode)); ++ if (!err) { ++ file->f_version = inode->i_version; ++ if (allocated) ++ au_set_fvdir_cache(file, allocated); ++ } else if (allocated) ++ au_vdir_free(allocated); ++ ++out: ++ return err; ++} ++ ++static loff_t calc_offset(struct au_vdir *vdir) ++{ ++ loff_t offset; ++ union au_vdir_deblk_p p; ++ ++ p.deblk = vdir->vd_deblk[vdir->vd_last.ul]; ++ offset = vdir->vd_last.p.deblk - p.deblk; ++ offset += vdir->vd_deblk_sz * vdir->vd_last.ul; ++ return offset; ++} ++ ++/* returns true or false */ ++static int seek_vdir(struct file *file, struct dir_context *ctx) ++{ ++ int valid; ++ unsigned int deblk_sz; ++ unsigned long ul, n; ++ loff_t offset; ++ union au_vdir_deblk_p p, deblk_end; ++ struct au_vdir *vdir_cache; ++ ++ valid = 1; ++ vdir_cache = au_fvdir_cache(file); ++ offset = calc_offset(vdir_cache); ++ AuDbg("offset %lld\n", offset); ++ if (ctx->pos == offset) ++ goto out; ++ ++ vdir_cache->vd_last.ul = 0; ++ vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0]; ++ if (!ctx->pos) ++ goto out; ++ ++ valid = 0; ++ deblk_sz = vdir_cache->vd_deblk_sz; ++ ul = div64_u64(ctx->pos, deblk_sz); ++ AuDbg("ul %lu\n", ul); ++ if (ul >= vdir_cache->vd_nblk) ++ goto out; ++ ++ n = vdir_cache->vd_nblk; ++ for (; ul < n; ul++) { ++ p.deblk = vdir_cache->vd_deblk[ul]; ++ deblk_end.deblk = p.deblk + deblk_sz; ++ offset = ul; ++ offset *= deblk_sz; ++ while (!is_deblk_end(&p, &deblk_end) && offset < ctx->pos) { ++ unsigned int l; ++ ++ l = calc_size(p.de->de_str.len); ++ offset += l; ++ p.deblk += l; ++ } ++ if (!is_deblk_end(&p, &deblk_end)) { ++ valid = 1; ++ vdir_cache->vd_last.ul = ul; ++ vdir_cache->vd_last.p = p; ++ break; ++ } ++ } ++ ++out: ++ /* smp_mb(); */ ++ AuTraceErr(!valid); ++ return valid; ++} ++ ++int au_vdir_fill_de(struct file *file, struct dir_context *ctx) ++{ ++ unsigned int l, deblk_sz; ++ union au_vdir_deblk_p deblk_end; ++ struct au_vdir *vdir_cache; ++ struct au_vdir_de *de; ++ ++ vdir_cache = au_fvdir_cache(file); ++ if (!seek_vdir(file, ctx)) ++ return 0; ++ ++ deblk_sz = vdir_cache->vd_deblk_sz; ++ while (1) { ++ deblk_end.deblk = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; ++ deblk_end.deblk += deblk_sz; ++ while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) { ++ de = vdir_cache->vd_last.p.de; ++ AuDbg("%.*s, off%lld, i%lu, dt%d\n", ++ de->de_str.len, de->de_str.name, ctx->pos, ++ (unsigned long)de->de_ino, de->de_type); ++ if (unlikely(!dir_emit(ctx, de->de_str.name, ++ de->de_str.len, de->de_ino, ++ de->de_type))) { ++ /* todo: ignore the error caused by udba? */ ++ /* return err; */ ++ return 0; ++ } ++ ++ l = calc_size(de->de_str.len); ++ vdir_cache->vd_last.p.deblk += l; ++ ctx->pos += l; ++ } ++ if (vdir_cache->vd_last.ul < vdir_cache->vd_nblk - 1) { ++ vdir_cache->vd_last.ul++; ++ vdir_cache->vd_last.p.deblk ++ = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; ++ ctx->pos = deblk_sz * vdir_cache->vd_last.ul; ++ continue; ++ } ++ break; ++ } ++ ++ /* smp_mb(); */ ++ return 0; ++} +diff --git a/fs/aufs/vfsub.c b/fs/aufs/vfsub.c +new file mode 100644 +index 0000000..2e54bad +--- /dev/null ++++ b/fs/aufs/vfsub.c +@@ -0,0 +1,871 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * sub-routines for VFS ++ */ ++ ++#include ++#include ++#include ++#include ++#include "../fs/mount.h" ++#include "aufs.h" ++ ++#ifdef CONFIG_AUFS_BR_FUSE ++int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb) ++{ ++ struct nsproxy *ns; ++ ++ if (!au_test_fuse(h_sb) || !au_userns) ++ return 0; ++ ++ ns = current->nsproxy; ++ /* no {get,put}_nsproxy(ns) */ ++ return real_mount(mnt)->mnt_ns == ns->mnt_ns ? 0 : -EACCES; ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_update_h_iattr(struct path *h_path, int *did) ++{ ++ int err; ++ struct kstat st; ++ struct super_block *h_sb; ++ ++ /* for remote fs, leave work for its getattr or d_revalidate */ ++ /* for bad i_attr fs, handle them in aufs_getattr() */ ++ /* still some fs may acquire i_mutex. we need to skip them */ ++ err = 0; ++ if (!did) ++ did = &err; ++ h_sb = h_path->dentry->d_sb; ++ *did = (!au_test_fs_remote(h_sb) && au_test_fs_refresh_iattr(h_sb)); ++ if (*did) ++ err = vfs_getattr(h_path, &st); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct file *vfsub_dentry_open(struct path *path, int flags) ++{ ++ struct file *file; ++ ++ file = dentry_open(path, flags /* | __FMODE_NONOTIFY */, ++ current_cred()); ++ if (!IS_ERR_OR_NULL(file) ++ && (file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) ++ i_readcount_inc(d_inode(path->dentry)); ++ ++ return file; ++} ++ ++struct file *vfsub_filp_open(const char *path, int oflags, int mode) ++{ ++ struct file *file; ++ ++ lockdep_off(); ++ file = filp_open(path, ++ oflags /* | __FMODE_NONOTIFY */, ++ mode); ++ lockdep_on(); ++ if (IS_ERR(file)) ++ goto out; ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ ++out: ++ return file; ++} ++ ++/* ++ * Ideally this function should call VFS:do_last() in order to keep all its ++ * checkings. But it is very hard for aufs to regenerate several VFS internal ++ * structure such as nameidata. This is a second (or third) best approach. ++ * cf. linux/fs/namei.c:do_last(), lookup_open() and atomic_open(). ++ */ ++int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args, struct au_branch *br) ++{ ++ int err; ++ struct file *file = args->file; ++ /* copied from linux/fs/namei.c:atomic_open() */ ++ struct dentry *const DENTRY_NOT_SET = (void *)-1UL; ++ ++ IMustLock(dir); ++ AuDebugOn(!dir->i_op->atomic_open); ++ ++ err = au_br_test_oflag(args->open_flag, br); ++ if (unlikely(err)) ++ goto out; ++ ++ args->file->f_path.dentry = DENTRY_NOT_SET; ++ args->file->f_path.mnt = au_br_mnt(br); ++ err = dir->i_op->atomic_open(dir, dentry, file, args->open_flag, ++ args->create_mode, args->opened); ++ if (err >= 0) { ++ /* some filesystems don't set FILE_CREATED while succeeded? */ ++ if (*args->opened & FILE_CREATED) ++ fsnotify_create(dir, dentry); ++ } else ++ goto out; ++ ++ ++ if (!err) { ++ /* todo: call VFS:may_open() here */ ++ err = open_check_o_direct(file); ++ /* todo: ima_file_check() too? */ ++ if (!err && (args->open_flag & __FMODE_EXEC)) ++ err = deny_write_access(file); ++ if (unlikely(err)) ++ /* note that the file is created and still opened */ ++ goto out; ++ } ++ ++ au_br_get(br); ++ fsnotify_open(file); ++ ++out: ++ return err; ++} ++ ++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path) ++{ ++ int err; ++ ++ err = kern_path(name, flags, path); ++ if (!err && d_is_positive(path->dentry)) ++ vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++struct dentry *vfsub_lookup_one_len_unlocked(const char *name, ++ struct dentry *parent, int len) ++{ ++ struct path path = { ++ .mnt = NULL ++ }; ++ ++ path.dentry = lookup_one_len_unlocked(name, parent, len); ++ if (IS_ERR(path.dentry)) ++ goto out; ++ if (d_is_positive(path.dentry)) ++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ ++ ++out: ++ AuTraceErrPtr(path.dentry); ++ return path.dentry; ++} ++ ++struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, ++ int len) ++{ ++ struct path path = { ++ .mnt = NULL ++ }; ++ ++ /* VFS checks it too, but by WARN_ON_ONCE() */ ++ IMustLock(d_inode(parent)); ++ ++ path.dentry = lookup_one_len(name, parent, len); ++ if (IS_ERR(path.dentry)) ++ goto out; ++ if (d_is_positive(path.dentry)) ++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ ++ ++out: ++ AuTraceErrPtr(path.dentry); ++ return path.dentry; ++} ++ ++void vfsub_call_lkup_one(void *args) ++{ ++ struct vfsub_lkup_one_args *a = args; ++ *a->errp = vfsub_lkup_one(a->name, a->parent); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2) ++{ ++ struct dentry *d; ++ ++ lockdep_off(); ++ d = lock_rename(d1, d2); ++ lockdep_on(); ++ au_hn_suspend(hdir1); ++ if (hdir1 != hdir2) ++ au_hn_suspend(hdir2); ++ ++ return d; ++} ++ ++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2) ++{ ++ au_hn_resume(hdir1); ++ if (hdir1 != hdir2) ++ au_hn_resume(hdir2); ++ lockdep_off(); ++ unlock_rename(d1, d2); ++ lockdep_on(); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_create(struct inode *dir, struct path *path, int mode, bool want_excl) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mknod(path, d, mode, 0); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_create(dir, path->dentry, mode, want_excl); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_symlink(struct inode *dir, struct path *path, const char *symname) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_symlink(path, d, symname); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_symlink(dir, path->dentry, symname); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mknod(path, d, mode, new_encode_dev(dev)); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_mknod(dir, path->dentry, mode, dev); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++static int au_test_nlink(struct inode *inode) ++{ ++ const unsigned int link_max = UINT_MAX >> 1; /* rough margin */ ++ ++ if (!au_test_fs_no_limit_nlink(inode->i_sb) ++ || inode->i_nlink < link_max) ++ return 0; ++ return -EMLINK; ++} ++ ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path, ++ struct inode **delegated_inode) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ err = au_test_nlink(d_inode(src_dentry)); ++ if (unlikely(err)) ++ return err; ++ ++ /* we don't call may_linkat() */ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_link(src_dentry, path, d); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_link(src_dentry, dir, path->dentry, delegated_inode); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ /* fuse has different memory inode for the same inumber */ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ tmp.dentry = src_dentry; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct path *path, ++ struct inode **delegated_inode) ++{ ++ int err; ++ struct path tmp = { ++ .mnt = path->mnt ++ }; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ IMustLock(src_dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ tmp.dentry = src_dentry->d_parent; ++ err = security_path_rename(&tmp, src_dentry, path, d, /*flags*/0); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_rename(src_dir, src_dentry, dir, path->dentry, ++ delegated_inode, /*flags*/0); ++ lockdep_on(); ++ if (!err) { ++ int did; ++ ++ tmp.dentry = d->d_parent; ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = src_dentry; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ tmp.dentry = src_dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_mkdir(struct inode *dir, struct path *path, int mode) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mkdir(path, d, mode); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_mkdir(dir, path->dentry, mode); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_rmdir(struct inode *dir, struct path *path) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_rmdir(path, d); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_rmdir(dir, path->dentry); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = { ++ .dentry = path->dentry->d_parent, ++ .mnt = path->mnt ++ }; ++ ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: support mmap_sem? */ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = vfs_read(file, ubuf, count, ppos); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++/* todo: kernel_read()? */ ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ union { ++ void *k; ++ char __user *u; ++ } buf; ++ ++ buf.k = kbuf; ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = vfsub_read_u(file, buf.u, count, ppos); ++ set_fs(oldfs); ++ return err; ++} ++ ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = vfs_write(file, ubuf, count, ppos); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ union { ++ void *k; ++ const char __user *u; ++ } buf; ++ ++ buf.k = kbuf; ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = vfsub_write_u(file, buf.u, count, ppos); ++ set_fs(oldfs); ++ return err; ++} ++ ++int vfsub_flush(struct file *file, fl_owner_t id) ++{ ++ int err; ++ ++ err = 0; ++ if (file->f_op->flush) { ++ if (!au_test_nfs(file->f_path.dentry->d_sb)) ++ err = file->f_op->flush(file, id); ++ else { ++ lockdep_off(); ++ err = file->f_op->flush(file, id); ++ lockdep_on(); ++ } ++ if (!err) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); ++ /*ignore*/ ++ } ++ return err; ++} ++ ++int vfsub_iterate_dir(struct file *file, struct dir_context *ctx) ++{ ++ int err; ++ ++ AuDbg("%pD, ctx{%pf, %llu}\n", file, ctx->actor, ctx->pos); ++ ++ lockdep_off(); ++ err = iterate_dir(file, ctx); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++long vfsub_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = do_splice_to(in, ppos, pipe, len, flags); ++ lockdep_on(); ++ file_accessed(in); ++ if (err >= 0) ++ vfsub_update_h_iattr(&in->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = do_splice_from(pipe, out, ppos, len, flags); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&out->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++int vfsub_fsync(struct file *file, struct path *path, int datasync) ++{ ++ int err; ++ ++ /* file can be NULL */ ++ lockdep_off(); ++ err = vfs_fsync(file, datasync); ++ lockdep_on(); ++ if (!err) { ++ if (!path) { ++ AuDebugOn(!file); ++ path = &file->f_path; ++ } ++ vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ ++ } ++ return err; ++} ++ ++/* cf. open.c:do_sys_truncate() and do_sys_ftruncate() */ ++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, ++ struct file *h_file) ++{ ++ int err; ++ struct inode *h_inode; ++ struct super_block *h_sb; ++ ++ if (!h_file) { ++ err = vfsub_truncate(h_path, length); ++ goto out; ++ } ++ ++ h_inode = d_inode(h_path->dentry); ++ h_sb = h_inode->i_sb; ++ lockdep_off(); ++ sb_start_write(h_sb); ++ lockdep_on(); ++ err = locks_verify_truncate(h_inode, h_file, length); ++ if (!err) ++ err = security_path_truncate(h_path); ++ if (!err) { ++ lockdep_off(); ++ err = do_truncate(h_path->dentry, length, attr, h_file); ++ lockdep_on(); ++ } ++ lockdep_off(); ++ sb_end_write(h_sb); ++ lockdep_on(); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_vfsub_mkdir_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++ int mode; ++}; ++ ++static void au_call_vfsub_mkdir(void *args) ++{ ++ struct au_vfsub_mkdir_args *a = args; ++ *a->errp = vfsub_mkdir(a->dir, a->path, a->mode); ++} ++ ++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode) ++{ ++ int err, do_sio, wkq_err; ++ ++ do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); ++ if (!do_sio) { ++ lockdep_off(); ++ err = vfsub_mkdir(dir, path, mode); ++ lockdep_on(); ++ } else { ++ struct au_vfsub_mkdir_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path, ++ .mode = mode ++ }; ++ wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++ ++struct au_vfsub_rmdir_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++}; ++ ++static void au_call_vfsub_rmdir(void *args) ++{ ++ struct au_vfsub_rmdir_args *a = args; ++ *a->errp = vfsub_rmdir(a->dir, a->path); ++} ++ ++int vfsub_sio_rmdir(struct inode *dir, struct path *path) ++{ ++ int err, do_sio, wkq_err; ++ ++ do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); ++ if (!do_sio) { ++ lockdep_off(); ++ err = vfsub_rmdir(dir, path); ++ lockdep_on(); ++ } else { ++ struct au_vfsub_rmdir_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path ++ }; ++ wkq_err = au_wkq_wait(au_call_vfsub_rmdir, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct notify_change_args { ++ int *errp; ++ struct path *path; ++ struct iattr *ia; ++ struct inode **delegated_inode; ++}; ++ ++static void call_notify_change(void *args) ++{ ++ struct notify_change_args *a = args; ++ struct inode *h_inode; ++ ++ h_inode = d_inode(a->path->dentry); ++ IMustLock(h_inode); ++ ++ *a->errp = -EPERM; ++ if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) { ++ lockdep_off(); ++ *a->errp = notify_change(a->path->dentry, a->ia, ++ a->delegated_inode); ++ lockdep_on(); ++ if (!*a->errp) ++ vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/ ++ } ++ AuTraceErr(*a->errp); ++} ++ ++int vfsub_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode) ++{ ++ int err; ++ struct notify_change_args args = { ++ .errp = &err, ++ .path = path, ++ .ia = ia, ++ .delegated_inode = delegated_inode ++ }; ++ ++ call_notify_change(&args); ++ ++ return err; ++} ++ ++int vfsub_sio_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode) ++{ ++ int err, wkq_err; ++ struct notify_change_args args = { ++ .errp = &err, ++ .path = path, ++ .ia = ia, ++ .delegated_inode = delegated_inode ++ }; ++ ++ wkq_err = au_wkq_wait(call_notify_change, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct unlink_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++ struct inode **delegated_inode; ++}; ++ ++static void call_unlink(void *args) ++{ ++ struct unlink_args *a = args; ++ struct dentry *d = a->path->dentry; ++ struct inode *h_inode; ++ const int stop_sillyrename = (au_test_nfs(d->d_sb) ++ && au_dcount(d) == 1); ++ ++ IMustLock(a->dir); ++ ++ a->path->dentry = d->d_parent; ++ *a->errp = security_path_unlink(a->path, d); ++ a->path->dentry = d; ++ if (unlikely(*a->errp)) ++ return; ++ ++ if (!stop_sillyrename) ++ dget(d); ++ h_inode = NULL; ++ if (d_is_positive(d)) { ++ h_inode = d_inode(d); ++ ihold(h_inode); ++ } ++ ++ lockdep_off(); ++ *a->errp = vfs_unlink(a->dir, d, a->delegated_inode); ++ lockdep_on(); ++ if (!*a->errp) { ++ struct path tmp = { ++ .dentry = d->d_parent, ++ .mnt = a->path->mnt ++ }; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ ++ } ++ ++ if (!stop_sillyrename) ++ dput(d); ++ if (h_inode) ++ iput(h_inode); ++ ++ AuTraceErr(*a->errp); ++} ++ ++/* ++ * @dir: must be locked. ++ * @dentry: target dentry. ++ */ ++int vfsub_unlink(struct inode *dir, struct path *path, ++ struct inode **delegated_inode, int force) ++{ ++ int err; ++ struct unlink_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path, ++ .delegated_inode = delegated_inode ++ }; ++ ++ if (!force) ++ call_unlink(&args); ++ else { ++ int wkq_err; ++ ++ wkq_err = au_wkq_wait(call_unlink, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} +diff --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h +new file mode 100644 +index 0000000..291bfae +--- /dev/null ++++ b/fs/aufs/vfsub.h +@@ -0,0 +1,297 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * sub-routines for VFS ++ */ ++ ++#ifndef __AUFS_VFSUB_H__ ++#define __AUFS_VFSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "debug.h" ++ ++/* copied from linux/fs/internal.h */ ++/* todo: BAD approach!! */ ++extern void __mnt_drop_write(struct vfsmount *); ++extern int open_check_o_direct(struct file *f); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for lower inode */ ++/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */ ++/* reduce? gave up. */ ++enum { ++ AuLsc_I_Begin = I_MUTEX_PARENT2, /* 5 */ ++ AuLsc_I_PARENT, /* lower inode, parent first */ ++ AuLsc_I_PARENT2, /* copyup dirs */ ++ AuLsc_I_PARENT3, /* copyup wh */ ++ AuLsc_I_CHILD, ++ AuLsc_I_CHILD2, ++ AuLsc_I_End ++}; ++ ++/* to debug easier, do not make them inlined functions */ ++#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx)) ++#define IMustLock(i) AuDebugOn(!inode_is_locked(i)) ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void vfsub_drop_nlink(struct inode *inode) ++{ ++ AuDebugOn(!inode->i_nlink); ++ drop_nlink(inode); ++} ++ ++static inline void vfsub_dead_dir(struct inode *inode) ++{ ++ AuDebugOn(!S_ISDIR(inode->i_mode)); ++ inode->i_flags |= S_DEAD; ++ clear_nlink(inode); ++} ++ ++static inline int vfsub_native_ro(struct inode *inode) ++{ ++ return (inode->i_sb->s_flags & MS_RDONLY) ++ || IS_RDONLY(inode) ++ /* || IS_APPEND(inode) */ ++ || IS_IMMUTABLE(inode); ++} ++ ++#ifdef CONFIG_AUFS_BR_FUSE ++int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb); ++#else ++AuStubInt0(vfsub_test_mntns, struct vfsmount *mnt, struct super_block *h_sb); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_update_h_iattr(struct path *h_path, int *did); ++struct file *vfsub_dentry_open(struct path *path, int flags); ++struct file *vfsub_filp_open(const char *path, int oflags, int mode); ++struct vfsub_aopen_args { ++ struct file *file; ++ unsigned int open_flag; ++ umode_t create_mode; ++ int *opened; ++}; ++struct au_branch; ++int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args, struct au_branch *br); ++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path); ++ ++struct dentry *vfsub_lookup_one_len_unlocked(const char *name, ++ struct dentry *parent, int len); ++struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, ++ int len); ++ ++struct vfsub_lkup_one_args { ++ struct dentry **errp; ++ struct qstr *name; ++ struct dentry *parent; ++}; ++ ++static inline struct dentry *vfsub_lkup_one(struct qstr *name, ++ struct dentry *parent) ++{ ++ return vfsub_lookup_one_len(name->name, parent, name->len); ++} ++ ++void vfsub_call_lkup_one(void *args); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int vfsub_mnt_want_write(struct vfsmount *mnt) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = mnt_want_write(mnt); ++ lockdep_on(); ++ return err; ++} ++ ++static inline void vfsub_mnt_drop_write(struct vfsmount *mnt) ++{ ++ lockdep_off(); ++ mnt_drop_write(mnt); ++ lockdep_on(); ++} ++ ++#if 0 /* reserved */ ++static inline void vfsub_mnt_drop_write_file(struct file *file) ++{ ++ lockdep_off(); ++ mnt_drop_write_file(file); ++ lockdep_on(); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_hinode; ++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2); ++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2); ++ ++int vfsub_create(struct inode *dir, struct path *path, int mode, ++ bool want_excl); ++int vfsub_symlink(struct inode *dir, struct path *path, ++ const char *symname); ++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev); ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, ++ struct path *path, struct inode **delegated_inode); ++int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry, ++ struct inode *hdir, struct path *path, ++ struct inode **delegated_inode); ++int vfsub_mkdir(struct inode *dir, struct path *path, int mode); ++int vfsub_rmdir(struct inode *dir, struct path *path); ++ ++/* ---------------------------------------------------------------------- */ ++ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos); ++int vfsub_flush(struct file *file, fl_owner_t id); ++int vfsub_iterate_dir(struct file *file, struct dir_context *ctx); ++ ++static inline loff_t vfsub_f_size_read(struct file *file) ++{ ++ return i_size_read(file_inode(file)); ++} ++ ++static inline unsigned int vfsub_file_flags(struct file *file) ++{ ++ unsigned int flags; ++ ++ spin_lock(&file->f_lock); ++ flags = file->f_flags; ++ spin_unlock(&file->f_lock); ++ ++ return flags; ++} ++ ++#if 0 /* reserved */ ++static inline void vfsub_file_accessed(struct file *h_file) ++{ ++ file_accessed(h_file); ++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); /*ignore*/ ++} ++#endif ++ ++#if 0 /* reserved */ ++static inline void vfsub_touch_atime(struct vfsmount *h_mnt, ++ struct dentry *h_dentry) ++{ ++ struct path h_path = { ++ .dentry = h_dentry, ++ .mnt = h_mnt ++ }; ++ touch_atime(&h_path); ++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/ ++} ++#endif ++ ++static inline int vfsub_update_time(struct inode *h_inode, struct timespec *ts, ++ int flags) ++{ ++ return update_time(h_inode, ts, flags); ++ /* no vfsub_update_h_iattr() since we don't have struct path */ ++} ++ ++#ifdef CONFIG_FS_POSIX_ACL ++static inline int vfsub_acl_chmod(struct inode *h_inode, umode_t h_mode) ++{ ++ int err; ++ ++ err = posix_acl_chmod(h_inode, h_mode); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ return err; ++} ++#else ++AuStubInt0(vfsub_acl_chmod, struct inode *h_inode, umode_t h_mode); ++#endif ++ ++long vfsub_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags); ++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags); ++ ++static inline long vfsub_truncate(struct path *path, loff_t length) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = vfs_truncate(path, length); ++ lockdep_on(); ++ return err; ++} ++ ++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, ++ struct file *h_file); ++int vfsub_fsync(struct file *file, struct path *path, int datasync); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin) ++{ ++ loff_t err; ++ ++ lockdep_off(); ++ err = vfs_llseek(file, offset, origin); ++ lockdep_on(); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode); ++int vfsub_sio_rmdir(struct inode *dir, struct path *path); ++int vfsub_sio_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode); ++int vfsub_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode); ++int vfsub_unlink(struct inode *dir, struct path *path, ++ struct inode **delegated_inode, int force); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int vfsub_setxattr(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_setxattr(dentry, name, value, size, flags); ++ lockdep_on(); ++ ++ return err; ++} ++ ++static inline int vfsub_removexattr(struct dentry *dentry, const char *name) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_removexattr(dentry, name); ++ lockdep_on(); ++ ++ return err; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_VFSUB_H__ */ +diff --git a/fs/aufs/wbr_policy.c b/fs/aufs/wbr_policy.c +new file mode 100644 +index 0000000..91a010a +--- /dev/null ++++ b/fs/aufs/wbr_policy.c +@@ -0,0 +1,752 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * policies for selecting one among multiple writable branches ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* subset of cpup_attr() */ ++static noinline_for_stack ++int au_cpdown_attr(struct path *h_path, struct dentry *h_src) ++{ ++ int err, sbits; ++ struct iattr ia; ++ struct inode *h_isrc; ++ ++ h_isrc = d_inode(h_src); ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID; ++ ia.ia_mode = h_isrc->i_mode; ++ ia.ia_uid = h_isrc->i_uid; ++ ia.ia_gid = h_isrc->i_gid; ++ sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(d_inode(h_path->dentry), h_isrc->i_flags); ++ /* no delegation since it is just created */ ++ err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); ++ ++ /* is this nfs only? */ ++ if (!err && sbits && au_test_nfs(h_path->dentry->d_sb)) { ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); ++ } ++ ++ return err; ++} ++ ++#define AuCpdown_PARENT_OPQ 1 ++#define AuCpdown_WHED (1 << 1) ++#define AuCpdown_MADE_DIR (1 << 2) ++#define AuCpdown_DIROPQ (1 << 3) ++#define au_ftest_cpdown(flags, name) ((flags) & AuCpdown_##name) ++#define au_fset_cpdown(flags, name) \ ++ do { (flags) |= AuCpdown_##name; } while (0) ++#define au_fclr_cpdown(flags, name) \ ++ do { (flags) &= ~AuCpdown_##name; } while (0) ++ ++static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst, ++ unsigned int *flags) ++{ ++ int err; ++ struct dentry *opq_dentry; ++ ++ opq_dentry = au_diropq_create(dentry, bdst); ++ err = PTR_ERR(opq_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out; ++ dput(opq_dentry); ++ au_fset_cpdown(*flags, DIROPQ); ++ ++out: ++ return err; ++} ++ ++static int au_cpdown_dir_wh(struct dentry *dentry, struct dentry *h_parent, ++ struct inode *dir, aufs_bindex_t bdst) ++{ ++ int err; ++ struct path h_path; ++ struct au_branch *br; ++ ++ br = au_sbr(dentry->d_sb, bdst); ++ h_path.dentry = au_wh_lkup(h_parent, &dentry->d_name, br); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ err = 0; ++ if (d_is_positive(h_path.dentry)) { ++ h_path.mnt = au_br_mnt(br); ++ err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path, ++ dentry); ++ } ++ dput(h_path.dentry); ++ ++out: ++ return err; ++} ++ ++static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg) ++{ ++ int err, rerr; ++ aufs_bindex_t bopq, btop; ++ struct path h_path; ++ struct dentry *parent; ++ struct inode *h_dir, *h_inode, *inode, *dir; ++ unsigned int *flags = arg; ++ ++ btop = au_dbtop(dentry); ++ /* dentry is di-locked */ ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ h_dir = d_inode(h_parent); ++ AuDebugOn(h_dir != au_h_iptr(dir, bdst)); ++ IMustLock(h_dir); ++ ++ err = au_lkup_neg(dentry, bdst, /*wh*/0); ++ if (unlikely(err < 0)) ++ goto out; ++ h_path.dentry = au_h_dptr(dentry, bdst); ++ h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst); ++ err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path, ++ S_IRWXU | S_IRUGO | S_IXUGO); ++ if (unlikely(err)) ++ goto out_put; ++ au_fset_cpdown(*flags, MADE_DIR); ++ ++ bopq = au_dbdiropq(dentry); ++ au_fclr_cpdown(*flags, WHED); ++ au_fclr_cpdown(*flags, DIROPQ); ++ if (au_dbwh(dentry) == bdst) ++ au_fset_cpdown(*flags, WHED); ++ if (!au_ftest_cpdown(*flags, PARENT_OPQ) && bopq <= bdst) ++ au_fset_cpdown(*flags, PARENT_OPQ); ++ h_inode = d_inode(h_path.dentry); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ if (au_ftest_cpdown(*flags, WHED)) { ++ err = au_cpdown_dir_opq(dentry, bdst, flags); ++ if (unlikely(err)) { ++ inode_unlock(h_inode); ++ goto out_dir; ++ } ++ } ++ ++ err = au_cpdown_attr(&h_path, au_h_dptr(dentry, btop)); ++ inode_unlock(h_inode); ++ if (unlikely(err)) ++ goto out_opq; ++ ++ if (au_ftest_cpdown(*flags, WHED)) { ++ err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst); ++ if (unlikely(err)) ++ goto out_opq; ++ } ++ ++ inode = d_inode(dentry); ++ if (au_ibbot(inode) < bdst) ++ au_set_ibbot(inode, bdst); ++ au_set_h_iptr(inode, bdst, au_igrab(h_inode), ++ au_hi_flags(inode, /*isdir*/1)); ++ au_fhsm_wrote(dentry->d_sb, bdst, /*force*/0); ++ goto out; /* success */ ++ ++ /* revert */ ++out_opq: ++ if (au_ftest_cpdown(*flags, DIROPQ)) { ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bdst); ++ inode_unlock(h_inode); ++ if (unlikely(rerr)) { ++ AuIOErr("failed removing diropq for %pd b%d (%d)\n", ++ dentry, bdst, rerr); ++ err = -EIO; ++ goto out; ++ } ++ } ++out_dir: ++ if (au_ftest_cpdown(*flags, MADE_DIR)) { ++ rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path); ++ if (unlikely(rerr)) { ++ AuIOErr("failed removing %pd b%d (%d)\n", ++ dentry, bdst, rerr); ++ err = -EIO; ++ } ++ } ++out_put: ++ au_set_h_dptr(dentry, bdst, NULL); ++ if (au_dbbot(dentry) == bdst) ++ au_update_dbbot(dentry); ++out: ++ dput(parent); ++ return err; ++} ++ ++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ int err; ++ unsigned int flags; ++ ++ flags = 0; ++ err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &flags); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies for create */ ++ ++int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err, i, j, ndentry; ++ aufs_bindex_t bopq; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries, *parent, *d; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ parent = dget_parent(dentry); ++ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0); ++ if (unlikely(err)) ++ goto out_free; ++ ++ err = bindex; ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ d = dentries[j]; ++ di_read_lock_parent2(d, !AuLock_IR); ++ bopq = au_dbdiropq(d); ++ di_read_unlock(d, !AuLock_IR); ++ if (bopq >= 0 && bopq < err) ++ err = bopq; ++ } ++ } ++ ++out_free: ++ dput(parent); ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ for (; bindex >= 0; bindex--) ++ if (!au_br_rdonly(au_sbr(sb, bindex))) ++ return bindex; ++ return -EROFS; ++} ++ ++/* top down parent */ ++static int au_wbr_create_tdp(struct dentry *dentry, ++ unsigned int flags __maybe_unused) ++{ ++ int err; ++ aufs_bindex_t btop, bindex; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ err = btop; ++ if (!au_br_rdonly(au_sbr(sb, btop))) ++ goto out; ++ ++ err = -EROFS; ++ parent = dget_parent(dentry); ++ for (bindex = au_dbtop(parent); bindex < btop; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = bindex; ++ break; ++ } ++ } ++ dput(parent); ++ ++ /* bottom up here */ ++ if (unlikely(err < 0)) { ++ err = au_wbr_bu(sb, btop - 1); ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ } ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* an exception for the policy other than tdp */ ++static int au_wbr_create_exp(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bwh, bdiropq; ++ struct dentry *parent; ++ ++ err = -1; ++ bwh = au_dbwh(dentry); ++ parent = dget_parent(dentry); ++ bdiropq = au_dbdiropq(parent); ++ if (bwh >= 0) { ++ if (bdiropq >= 0) ++ err = min(bdiropq, bwh); ++ else ++ err = bwh; ++ AuDbg("%d\n", err); ++ } else if (bdiropq >= 0) { ++ err = bdiropq; ++ AuDbg("%d\n", err); ++ } ++ dput(parent); ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++ if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err))) ++ err = -1; ++ ++ AuDbg("%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* round robin */ ++static int au_wbr_create_init_rr(struct super_block *sb) ++{ ++ int err; ++ ++ err = au_wbr_bu(sb, au_sbbot(sb)); ++ atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */ ++ /* smp_mb(); */ ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_rr(struct dentry *dentry, unsigned int flags) ++{ ++ int err, nbr; ++ unsigned int u; ++ aufs_bindex_t bindex, bbot; ++ struct super_block *sb; ++ atomic_t *next; ++ ++ err = au_wbr_create_exp(dentry); ++ if (err >= 0) ++ goto out; ++ ++ sb = dentry->d_sb; ++ next = &au_sbi(sb)->si_wbr_rr_next; ++ bbot = au_sbbot(sb); ++ nbr = bbot + 1; ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ if (!au_ftest_wbr(flags, DIR)) { ++ err = atomic_dec_return(next) + 1; ++ /* modulo for 0 is meaningless */ ++ if (unlikely(!err)) ++ err = atomic_dec_return(next) + 1; ++ } else ++ err = atomic_read(next); ++ AuDbg("%d\n", err); ++ u = err; ++ err = u % nbr; ++ AuDbg("%d\n", err); ++ if (!au_br_rdonly(au_sbr(sb, err))) ++ break; ++ err = -EROFS; ++ } ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out: ++ AuDbg("%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* most free space */ ++static void au_mfs(struct dentry *dentry, struct dentry *parent) ++{ ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_wbr_mfs *mfs; ++ struct dentry *h_parent; ++ aufs_bindex_t bindex, bbot; ++ int err; ++ unsigned long long b, bavail; ++ struct path h_path; ++ /* reduce the stack usage */ ++ struct kstatfs *st; ++ ++ st = kmalloc(sizeof(*st), GFP_NOFS); ++ if (unlikely(!st)) { ++ AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM); ++ return; ++ } ++ ++ bavail = 0; ++ sb = dentry->d_sb; ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ MtxMustLock(&mfs->mfs_lock); ++ mfs->mfs_bindex = -EROFS; ++ mfs->mfsrr_bytes = 0; ++ if (!parent) { ++ bindex = 0; ++ bbot = au_sbbot(sb); ++ } else { ++ bindex = au_dbtop(parent); ++ bbot = au_dbtaildir(parent); ++ } ++ ++ for (; bindex <= bbot; bindex++) { ++ if (parent) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ } ++ br = au_sbr(sb, bindex); ++ if (au_br_rdonly(br)) ++ continue; ++ ++ /* sb->s_root for NFS is unreliable */ ++ h_path.mnt = au_br_mnt(br); ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, st); ++ if (unlikely(err)) { ++ AuWarn1("failed statfs, b%d, %d\n", bindex, err); ++ continue; ++ } ++ ++ /* when the available size is equal, select the lower one */ ++ BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail) ++ || sizeof(b) < sizeof(st->f_bsize)); ++ b = st->f_bavail * st->f_bsize; ++ br->br_wbr->wbr_bytes = b; ++ if (b >= bavail) { ++ bavail = b; ++ mfs->mfs_bindex = bindex; ++ mfs->mfs_jiffy = jiffies; ++ } ++ } ++ ++ mfs->mfsrr_bytes = bavail; ++ AuDbg("b%d\n", mfs->mfs_bindex); ++ kfree(st); ++} ++ ++static int au_wbr_create_mfs(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ struct dentry *parent; ++ struct super_block *sb; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_exp(dentry); ++ if (err >= 0) ++ goto out; ++ ++ sb = dentry->d_sb; ++ parent = NULL; ++ if (au_ftest_wbr(flags, PARENT)) ++ parent = dget_parent(dentry); ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) ++ || mfs->mfs_bindex < 0 ++ || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex))) ++ au_mfs(dentry, parent); ++ mutex_unlock(&mfs->mfs_lock); ++ err = mfs->mfs_bindex; ++ dput(parent); ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_init_mfs(struct super_block *sb) ++{ ++ struct au_wbr_mfs *mfs; ++ ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_init(&mfs->mfs_lock); ++ mfs->mfs_jiffy = 0; ++ mfs->mfs_bindex = -EROFS; ++ ++ return 0; ++} ++ ++static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused) ++{ ++ mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* most free space and then round robin */ ++static int au_wbr_create_mfsrr(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_mfs(dentry, flags); ++ if (err >= 0) { ++ mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (mfs->mfsrr_bytes < mfs->mfsrr_watermark) ++ err = au_wbr_create_rr(dentry, flags); ++ mutex_unlock(&mfs->mfs_lock); ++ } ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_init_mfsrr(struct super_block *sb) ++{ ++ int err; ++ ++ au_wbr_create_init_mfs(sb); /* ignore */ ++ err = au_wbr_create_init_rr(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* top down parent and most free space */ ++static int au_wbr_create_pmfs(struct dentry *dentry, unsigned int flags) ++{ ++ int err, e2; ++ unsigned long long b; ++ aufs_bindex_t bindex, btop, bbot; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent; ++ struct au_branch *br; ++ ++ err = au_wbr_create_tdp(dentry, flags); ++ if (unlikely(err < 0)) ++ goto out; ++ parent = dget_parent(dentry); ++ btop = au_dbtop(parent); ++ bbot = au_dbtaildir(parent); ++ if (btop == bbot) ++ goto out_parent; /* success */ ++ ++ e2 = au_wbr_create_mfs(dentry, flags); ++ if (e2 < 0) ++ goto out_parent; /* success */ ++ ++ /* when the available size is equal, select upper one */ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, err); ++ b = br->br_wbr->wbr_bytes; ++ AuDbg("b%d, %llu\n", err, b); ++ ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ ++ br = au_sbr(sb, bindex); ++ if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) { ++ b = br->br_wbr->wbr_bytes; ++ err = bindex; ++ AuDbg("b%d, %llu\n", err, b); ++ } ++ } ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out_parent: ++ dput(parent); ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * - top down parent ++ * - most free space with parent ++ * - most free space round-robin regardless parent ++ */ ++static int au_wbr_create_pmfsrr(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ unsigned long long watermark; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_pmfs(dentry, flags | AuWbr_PARENT); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, err); ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ watermark = mfs->mfsrr_watermark; ++ mutex_unlock(&mfs->mfs_lock); ++ if (br->br_wbr->wbr_bytes < watermark) ++ /* regardless the parent dir */ ++ err = au_wbr_create_mfsrr(dentry, flags); ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies for copyup */ ++ ++/* top down parent */ ++static int au_wbr_copyup_tdp(struct dentry *dentry) ++{ ++ return au_wbr_create_tdp(dentry, /*flags, anything is ok*/0); ++} ++ ++/* bottom up parent */ ++static int au_wbr_copyup_bup(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bindex, btop; ++ struct dentry *parent, *h_parent; ++ struct super_block *sb; ++ ++ err = -EROFS; ++ sb = dentry->d_sb; ++ parent = dget_parent(dentry); ++ btop = au_dbtop(parent); ++ for (bindex = au_dbtop(dentry); bindex >= btop; bindex--) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = bindex; ++ break; ++ } ++ } ++ dput(parent); ++ ++ /* bottom up here */ ++ if (unlikely(err < 0)) ++ err = au_wbr_bu(sb, btop - 1); ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* bottom up */ ++int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t btop) ++{ ++ int err; ++ ++ err = au_wbr_bu(dentry->d_sb, btop); ++ AuDbg("b%d\n", err); ++ if (err > btop) ++ err = au_wbr_nonopq(dentry, err); ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_copyup_bu(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t btop; ++ ++ btop = au_dbtop(dentry); ++ err = au_wbr_do_copyup_bu(dentry, btop); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_wbr_copyup_operations au_wbr_copyup_ops[] = { ++ [AuWbrCopyup_TDP] = { ++ .copyup = au_wbr_copyup_tdp ++ }, ++ [AuWbrCopyup_BUP] = { ++ .copyup = au_wbr_copyup_bup ++ }, ++ [AuWbrCopyup_BU] = { ++ .copyup = au_wbr_copyup_bu ++ } ++}; ++ ++struct au_wbr_create_operations au_wbr_create_ops[] = { ++ [AuWbrCreate_TDP] = { ++ .create = au_wbr_create_tdp ++ }, ++ [AuWbrCreate_RR] = { ++ .create = au_wbr_create_rr, ++ .init = au_wbr_create_init_rr ++ }, ++ [AuWbrCreate_MFS] = { ++ .create = au_wbr_create_mfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSV] = { ++ .create = au_wbr_create_mfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSRR] = { ++ .create = au_wbr_create_mfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSRRV] = { ++ .create = au_wbr_create_mfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFS] = { ++ .create = au_wbr_create_pmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSV] = { ++ .create = au_wbr_create_pmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSRR] = { ++ .create = au_wbr_create_pmfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSRRV] = { ++ .create = au_wbr_create_pmfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ } ++}; +diff --git a/fs/aufs/whout.c b/fs/aufs/whout.c +new file mode 100644 +index 0000000..16a96f88 +--- /dev/null ++++ b/fs/aufs/whout.c +@@ -0,0 +1,1047 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * whiteout for logical deletion and opaque directory ++ */ ++ ++#include "aufs.h" ++ ++#define WH_MASK S_IRUGO ++ ++/* ++ * If a directory contains this file, then it is opaque. We start with the ++ * .wh. flag so that it is blocked by lookup. ++ */ ++static struct qstr diropq_name = QSTR_INIT(AUFS_WH_DIROPQ, ++ sizeof(AUFS_WH_DIROPQ) - 1); ++ ++/* ++ * generate whiteout name, which is NOT terminated by NULL. ++ * @name: original d_name.name ++ * @len: original d_name.len ++ * @wh: whiteout qstr ++ * returns zero when succeeds, otherwise error. ++ * succeeded value as wh->name should be freed by kfree(). ++ */ ++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name) ++{ ++ char *p; ++ ++ if (unlikely(name->len > PATH_MAX - AUFS_WH_PFX_LEN)) ++ return -ENAMETOOLONG; ++ ++ wh->len = name->len + AUFS_WH_PFX_LEN; ++ p = kmalloc(wh->len, GFP_NOFS); ++ wh->name = p; ++ if (p) { ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ memcpy(p + AUFS_WH_PFX_LEN, name->name, name->len); ++ /* smp_mb(); */ ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if the @wh_name exists under @h_parent. ++ * @try_sio specifies the necessary of super-io. ++ */ ++int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio) ++{ ++ int err; ++ struct dentry *wh_dentry; ++ ++ if (!try_sio) ++ wh_dentry = vfsub_lkup_one(wh_name, h_parent); ++ else ++ wh_dentry = au_sio_lkup_one(wh_name, h_parent); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) { ++ if (err == -ENAMETOOLONG) ++ err = 0; ++ goto out; ++ } ++ ++ err = 0; ++ if (d_is_negative(wh_dentry)) ++ goto out_wh; /* success */ ++ ++ err = 1; ++ if (d_is_reg(wh_dentry)) ++ goto out_wh; /* success */ ++ ++ err = -EIO; ++ AuIOErr("%pd Invalid whiteout entry type 0%o.\n", ++ wh_dentry, d_inode(wh_dentry)->i_mode); ++ ++out_wh: ++ dput(wh_dentry); ++out: ++ return err; ++} ++ ++/* ++ * test if the @h_dentry sets opaque or not. ++ */ ++int au_diropq_test(struct dentry *h_dentry) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ h_dir = d_inode(h_dentry); ++ err = au_wh_test(h_dentry, &diropq_name, ++ au_test_h_perm_sio(h_dir, MAY_EXEC)); ++ return err; ++} ++ ++/* ++ * returns a negative dentry whose name is unique and temporary. ++ */ ++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, ++ struct qstr *prefix) ++{ ++ struct dentry *dentry; ++ int i; ++ char defname[NAME_MAX - AUFS_MAX_NAMELEN + DNAME_INLINE_LEN + 1], ++ *name, *p; ++ /* strict atomic_t is unnecessary here */ ++ static unsigned short cnt; ++ struct qstr qs; ++ ++ BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN); ++ ++ name = defname; ++ qs.len = sizeof(defname) - DNAME_INLINE_LEN + prefix->len - 1; ++ if (unlikely(prefix->len > DNAME_INLINE_LEN)) { ++ dentry = ERR_PTR(-ENAMETOOLONG); ++ if (unlikely(qs.len > NAME_MAX)) ++ goto out; ++ dentry = ERR_PTR(-ENOMEM); ++ name = kmalloc(qs.len + 1, GFP_NOFS); ++ if (unlikely(!name)) ++ goto out; ++ } ++ ++ /* doubly whiteout-ed */ ++ memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2); ++ p = name + AUFS_WH_PFX_LEN * 2; ++ memcpy(p, prefix->name, prefix->len); ++ p += prefix->len; ++ *p++ = '.'; ++ AuDebugOn(name + qs.len + 1 - p <= AUFS_WH_TMP_LEN); ++ ++ qs.name = name; ++ for (i = 0; i < 3; i++) { ++ sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++); ++ dentry = au_sio_lkup_one(&qs, h_parent); ++ if (IS_ERR(dentry) || d_is_negative(dentry)) ++ goto out_name; ++ dput(dentry); ++ } ++ /* pr_warn("could not get random name\n"); */ ++ dentry = ERR_PTR(-EEXIST); ++ AuDbg("%.*s\n", AuLNPair(&qs)); ++ BUG(); ++ ++out_name: ++ if (name != defname) ++ kfree(name); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ++ * rename the @h_dentry on @br to the whiteouted temporary name. ++ */ ++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br) ++{ ++ int err; ++ struct path h_path = { ++ .mnt = au_br_mnt(br) ++ }; ++ struct inode *h_dir, *delegated; ++ struct dentry *h_parent; ++ ++ h_parent = h_dentry->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ h_path.dentry = au_whtmp_lkup(h_parent, br, &h_dentry->d_name); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ /* under the same dir, no need to lock_rename() */ ++ delegated = NULL; ++ err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path, &delegated); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ dput(h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * functions for removing a whiteout ++ */ ++ ++static int do_unlink_wh(struct inode *h_dir, struct path *h_path) ++{ ++ int err, force; ++ struct inode *delegated; ++ ++ /* ++ * forces superio when the dir has a sticky bit. ++ * this may be a violation of unix fs semantics. ++ */ ++ force = (h_dir->i_mode & S_ISVTX) ++ && !uid_eq(current_fsuid(), d_inode(h_path->dentry)->i_uid); ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, h_path, &delegated, force); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ return err; ++} ++ ++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, ++ struct dentry *dentry) ++{ ++ int err; ++ ++ err = do_unlink_wh(h_dir, h_path); ++ if (!err && dentry) ++ au_set_dbwh(dentry, -1); ++ ++ return err; ++} ++ ++static int unlink_wh_name(struct dentry *h_parent, struct qstr *wh, ++ struct au_branch *br) ++{ ++ int err; ++ struct path h_path = { ++ .mnt = au_br_mnt(br) ++ }; ++ ++ err = 0; ++ h_path.dentry = vfsub_lkup_one(wh, h_parent); ++ if (IS_ERR(h_path.dentry)) ++ err = PTR_ERR(h_path.dentry); ++ else { ++ if (d_is_reg(h_path.dentry)) ++ err = do_unlink_wh(d_inode(h_parent), &h_path); ++ dput(h_path.dentry); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * initialize/clean whiteout for a branch ++ */ ++ ++static void au_wh_clean(struct inode *h_dir, struct path *whpath, ++ const int isdir) ++{ ++ int err; ++ struct inode *delegated; ++ ++ if (d_is_negative(whpath->dentry)) ++ return; ++ ++ if (isdir) ++ err = vfsub_rmdir(h_dir, whpath); ++ else { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, whpath, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } ++ if (unlikely(err)) ++ pr_warn("failed removing %pd (%d), ignored.\n", ++ whpath->dentry, err); ++} ++ ++static int test_linkable(struct dentry *h_root) ++{ ++ struct inode *h_dir = d_inode(h_root); ++ ++ if (h_dir->i_op->link) ++ return 0; ++ ++ pr_err("%pd (%s) doesn't support link(2), use noplink and rw+nolwh\n", ++ h_root, au_sbtype(h_root->d_sb)); ++ return -ENOSYS; ++} ++ ++/* todo: should this mkdir be done in /sbin/mount.aufs helper? */ ++static int au_whdir(struct inode *h_dir, struct path *path) ++{ ++ int err; ++ ++ err = -EEXIST; ++ if (d_is_negative(path->dentry)) { ++ int mode = S_IRWXU; ++ ++ if (au_test_nfs(path->dentry->d_sb)) ++ mode |= S_IXUGO; ++ err = vfsub_mkdir(h_dir, path, mode); ++ } else if (d_is_dir(path->dentry)) ++ err = 0; ++ else ++ pr_err("unknown %pd exists\n", path->dentry); ++ ++ return err; ++} ++ ++struct au_wh_base { ++ const struct qstr *name; ++ struct dentry *dentry; ++}; ++ ++static void au_wh_init_ro(struct inode *h_dir, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/0); ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++} ++ ++/* ++ * returns tri-state, ++ * minus: error, caller should print the message ++ * zero: succuess ++ * plus: error, caller should NOT print the message ++ */ ++static int au_wh_init_rw_nolink(struct dentry *h_root, struct au_wbr *wbr, ++ int do_plink, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ h_dir = d_inode(h_root); ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/0); ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ if (do_plink) { ++ err = test_linkable(h_root); ++ if (unlikely(err)) { ++ err = 1; ++ goto out; ++ } ++ ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); ++ } else ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * for the moment, aufs supports the branch filesystem which does not support ++ * link(2). testing on FAT which does not support i_op->setattr() fully either, ++ * copyup failed. finally, such filesystem will not be used as the writable ++ * branch. ++ * ++ * returns tri-state, see above. ++ */ ++static int au_wh_init_rw(struct dentry *h_root, struct au_wbr *wbr, ++ int do_plink, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ WbrWhMustWriteLock(wbr); ++ ++ err = test_linkable(h_root); ++ if (unlikely(err)) { ++ err = 1; ++ goto out; ++ } ++ ++ /* ++ * todo: should this create be done in /sbin/mount.aufs helper? ++ */ ++ err = -EEXIST; ++ h_dir = d_inode(h_root); ++ if (d_is_negative(base[AuBrWh_BASE].dentry)) { ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ err = vfsub_create(h_dir, h_path, WH_MASK, /*want_excl*/true); ++ } else if (d_is_reg(base[AuBrWh_BASE].dentry)) ++ err = 0; ++ else ++ pr_err("unknown %pd2 exists\n", base[AuBrWh_BASE].dentry); ++ if (unlikely(err)) ++ goto out; ++ ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ if (do_plink) { ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); ++ } else ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ wbr->wbr_whbase = dget(base[AuBrWh_BASE].dentry); ++ ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * initialize the whiteout base file/dir for @br. ++ */ ++int au_wh_init(struct au_branch *br, struct super_block *sb) ++{ ++ int err, i; ++ const unsigned char do_plink ++ = !!au_opt_test(au_mntflags(sb), PLINK); ++ struct inode *h_dir; ++ struct path path = br->br_path; ++ struct dentry *h_root = path.dentry; ++ struct au_wbr *wbr = br->br_wbr; ++ static const struct qstr base_name[] = { ++ [AuBrWh_BASE] = QSTR_INIT(AUFS_BASE_NAME, ++ sizeof(AUFS_BASE_NAME) - 1), ++ [AuBrWh_PLINK] = QSTR_INIT(AUFS_PLINKDIR_NAME, ++ sizeof(AUFS_PLINKDIR_NAME) - 1), ++ [AuBrWh_ORPH] = QSTR_INIT(AUFS_ORPHDIR_NAME, ++ sizeof(AUFS_ORPHDIR_NAME) - 1) ++ }; ++ struct au_wh_base base[] = { ++ [AuBrWh_BASE] = { ++ .name = base_name + AuBrWh_BASE, ++ .dentry = NULL ++ }, ++ [AuBrWh_PLINK] = { ++ .name = base_name + AuBrWh_PLINK, ++ .dentry = NULL ++ }, ++ [AuBrWh_ORPH] = { ++ .name = base_name + AuBrWh_ORPH, ++ .dentry = NULL ++ } ++ }; ++ ++ if (wbr) ++ WbrWhMustWriteLock(wbr); ++ ++ for (i = 0; i < AuBrWh_Last; i++) { ++ /* doubly whiteouted */ ++ struct dentry *d; ++ ++ d = au_wh_lkup(h_root, (void *)base[i].name, br); ++ err = PTR_ERR(d); ++ if (IS_ERR(d)) ++ goto out; ++ ++ base[i].dentry = d; ++ AuDebugOn(wbr ++ && wbr->wbr_wh[i] ++ && wbr->wbr_wh[i] != base[i].dentry); ++ } ++ ++ if (wbr) ++ for (i = 0; i < AuBrWh_Last; i++) { ++ dput(wbr->wbr_wh[i]); ++ wbr->wbr_wh[i] = NULL; ++ } ++ ++ err = 0; ++ if (!au_br_writable(br->br_perm)) { ++ h_dir = d_inode(h_root); ++ au_wh_init_ro(h_dir, base, &path); ++ } else if (!au_br_wh_linkable(br->br_perm)) { ++ err = au_wh_init_rw_nolink(h_root, wbr, do_plink, base, &path); ++ if (err > 0) ++ goto out; ++ else if (err) ++ goto out_err; ++ } else { ++ err = au_wh_init_rw(h_root, wbr, do_plink, base, &path); ++ if (err > 0) ++ goto out; ++ else if (err) ++ goto out_err; ++ } ++ goto out; /* success */ ++ ++out_err: ++ pr_err("an error(%d) on the writable branch %pd(%s)\n", ++ err, h_root, au_sbtype(h_root->d_sb)); ++out: ++ for (i = 0; i < AuBrWh_Last; i++) ++ dput(base[i].dentry); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * whiteouts are all hard-linked usually. ++ * when its link count reaches a ceiling, we create a new whiteout base ++ * asynchronously. ++ */ ++ ++struct reinit_br_wh { ++ struct super_block *sb; ++ struct au_branch *br; ++}; ++ ++static void reinit_br_wh(void *arg) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct path h_path; ++ struct reinit_br_wh *a = arg; ++ struct au_wbr *wbr; ++ struct inode *dir, *delegated; ++ struct dentry *h_root; ++ struct au_hinode *hdir; ++ ++ err = 0; ++ wbr = a->br->br_wbr; ++ /* big aufs lock */ ++ si_noflush_write_lock(a->sb); ++ if (!au_br_writable(a->br->br_perm)) ++ goto out; ++ bindex = au_br_index(a->sb, a->br->br_id); ++ if (unlikely(bindex < 0)) ++ goto out; ++ ++ di_read_lock_parent(a->sb->s_root, AuLock_IR); ++ dir = d_inode(a->sb->s_root); ++ hdir = au_hi(dir, bindex); ++ h_root = au_h_dptr(a->sb->s_root, bindex); ++ AuDebugOn(h_root != au_br_dentry(a->br)); ++ ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ wbr_wh_write_lock(wbr); ++ err = au_h_verify(wbr->wbr_whbase, au_opt_udba(a->sb), hdir->hi_inode, ++ h_root, a->br); ++ if (!err) { ++ h_path.dentry = wbr->wbr_whbase; ++ h_path.mnt = au_br_mnt(a->br); ++ delegated = NULL; ++ err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, ++ /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } else { ++ pr_warn("%pd is moved, ignored\n", wbr->wbr_whbase); ++ err = 0; ++ } ++ dput(wbr->wbr_whbase); ++ wbr->wbr_whbase = NULL; ++ if (!err) ++ err = au_wh_init(a->br, a->sb); ++ wbr_wh_write_unlock(wbr); ++ au_hn_inode_unlock(hdir); ++ di_read_unlock(a->sb->s_root, AuLock_IR); ++ if (!err) ++ au_fhsm_wrote(a->sb, bindex, /*force*/0); ++ ++out: ++ if (wbr) ++ atomic_dec(&wbr->wbr_wh_running); ++ au_br_put(a->br); ++ si_write_unlock(a->sb); ++ au_nwt_done(&au_sbi(a->sb)->si_nowait); ++ kfree(arg); ++ if (unlikely(err)) ++ AuIOErr("err %d\n", err); ++} ++ ++static void kick_reinit_br_wh(struct super_block *sb, struct au_branch *br) ++{ ++ int do_dec, wkq_err; ++ struct reinit_br_wh *arg; ++ ++ do_dec = 1; ++ if (atomic_inc_return(&br->br_wbr->wbr_wh_running) != 1) ++ goto out; ++ ++ /* ignore ENOMEM */ ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (arg) { ++ /* ++ * dec(wh_running), kfree(arg) and dec(br_count) ++ * in reinit function ++ */ ++ arg->sb = sb; ++ arg->br = br; ++ au_br_get(br); ++ wkq_err = au_wkq_nowait(reinit_br_wh, arg, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ atomic_dec(&br->br_wbr->wbr_wh_running); ++ au_br_put(br); ++ kfree(arg); ++ } ++ do_dec = 0; ++ } ++ ++out: ++ if (do_dec) ++ atomic_dec(&br->br_wbr->wbr_wh_running); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create the whiteout @wh. ++ */ ++static int link_or_create_wh(struct super_block *sb, aufs_bindex_t bindex, ++ struct dentry *wh) ++{ ++ int err; ++ struct path h_path = { ++ .dentry = wh ++ }; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *h_parent; ++ struct inode *h_dir, *delegated; ++ ++ h_parent = wh->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ br = au_sbr(sb, bindex); ++ h_path.mnt = au_br_mnt(br); ++ wbr = br->br_wbr; ++ wbr_wh_read_lock(wbr); ++ if (wbr->wbr_whbase) { ++ delegated = NULL; ++ err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ if (!err || err != -EMLINK) ++ goto out; ++ ++ /* link count full. re-initialize br_whbase. */ ++ kick_reinit_br_wh(sb, br); ++ } ++ ++ /* return this error in this context */ ++ err = vfsub_create(h_dir, &h_path, WH_MASK, /*want_excl*/true); ++ if (!err) ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ ++out: ++ wbr_wh_read_unlock(wbr); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create or remove the diropq. ++ */ ++static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags) ++{ ++ struct dentry *opq_dentry, *h_dentry; ++ struct super_block *sb; ++ struct au_branch *br; ++ int err; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ h_dentry = au_h_dptr(dentry, bindex); ++ opq_dentry = vfsub_lkup_one(&diropq_name, h_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out; ++ ++ if (au_ftest_diropq(flags, CREATE)) { ++ err = link_or_create_wh(sb, bindex, opq_dentry); ++ if (!err) { ++ au_set_dbdiropq(dentry, bindex); ++ goto out; /* success */ ++ } ++ } else { ++ struct path tmp = { ++ .dentry = opq_dentry, ++ .mnt = au_br_mnt(br) ++ }; ++ err = do_unlink_wh(au_h_iptr(d_inode(dentry), bindex), &tmp); ++ if (!err) ++ au_set_dbdiropq(dentry, -1); ++ } ++ dput(opq_dentry); ++ opq_dentry = ERR_PTR(err); ++ ++out: ++ return opq_dentry; ++} ++ ++struct do_diropq_args { ++ struct dentry **errp; ++ struct dentry *dentry; ++ aufs_bindex_t bindex; ++ unsigned int flags; ++}; ++ ++static void call_do_diropq(void *args) ++{ ++ struct do_diropq_args *a = args; ++ *a->errp = do_diropq(a->dentry, a->bindex, a->flags); ++} ++ ++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags) ++{ ++ struct dentry *diropq, *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!au_test_h_perm_sio(d_inode(h_dentry), MAY_EXEC | MAY_WRITE)) ++ diropq = do_diropq(dentry, bindex, flags); ++ else { ++ int wkq_err; ++ struct do_diropq_args args = { ++ .errp = &diropq, ++ .dentry = dentry, ++ .bindex = bindex, ++ .flags = flags ++ }; ++ ++ wkq_err = au_wkq_wait(call_do_diropq, &args); ++ if (unlikely(wkq_err)) ++ diropq = ERR_PTR(wkq_err); ++ } ++ ++ return diropq; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * lookup whiteout dentry. ++ * @h_parent: lower parent dentry which must exist and be locked ++ * @base_name: name of dentry which will be whiteouted ++ * returns dentry for whiteout. ++ */ ++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, ++ struct au_branch *br) ++{ ++ int err; ++ struct qstr wh_name; ++ struct dentry *wh_dentry; ++ ++ err = au_wh_name_alloc(&wh_name, base_name); ++ wh_dentry = ERR_PTR(err); ++ if (!err) { ++ wh_dentry = vfsub_lkup_one(&wh_name, h_parent); ++ kfree(wh_name.name); ++ } ++ return wh_dentry; ++} ++ ++/* ++ * link/create a whiteout for @dentry on @bindex. ++ */ ++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent) ++{ ++ struct dentry *wh_dentry; ++ struct super_block *sb; ++ int err; ++ ++ sb = dentry->d_sb; ++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex)); ++ if (!IS_ERR(wh_dentry) && d_is_negative(wh_dentry)) { ++ err = link_or_create_wh(sb, bindex, wh_dentry); ++ if (!err) { ++ au_set_dbwh(dentry, bindex); ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ } else { ++ dput(wh_dentry); ++ wh_dentry = ERR_PTR(err); ++ } ++ } ++ ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Delete all whiteouts in this directory on branch bindex. */ ++static int del_wh_children(struct dentry *h_dentry, struct au_nhash *whlist, ++ aufs_bindex_t bindex, struct au_branch *br) ++{ ++ int err; ++ unsigned long ul, n; ++ struct qstr wh_name; ++ char *p; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct au_vdir_destr *str; ++ ++ err = -ENOMEM; ++ p = (void *)__get_free_page(GFP_NOFS); ++ wh_name.name = p; ++ if (unlikely(!wh_name.name)) ++ goto out; ++ ++ err = 0; ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ p += AUFS_WH_PFX_LEN; ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (ul = 0; !err && ul < n; ul++, head++) { ++ hlist_for_each_entry(pos, head, wh_hash) { ++ if (pos->wh_bindex != bindex) ++ continue; ++ ++ str = &pos->wh_str; ++ if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) { ++ memcpy(p, str->name, str->len); ++ wh_name.len = AUFS_WH_PFX_LEN + str->len; ++ err = unlink_wh_name(h_dentry, &wh_name, br); ++ if (!err) ++ continue; ++ break; ++ } ++ AuIOErr("whiteout name too long %.*s\n", ++ str->len, str->name); ++ err = -EIO; ++ break; ++ } ++ } ++ free_page((unsigned long)wh_name.name); ++ ++out: ++ return err; ++} ++ ++struct del_wh_children_args { ++ int *errp; ++ struct dentry *h_dentry; ++ struct au_nhash *whlist; ++ aufs_bindex_t bindex; ++ struct au_branch *br; ++}; ++ ++static void call_del_wh_children(void *args) ++{ ++ struct del_wh_children_args *a = args; ++ *a->errp = del_wh_children(a->h_dentry, a->whlist, a->bindex, a->br); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp) ++{ ++ struct au_whtmp_rmdir *whtmp; ++ int err; ++ unsigned int rdhash; ++ ++ SiMustAnyLock(sb); ++ ++ whtmp = kzalloc(sizeof(*whtmp), gfp); ++ if (unlikely(!whtmp)) { ++ whtmp = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ /* no estimation for dir size */ ++ rdhash = au_sbi(sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = AUFS_RDHASH_DEF; ++ err = au_nhash_alloc(&whtmp->whlist, rdhash, gfp); ++ if (unlikely(err)) { ++ kfree(whtmp); ++ whtmp = ERR_PTR(err); ++ } ++ ++out: ++ return whtmp; ++} ++ ++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp) ++{ ++ if (whtmp->br) ++ au_br_put(whtmp->br); ++ dput(whtmp->wh_dentry); ++ iput(whtmp->dir); ++ au_nhash_wh_free(&whtmp->whlist); ++ kfree(whtmp); ++} ++ ++/* ++ * rmdir the whiteouted temporary named dir @h_dentry. ++ * @whlist: whiteouted children. ++ */ ++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_nhash *whlist) ++{ ++ int err; ++ unsigned int h_nlink; ++ struct path h_tmp; ++ struct inode *wh_inode, *h_dir; ++ struct au_branch *br; ++ ++ h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */ ++ IMustLock(h_dir); ++ ++ br = au_sbr(dir->i_sb, bindex); ++ wh_inode = d_inode(wh_dentry); ++ inode_lock_nested(wh_inode, AuLsc_I_CHILD); ++ ++ /* ++ * someone else might change some whiteouts while we were sleeping. ++ * it means this whlist may have an obsoleted entry. ++ */ ++ if (!au_test_h_perm_sio(wh_inode, MAY_EXEC | MAY_WRITE)) ++ err = del_wh_children(wh_dentry, whlist, bindex, br); ++ else { ++ int wkq_err; ++ struct del_wh_children_args args = { ++ .errp = &err, ++ .h_dentry = wh_dentry, ++ .whlist = whlist, ++ .bindex = bindex, ++ .br = br ++ }; ++ ++ wkq_err = au_wkq_wait(call_del_wh_children, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ inode_unlock(wh_inode); ++ ++ if (!err) { ++ h_tmp.dentry = wh_dentry; ++ h_tmp.mnt = au_br_mnt(br); ++ h_nlink = h_dir->i_nlink; ++ err = vfsub_rmdir(h_dir, &h_tmp); ++ /* some fs doesn't change the parent nlink in some cases */ ++ h_nlink -= h_dir->i_nlink; ++ } ++ ++ if (!err) { ++ if (au_ibtop(dir) == bindex) { ++ /* todo: dir->i_mutex is necessary */ ++ au_cpup_attr_timesizes(dir); ++ if (h_nlink) ++ vfsub_drop_nlink(dir); ++ } ++ return 0; /* success */ ++ } ++ ++ pr_warn("failed removing %pd(%d), ignored\n", wh_dentry, err); ++ return err; ++} ++ ++static void call_rmdir_whtmp(void *args) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct au_whtmp_rmdir *a = args; ++ struct super_block *sb; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ struct au_hinode *hdir; ++ ++ /* rmdir by nfsd may cause deadlock with this i_mutex */ ++ /* inode_lock(a->dir); */ ++ err = -EROFS; ++ sb = a->dir->i_sb; ++ si_read_lock(sb, !AuLock_FLUSH); ++ if (!au_br_writable(a->br->br_perm)) ++ goto out; ++ bindex = au_br_index(sb, a->br->br_id); ++ if (unlikely(bindex < 0)) ++ goto out; ++ ++ err = -EIO; ++ ii_write_lock_parent(a->dir); ++ h_parent = dget_parent(a->wh_dentry); ++ h_dir = d_inode(h_parent); ++ hdir = au_hi(a->dir, bindex); ++ err = vfsub_mnt_want_write(au_br_mnt(a->br)); ++ if (unlikely(err)) ++ goto out_mnt; ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent, ++ a->br); ++ if (!err) ++ err = au_whtmp_rmdir(a->dir, bindex, a->wh_dentry, &a->whlist); ++ au_hn_inode_unlock(hdir); ++ vfsub_mnt_drop_write(au_br_mnt(a->br)); ++ ++out_mnt: ++ dput(h_parent); ++ ii_write_unlock(a->dir); ++out: ++ /* inode_unlock(a->dir); */ ++ au_whtmp_rmdir_free(a); ++ si_read_unlock(sb); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ if (unlikely(err)) ++ AuIOErr("err %d\n", err); ++} ++ ++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args) ++{ ++ int wkq_err; ++ struct super_block *sb; ++ ++ IMustLock(dir); ++ ++ /* all post-process will be done in do_rmdir_whtmp(). */ ++ sb = dir->i_sb; ++ args->dir = au_igrab(dir); ++ args->br = au_sbr(sb, bindex); ++ au_br_get(args->br); ++ args->wh_dentry = dget(wh_dentry); ++ wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ pr_warn("rmdir error %pd (%d), ignored\n", wh_dentry, wkq_err); ++ au_whtmp_rmdir_free(args); ++ } ++} +diff --git a/fs/aufs/whout.h b/fs/aufs/whout.h +new file mode 100644 +index 0000000..4077dd1 +--- /dev/null ++++ b/fs/aufs/whout.h +@@ -0,0 +1,72 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * whiteout for logical deletion and opaque directory ++ */ ++ ++#ifndef __AUFS_WHOUT_H__ ++#define __AUFS_WHOUT_H__ ++ ++#ifdef __KERNEL__ ++ ++#include "dir.h" ++ ++/* whout.c */ ++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name); ++int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio); ++int au_diropq_test(struct dentry *h_dentry); ++struct au_branch; ++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, ++ struct qstr *prefix); ++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br); ++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, ++ struct dentry *dentry); ++int au_wh_init(struct au_branch *br, struct super_block *sb); ++ ++/* diropq flags */ ++#define AuDiropq_CREATE 1 ++#define au_ftest_diropq(flags, name) ((flags) & AuDiropq_##name) ++#define au_fset_diropq(flags, name) \ ++ do { (flags) |= AuDiropq_##name; } while (0) ++#define au_fclr_diropq(flags, name) \ ++ do { (flags) &= ~AuDiropq_##name; } while (0) ++ ++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags); ++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, ++ struct au_branch *br); ++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent); ++ ++/* real rmdir for the whiteout-ed dir */ ++struct au_whtmp_rmdir { ++ struct inode *dir; ++ struct au_branch *br; ++ struct dentry *wh_dentry; ++ struct au_nhash whlist; ++}; ++ ++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp); ++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp); ++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_nhash *whlist); ++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct dentry *au_diropq_create(struct dentry *dentry, ++ aufs_bindex_t bindex) ++{ ++ return au_diropq_sio(dentry, bindex, AuDiropq_CREATE); ++} ++ ++static inline int au_diropq_remove(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ return PTR_ERR(au_diropq_sio(dentry, bindex, !AuDiropq_CREATE)); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_WHOUT_H__ */ +diff --git a/fs/aufs/wkq.c b/fs/aufs/wkq.c +new file mode 100644 +index 0000000..65c0137 +--- /dev/null ++++ b/fs/aufs/wkq.c +@@ -0,0 +1,205 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * workqueue for asynchronous/super-io operations ++ * todo: try new dredential scheme ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* internal workqueue named AUFS_WKQ_NAME */ ++ ++static struct workqueue_struct *au_wkq; ++ ++struct au_wkinfo { ++ struct work_struct wk; ++ struct kobject *kobj; ++ ++ unsigned int flags; /* see wkq.h */ ++ ++ au_wkq_func_t func; ++ void *args; ++ ++ struct completion *comp; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void wkq_func(struct work_struct *wk) ++{ ++ struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk); ++ ++ AuDebugOn(!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)); ++ AuDebugOn(rlimit(RLIMIT_FSIZE) != RLIM_INFINITY); ++ ++ wkinfo->func(wkinfo->args); ++ if (au_ftest_wkq(wkinfo->flags, WAIT)) ++ complete(wkinfo->comp); ++ else { ++ kobject_put(wkinfo->kobj); ++ module_put(THIS_MODULE); /* todo: ?? */ ++ kfree(wkinfo); ++ } ++} ++ ++/* ++ * Since struct completion is large, try allocating it dynamically. ++ */ ++#if 1 /* defined(CONFIG_4KSTACKS) || defined(AuTest4KSTACKS) */ ++#define AuWkqCompDeclare(name) struct completion *comp = NULL ++ ++static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) ++{ ++ *comp = kmalloc(sizeof(**comp), GFP_NOFS); ++ if (*comp) { ++ init_completion(*comp); ++ wkinfo->comp = *comp; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++static void au_wkq_comp_free(struct completion *comp) ++{ ++ kfree(comp); ++} ++ ++#else ++ ++/* no braces */ ++#define AuWkqCompDeclare(name) \ ++ DECLARE_COMPLETION_ONSTACK(_ ## name); \ ++ struct completion *comp = &_ ## name ++ ++static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) ++{ ++ wkinfo->comp = *comp; ++ return 0; ++} ++ ++static void au_wkq_comp_free(struct completion *comp __maybe_unused) ++{ ++ /* empty */ ++} ++#endif /* 4KSTACKS */ ++ ++static void au_wkq_run(struct au_wkinfo *wkinfo) ++{ ++ if (au_ftest_wkq(wkinfo->flags, NEST)) { ++ if (au_wkq_test()) { ++ AuWarn1("wkq from wkq, unless silly-rename on NFS," ++ " due to a dead dir by UDBA?\n"); ++ AuDebugOn(au_ftest_wkq(wkinfo->flags, WAIT)); ++ } ++ } else ++ au_dbg_verify_kthread(); ++ ++ if (au_ftest_wkq(wkinfo->flags, WAIT)) { ++ INIT_WORK_ONSTACK(&wkinfo->wk, wkq_func); ++ queue_work(au_wkq, &wkinfo->wk); ++ } else { ++ INIT_WORK(&wkinfo->wk, wkq_func); ++ schedule_work(&wkinfo->wk); ++ } ++} ++ ++/* ++ * Be careful. It is easy to make deadlock happen. ++ * processA: lock, wkq and wait ++ * processB: wkq and wait, lock in wkq ++ * --> deadlock ++ */ ++int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args) ++{ ++ int err; ++ AuWkqCompDeclare(comp); ++ struct au_wkinfo wkinfo = { ++ .flags = flags, ++ .func = func, ++ .args = args ++ }; ++ ++ err = au_wkq_comp_alloc(&wkinfo, &comp); ++ if (!err) { ++ au_wkq_run(&wkinfo); ++ /* no timeout, no interrupt */ ++ wait_for_completion(wkinfo.comp); ++ au_wkq_comp_free(comp); ++ destroy_work_on_stack(&wkinfo.wk); ++ } ++ ++ return err; ++ ++} ++ ++/* ++ * Note: dget/dput() in func for aufs dentries are not supported. It will be a ++ * problem in a concurrent umounting. ++ */ ++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, ++ unsigned int flags) ++{ ++ int err; ++ struct au_wkinfo *wkinfo; ++ ++ percpu_counter_inc(&au_sbi(sb)->si_nowait.nw_len); ++ ++ /* ++ * wkq_func() must free this wkinfo. ++ * it highly depends upon the implementation of workqueue. ++ */ ++ err = 0; ++ wkinfo = kmalloc(sizeof(*wkinfo), GFP_NOFS); ++ if (wkinfo) { ++ wkinfo->kobj = &au_sbi(sb)->si_kobj; ++ wkinfo->flags = flags & ~AuWkq_WAIT; ++ wkinfo->func = func; ++ wkinfo->args = args; ++ wkinfo->comp = NULL; ++ kobject_get(wkinfo->kobj); ++ __module_get(THIS_MODULE); /* todo: ?? */ ++ ++ au_wkq_run(wkinfo); ++ } else { ++ err = -ENOMEM; ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_nwt_init(struct au_nowait_tasks *nwt) ++{ ++ percpu_counter_init(&nwt->nw_len, 0, GFP_NOFS); ++ init_waitqueue_head(&nwt->nw_wq); ++} ++ ++void au_nwt_fin(struct au_nowait_tasks *nwt) ++{ ++ AuDebugOn(percpu_counter_sum(&nwt->nw_len)); ++ percpu_counter_destroy(&nwt->nw_len); ++} ++ ++void au_wkq_fin(void) ++{ ++ destroy_workqueue(au_wkq); ++} ++ ++int __init au_wkq_init(void) ++{ ++ int err; ++ ++ err = 0; ++ au_wkq = alloc_workqueue(AUFS_WKQ_NAME, 0, WQ_DFL_ACTIVE); ++ if (IS_ERR(au_wkq)) ++ err = PTR_ERR(au_wkq); ++ else if (!au_wkq) ++ err = -ENOMEM; ++ ++ return err; ++} +diff --git a/fs/aufs/wkq.h b/fs/aufs/wkq.h +new file mode 100644 +index 0000000..0b870cc +--- /dev/null ++++ b/fs/aufs/wkq.h +@@ -0,0 +1,82 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * workqueue for asynchronous/super-io operations ++ * todo: try new credentials management scheme ++ */ ++ ++#ifndef __AUFS_WKQ_H__ ++#define __AUFS_WKQ_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct super_block; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * in the next operation, wait for the 'nowait' tasks in system-wide workqueue ++ */ ++struct au_nowait_tasks { ++ struct percpu_counter nw_len; ++ wait_queue_head_t nw_wq; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++typedef void (*au_wkq_func_t)(void *args); ++ ++/* wkq flags */ ++#define AuWkq_WAIT 1 ++#define AuWkq_NEST (1 << 1) ++#define au_ftest_wkq(flags, name) ((flags) & AuWkq_##name) ++#define au_fset_wkq(flags, name) \ ++ do { (flags) |= AuWkq_##name; } while (0) ++#define au_fclr_wkq(flags, name) \ ++ do { (flags) &= ~AuWkq_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_HNOTIFY ++#undef AuWkq_NEST ++#define AuWkq_NEST 0 ++#endif ++ ++/* wkq.c */ ++int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args); ++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, ++ unsigned int flags); ++void au_nwt_init(struct au_nowait_tasks *nwt); ++void au_nwt_fin(struct au_nowait_tasks *nwt); ++int __init au_wkq_init(void); ++void au_wkq_fin(void); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int au_wkq_test(void) ++{ ++ return current->flags & PF_WQ_WORKER; ++} ++ ++static inline int au_wkq_wait(au_wkq_func_t func, void *args) ++{ ++ return au_wkq_do_wait(AuWkq_WAIT, func, args); ++} ++ ++static inline void au_nwt_done(struct au_nowait_tasks *nwt) ++{ ++ percpu_counter_dec(&nwt->nw_len); ++ if (!percpu_counter_sum(&nwt->nw_len)) ++ wake_up_all(&nwt->nw_wq); ++} ++ ++static inline int au_nwt_flush(struct au_nowait_tasks *nwt) ++{ ++ wait_event(nwt->nw_wq, !percpu_counter_sum(&nwt->nw_len)); ++ return 0; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_WKQ_H__ */ +diff --git a/fs/aufs/xattr.c b/fs/aufs/xattr.c +new file mode 100644 +index 0000000..c12518f +--- /dev/null ++++ b/fs/aufs/xattr.c +@@ -0,0 +1,332 @@ ++/* ++ * Copyright (C) 2014-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * handling xattr functions ++ */ ++ ++#include ++#include "aufs.h" ++ ++static int au_xattr_ignore(int err, char *name, unsigned int ignore_flags) ++{ ++ if (!ignore_flags) ++ goto out; ++ switch (err) { ++ case -ENOMEM: ++ case -EDQUOT: ++ goto out; ++ } ++ ++ if ((ignore_flags & AuBrAttr_ICEX) == AuBrAttr_ICEX) { ++ err = 0; ++ goto out; ++ } ++ ++#define cmp(brattr, prefix) do { \ ++ if (!strncmp(name, XATTR_##prefix##_PREFIX, \ ++ XATTR_##prefix##_PREFIX_LEN)) { \ ++ if (ignore_flags & AuBrAttr_ICEX_##brattr) \ ++ err = 0; \ ++ goto out; \ ++ } \ ++ } while (0) ++ ++ cmp(SEC, SECURITY); ++ cmp(SYS, SYSTEM); ++ cmp(TR, TRUSTED); ++ cmp(USR, USER); ++#undef cmp ++ ++ if (ignore_flags & AuBrAttr_ICEX_OTH) ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static const int au_xattr_out_of_list = AuBrAttr_ICEX_OTH << 1; ++ ++static int au_do_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, ++ char *name, char **buf, unsigned int ignore_flags, ++ unsigned int verbose) ++{ ++ int err; ++ ssize_t ssz; ++ struct inode *h_idst; ++ ++ ssz = vfs_getxattr_alloc(h_src, name, buf, 0, GFP_NOFS); ++ err = ssz; ++ if (unlikely(err <= 0)) { ++ if (err == -ENODATA ++ || (err == -EOPNOTSUPP ++ && ((ignore_flags & au_xattr_out_of_list) ++ || (au_test_nfs_noacl(d_inode(h_src)) ++ && (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) ++ || !strcmp(name, ++ XATTR_NAME_POSIX_ACL_DEFAULT)))) ++ )) ++ err = 0; ++ if (err && (verbose || au_debug_test())) ++ pr_err("%s, err %d\n", name, err); ++ goto out; ++ } ++ ++ /* unlock it temporary */ ++ h_idst = d_inode(h_dst); ++ inode_unlock(h_idst); ++ err = vfsub_setxattr(h_dst, name, *buf, ssz, /*flags*/0); ++ inode_lock_nested(h_idst, AuLsc_I_CHILD2); ++ if (unlikely(err)) { ++ if (verbose || au_debug_test()) ++ pr_err("%s, err %d\n", name, err); ++ err = au_xattr_ignore(err, name, ignore_flags); ++ } ++ ++out: ++ return err; ++} ++ ++int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags, ++ unsigned int verbose) ++{ ++ int err, unlocked, acl_access, acl_default; ++ ssize_t ssz; ++ struct inode *h_isrc, *h_idst; ++ char *value, *p, *o, *e; ++ ++ /* try stopping to update the source inode while we are referencing */ ++ /* there should not be the parent-child relationship between them */ ++ h_isrc = d_inode(h_src); ++ h_idst = d_inode(h_dst); ++ inode_unlock(h_idst); ++ inode_lock_nested(h_isrc, AuLsc_I_CHILD); ++ inode_lock_nested(h_idst, AuLsc_I_CHILD2); ++ unlocked = 0; ++ ++ /* some filesystems don't list POSIX ACL, for example tmpfs */ ++ ssz = vfs_listxattr(h_src, NULL, 0); ++ err = ssz; ++ if (unlikely(err < 0)) { ++ AuTraceErr(err); ++ if (err == -ENODATA ++ || err == -EOPNOTSUPP) ++ err = 0; /* ignore */ ++ goto out; ++ } ++ ++ err = 0; ++ p = NULL; ++ o = NULL; ++ if (ssz) { ++ err = -ENOMEM; ++ p = kmalloc(ssz, GFP_NOFS); ++ o = p; ++ if (unlikely(!p)) ++ goto out; ++ err = vfs_listxattr(h_src, p, ssz); ++ } ++ inode_unlock(h_isrc); ++ unlocked = 1; ++ AuDbg("err %d, ssz %zd\n", err, ssz); ++ if (unlikely(err < 0)) ++ goto out_free; ++ ++ err = 0; ++ e = p + ssz; ++ value = NULL; ++ acl_access = 0; ++ acl_default = 0; ++ while (!err && p < e) { ++ acl_access |= !strncmp(p, XATTR_NAME_POSIX_ACL_ACCESS, ++ sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1); ++ acl_default |= !strncmp(p, XATTR_NAME_POSIX_ACL_DEFAULT, ++ sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) ++ - 1); ++ err = au_do_cpup_xattr(h_dst, h_src, p, &value, ignore_flags, ++ verbose); ++ p += strlen(p) + 1; ++ } ++ AuTraceErr(err); ++ ignore_flags |= au_xattr_out_of_list; ++ if (!err && !acl_access) { ++ err = au_do_cpup_xattr(h_dst, h_src, ++ XATTR_NAME_POSIX_ACL_ACCESS, &value, ++ ignore_flags, verbose); ++ AuTraceErr(err); ++ } ++ if (!err && !acl_default) { ++ err = au_do_cpup_xattr(h_dst, h_src, ++ XATTR_NAME_POSIX_ACL_DEFAULT, &value, ++ ignore_flags, verbose); ++ AuTraceErr(err); ++ } ++ ++ kfree(value); ++ ++out_free: ++ kfree(o); ++out: ++ if (!unlocked) ++ inode_unlock(h_isrc); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++enum { ++ AU_XATTR_LIST, ++ AU_XATTR_GET ++}; ++ ++struct au_lgxattr { ++ int type; ++ union { ++ struct { ++ char *list; ++ size_t size; ++ } list; ++ struct { ++ const char *name; ++ void *value; ++ size_t size; ++ } get; ++ } u; ++}; ++ ++static ssize_t au_lgxattr(struct dentry *dentry, struct au_lgxattr *arg) ++{ ++ ssize_t err; ++ struct path h_path; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ err = au_h_path_getattr(dentry, /*force*/1, &h_path); ++ if (unlikely(err)) ++ goto out_si; ++ if (unlikely(!h_path.dentry)) ++ /* illegally overlapped or something */ ++ goto out_di; /* pretending success */ ++ ++ /* always topmost entry only */ ++ switch (arg->type) { ++ case AU_XATTR_LIST: ++ err = vfs_listxattr(h_path.dentry, ++ arg->u.list.list, arg->u.list.size); ++ break; ++ case AU_XATTR_GET: ++ AuDebugOn(d_is_negative(h_path.dentry)); ++ err = vfs_getxattr(h_path.dentry, ++ arg->u.get.name, arg->u.get.value, ++ arg->u.get.size); ++ break; ++ } ++ ++out_di: ++ di_read_unlock(dentry, AuLock_IR); ++out_si: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size) ++{ ++ struct au_lgxattr arg = { ++ .type = AU_XATTR_LIST, ++ .u.list = { ++ .list = list, ++ .size = size ++ }, ++ }; ++ ++ return au_lgxattr(dentry, &arg); ++} ++ ++ssize_t aufs_getxattr(struct dentry *dentry, struct inode *inode __maybe_unused, ++ const char *name, void *value, size_t size) ++{ ++ struct au_lgxattr arg = { ++ .type = AU_XATTR_GET, ++ .u.get = { ++ .name = name, ++ .value = value, ++ .size = size ++ }, ++ }; ++ ++ return au_lgxattr(dentry, &arg); ++} ++ ++int aufs_setxattr(struct dentry *dentry, struct inode *inode, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ struct au_srxattr arg = { ++ .type = AU_XATTR_SET, ++ .u.set = { ++ .name = name, ++ .value = value, ++ .size = size, ++ .flags = flags ++ }, ++ }; ++ ++ return au_srxattr(dentry, inode, &arg); ++} ++ ++int aufs_removexattr(struct dentry *dentry, const char *name) ++{ ++ struct au_srxattr arg = { ++ .type = AU_XATTR_REMOVE, ++ .u.remove = { ++ .name = name ++ }, ++ }; ++ ++ return au_srxattr(dentry, d_inode(dentry), &arg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#if 0 ++static size_t au_xattr_list(struct dentry *dentry, char *list, size_t list_size, ++ const char *name, size_t name_len, int type) ++{ ++ return aufs_listxattr(dentry, list, list_size); ++} ++ ++static int au_xattr_get(struct dentry *dentry, const char *name, void *buffer, ++ size_t size, int type) ++{ ++ return aufs_getxattr(dentry, name, buffer, size); ++} ++ ++static int au_xattr_set(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags, int type) ++{ ++ return aufs_setxattr(dentry, name, value, size, flags); ++} ++ ++static const struct xattr_handler au_xattr_handler = { ++ /* no prefix, no flags */ ++ .list = au_xattr_list, ++ .get = au_xattr_get, ++ .set = au_xattr_set ++ /* why no remove? */ ++}; ++ ++static const struct xattr_handler *au_xattr_handlers[] = { ++ &au_xattr_handler ++}; ++ ++void au_xattr_init(struct super_block *sb) ++{ ++ /* sb->s_xattr = au_xattr_handlers; */ ++} ++#endif +diff --git a/fs/aufs/xino.c b/fs/aufs/xino.c +new file mode 100644 +index 0000000..4d1d5d4 +--- /dev/null ++++ b/fs/aufs/xino.c +@@ -0,0 +1,1304 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * external inode number translation table and bitmap ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* todo: unnecessary to support mmap_sem since kernel-space? */ ++ssize_t xino_fread(vfs_readf_t func, struct file *file, void *kbuf, size_t size, ++ loff_t *pos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ union { ++ void *k; ++ char __user *u; ++ } buf; ++ ++ buf.k = kbuf; ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ do { ++ /* todo: signal_pending? */ ++ err = func(file, buf.u, size, pos); ++ } while (err == -EAGAIN || err == -EINTR); ++ set_fs(oldfs); ++ ++#if 0 /* reserved for future use */ ++ if (err > 0) ++ fsnotify_access(file->f_path.dentry); ++#endif ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static ssize_t xino_fwrite_wkq(vfs_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos); ++ ++static ssize_t do_xino_fwrite(vfs_writef_t func, struct file *file, void *kbuf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ union { ++ void *k; ++ const char __user *u; ++ } buf; ++ int i; ++ const int prevent_endless = 10; ++ ++ i = 0; ++ buf.k = kbuf; ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ do { ++ err = func(file, buf.u, size, pos); ++ if (err == -EINTR ++ && !au_wkq_test() ++ && fatal_signal_pending(current)) { ++ set_fs(oldfs); ++ err = xino_fwrite_wkq(func, file, kbuf, size, pos); ++ BUG_ON(err == -EINTR); ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ } ++ } while (i++ < prevent_endless ++ && (err == -EAGAIN || err == -EINTR)); ++ set_fs(oldfs); ++ ++#if 0 /* reserved for future use */ ++ if (err > 0) ++ fsnotify_modify(file->f_path.dentry); ++#endif ++ ++ return err; ++} ++ ++struct do_xino_fwrite_args { ++ ssize_t *errp; ++ vfs_writef_t func; ++ struct file *file; ++ void *buf; ++ size_t size; ++ loff_t *pos; ++}; ++ ++static void call_do_xino_fwrite(void *args) ++{ ++ struct do_xino_fwrite_args *a = args; ++ *a->errp = do_xino_fwrite(a->func, a->file, a->buf, a->size, a->pos); ++} ++ ++static ssize_t xino_fwrite_wkq(vfs_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ int wkq_err; ++ struct do_xino_fwrite_args args = { ++ .errp = &err, ++ .func = func, ++ .file = file, ++ .buf = buf, ++ .size = size, ++ .pos = pos ++ }; ++ ++ /* ++ * it breaks RLIMIT_FSIZE and normal user's limit, ++ * users should care about quota and real 'filesystem full.' ++ */ ++ wkq_err = au_wkq_wait(call_do_xino_fwrite, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++ssize_t xino_fwrite(vfs_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ ++ if (rlimit(RLIMIT_FSIZE) == RLIM_INFINITY) { ++ lockdep_off(); ++ err = do_xino_fwrite(func, file, buf, size, pos); ++ lockdep_on(); ++ } else ++ err = xino_fwrite_wkq(func, file, buf, size, pos); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create a new xinofile at the same place/path as @base_file. ++ */ ++struct file *au_xino_create2(struct file *base_file, struct file *copy_src) ++{ ++ struct file *file; ++ struct dentry *base, *parent; ++ struct inode *dir, *delegated; ++ struct qstr *name; ++ struct path path; ++ int err; ++ ++ base = base_file->f_path.dentry; ++ parent = base->d_parent; /* dir inode is locked */ ++ dir = d_inode(parent); ++ IMustLock(dir); ++ ++ file = ERR_PTR(-EINVAL); ++ name = &base->d_name; ++ path.dentry = vfsub_lookup_one_len(name->name, parent, name->len); ++ if (IS_ERR(path.dentry)) { ++ file = (void *)path.dentry; ++ pr_err("%pd lookup err %ld\n", ++ base, PTR_ERR(path.dentry)); ++ goto out; ++ } ++ ++ /* no need to mnt_want_write() since we call dentry_open() later */ ++ err = vfs_create(dir, path.dentry, S_IRUGO | S_IWUGO, NULL); ++ if (unlikely(err)) { ++ file = ERR_PTR(err); ++ pr_err("%pd create err %d\n", base, err); ++ goto out_dput; ++ } ++ ++ path.mnt = base_file->f_path.mnt; ++ file = vfsub_dentry_open(&path, ++ O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE ++ /* | __FMODE_NONOTIFY */); ++ if (IS_ERR(file)) { ++ pr_err("%pd open err %ld\n", base, PTR_ERR(file)); ++ goto out_dput; ++ } ++ ++ delegated = NULL; ++ err = vfsub_unlink(dir, &file->f_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) { ++ pr_err("%pd unlink err %d\n", base, err); ++ goto out_fput; ++ } ++ ++ if (copy_src) { ++ /* no one can touch copy_src xino */ ++ err = au_copy_file(file, copy_src, vfsub_f_size_read(copy_src)); ++ if (unlikely(err)) { ++ pr_err("%pd copy err %d\n", base, err); ++ goto out_fput; ++ } ++ } ++ goto out_dput; /* success */ ++ ++out_fput: ++ fput(file); ++ file = ERR_PTR(err); ++out_dput: ++ dput(path.dentry); ++out: ++ return file; ++} ++ ++struct au_xino_lock_dir { ++ struct au_hinode *hdir; ++ struct dentry *parent; ++ struct inode *dir; ++}; ++ ++static void au_xino_lock_dir(struct super_block *sb, struct file *xino, ++ struct au_xino_lock_dir *ldir) ++{ ++ aufs_bindex_t brid, bindex; ++ ++ ldir->hdir = NULL; ++ bindex = -1; ++ brid = au_xino_brid(sb); ++ if (brid >= 0) ++ bindex = au_br_index(sb, brid); ++ if (bindex >= 0) { ++ ldir->hdir = au_hi(d_inode(sb->s_root), bindex); ++ au_hn_inode_lock_nested(ldir->hdir, AuLsc_I_PARENT); ++ } else { ++ ldir->parent = dget_parent(xino->f_path.dentry); ++ ldir->dir = d_inode(ldir->parent); ++ inode_lock_nested(ldir->dir, AuLsc_I_PARENT); ++ } ++} ++ ++static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir) ++{ ++ if (ldir->hdir) ++ au_hn_inode_unlock(ldir->hdir); ++ else { ++ inode_unlock(ldir->dir); ++ dput(ldir->parent); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* trucate xino files asynchronously */ ++ ++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err; ++ unsigned long jiffy; ++ blkcnt_t blocks; ++ aufs_bindex_t bi, bbot; ++ struct kstatfs *st; ++ struct au_branch *br; ++ struct file *new_xino, *file; ++ struct super_block *h_sb; ++ struct au_xino_lock_dir ldir; ++ ++ err = -ENOMEM; ++ st = kmalloc(sizeof(*st), GFP_NOFS); ++ if (unlikely(!st)) ++ goto out; ++ ++ err = -EINVAL; ++ bbot = au_sbbot(sb); ++ if (unlikely(bindex < 0 || bbot < bindex)) ++ goto out_st; ++ br = au_sbr(sb, bindex); ++ file = br->br_xino.xi_file; ++ if (!file) ++ goto out_st; ++ ++ err = vfs_statfs(&file->f_path, st); ++ if (unlikely(err)) ++ AuErr1("statfs err %d, ignored\n", err); ++ jiffy = jiffies; ++ blocks = file_inode(file)->i_blocks; ++ pr_info("begin truncating xino(b%d), ib%llu, %llu/%llu free blks\n", ++ bindex, (u64)blocks, st->f_bfree, st->f_blocks); ++ ++ au_xino_lock_dir(sb, file, &ldir); ++ /* mnt_want_write() is unnecessary here */ ++ new_xino = au_xino_create2(file, file); ++ au_xino_unlock_dir(&ldir); ++ err = PTR_ERR(new_xino); ++ if (IS_ERR(new_xino)) { ++ pr_err("err %d, ignored\n", err); ++ goto out_st; ++ } ++ err = 0; ++ fput(file); ++ br->br_xino.xi_file = new_xino; ++ ++ h_sb = au_br_sb(br); ++ for (bi = 0; bi <= bbot; bi++) { ++ if (unlikely(bi == bindex)) ++ continue; ++ br = au_sbr(sb, bi); ++ if (au_br_sb(br) != h_sb) ++ continue; ++ ++ fput(br->br_xino.xi_file); ++ br->br_xino.xi_file = new_xino; ++ get_file(new_xino); ++ } ++ ++ err = vfs_statfs(&new_xino->f_path, st); ++ if (!err) { ++ pr_info("end truncating xino(b%d), ib%llu, %llu/%llu free blks\n", ++ bindex, (u64)file_inode(new_xino)->i_blocks, ++ st->f_bfree, st->f_blocks); ++ if (file_inode(new_xino)->i_blocks < blocks) ++ au_sbi(sb)->si_xino_jiffy = jiffy; ++ } else ++ AuErr1("statfs err %d, ignored\n", err); ++ ++out_st: ++ kfree(st); ++out: ++ return err; ++} ++ ++struct xino_do_trunc_args { ++ struct super_block *sb; ++ struct au_branch *br; ++}; ++ ++static void xino_do_trunc(void *_args) ++{ ++ struct xino_do_trunc_args *args = _args; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct inode *dir; ++ int err; ++ aufs_bindex_t bindex; ++ ++ err = 0; ++ sb = args->sb; ++ dir = d_inode(sb->s_root); ++ br = args->br; ++ ++ si_noflush_write_lock(sb); ++ ii_read_lock_parent(dir); ++ bindex = au_br_index(sb, br->br_id); ++ err = au_xino_trunc(sb, bindex); ++ ii_read_unlock(dir); ++ if (unlikely(err)) ++ pr_warn("err b%d, (%d)\n", bindex, err); ++ atomic_dec(&br->br_xino_running); ++ au_br_put(br); ++ si_write_unlock(sb); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ kfree(args); ++} ++ ++static int xino_trunc_test(struct super_block *sb, struct au_branch *br) ++{ ++ int err; ++ struct kstatfs st; ++ struct au_sbinfo *sbinfo; ++ ++ /* todo: si_xino_expire and the ratio should be customizable */ ++ sbinfo = au_sbi(sb); ++ if (time_before(jiffies, ++ sbinfo->si_xino_jiffy + sbinfo->si_xino_expire)) ++ return 0; ++ ++ /* truncation border */ ++ err = vfs_statfs(&br->br_xino.xi_file->f_path, &st); ++ if (unlikely(err)) { ++ AuErr1("statfs err %d, ignored\n", err); ++ return 0; ++ } ++ if (div64_u64(st.f_bfree * 100, st.f_blocks) >= AUFS_XINO_DEF_TRUNC) ++ return 0; ++ ++ return 1; ++} ++ ++static void xino_try_trunc(struct super_block *sb, struct au_branch *br) ++{ ++ struct xino_do_trunc_args *args; ++ int wkq_err; ++ ++ if (!xino_trunc_test(sb, br)) ++ return; ++ ++ if (atomic_inc_return(&br->br_xino_running) > 1) ++ goto out; ++ ++ /* lock and kfree() will be called in trunc_xino() */ ++ args = kmalloc(sizeof(*args), GFP_NOFS); ++ if (unlikely(!args)) { ++ AuErr1("no memory\n"); ++ goto out_args; ++ } ++ ++ au_br_get(br); ++ args->sb = sb; ++ args->br = br; ++ wkq_err = au_wkq_nowait(xino_do_trunc, args, sb, /*flags*/0); ++ if (!wkq_err) ++ return; /* success */ ++ ++ pr_err("wkq %d\n", wkq_err); ++ au_br_put(br); ++ ++out_args: ++ kfree(args); ++out: ++ atomic_dec(&br->br_xino_running); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_xino_do_write(vfs_writef_t write, struct file *file, ++ ino_t h_ino, ino_t ino) ++{ ++ loff_t pos; ++ ssize_t sz; ++ ++ pos = h_ino; ++ if (unlikely(au_loff_max / sizeof(ino) - 1 < pos)) { ++ AuIOErr1("too large hi%lu\n", (unsigned long)h_ino); ++ return -EFBIG; ++ } ++ pos *= sizeof(ino); ++ sz = xino_fwrite(write, file, &ino, sizeof(ino), &pos); ++ if (sz == sizeof(ino)) ++ return 0; /* success */ ++ ++ AuIOErr("write failed (%zd)\n", sz); ++ return -EIO; ++} ++ ++/* ++ * write @ino to the xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ * even if @ino is zero, it is written to the xinofile and means no entry. ++ * if the size of the xino file on a specific filesystem exceeds the watermark, ++ * try truncating it. ++ */ ++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino) ++{ ++ int err; ++ unsigned int mnt_flags; ++ struct au_branch *br; ++ ++ BUILD_BUG_ON(sizeof(long long) != sizeof(au_loff_max) ++ || ((loff_t)-1) > 0); ++ SiMustAnyLock(sb); ++ ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, XINO)) ++ return 0; ++ ++ br = au_sbr(sb, bindex); ++ err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file, ++ h_ino, ino); ++ if (!err) { ++ if (au_opt_test(mnt_flags, TRUNC_XINO) ++ && au_test_fs_trunc_xino(au_br_sb(br))) ++ xino_try_trunc(sb, br); ++ return 0; /* success */ ++ } ++ ++ AuIOErr("write failed (%d)\n", err); ++ return -EIO; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* aufs inode number bitmap */ ++ ++static const int page_bits = (int)PAGE_SIZE * BITS_PER_BYTE; ++static ino_t xib_calc_ino(unsigned long pindex, int bit) ++{ ++ ino_t ino; ++ ++ AuDebugOn(bit < 0 || page_bits <= bit); ++ ino = AUFS_FIRST_INO + pindex * page_bits + bit; ++ return ino; ++} ++ ++static void xib_calc_bit(ino_t ino, unsigned long *pindex, int *bit) ++{ ++ AuDebugOn(ino < AUFS_FIRST_INO); ++ ino -= AUFS_FIRST_INO; ++ *pindex = ino / page_bits; ++ *bit = ino % page_bits; ++} ++ ++static int xib_pindex(struct super_block *sb, unsigned long pindex) ++{ ++ int err; ++ loff_t pos; ++ ssize_t sz; ++ struct au_sbinfo *sbinfo; ++ struct file *xib; ++ unsigned long *p; ++ ++ sbinfo = au_sbi(sb); ++ MtxMustLock(&sbinfo->si_xib_mtx); ++ AuDebugOn(pindex > ULONG_MAX / PAGE_SIZE ++ || !au_opt_test(sbinfo->si_mntflags, XINO)); ++ ++ if (pindex == sbinfo->si_xib_last_pindex) ++ return 0; ++ ++ xib = sbinfo->si_xib; ++ p = sbinfo->si_xib_buf; ++ pos = sbinfo->si_xib_last_pindex; ++ pos *= PAGE_SIZE; ++ sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos); ++ if (unlikely(sz != PAGE_SIZE)) ++ goto out; ++ ++ pos = pindex; ++ pos *= PAGE_SIZE; ++ if (vfsub_f_size_read(xib) >= pos + PAGE_SIZE) ++ sz = xino_fread(sbinfo->si_xread, xib, p, PAGE_SIZE, &pos); ++ else { ++ memset(p, 0, PAGE_SIZE); ++ sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos); ++ } ++ if (sz == PAGE_SIZE) { ++ sbinfo->si_xib_last_pindex = pindex; ++ return 0; /* success */ ++ } ++ ++out: ++ AuIOErr1("write failed (%zd)\n", sz); ++ err = sz; ++ if (sz >= 0) ++ err = -EIO; ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_xib_clear_bit(struct inode *inode) ++{ ++ int err, bit; ++ unsigned long pindex; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ AuDebugOn(inode->i_nlink); ++ ++ sb = inode->i_sb; ++ xib_calc_bit(inode->i_ino, &pindex, &bit); ++ AuDebugOn(page_bits <= bit); ++ sbinfo = au_sbi(sb); ++ mutex_lock(&sbinfo->si_xib_mtx); ++ err = xib_pindex(sb, pindex); ++ if (!err) { ++ clear_bit(bit, sbinfo->si_xib_buf); ++ sbinfo->si_xib_next_bit = bit; ++ } ++ mutex_unlock(&sbinfo->si_xib_mtx); ++} ++ ++/* for s_op->delete_inode() */ ++void au_xino_delete_inode(struct inode *inode, const int unlinked) ++{ ++ int err; ++ unsigned int mnt_flags; ++ aufs_bindex_t bindex, bbot, bi; ++ unsigned char try_trunc; ++ struct au_iinfo *iinfo; ++ struct super_block *sb; ++ struct au_hinode *hi; ++ struct inode *h_inode; ++ struct au_branch *br; ++ vfs_writef_t xwrite; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ ++ sb = inode->i_sb; ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, XINO) ++ || inode->i_ino == AUFS_ROOT_INO) ++ return; ++ ++ if (unlinked) { ++ au_xigen_inc(inode); ++ au_xib_clear_bit(inode); ++ } ++ ++ iinfo = au_ii(inode); ++ bindex = iinfo->ii_btop; ++ if (bindex < 0) ++ return; ++ ++ xwrite = au_sbi(sb)->si_xwrite; ++ try_trunc = !!au_opt_test(mnt_flags, TRUNC_XINO); ++ hi = au_hinode(iinfo, bindex); ++ bbot = iinfo->ii_bbot; ++ for (; bindex <= bbot; bindex++, hi++) { ++ h_inode = hi->hi_inode; ++ if (!h_inode ++ || (!unlinked && h_inode->i_nlink)) ++ continue; ++ ++ /* inode may not be revalidated */ ++ bi = au_br_index(sb, hi->hi_id); ++ if (bi < 0) ++ continue; ++ ++ br = au_sbr(sb, bi); ++ err = au_xino_do_write(xwrite, br->br_xino.xi_file, ++ h_inode->i_ino, /*ino*/0); ++ if (!err && try_trunc ++ && au_test_fs_trunc_xino(au_br_sb(br))) ++ xino_try_trunc(sb, br); ++ } ++} ++ ++/* get an unused inode number from bitmap */ ++ino_t au_xino_new_ino(struct super_block *sb) ++{ ++ ino_t ino; ++ unsigned long *p, pindex, ul, pend; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ int free_bit, err; ++ ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return iunique(sb, AUFS_FIRST_INO); ++ ++ sbinfo = au_sbi(sb); ++ mutex_lock(&sbinfo->si_xib_mtx); ++ p = sbinfo->si_xib_buf; ++ free_bit = sbinfo->si_xib_next_bit; ++ if (free_bit < page_bits && !test_bit(free_bit, p)) ++ goto out; /* success */ ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ ++ pindex = sbinfo->si_xib_last_pindex; ++ for (ul = pindex - 1; ul < ULONG_MAX; ul--) { ++ err = xib_pindex(sb, ul); ++ if (unlikely(err)) ++ goto out_err; ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ } ++ ++ file = sbinfo->si_xib; ++ pend = vfsub_f_size_read(file) / PAGE_SIZE; ++ for (ul = pindex + 1; ul <= pend; ul++) { ++ err = xib_pindex(sb, ul); ++ if (unlikely(err)) ++ goto out_err; ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ } ++ BUG(); ++ ++out: ++ set_bit(free_bit, p); ++ sbinfo->si_xib_next_bit = free_bit + 1; ++ pindex = sbinfo->si_xib_last_pindex; ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ ino = xib_calc_ino(pindex, free_bit); ++ AuDbg("i%lu\n", (unsigned long)ino); ++ return ino; ++out_err: ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ AuDbg("i0\n"); ++ return 0; ++} ++ ++/* ++ * read @ino from xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ * if @ino does not exist and @do_new is true, get new one. ++ */ ++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t *ino) ++{ ++ int err; ++ ssize_t sz; ++ loff_t pos; ++ struct file *file; ++ struct au_sbinfo *sbinfo; ++ ++ *ino = 0; ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return 0; /* no xino */ ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ pos = h_ino; ++ if (unlikely(au_loff_max / sizeof(*ino) - 1 < pos)) { ++ AuIOErr1("too large hi%lu\n", (unsigned long)h_ino); ++ return -EFBIG; ++ } ++ pos *= sizeof(*ino); ++ ++ file = au_sbr(sb, bindex)->br_xino.xi_file; ++ if (vfsub_f_size_read(file) < pos + sizeof(*ino)) ++ return 0; /* no ino */ ++ ++ sz = xino_fread(sbinfo->si_xread, file, ino, sizeof(*ino), &pos); ++ if (sz == sizeof(*ino)) ++ return 0; /* success */ ++ ++ err = sz; ++ if (unlikely(sz >= 0)) { ++ err = -EIO; ++ AuIOErr("xino read error (%zd)\n", sz); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* create and set a new xino file */ ++ ++struct file *au_xino_create(struct super_block *sb, char *fname, int silent) ++{ ++ struct file *file; ++ struct dentry *h_parent, *d; ++ struct inode *h_dir, *inode; ++ int err; ++ ++ /* ++ * at mount-time, and the xino file is the default path, ++ * hnotify is disabled so we have no notify events to ignore. ++ * when a user specified the xino, we cannot get au_hdir to be ignored. ++ */ ++ file = vfsub_filp_open(fname, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE ++ /* | __FMODE_NONOTIFY */, ++ S_IRUGO | S_IWUGO); ++ if (IS_ERR(file)) { ++ if (!silent) ++ pr_err("open %s(%ld)\n", fname, PTR_ERR(file)); ++ return file; ++ } ++ ++ /* keep file count */ ++ err = 0; ++ inode = file_inode(file); ++ h_parent = dget_parent(file->f_path.dentry); ++ h_dir = d_inode(h_parent); ++ inode_lock_nested(h_dir, AuLsc_I_PARENT); ++ /* mnt_want_write() is unnecessary here */ ++ /* no delegation since it is just created */ ++ if (inode->i_nlink) ++ err = vfsub_unlink(h_dir, &file->f_path, /*delegated*/NULL, ++ /*force*/0); ++ inode_unlock(h_dir); ++ dput(h_parent); ++ if (unlikely(err)) { ++ if (!silent) ++ pr_err("unlink %s(%d)\n", fname, err); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ d = file->f_path.dentry; ++ if (unlikely(sb == d->d_sb)) { ++ if (!silent) ++ pr_err("%s must be outside\n", fname); ++ goto out; ++ } ++ if (unlikely(au_test_fs_bad_xino(d->d_sb))) { ++ if (!silent) ++ pr_err("xino doesn't support %s(%s)\n", ++ fname, au_sbtype(d->d_sb)); ++ goto out; ++ } ++ return file; /* success */ ++ ++out: ++ fput(file); ++ file = ERR_PTR(err); ++ return file; ++} ++ ++/* ++ * find another branch who is on the same filesystem of the specified ++ * branch{@btgt}. search until @bbot. ++ */ ++static int is_sb_shared(struct super_block *sb, aufs_bindex_t btgt, ++ aufs_bindex_t bbot) ++{ ++ aufs_bindex_t bindex; ++ struct super_block *tgt_sb = au_sbr_sb(sb, btgt); ++ ++ for (bindex = 0; bindex < btgt; bindex++) ++ if (unlikely(tgt_sb == au_sbr_sb(sb, bindex))) ++ return bindex; ++ for (bindex++; bindex <= bbot; bindex++) ++ if (unlikely(tgt_sb == au_sbr_sb(sb, bindex))) ++ return bindex; ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * initialize the xinofile for the specified branch @br ++ * at the place/path where @base_file indicates. ++ * test whether another branch is on the same filesystem or not, ++ * if @do_test is true. ++ */ ++int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t h_ino, ++ struct file *base_file, int do_test) ++{ ++ int err; ++ ino_t ino; ++ aufs_bindex_t bbot, bindex; ++ struct au_branch *shared_br, *b; ++ struct file *file; ++ struct super_block *tgt_sb; ++ ++ shared_br = NULL; ++ bbot = au_sbbot(sb); ++ if (do_test) { ++ tgt_sb = au_br_sb(br); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ b = au_sbr(sb, bindex); ++ if (tgt_sb == au_br_sb(b)) { ++ shared_br = b; ++ break; ++ } ++ } ++ } ++ ++ if (!shared_br || !shared_br->br_xino.xi_file) { ++ struct au_xino_lock_dir ldir; ++ ++ au_xino_lock_dir(sb, base_file, &ldir); ++ /* mnt_want_write() is unnecessary here */ ++ file = au_xino_create2(base_file, NULL); ++ au_xino_unlock_dir(&ldir); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ br->br_xino.xi_file = file; ++ } else { ++ br->br_xino.xi_file = shared_br->br_xino.xi_file; ++ get_file(br->br_xino.xi_file); ++ } ++ ++ ino = AUFS_ROOT_INO; ++ err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file, ++ h_ino, ino); ++ if (unlikely(err)) { ++ fput(br->br_xino.xi_file); ++ br->br_xino.xi_file = NULL; ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* trucate a xino bitmap file */ ++ ++/* todo: slow */ ++static int do_xib_restore(struct super_block *sb, struct file *file, void *page) ++{ ++ int err, bit; ++ ssize_t sz; ++ unsigned long pindex; ++ loff_t pos, pend; ++ struct au_sbinfo *sbinfo; ++ vfs_readf_t func; ++ ino_t *ino; ++ unsigned long *p; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ MtxMustLock(&sbinfo->si_xib_mtx); ++ p = sbinfo->si_xib_buf; ++ func = sbinfo->si_xread; ++ pend = vfsub_f_size_read(file); ++ pos = 0; ++ while (pos < pend) { ++ sz = xino_fread(func, file, page, PAGE_SIZE, &pos); ++ err = sz; ++ if (unlikely(sz <= 0)) ++ goto out; ++ ++ err = 0; ++ for (ino = page; sz > 0; ino++, sz -= sizeof(ino)) { ++ if (unlikely(*ino < AUFS_FIRST_INO)) ++ continue; ++ ++ xib_calc_bit(*ino, &pindex, &bit); ++ AuDebugOn(page_bits <= bit); ++ err = xib_pindex(sb, pindex); ++ if (!err) ++ set_bit(bit, p); ++ else ++ goto out; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++static int xib_restore(struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ void *page; ++ ++ err = -ENOMEM; ++ page = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!page)) ++ goto out; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) ++ if (!bindex || is_sb_shared(sb, bindex, bindex - 1) < 0) ++ err = do_xib_restore ++ (sb, au_sbr(sb, bindex)->br_xino.xi_file, page); ++ else ++ AuDbg("b%d\n", bindex); ++ free_page((unsigned long)page); ++ ++out: ++ return err; ++} ++ ++int au_xib_trunc(struct super_block *sb) ++{ ++ int err; ++ ssize_t sz; ++ loff_t pos; ++ struct au_xino_lock_dir ldir; ++ struct au_sbinfo *sbinfo; ++ unsigned long *p; ++ struct file *file; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ if (!au_opt_test(sbinfo->si_mntflags, XINO)) ++ goto out; ++ ++ file = sbinfo->si_xib; ++ if (vfsub_f_size_read(file) <= PAGE_SIZE) ++ goto out; ++ ++ au_xino_lock_dir(sb, file, &ldir); ++ /* mnt_want_write() is unnecessary here */ ++ file = au_xino_create2(sbinfo->si_xib, NULL); ++ au_xino_unlock_dir(&ldir); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = file; ++ ++ p = sbinfo->si_xib_buf; ++ memset(p, 0, PAGE_SIZE); ++ pos = 0; ++ sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xib, p, PAGE_SIZE, &pos); ++ if (unlikely(sz != PAGE_SIZE)) { ++ err = sz; ++ AuIOErr("err %d\n", err); ++ if (sz >= 0) ++ err = -EIO; ++ goto out; ++ } ++ ++ mutex_lock(&sbinfo->si_xib_mtx); ++ /* mnt_want_write() is unnecessary here */ ++ err = xib_restore(sb); ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * xino mount option handlers ++ */ ++ ++/* xino bitmap */ ++static void xino_clear_xib(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ sbinfo->si_xread = NULL; ++ sbinfo->si_xwrite = NULL; ++ if (sbinfo->si_xib) ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = NULL; ++ free_page((unsigned long)sbinfo->si_xib_buf); ++ sbinfo->si_xib_buf = NULL; ++} ++ ++static int au_xino_set_xib(struct super_block *sb, struct file *base) ++{ ++ int err; ++ loff_t pos; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ file = au_xino_create2(base, sbinfo->si_xib); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ if (sbinfo->si_xib) ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = file; ++ sbinfo->si_xread = vfs_readf(file); ++ sbinfo->si_xwrite = vfs_writef(file); ++ ++ err = -ENOMEM; ++ if (!sbinfo->si_xib_buf) ++ sbinfo->si_xib_buf = (void *)get_zeroed_page(GFP_NOFS); ++ if (unlikely(!sbinfo->si_xib_buf)) ++ goto out_unset; ++ ++ sbinfo->si_xib_last_pindex = 0; ++ sbinfo->si_xib_next_bit = 0; ++ if (vfsub_f_size_read(file) < PAGE_SIZE) { ++ pos = 0; ++ err = xino_fwrite(sbinfo->si_xwrite, file, sbinfo->si_xib_buf, ++ PAGE_SIZE, &pos); ++ if (unlikely(err != PAGE_SIZE)) ++ goto out_free; ++ } ++ err = 0; ++ goto out; /* success */ ++ ++out_free: ++ free_page((unsigned long)sbinfo->si_xib_buf); ++ sbinfo->si_xib_buf = NULL; ++ if (err >= 0) ++ err = -EIO; ++out_unset: ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = NULL; ++ sbinfo->si_xread = NULL; ++ sbinfo->si_xwrite = NULL; ++out: ++ return err; ++} ++ ++/* xino for each branch */ ++static void xino_clear_br(struct super_block *sb) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!br || !br->br_xino.xi_file) ++ continue; ++ ++ fput(br->br_xino.xi_file); ++ br->br_xino.xi_file = NULL; ++ } ++} ++ ++static int au_xino_set_br(struct super_block *sb, struct file *base) ++{ ++ int err; ++ ino_t ino; ++ aufs_bindex_t bindex, bbot, bshared; ++ struct { ++ struct file *old, *new; ++ } *fpair, *p; ++ struct au_branch *br; ++ struct inode *inode; ++ vfs_writef_t writef; ++ ++ SiMustWriteLock(sb); ++ ++ err = -ENOMEM; ++ bbot = au_sbbot(sb); ++ fpair = kcalloc(bbot + 1, sizeof(*fpair), GFP_NOFS); ++ if (unlikely(!fpair)) ++ goto out; ++ ++ inode = d_inode(sb->s_root); ++ ino = AUFS_ROOT_INO; ++ writef = au_sbi(sb)->si_xwrite; ++ for (bindex = 0, p = fpair; bindex <= bbot; bindex++, p++) { ++ bshared = is_sb_shared(sb, bindex, bindex - 1); ++ if (bshared >= 0) { ++ /* shared xino */ ++ *p = fpair[bshared]; ++ get_file(p->new); ++ } ++ ++ if (!p->new) { ++ /* new xino */ ++ br = au_sbr(sb, bindex); ++ p->old = br->br_xino.xi_file; ++ p->new = au_xino_create2(base, br->br_xino.xi_file); ++ err = PTR_ERR(p->new); ++ if (IS_ERR(p->new)) { ++ p->new = NULL; ++ goto out_pair; ++ } ++ } ++ ++ err = au_xino_do_write(writef, p->new, ++ au_h_iptr(inode, bindex)->i_ino, ino); ++ if (unlikely(err)) ++ goto out_pair; ++ } ++ ++ for (bindex = 0, p = fpair; bindex <= bbot; bindex++, p++) { ++ br = au_sbr(sb, bindex); ++ if (br->br_xino.xi_file) ++ fput(br->br_xino.xi_file); ++ get_file(p->new); ++ br->br_xino.xi_file = p->new; ++ } ++ ++out_pair: ++ for (bindex = 0, p = fpair; bindex <= bbot; bindex++, p++) ++ if (p->new) ++ fput(p->new); ++ else ++ break; ++ kfree(fpair); ++out: ++ return err; ++} ++ ++void au_xino_clr(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ au_xigen_clr(sb); ++ xino_clear_xib(sb); ++ xino_clear_br(sb); ++ sbinfo = au_sbi(sb); ++ /* lvalue, do not call au_mntflags() */ ++ au_opt_clr(sbinfo->si_mntflags, XINO); ++} ++ ++int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount) ++{ ++ int err, skip; ++ struct dentry *parent, *cur_parent; ++ struct qstr *dname, *cur_name; ++ struct file *cur_xino; ++ struct inode *dir; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ parent = dget_parent(xino->file->f_path.dentry); ++ if (remount) { ++ skip = 0; ++ dname = &xino->file->f_path.dentry->d_name; ++ cur_xino = sbinfo->si_xib; ++ if (cur_xino) { ++ cur_parent = dget_parent(cur_xino->f_path.dentry); ++ cur_name = &cur_xino->f_path.dentry->d_name; ++ skip = (cur_parent == parent ++ && au_qstreq(dname, cur_name)); ++ dput(cur_parent); ++ } ++ if (skip) ++ goto out; ++ } ++ ++ au_opt_set(sbinfo->si_mntflags, XINO); ++ dir = d_inode(parent); ++ inode_lock_nested(dir, AuLsc_I_PARENT); ++ /* mnt_want_write() is unnecessary here */ ++ err = au_xino_set_xib(sb, xino->file); ++ if (!err) ++ err = au_xigen_set(sb, xino->file); ++ if (!err) ++ err = au_xino_set_br(sb, xino->file); ++ inode_unlock(dir); ++ if (!err) ++ goto out; /* success */ ++ ++ /* reset all */ ++ AuIOErr("failed creating xino(%d).\n", err); ++ au_xigen_clr(sb); ++ xino_clear_xib(sb); ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create a xinofile at the default place/path. ++ */ ++struct file *au_xino_def(struct super_block *sb) ++{ ++ struct file *file; ++ char *page, *p; ++ struct au_branch *br; ++ struct super_block *h_sb; ++ struct path path; ++ aufs_bindex_t bbot, bindex, bwr; ++ ++ br = NULL; ++ bbot = au_sbbot(sb); ++ bwr = -1; ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm) ++ && !au_test_fs_bad_xino(au_br_sb(br))) { ++ bwr = bindex; ++ break; ++ } ++ } ++ ++ if (bwr >= 0) { ++ file = ERR_PTR(-ENOMEM); ++ page = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!page)) ++ goto out; ++ path.mnt = au_br_mnt(br); ++ path.dentry = au_h_dptr(sb->s_root, bwr); ++ p = d_path(&path, page, PATH_MAX - sizeof(AUFS_XINO_FNAME)); ++ file = (void *)p; ++ if (!IS_ERR(p)) { ++ strcat(p, "/" AUFS_XINO_FNAME); ++ AuDbg("%s\n", p); ++ file = au_xino_create(sb, p, /*silent*/0); ++ if (!IS_ERR(file)) ++ au_xino_brid_set(sb, br->br_id); ++ } ++ free_page((unsigned long)page); ++ } else { ++ file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0); ++ if (IS_ERR(file)) ++ goto out; ++ h_sb = file->f_path.dentry->d_sb; ++ if (unlikely(au_test_fs_bad_xino(h_sb))) { ++ pr_err("xino doesn't support %s(%s)\n", ++ AUFS_XINO_DEFPATH, au_sbtype(h_sb)); ++ fput(file); ++ file = ERR_PTR(-EINVAL); ++ } ++ if (!IS_ERR(file)) ++ au_xino_brid_set(sb, -1); ++ } ++ ++out: ++ return file; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_xino_path(struct seq_file *seq, struct file *file) ++{ ++ int err; ++ ++ err = au_seq_path(seq, &file->f_path); ++ if (unlikely(err)) ++ goto out; ++ ++#define Deleted "\\040(deleted)" ++ seq->count -= sizeof(Deleted) - 1; ++ AuDebugOn(memcmp(seq->buf + seq->count, Deleted, ++ sizeof(Deleted) - 1)); ++#undef Deleted ++ ++out: ++ return err; ++} +diff --git a/fs/dcache.c b/fs/dcache.c +index d6847d7..c3c0b6d 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -1202,7 +1202,7 @@ enum d_walk_ret { + * + * The @enter() and @finish() callbacks are called with d_lock held. + */ +-static void d_walk(struct dentry *parent, void *data, ++void d_walk(struct dentry *parent, void *data, + enum d_walk_ret (*enter)(void *, struct dentry *), + void (*finish)(void *)) + { +diff --git a/fs/fcntl.c b/fs/fcntl.c +index 350a2c8..6f42279 100644 +--- a/fs/fcntl.c ++++ b/fs/fcntl.c +@@ -29,7 +29,7 @@ + + #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME) + +-static int setfl(int fd, struct file * filp, unsigned long arg) ++int setfl(int fd, struct file * filp, unsigned long arg) + { + struct inode * inode = file_inode(filp); + int error = 0; +@@ -60,6 +60,8 @@ static int setfl(int fd, struct file * filp, unsigned long arg) + + if (filp->f_op->check_flags) + error = filp->f_op->check_flags(arg); ++ if (!error && filp->f_op->setfl) ++ error = filp->f_op->setfl(filp, arg); + if (error) + return error; + +diff --git a/fs/inode.c b/fs/inode.c +index 4ccbc21..aa6d071 100644 +--- a/fs/inode.c ++++ b/fs/inode.c +@@ -1591,7 +1591,7 @@ EXPORT_SYMBOL(generic_update_time); + * This does the actual work of updating an inodes time or version. Must have + * had called mnt_want_write() before calling this. + */ +-static int update_time(struct inode *inode, struct timespec *time, int flags) ++int update_time(struct inode *inode, struct timespec *time, int flags) + { + int (*update_time)(struct inode *, struct timespec *, int); + +diff --git a/fs/proc/base.c b/fs/proc/base.c +index a11eb71..8f10865 100644 +--- a/fs/proc/base.c ++++ b/fs/proc/base.c +@@ -1939,7 +1939,7 @@ static int map_files_get_link(struct dentry *dentry, struct path *path) + down_read(&mm->mmap_sem); + vma = find_exact_vma(mm, vm_start, vm_end); + if (vma && vma->vm_file) { +- *path = vma->vm_file->f_path; ++ *path = vma_pr_or_file(vma)->f_path; + path_get(path); + rc = 0; + } +diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c +index f8595e8..cb8eda0 100644 +--- a/fs/proc/nommu.c ++++ b/fs/proc/nommu.c +@@ -45,7 +45,10 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region) + file = region->vm_file; + + if (file) { +- struct inode *inode = file_inode(region->vm_file); ++ struct inode *inode; ++ ++ file = vmr_pr_or_file(region); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + } +diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c +index 4648c7f..061cb85 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -298,7 +298,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) + const char *name = NULL; + + if (file) { +- struct inode *inode = file_inode(vma->vm_file); ++ struct inode *inode; ++ ++ file = vma_pr_or_file(vma); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT; +@@ -1624,7 +1627,7 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid) + struct proc_maps_private *proc_priv = &numa_priv->proc_maps; + struct vm_area_struct *vma = v; + struct numa_maps *md = &numa_priv->md; +- struct file *file = vma->vm_file; ++ struct file *file = vma_pr_or_file(vma); + struct mm_struct *mm = vma->vm_mm; + struct mm_walk walk = { + .hugetlb_entry = gather_hugetlb_stats, +diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c +index faacb0c..17b43be 100644 +--- a/fs/proc/task_nommu.c ++++ b/fs/proc/task_nommu.c +@@ -163,7 +163,10 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma, + file = vma->vm_file; + + if (file) { +- struct inode *inode = file_inode(vma->vm_file); ++ struct inode *inode; ++ ++ file = vma_pr_or_file(vma); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT; +diff --git a/fs/read_write.c b/fs/read_write.c +index 933b53a..2d13282 100644 +--- a/fs/read_write.c ++++ b/fs/read_write.c +@@ -515,6 +515,28 @@ ssize_t __vfs_write(struct file *file, const char __user *p, size_t count, + } + EXPORT_SYMBOL(__vfs_write); + ++vfs_readf_t vfs_readf(struct file *file) ++{ ++ const struct file_operations *fop = file->f_op; ++ ++ if (fop->read) ++ return fop->read; ++ if (fop->read_iter) ++ return new_sync_read; ++ return ERR_PTR(-ENOSYS); ++} ++ ++vfs_writef_t vfs_writef(struct file *file) ++{ ++ const struct file_operations *fop = file->f_op; ++ ++ if (fop->write) ++ return fop->write; ++ if (fop->write_iter) ++ return new_sync_write; ++ return ERR_PTR(-ENOSYS); ++} ++ + ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos) + { + mm_segment_t old_fs; +diff --git a/fs/splice.c b/fs/splice.c +index dd9bf7e..9326c2a 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -1111,8 +1111,8 @@ EXPORT_SYMBOL(generic_splice_sendpage); + /* + * Attempt to initiate a splice from pipe to file. + */ +-static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, +- loff_t *ppos, size_t len, unsigned int flags) ++long do_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags) + { + ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, + loff_t *, size_t, unsigned int); +@@ -1128,9 +1128,9 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + /* + * Attempt to initiate a splice from a file to a pipe. + */ +-static long do_splice_to(struct file *in, loff_t *ppos, +- struct pipe_inode_info *pipe, size_t len, +- unsigned int flags) ++long do_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) + { + ssize_t (*splice_read)(struct file *, loff_t *, + struct pipe_inode_info *, size_t, unsigned int); +diff --git a/include/linux/file.h b/include/linux/file.h +index 7444f5f..bdac0be 100644 +--- a/include/linux/file.h ++++ b/include/linux/file.h +@@ -19,6 +19,7 @@ struct dentry; + struct path; + extern struct file *alloc_file(struct path *, fmode_t mode, + const struct file_operations *fop); ++extern struct file *get_empty_filp(void); + + static inline void fput_light(struct file *file, int fput_needed) + { +diff --git a/include/linux/fs.h b/include/linux/fs.h +index dd28814..b689a48 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1306,6 +1306,7 @@ extern void fasync_free(struct fasync_struct *); + /* can be called from interrupts */ + extern void kill_fasync(struct fasync_struct **, int, int); + ++extern int setfl(int fd, struct file * filp, unsigned long arg); + extern void __f_setown(struct file *filp, struct pid *, enum pid_type, int force); + extern void f_setown(struct file *filp, unsigned long arg, int force); + extern void f_delown(struct file *filp); +@@ -1690,6 +1691,7 @@ struct file_operations { + ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); + unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); + int (*check_flags)(int); ++ int (*setfl)(struct file *, unsigned long); + int (*flock) (struct file *, int, struct file_lock *); + ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); + ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); +@@ -1750,6 +1752,12 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, + struct iovec *fast_pointer, + struct iovec **ret_pointer); + ++typedef ssize_t (*vfs_readf_t)(struct file *, char __user *, size_t, loff_t *); ++typedef ssize_t (*vfs_writef_t)(struct file *, const char __user *, size_t, ++ loff_t *); ++vfs_readf_t vfs_readf(struct file *file); ++vfs_writef_t vfs_writef(struct file *file); ++ + extern ssize_t __vfs_read(struct file *, char __user *, size_t, loff_t *); + extern ssize_t __vfs_write(struct file *, const char __user *, size_t, loff_t *); + extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *); +@@ -2105,6 +2113,7 @@ extern int current_umask(void); + extern void ihold(struct inode * inode); + extern void iput(struct inode *); + extern int generic_update_time(struct inode *, struct timespec *, int); ++extern int update_time(struct inode *, struct timespec *, int); + + /* /sys/fs */ + extern struct kobject *fs_kobj; +diff --git a/include/linux/mm.h b/include/linux/mm.h +index ece042d..1e24513 100644 +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -1239,6 +1239,28 @@ static inline int fixup_user_fault(struct task_struct *tsk, + } + #endif + ++extern void vma_do_file_update_time(struct vm_area_struct *, const char[], int); ++extern struct file *vma_do_pr_or_file(struct vm_area_struct *, const char[], ++ int); ++extern void vma_do_get_file(struct vm_area_struct *, const char[], int); ++extern void vma_do_fput(struct vm_area_struct *, const char[], int); ++ ++#define vma_file_update_time(vma) vma_do_file_update_time(vma, __func__, \ ++ __LINE__) ++#define vma_pr_or_file(vma) vma_do_pr_or_file(vma, __func__, \ ++ __LINE__) ++#define vma_get_file(vma) vma_do_get_file(vma, __func__, __LINE__) ++#define vma_fput(vma) vma_do_fput(vma, __func__, __LINE__) ++ ++#ifndef CONFIG_MMU ++extern struct file *vmr_do_pr_or_file(struct vm_region *, const char[], int); ++extern void vmr_do_fput(struct vm_region *, const char[], int); ++ ++#define vmr_pr_or_file(region) vmr_do_pr_or_file(region, __func__, \ ++ __LINE__) ++#define vmr_fput(region) vmr_do_fput(region, __func__, __LINE__) ++#endif /* !CONFIG_MMU */ ++ + extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); + extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, + void *buf, int len, int write); +diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h +index ca3e517..10bc491 100644 +--- a/include/linux/mm_types.h ++++ b/include/linux/mm_types.h +@@ -274,6 +274,7 @@ struct vm_region { + unsigned long vm_top; /* region allocated to here */ + unsigned long vm_pgoff; /* the offset in vm_file corresponding to vm_start */ + struct file *vm_file; /* the backing file or NULL */ ++ struct file *vm_prfile; /* the virtual backing file or NULL */ + + int vm_usage; /* region usage count (access under nommu_region_sem) */ + bool vm_icache_flushed : 1; /* true if the icache has been flushed for +@@ -348,6 +349,7 @@ struct vm_area_struct { + unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE + units */ + struct file * vm_file; /* File we map to (can be NULL). */ ++ struct file *vm_prfile; /* shadow of vm_file */ + void * vm_private_data; /* was vm_pte (shared mem) */ + + #ifndef CONFIG_MMU +diff --git a/include/linux/splice.h b/include/linux/splice.h +index da2751d..2e0fca6 100644 +--- a/include/linux/splice.h ++++ b/include/linux/splice.h +@@ -83,4 +83,10 @@ extern void splice_shrink_spd(struct splice_pipe_desc *); + extern void spd_release_page(struct splice_pipe_desc *, unsigned int); + + extern const struct pipe_buf_operations page_cache_pipe_buf_ops; ++ ++extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags); ++extern long do_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags); + #endif +diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild +index 8bdae34..65dbd5f 100644 +--- a/include/uapi/linux/Kbuild ++++ b/include/uapi/linux/Kbuild +@@ -59,6 +59,7 @@ header-y += atmsvc.h + header-y += atm_tcp.h + header-y += atm_zatm.h + header-y += audit.h ++header-y += aufs_type.h + header-y += auto_fs4.h + header-y += auto_fs.h + header-y += auxvec.h +diff --git a/include/uapi/linux/aufs_type.h b/include/uapi/linux/aufs_type.h +new file mode 100644 +index 0000000..4e08bdf +--- /dev/null ++++ b/include/uapi/linux/aufs_type.h +@@ -0,0 +1,406 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++#ifndef __AUFS_TYPE_H__ ++#define __AUFS_TYPE_H__ ++ ++#define AUFS_NAME "aufs" ++ ++#ifdef __KERNEL__ ++/* ++ * define it before including all other headers. ++ * sched.h may use pr_* macros before defining "current", so define the ++ * no-current version first, and re-define later. ++ */ ++#define pr_fmt(fmt) AUFS_NAME " %s:%d: " fmt, __func__, __LINE__ ++#include ++#undef pr_fmt ++#define pr_fmt(fmt) \ ++ AUFS_NAME " %s:%d:%.*s[%d]: " fmt, __func__, __LINE__, \ ++ (int)sizeof(current->comm), current->comm, current->pid ++#else ++#include ++#include ++#endif /* __KERNEL__ */ ++ ++#include ++ ++#define AUFS_VERSION "4.x-rcN" ++ ++/* todo? move this to linux-2.6.19/include/magic.h */ ++#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_BRANCH_MAX_127 ++typedef int8_t aufs_bindex_t; ++#define AUFS_BRANCH_MAX 127 ++#else ++typedef int16_t aufs_bindex_t; ++#ifdef CONFIG_AUFS_BRANCH_MAX_511 ++#define AUFS_BRANCH_MAX 511 ++#elif defined(CONFIG_AUFS_BRANCH_MAX_1023) ++#define AUFS_BRANCH_MAX 1023 ++#elif defined(CONFIG_AUFS_BRANCH_MAX_32767) ++#define AUFS_BRANCH_MAX 32767 ++#endif ++#endif ++ ++#ifdef __KERNEL__ ++#ifndef AUFS_BRANCH_MAX ++#error unknown CONFIG_AUFS_BRANCH_MAX value ++#endif ++#endif /* __KERNEL__ */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AUFS_FSTYPE AUFS_NAME ++ ++#define AUFS_ROOT_INO 2 ++#define AUFS_FIRST_INO 11 ++ ++#define AUFS_WH_PFX ".wh." ++#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1) ++#define AUFS_WH_TMP_LEN 4 ++/* a limit for rmdir/rename a dir and copyup */ ++#define AUFS_MAX_NAMELEN (NAME_MAX \ ++ - AUFS_WH_PFX_LEN * 2 /* doubly whiteouted */\ ++ - 1 /* dot */\ ++ - AUFS_WH_TMP_LEN) /* hex */ ++#define AUFS_XINO_FNAME "." AUFS_NAME ".xino" ++#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME ++#define AUFS_XINO_DEF_SEC 30 /* seconds */ ++#define AUFS_XINO_DEF_TRUNC 45 /* percentage */ ++#define AUFS_DIRWH_DEF 3 ++#define AUFS_RDCACHE_DEF 10 /* seconds */ ++#define AUFS_RDCACHE_MAX 3600 /* seconds */ ++#define AUFS_RDBLK_DEF 512 /* bytes */ ++#define AUFS_RDHASH_DEF 32 ++#define AUFS_WKQ_NAME AUFS_NAME "d" ++#define AUFS_MFS_DEF_SEC 30 /* seconds */ ++#define AUFS_MFS_MAX_SEC 3600 /* seconds */ ++#define AUFS_FHSM_CACHE_DEF_SEC 30 /* seconds */ ++#define AUFS_PLINK_WARN 50 /* number of plinks in a single bucket */ ++ ++/* pseudo-link maintenace under /proc */ ++#define AUFS_PLINK_MAINT_NAME "plink_maint" ++#define AUFS_PLINK_MAINT_DIR "fs/" AUFS_NAME ++#define AUFS_PLINK_MAINT_PATH AUFS_PLINK_MAINT_DIR "/" AUFS_PLINK_MAINT_NAME ++ ++#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */ ++#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME ++ ++#define AUFS_BASE_NAME AUFS_WH_PFX AUFS_NAME ++#define AUFS_PLINKDIR_NAME AUFS_WH_PFX "plnk" ++#define AUFS_ORPHDIR_NAME AUFS_WH_PFX "orph" ++ ++/* doubly whiteouted */ ++#define AUFS_WH_BASE AUFS_WH_PFX AUFS_BASE_NAME ++#define AUFS_WH_PLINKDIR AUFS_WH_PFX AUFS_PLINKDIR_NAME ++#define AUFS_WH_ORPHDIR AUFS_WH_PFX AUFS_ORPHDIR_NAME ++ ++/* branch permissions and attributes */ ++#define AUFS_BRPERM_RW "rw" ++#define AUFS_BRPERM_RO "ro" ++#define AUFS_BRPERM_RR "rr" ++#define AUFS_BRATTR_COO_REG "coo_reg" ++#define AUFS_BRATTR_COO_ALL "coo_all" ++#define AUFS_BRATTR_FHSM "fhsm" ++#define AUFS_BRATTR_UNPIN "unpin" ++#define AUFS_BRATTR_ICEX "icex" ++#define AUFS_BRATTR_ICEX_SEC "icexsec" ++#define AUFS_BRATTR_ICEX_SYS "icexsys" ++#define AUFS_BRATTR_ICEX_TR "icextr" ++#define AUFS_BRATTR_ICEX_USR "icexusr" ++#define AUFS_BRATTR_ICEX_OTH "icexoth" ++#define AUFS_BRRATTR_WH "wh" ++#define AUFS_BRWATTR_NLWH "nolwh" ++#define AUFS_BRWATTR_MOO "moo" ++ ++#define AuBrPerm_RW 1 /* writable, hardlinkable wh */ ++#define AuBrPerm_RO (1 << 1) /* readonly */ ++#define AuBrPerm_RR (1 << 2) /* natively readonly */ ++#define AuBrPerm_Mask (AuBrPerm_RW | AuBrPerm_RO | AuBrPerm_RR) ++ ++#define AuBrAttr_COO_REG (1 << 3) /* copy-up on open */ ++#define AuBrAttr_COO_ALL (1 << 4) ++#define AuBrAttr_COO_Mask (AuBrAttr_COO_REG | AuBrAttr_COO_ALL) ++ ++#define AuBrAttr_FHSM (1 << 5) /* file-based hsm */ ++#define AuBrAttr_UNPIN (1 << 6) /* rename-able top dir of ++ branch. meaningless since ++ linux-3.18-rc1 */ ++ ++/* ignore error in copying XATTR */ ++#define AuBrAttr_ICEX_SEC (1 << 7) ++#define AuBrAttr_ICEX_SYS (1 << 8) ++#define AuBrAttr_ICEX_TR (1 << 9) ++#define AuBrAttr_ICEX_USR (1 << 10) ++#define AuBrAttr_ICEX_OTH (1 << 11) ++#define AuBrAttr_ICEX (AuBrAttr_ICEX_SEC \ ++ | AuBrAttr_ICEX_SYS \ ++ | AuBrAttr_ICEX_TR \ ++ | AuBrAttr_ICEX_USR \ ++ | AuBrAttr_ICEX_OTH) ++ ++#define AuBrRAttr_WH (1 << 12) /* whiteout-able */ ++#define AuBrRAttr_Mask AuBrRAttr_WH ++ ++#define AuBrWAttr_NoLinkWH (1 << 13) /* un-hardlinkable whiteouts */ ++#define AuBrWAttr_MOO (1 << 14) /* move-up on open */ ++#define AuBrWAttr_Mask (AuBrWAttr_NoLinkWH | AuBrWAttr_MOO) ++ ++#define AuBrAttr_CMOO_Mask (AuBrAttr_COO_Mask | AuBrWAttr_MOO) ++ ++/* #warning test userspace */ ++#ifdef __KERNEL__ ++#ifndef CONFIG_AUFS_FHSM ++#undef AuBrAttr_FHSM ++#define AuBrAttr_FHSM 0 ++#endif ++#ifndef CONFIG_AUFS_XATTR ++#undef AuBrAttr_ICEX ++#define AuBrAttr_ICEX 0 ++#undef AuBrAttr_ICEX_SEC ++#define AuBrAttr_ICEX_SEC 0 ++#undef AuBrAttr_ICEX_SYS ++#define AuBrAttr_ICEX_SYS 0 ++#undef AuBrAttr_ICEX_TR ++#define AuBrAttr_ICEX_TR 0 ++#undef AuBrAttr_ICEX_USR ++#define AuBrAttr_ICEX_USR 0 ++#undef AuBrAttr_ICEX_OTH ++#define AuBrAttr_ICEX_OTH 0 ++#endif ++#endif ++ ++/* the longest combination */ ++/* AUFS_BRATTR_ICEX and AUFS_BRATTR_ICEX_TR don't affect here */ ++#define AuBrPermStrSz sizeof(AUFS_BRPERM_RW \ ++ "+" AUFS_BRATTR_COO_REG \ ++ "+" AUFS_BRATTR_FHSM \ ++ "+" AUFS_BRATTR_UNPIN \ ++ "+" AUFS_BRATTR_ICEX_SEC \ ++ "+" AUFS_BRATTR_ICEX_SYS \ ++ "+" AUFS_BRATTR_ICEX_USR \ ++ "+" AUFS_BRATTR_ICEX_OTH \ ++ "+" AUFS_BRWATTR_NLWH) ++ ++typedef struct { ++ char a[AuBrPermStrSz]; ++} au_br_perm_str_t; ++ ++static inline int au_br_writable(int brperm) ++{ ++ return brperm & AuBrPerm_RW; ++} ++ ++static inline int au_br_whable(int brperm) ++{ ++ return brperm & (AuBrPerm_RW | AuBrRAttr_WH); ++} ++ ++static inline int au_br_wh_linkable(int brperm) ++{ ++ return !(brperm & AuBrWAttr_NoLinkWH); ++} ++ ++static inline int au_br_cmoo(int brperm) ++{ ++ return brperm & AuBrAttr_CMOO_Mask; ++} ++ ++static inline int au_br_fhsm(int brperm) ++{ ++ return brperm & AuBrAttr_FHSM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ioctl */ ++enum { ++ /* readdir in userspace */ ++ AuCtl_RDU, ++ AuCtl_RDU_INO, ++ ++ AuCtl_WBR_FD, /* pathconf wrapper */ ++ AuCtl_IBUSY, /* busy inode */ ++ AuCtl_MVDOWN, /* move-down */ ++ AuCtl_BR, /* info about branches */ ++ AuCtl_FHSM_FD /* connection for fhsm */ ++}; ++ ++/* borrowed from linux/include/linux/kernel.h */ ++#ifndef ALIGN ++#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) ++#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) ++#endif ++ ++/* borrowed from linux/include/linux/compiler-gcc3.h */ ++#ifndef __aligned ++#define __aligned(x) __attribute__((aligned(x))) ++#endif ++ ++#ifdef __KERNEL__ ++#ifndef __packed ++#define __packed __attribute__((packed)) ++#endif ++#endif ++ ++struct au_rdu_cookie { ++ uint64_t h_pos; ++ int16_t bindex; ++ uint8_t flags; ++ uint8_t pad; ++ uint32_t generation; ++} __aligned(8); ++ ++struct au_rdu_ent { ++ uint64_t ino; ++ int16_t bindex; ++ uint8_t type; ++ uint8_t nlen; ++ uint8_t wh; ++ char name[0]; ++} __aligned(8); ++ ++static inline int au_rdu_len(int nlen) ++{ ++ /* include the terminating NULL */ ++ return ALIGN(sizeof(struct au_rdu_ent) + nlen + 1, ++ sizeof(uint64_t)); ++} ++ ++union au_rdu_ent_ul { ++ struct au_rdu_ent __user *e; ++ uint64_t ul; ++}; ++ ++enum { ++ AufsCtlRduV_SZ, ++ AufsCtlRduV_End ++}; ++ ++struct aufs_rdu { ++ /* input */ ++ union { ++ uint64_t sz; /* AuCtl_RDU */ ++ uint64_t nent; /* AuCtl_RDU_INO */ ++ }; ++ union au_rdu_ent_ul ent; ++ uint16_t verify[AufsCtlRduV_End]; ++ ++ /* input/output */ ++ uint32_t blk; ++ ++ /* output */ ++ union au_rdu_ent_ul tail; ++ /* number of entries which were added in a single call */ ++ uint64_t rent; ++ uint8_t full; ++ uint8_t shwh; ++ ++ struct au_rdu_cookie cookie; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_wbr_fd { ++ uint32_t oflags; ++ int16_t brid; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_ibusy { ++ uint64_t ino, h_ino; ++ int16_t bindex; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* error code for move-down */ ++/* the actual message strings are implemented in aufs-util.git */ ++enum { ++ EAU_MVDOWN_OPAQUE = 1, ++ EAU_MVDOWN_WHITEOUT, ++ EAU_MVDOWN_UPPER, ++ EAU_MVDOWN_BOTTOM, ++ EAU_MVDOWN_NOUPPER, ++ EAU_MVDOWN_NOLOWERBR, ++ EAU_Last ++}; ++ ++/* flags for move-down */ ++#define AUFS_MVDOWN_DMSG 1 ++#define AUFS_MVDOWN_OWLOWER (1 << 1) /* overwrite lower */ ++#define AUFS_MVDOWN_KUPPER (1 << 2) /* keep upper */ ++#define AUFS_MVDOWN_ROLOWER (1 << 3) /* do even if lower is RO */ ++#define AUFS_MVDOWN_ROLOWER_R (1 << 4) /* did on lower RO */ ++#define AUFS_MVDOWN_ROUPPER (1 << 5) /* do even if upper is RO */ ++#define AUFS_MVDOWN_ROUPPER_R (1 << 6) /* did on upper RO */ ++#define AUFS_MVDOWN_BRID_UPPER (1 << 7) /* upper brid */ ++#define AUFS_MVDOWN_BRID_LOWER (1 << 8) /* lower brid */ ++#define AUFS_MVDOWN_FHSM_LOWER (1 << 9) /* find fhsm attr for lower */ ++#define AUFS_MVDOWN_STFS (1 << 10) /* req. stfs */ ++#define AUFS_MVDOWN_STFS_FAILED (1 << 11) /* output: stfs is unusable */ ++#define AUFS_MVDOWN_BOTTOM (1 << 12) /* output: no more lowers */ ++ ++/* index for move-down */ ++enum { ++ AUFS_MVDOWN_UPPER, ++ AUFS_MVDOWN_LOWER, ++ AUFS_MVDOWN_NARRAY ++}; ++ ++/* ++ * additional info of move-down ++ * number of free blocks and inodes. ++ * subset of struct kstatfs, but smaller and always 64bit. ++ */ ++struct aufs_stfs { ++ uint64_t f_blocks; ++ uint64_t f_bavail; ++ uint64_t f_files; ++ uint64_t f_ffree; ++}; ++ ++struct aufs_stbr { ++ int16_t brid; /* optional input */ ++ int16_t bindex; /* output */ ++ struct aufs_stfs stfs; /* output when AUFS_MVDOWN_STFS set */ ++} __aligned(8); ++ ++struct aufs_mvdown { ++ uint32_t flags; /* input/output */ ++ struct aufs_stbr stbr[AUFS_MVDOWN_NARRAY]; /* input/output */ ++ int8_t au_errno; /* output */ ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++union aufs_brinfo { ++ /* PATH_MAX may differ between kernel-space and user-space */ ++ char _spacer[4096]; ++ struct { ++ int16_t id; ++ int perm; ++ char path[0]; ++ }; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuCtlType 'A' ++#define AUFS_CTL_RDU _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu) ++#define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu) ++#define AUFS_CTL_WBR_FD _IOW(AuCtlType, AuCtl_WBR_FD, \ ++ struct aufs_wbr_fd) ++#define AUFS_CTL_IBUSY _IOWR(AuCtlType, AuCtl_IBUSY, struct aufs_ibusy) ++#define AUFS_CTL_MVDOWN _IOWR(AuCtlType, AuCtl_MVDOWN, \ ++ struct aufs_mvdown) ++#define AUFS_CTL_BRINFO _IOW(AuCtlType, AuCtl_BR, union aufs_brinfo) ++#define AUFS_CTL_FHSM_FD _IOW(AuCtlType, AuCtl_FHSM_FD, int) ++ ++#endif /* __AUFS_TYPE_H__ */ +diff --git a/kernel/fork.c b/kernel/fork.c +index 4a7ec0c..8c8f7ac 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -479,7 +479,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) + struct inode *inode = file_inode(file); + struct address_space *mapping = file->f_mapping; + +- get_file(file); ++ vma_get_file(tmp); + if (tmp->vm_flags & VM_DENYWRITE) + atomic_dec(&inode->i_writecount); + i_mmap_lock_write(mapping); +diff --git a/mm/Makefile b/mm/Makefile +index 78c6f7d..aea4230 100644 +--- a/mm/Makefile ++++ b/mm/Makefile +@@ -37,7 +37,7 @@ obj-y := filemap.o mempool.o oom_kill.o \ + mm_init.o mmu_context.o percpu.o slab_common.o \ + compaction.o vmacache.o \ + interval_tree.o list_lru.o workingset.o \ +- debug.o $(mmu-y) ++ prfile.o debug.o $(mmu-y) + + obj-y += init-mm.o + +diff --git a/mm/filemap.c b/mm/filemap.c +index 20f3b1f..ee827ce 100644 +--- a/mm/filemap.c ++++ b/mm/filemap.c +@@ -2208,7 +2208,7 @@ int filemap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) + int ret = VM_FAULT_LOCKED; + + sb_start_pagefault(inode->i_sb); +- file_update_time(vma->vm_file); ++ vma_file_update_time(vma); + lock_page(page); + if (page->mapping != inode->i_mapping) { + unlock_page(page); +diff --git a/mm/memory.c b/mm/memory.c +index cd1f29e..f0c204c 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -2100,7 +2100,7 @@ static inline int wp_page_reuse(struct mm_struct *mm, + } + + if (!page_mkwrite) +- file_update_time(vma->vm_file); ++ vma_file_update_time(vma); + } + + return VM_FAULT_WRITE; +diff --git a/mm/mmap.c b/mm/mmap.c +index de2c176..b7f391c 100644 +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -162,7 +162,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma) + if (vma->vm_ops && vma->vm_ops->close) + vma->vm_ops->close(vma); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + mpol_put(vma_policy(vma)); + kmem_cache_free(vm_area_cachep, vma); + return next; +@@ -782,7 +782,7 @@ again: remove_next = 1 + (end > next->vm_end); + if (remove_next) { + if (file) { + uprobe_munmap(next, next->vm_start, next->vm_end); +- fput(file); ++ vma_fput(vma); + } + if (next->anon_vma) + anon_vma_merge(vma, next); +@@ -1563,8 +1563,8 @@ out: + return addr; + + unmap_and_free_vma: ++ vma_fput(vma); + vma->vm_file = NULL; +- fput(file); + + /* Undo any partial mapping done by a device driver. */ + unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end); +@@ -2358,7 +2358,7 @@ static int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, + goto out_free_mpol; + + if (new->vm_file) +- get_file(new->vm_file); ++ vma_get_file(new); + + if (new->vm_ops && new->vm_ops->open) + new->vm_ops->open(new); +@@ -2377,7 +2377,7 @@ static int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, + if (new->vm_ops && new->vm_ops->close) + new->vm_ops->close(new); + if (new->vm_file) +- fput(new->vm_file); ++ vma_fput(new); + unlink_anon_vmas(new); + out_free_mpol: + mpol_put(vma_policy(new)); +@@ -2528,7 +2528,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, + struct vm_area_struct *vma; + unsigned long populate = 0; + unsigned long ret = -EINVAL; +- struct file *file; ++ struct file *file, *prfile; + + pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. See Documentation/vm/remap_file_pages.txt.\n", + current->comm, current->pid); +@@ -2597,10 +2597,27 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, + } + } + +- file = get_file(vma->vm_file); ++ vma_get_file(vma); ++ file = vma->vm_file; ++ prfile = vma->vm_prfile; + ret = do_mmap_pgoff(vma->vm_file, start, size, + prot, flags, pgoff, &populate); ++ if (!IS_ERR_VALUE(ret) && file && prfile) { ++ struct vm_area_struct *new_vma; ++ ++ new_vma = find_vma(mm, ret); ++ if (!new_vma->vm_prfile) ++ new_vma->vm_prfile = prfile; ++ if (new_vma != vma) ++ get_file(prfile); ++ } ++ /* ++ * two fput()s instead of vma_fput(vma), ++ * coz vma may not be available anymore. ++ */ + fput(file); ++ if (prfile) ++ fput(prfile); + out: + up_write(&mm->mmap_sem); + if (populate) +@@ -2873,7 +2890,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, + if (anon_vma_clone(new_vma, vma)) + goto out_free_mempol; + if (new_vma->vm_file) +- get_file(new_vma->vm_file); ++ vma_get_file(new_vma); + if (new_vma->vm_ops && new_vma->vm_ops->open) + new_vma->vm_ops->open(new_vma); + vma_link(mm, new_vma, prev, rb_link, rb_parent); +diff --git a/mm/nommu.c b/mm/nommu.c +index c2e588802..c39edc4 100644 +--- a/mm/nommu.c ++++ b/mm/nommu.c +@@ -644,7 +644,7 @@ static void __put_nommu_region(struct vm_region *region) + up_write(&nommu_region_sem); + + if (region->vm_file) +- fput(region->vm_file); ++ vmr_fput(region); + + /* IO memory and memory shared directly out of the pagecache + * from ramfs/tmpfs mustn't be released here */ +@@ -802,7 +802,7 @@ static void delete_vma(struct mm_struct *mm, struct vm_area_struct *vma) + if (vma->vm_ops && vma->vm_ops->close) + vma->vm_ops->close(vma); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + put_nommu_region(vma->vm_region); + kmem_cache_free(vm_area_cachep, vma); + } +@@ -1328,7 +1328,7 @@ unsigned long do_mmap(struct file *file, + goto error_just_free; + } + } +- fput(region->vm_file); ++ vmr_fput(region); + kmem_cache_free(vm_region_jar, region); + region = pregion; + result = start; +@@ -1403,10 +1403,10 @@ error_just_free: + up_write(&nommu_region_sem); + error: + if (region->vm_file) +- fput(region->vm_file); ++ vmr_fput(region); + kmem_cache_free(vm_region_jar, region); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + kmem_cache_free(vm_area_cachep, vma); + return ret; + +diff --git a/mm/prfile.c b/mm/prfile.c +new file mode 100644 +index 0000000..b323b8a +--- /dev/null ++++ b/mm/prfile.c +@@ -0,0 +1,86 @@ ++/* ++ * Mainly for aufs which mmap(2) diffrent file and wants to print different path ++ * in /proc/PID/maps. ++ * Call these functions via macros defined in linux/mm.h. ++ * ++ * See Documentation/filesystems/aufs/design/06mmap.txt ++ * ++ * Copyright (c) 2014 Junjro R. Okajima ++ * Copyright (c) 2014 Ian Campbell ++ */ ++ ++#include ++#include ++#include ++ ++/* #define PRFILE_TRACE */ ++static inline void prfile_trace(struct file *f, struct file *pr, ++ const char func[], int line, const char func2[]) ++{ ++#ifdef PRFILE_TRACE ++ if (pr) ++ pr_info("%s:%d: %s, %s\n", func, line, func2, ++ f ? (char *)f->f_path.dentry->d_name.name : "(null)"); ++#endif ++} ++ ++void vma_do_file_update_time(struct vm_area_struct *vma, const char func[], ++ int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ file_update_time(f); ++ if (f && pr) ++ file_update_time(pr); ++} ++ ++struct file *vma_do_pr_or_file(struct vm_area_struct *vma, const char func[], ++ int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ return (f && pr) ? pr : f; ++} ++ ++void vma_do_get_file(struct vm_area_struct *vma, const char func[], int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ get_file(f); ++ if (f && pr) ++ get_file(pr); ++} ++ ++void vma_do_fput(struct vm_area_struct *vma, const char func[], int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ fput(f); ++ if (f && pr) ++ fput(pr); ++} ++ ++#ifndef CONFIG_MMU ++struct file *vmr_do_pr_or_file(struct vm_region *region, const char func[], ++ int line) ++{ ++ struct file *f = region->vm_file, *pr = region->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ return (f && pr) ? pr : f; ++} ++ ++void vmr_do_fput(struct vm_region *region, const char func[], int line) ++{ ++ struct file *f = region->vm_file, *pr = region->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ fput(f); ++ if (f && pr) ++ fput(pr); ++} ++#endif /* !CONFIG_MMU */ diff --git a/kernel/tools/perf/files/patches/mageia/fs-ext4-don-t-call-ext4_should_journal_data-on-the-jour.patch b/kernel/tools/perf/files/patches/mageia/fs-ext4-don-t-call-ext4_should_journal_data-on-the-jour.patch new file mode 100644 index 0000000000..cf55d7cc5c --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/fs-ext4-don-t-call-ext4_should_journal_data-on-the-jour.patch @@ -0,0 +1,45 @@ +From 6a7fd522a7c94cdef0a3b08acf8e6702056e635c Mon Sep 17 00:00:00 2001 +From: Vegard Nossum +Date: Mon, 4 Jul 2016 11:03:00 -0400 +Subject: [PATCH] ext4: don't call ext4_should_journal_data() on the journal + inode + +If ext4_fill_super() fails early, it's possible for ext4_evict_inode() +to call ext4_should_journal_data() before superblock options and flags +are fully set up. In that case, the iput() on the journal inode can +end up causing a BUG(). + +Work around this problem by reordering the tests so we only call +ext4_should_journal_data() after we know it's not the journal inode. + +Fixes: 2d859db3e4 ("ext4: fix data corruption in inodes with journalled data") +Fixes: 2b405bfa84 ("ext4: fix data=journal fast mount/umount hang") +Cc: Jan Kara +Cc: stable@vger.kernel.org +Signed-off-by: Vegard Nossum +Signed-off-by: Theodore Ts'o +Reviewed-by: Jan Kara +--- + fs/ext4/inode.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 321a31c..ea39d19 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -211,9 +211,9 @@ void ext4_evict_inode(struct inode *inode) + * Note that directories do not have this problem because they + * don't use page cache. + */ +- if (ext4_should_journal_data(inode) && +- (S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode)) && +- inode->i_ino != EXT4_JOURNAL_INO) { ++ if (inode->i_ino != EXT4_JOURNAL_INO && ++ ext4_should_journal_data(inode) && ++ (S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode))) { + journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; + tid_t commit_tid = EXT4_I(inode)->i_datasync_tid; + +-- +2.9.2 + diff --git a/kernel/tools/perf/files/patches/mageia/fs-ext4-fix-deadlock-during-page-writeback.patch b/kernel/tools/perf/files/patches/mageia/fs-ext4-fix-deadlock-during-page-writeback.patch new file mode 100644 index 0000000000..ea56d5d8c3 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/fs-ext4-fix-deadlock-during-page-writeback.patch @@ -0,0 +1,78 @@ +From 646caa9c8e196880b41cd3e3d33a2ebc752bdb85 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Mon, 4 Jul 2016 10:14:01 -0400 +Subject: [PATCH] ext4: fix deadlock during page writeback + +Commit 06bd3c36a733 (ext4: fix data exposure after a crash) uncovered a +deadlock in ext4_writepages() which was previously much harder to hit. +After this commit xfstest generic/130 reproduces the deadlock on small +filesystems. + +The problem happens when ext4_do_update_inode() sets LARGE_FILE feature +and marks current inode handle as synchronous. That subsequently results +in ext4_journal_stop() called from ext4_writepages() to block waiting for +transaction commit while still holding page locks, reference to io_end, +and some prepared bio in mpd structure each of which can possibly block +transaction commit from completing and thus results in deadlock. + +Fix the problem by releasing page locks, io_end reference, and +submitting prepared bio before calling ext4_journal_stop(). + +[ Changed to defer the call to ext4_journal_stop() only if the handle + is synchronous. --tytso ] + +Reported-and-tested-by: Eryu Guan +Signed-off-by: Theodore Ts'o +CC: stable@vger.kernel.org +Signed-off-by: Jan Kara +--- + fs/ext4/inode.c | 29 ++++++++++++++++++++++++++--- + 1 file changed, 26 insertions(+), 3 deletions(-) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 44ee5d9..321a31c 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -2754,13 +2754,36 @@ retry: + done = true; + } + } +- ext4_journal_stop(handle); ++ /* ++ * Caution: If the handle is synchronous, ++ * ext4_journal_stop() can wait for transaction commit ++ * to finish which may depend on writeback of pages to ++ * complete or on page lock to be released. In that ++ * case, we have to wait until after after we have ++ * submitted all the IO, released page locks we hold, ++ * and dropped io_end reference (for extent conversion ++ * to be able to complete) before stopping the handle. ++ */ ++ if (!ext4_handle_valid(handle) || handle->h_sync == 0) { ++ ext4_journal_stop(handle); ++ handle = NULL; ++ } + /* Submit prepared bio */ + ext4_io_submit(&mpd.io_submit); + /* Unlock pages we didn't use */ + mpage_release_unused_pages(&mpd, give_up_on_write); +- /* Drop our io_end reference we got from init */ +- ext4_put_io_end(mpd.io_submit.io_end); ++ /* ++ * Drop our io_end reference we got from init. We have ++ * to be careful and use deferred io_end finishing if ++ * we are still holding the transaction as we can ++ * release the last reference to io_end which may end ++ * up doing unwritten extent conversion. ++ */ ++ if (handle) { ++ ext4_put_io_end_defer(mpd.io_submit.io_end); ++ ext4_journal_stop(handle); ++ } else ++ ext4_put_io_end(mpd.io_submit.io_end); + + if (ret == -ENOSPC && sbi->s_journal) { + /* +-- +2.9.2 + diff --git a/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-2.6.31.patch b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-2.6.31.patch new file mode 100644 index 0000000000..ac0254e505 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-2.6.31.patch @@ -0,0 +1,100 @@ +Adapt mach64 to build with 2.6.31 series kernels + +Signed-off-by: Thomas Backlund + +diff -urp linux-2.6.31-rc3-git5-mnb1/drivers/gpu/drm/mach64/mach64_dma.c linux-2.6.31-rc3-git5-mnb1/drivers/gpu/drm/mach64.fixed/mach64_dma.c +--- linux-2.6.31-rc3-git5-mnb1/drivers/gpu/drm/mach64/mach64_dma.c 2009-07-23 00:24:12.000000000 +0300 ++++ linux-2.6.31-rc3-git5-mnb1/drivers/gpu/drm/mach64.fixed/mach64_dma.c 2009-07-23 02:28:21.000000000 +0300 +@@ -1006,7 +1006,7 @@ static int mach64_do_dma_init(struct drm + + DRM_DEBUG("\n"); + +- dev_priv = drm_alloc(sizeof(drm_mach64_private_t), DRM_MEM_DRIVER); ++ dev_priv = kmalloc(sizeof(drm_mach64_private_t), GFP_KERNEL); + if (dev_priv == NULL) + return -ENOMEM; + +@@ -1386,8 +1386,7 @@ int mach64_do_cleanup_dma(struct drm_dev + + mach64_destroy_freelist(dev); + +- drm_free(dev_priv, sizeof(drm_mach64_private_t), +- DRM_MEM_DRIVER); ++ kfree(dev_priv); + dev->dev_private = NULL; + } + +@@ -1476,8 +1475,8 @@ int mach64_init_freelist(struct drm_devi + for (i = 0; i < dma->buf_count; i++) { + if ((entry = + (drm_mach64_freelist_t *) +- drm_alloc(sizeof(drm_mach64_freelist_t), +- DRM_MEM_BUFLISTS)) == NULL) ++ kmalloc(sizeof(drm_mach64_freelist_t), ++ GFP_KERNEL)) == NULL) + return -ENOMEM; + memset(entry, 0, sizeof(drm_mach64_freelist_t)); + entry->buf = dma->buflist[i]; +@@ -1500,18 +1499,18 @@ void mach64_destroy_freelist(struct drm_ + list_for_each_safe(ptr, tmp, &dev_priv->pending) { + list_del(ptr); + entry = list_entry(ptr, drm_mach64_freelist_t, list); +- drm_free(entry, sizeof(*entry), DRM_MEM_BUFLISTS); ++ kfree(entry); + } + list_for_each_safe(ptr, tmp, &dev_priv->placeholders) { + list_del(ptr); + entry = list_entry(ptr, drm_mach64_freelist_t, list); +- drm_free(entry, sizeof(*entry), DRM_MEM_BUFLISTS); ++ kfree(entry); + } + + list_for_each_safe(ptr, tmp, &dev_priv->free_list) { + list_del(ptr); + entry = list_entry(ptr, drm_mach64_freelist_t, list); +- drm_free(entry, sizeof(*entry), DRM_MEM_BUFLISTS); ++ kfree(entry); + } + } + +diff -urp linux-2.6.31-rc3-git5-mnb1/drivers/gpu/drm/mach64/mach64_state.c linux-2.6.31-rc3-git5-mnb1/drivers/gpu/drm/mach64.fixed/mach64_state.c +--- linux-2.6.31-rc3-git5-mnb1/drivers/gpu/drm/mach64/mach64_state.c 2009-07-23 00:24:12.000000000 +0300 ++++ linux-2.6.31-rc3-git5-mnb1/drivers/gpu/drm/mach64.fixed/mach64_state.c 2009-07-23 02:29:24.000000000 +0300 +@@ -490,12 +490,12 @@ static __inline__ int copy_from_user_ver + unsigned long n = bytes; /* dwords remaining in buffer */ + u32 *from, *orig_from; + +- from = drm_alloc(bytes, DRM_MEM_DRIVER); ++ from = kmalloc(bytes, GFP_KERNEL); + if (from == NULL) + return -ENOMEM; + + if (DRM_COPY_FROM_USER(from, ufrom, bytes)) { +- drm_free(from, bytes, DRM_MEM_DRIVER); ++ kfree(from); + return -EFAULT; + } + orig_from = from; /* we'll be modifying the "from" ptr, so save it */ +@@ -526,19 +526,19 @@ static __inline__ int copy_from_user_ver + to += count; + } else { + DRM_ERROR("Got bad command: 0x%04x\n", reg); +- drm_free(orig_from, bytes, DRM_MEM_DRIVER); ++ kfree(orig_from); + return -EACCES; + } + } else { + DRM_ERROR + ("Got bad command count(=%u) dwords remaining=%lu\n", + count, n); +- drm_free(orig_from, bytes, DRM_MEM_DRIVER); ++ kfree(orig_from); + return -EINVAL; + } + } + +- drm_free(orig_from, bytes, DRM_MEM_DRIVER); ++ kfree(orig_from); + if (n == 0) + return 0; + else { diff --git a/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-2.6.36-buildfix.patch b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-2.6.36-buildfix.patch new file mode 100644 index 0000000000..ef42898382 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-2.6.36-buildfix.patch @@ -0,0 +1,27 @@ +--- linux-2.6.35/drivers/gpu/drm/mach64/mach64_state.c.orig 2010-10-03 13:29:10.000000000 +0300 ++++ linux-2.6.35/drivers/gpu/drm/mach64/mach64_state.c 2010-10-03 14:04:45.991164007 +0300 +@@ -41,15 +41,15 @@ + * + */ + struct drm_ioctl_desc mach64_ioctls[] = { +- DRM_IOCTL_DEF(DRM_MACH64_INIT, mach64_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), +- DRM_IOCTL_DEF(DRM_MACH64_CLEAR, mach64_dma_clear, DRM_AUTH), +- DRM_IOCTL_DEF(DRM_MACH64_SWAP, mach64_dma_swap, DRM_AUTH), +- DRM_IOCTL_DEF(DRM_MACH64_IDLE, mach64_dma_idle, DRM_AUTH), +- DRM_IOCTL_DEF(DRM_MACH64_RESET, mach64_engine_reset, DRM_AUTH), +- DRM_IOCTL_DEF(DRM_MACH64_VERTEX, mach64_dma_vertex, DRM_AUTH), +- DRM_IOCTL_DEF(DRM_MACH64_BLIT, mach64_dma_blit, DRM_AUTH), +- DRM_IOCTL_DEF(DRM_MACH64_FLUSH, mach64_dma_flush, DRM_AUTH), +- DRM_IOCTL_DEF(DRM_MACH64_GETPARAM, mach64_get_param, DRM_AUTH), ++ DRM_IOCTL_DEF_DRV(MACH64_INIT, mach64_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), ++ DRM_IOCTL_DEF_DRV(MACH64_CLEAR, mach64_dma_clear, DRM_AUTH), ++ DRM_IOCTL_DEF_DRV(MACH64_SWAP, mach64_dma_swap, DRM_AUTH), ++ DRM_IOCTL_DEF_DRV(MACH64_IDLE, mach64_dma_idle, DRM_AUTH), ++ DRM_IOCTL_DEF_DRV(MACH64_RESET, mach64_engine_reset, DRM_AUTH), ++ DRM_IOCTL_DEF_DRV(MACH64_VERTEX, mach64_dma_vertex, DRM_AUTH), ++ DRM_IOCTL_DEF_DRV(MACH64_BLIT, mach64_dma_blit, DRM_AUTH), ++ DRM_IOCTL_DEF_DRV(MACH64_FLUSH, mach64_dma_flush, DRM_AUTH), ++ DRM_IOCTL_DEF_DRV(MACH64_GETPARAM, mach64_get_param, DRM_AUTH), + }; + + int mach64_max_ioctl = DRM_ARRAY_SIZE(mach64_ioctls); diff --git a/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-2.6.37-buildfix.patch b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-2.6.37-buildfix.patch new file mode 100644 index 0000000000..43dc70ecd9 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-2.6.37-buildfix.patch @@ -0,0 +1,24 @@ + +Fix build for 2.6.37 + +Signed-off-by: Thomas Backlund + +--- a/drivers/gpu/drm/mach64/mach64_drv.c.orig 2011-01-02 16:55:48.000000000 +0200 ++++ a/drivers/gpu/drm/mach64/mach64_drv.c 2011-01-02 17:53:54.808775632 +0200 +@@ -51,8 +51,6 @@ static struct drm_driver driver = { + .irq_uninstall = mach64_driver_irq_uninstall, + .irq_handler = mach64_driver_irq_handler, + .reclaim_buffers = drm_core_reclaim_buffers, +- .get_map_ofs = drm_core_get_map_ofs, +- .get_reg_ofs = drm_core_get_reg_ofs, + .ioctls = mach64_ioctls, + .dma_ioctl = mach64_dma_buffers, + .fops = { +@@ -63,6 +61,7 @@ static struct drm_driver driver = { + .mmap = drm_mmap, + .poll = drm_poll, + .fasync = drm_fasync, ++ .llseek = noop_llseek, + }, + .pci_driver = { + .name = DRIVER_NAME, diff --git a/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.0-buildfix.patch b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.0-buildfix.patch new file mode 100644 index 0000000000..9d7538a9e2 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.0-buildfix.patch @@ -0,0 +1,44 @@ + +fix build with linux-3.0 + +Signed-off-by: Thomas Backlund + + drivers/gpu/drm/mach64/mach64_drv.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +--- a/drivers/gpu/drm/mach64/mach64_drv.c.orig 2011-07-15 02:48:40.000000000 +0300 ++++ a/drivers/gpu/drm/mach64/mach64_drv.c 2011-07-15 13:24:41.454753025 +0300 +@@ -63,10 +63,6 @@ static struct drm_driver driver = { + .fasync = drm_fasync, + .llseek = noop_llseek, + }, +- .pci_driver = { +- .name = DRIVER_NAME, +- .id_table = pciidlist, +- }, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, +@@ -76,15 +72,20 @@ static struct drm_driver driver = { + .patchlevel = DRIVER_PATCHLEVEL, + }; + ++static struct pci_driver mach64_pci_driver = { ++ .name = DRIVER_NAME, ++ .id_table = pciidlist, ++}; ++ + static int __init mach64_init(void) + { + driver.num_ioctls = mach64_max_ioctl; +- return drm_init(&driver); ++ return drm_pci_init(&driver, &mach64_pci_driver); + } + + static void __exit mach64_exit(void) + { +- drm_exit(&driver); ++ drm_pci_exit(&driver, &mach64_pci_driver); + } + + module_init(mach64_init); diff --git a/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.12-buildfix.patch b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.12-buildfix.patch new file mode 100644 index 0000000000..5ec066982f --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.12-buildfix.patch @@ -0,0 +1,17 @@ +--- linux/drivers/gpu/drm/mach64/mach64_drv.c.orig 2013-10-13 12:19:41.000000000 +0300 ++++ linux/drivers/gpu/drm/mach64/mach64_drv.c 2013-10-13 14:27:25.684247911 +0300 +@@ -46,13 +46,12 @@ static const struct file_operations mach + .unlocked_ioctl = drm_ioctl, + .mmap = drm_mmap, + .poll = drm_poll, +- .fasync = drm_fasync, + .llseek = noop_llseek, + }; + + static struct drm_driver driver = { + .driver_features = +- DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_HAVE_DMA ++ DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_HAVE_DMA + | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, + .lastclose = mach64_driver_lastclose, + .get_vblank_counter = mach64_get_vblank_counter, diff --git a/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.17-buildfix.patch b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.17-buildfix.patch new file mode 100644 index 0000000000..6b7b378035 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.17-buildfix.patch @@ -0,0 +1,31 @@ + +Adapt for kernel-3.17 + +DRM_ARRAY_SIZE is a duplicate of ARRAY_SIZE and have been dropped. + +drm_dev_to_irq has been dropped, so call dev->pdev->irq directly +for code simplicity. + +Signed-off-by: Thomas Backlund + +diff -urp linux/drivers/gpu/drm/mach64/mach64_state.c.orig linux/drivers/gpu/drm/mach64/mach64_state.c +--- linux/drivers/gpu/drm/mach64/mach64_state.c.orig ++++ linux/drivers/gpu/drm/mach64/mach64_state.c +@@ -52,7 +52,7 @@ struct drm_ioctl_desc mach64_ioctls[] = + DRM_IOCTL_DEF_DRV(MACH64_GETPARAM, mach64_get_param, DRM_AUTH), + }; + +-int mach64_max_ioctl = DRM_ARRAY_SIZE(mach64_ioctls); ++int mach64_max_ioctl = ARRAY_SIZE(mach64_ioctls); + + /* ================================================================ + * DMA hardware state programming functions +@@ -895,7 +895,7 @@ int mach64_get_param(struct drm_device * + value = mach64_do_get_frames_queued(dev_priv); + break; + case MACH64_PARAM_IRQ_NR: +- value = drm_dev_to_irq(dev); ++ value = dev->pdev->irq; + break; + default: + return -EINVAL; diff --git a/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.18-buildfix.patch b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.18-buildfix.patch new file mode 100644 index 0000000000..bc0d460667 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.18-buildfix.patch @@ -0,0 +1,142 @@ + +Fix build with kernel 3.18 + +Signed-off-by: Thomas Backlund + +diff -urp linux/drivers/gpu/drm/mach64.orig/mach64_dma.c linux/drivers/gpu/drm/mach64/mach64_dma.c +--- linux/drivers/gpu/drm/mach64.orig/mach64_dma.c 2014-11-29 22:01:54.000000000 +0200 ++++ linux/drivers/gpu/drm/mach64/mach64_dma.c 2014-11-30 00:02:06.906821818 +0200 +@@ -1038,21 +1038,21 @@ static int mach64_do_dma_init(struct drm + INIT_LIST_HEAD(&dev_priv->placeholders); + INIT_LIST_HEAD(&dev_priv->pending); + +- dev_priv->sarea = drm_getsarea(dev); ++ dev_priv->sarea = drm_legacy_getsarea(dev); + if (!dev_priv->sarea) { + DRM_ERROR("can not find sarea!\n"); + dev->dev_private = (void *)dev_priv; + mach64_do_cleanup_dma(dev); + return -EINVAL; + } +- dev_priv->fb = drm_core_findmap(dev, init->fb_offset); ++ dev_priv->fb = drm_legacy_findmap(dev, init->fb_offset); + if (!dev_priv->fb) { + DRM_ERROR("can not find frame buffer map!\n"); + dev->dev_private = (void *)dev_priv; + mach64_do_cleanup_dma(dev); + return -EINVAL; + } +- dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); ++ dev_priv->mmio = drm_legacy_findmap(dev, init->mmio_offset); + if (!dev_priv->mmio) { + DRM_ERROR("can not find mmio map!\n"); + dev->dev_private = (void *)dev_priv; +@@ -1060,7 +1060,7 @@ static int mach64_do_dma_init(struct drm + return -EINVAL; + } + +- dev_priv->ring_map = drm_core_findmap(dev, init->ring_offset); ++ dev_priv->ring_map = drm_legacy_findmap(dev, init->ring_offset); + if (!dev_priv->ring_map) { + DRM_ERROR("can not find ring map!\n"); + dev->dev_private = (void *)dev_priv; +@@ -1072,7 +1072,7 @@ static int mach64_do_dma_init(struct drm + ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); + + if (!dev_priv->is_pci) { +- drm_core_ioremap(dev_priv->ring_map, dev); ++ drm_legacy_ioremap(dev_priv->ring_map, dev); + if (!dev_priv->ring_map->handle) { + DRM_ERROR("can not ioremap virtual address for" + " descriptor ring\n"); +@@ -1082,7 +1082,7 @@ static int mach64_do_dma_init(struct drm + } + dev->agp_buffer_token = init->buffers_offset; + dev->agp_buffer_map = +- drm_core_findmap(dev, init->buffers_offset); ++ drm_legacy_findmap(dev, init->buffers_offset); + if (!dev->agp_buffer_map) { + DRM_ERROR("can not find dma buffer map!\n"); + dev->dev_private = (void *)dev_priv; +@@ -1093,7 +1093,7 @@ static int mach64_do_dma_init(struct drm + dev isn't passed all the way though the mach64 - DA */ + dev_priv->dev_buffers = dev->agp_buffer_map; + +- drm_core_ioremap(dev->agp_buffer_map, dev); ++ drm_legacy_ioremap(dev->agp_buffer_map, dev); + if (!dev->agp_buffer_map->handle) { + DRM_ERROR("can not ioremap virtual address for" + " dma buffer\n"); +@@ -1102,7 +1102,7 @@ static int mach64_do_dma_init(struct drm + return -ENOMEM; + } + dev_priv->agp_textures = +- drm_core_findmap(dev, init->agp_textures_offset); ++ drm_legacy_findmap(dev, init->agp_textures_offset); + if (!dev_priv->agp_textures) { + DRM_ERROR("can not find agp texture region!\n"); + dev->dev_private = (void *)dev_priv; +@@ -1376,10 +1376,10 @@ int mach64_do_cleanup_dma(struct drm_dev + + if (!dev_priv->is_pci) { + if (dev_priv->ring_map) +- drm_core_ioremapfree(dev_priv->ring_map, dev); ++ drm_legacy_ioremapfree(dev_priv->ring_map, dev); + + if (dev->agp_buffer_map) { +- drm_core_ioremapfree(dev->agp_buffer_map, dev); ++ drm_legacy_ioremapfree(dev->agp_buffer_map, dev); + dev->agp_buffer_map = NULL; + } + } +diff -urp linux/drivers/gpu/drm/mach64.orig/mach64_drv.c linux/drivers/gpu/drm/mach64/mach64_drv.c +--- linux/drivers/gpu/drm/mach64.orig/mach64_drv.c 2014-11-29 22:01:54.000000000 +0200 ++++ linux/drivers/gpu/drm/mach64/mach64_drv.c 2014-11-29 23:14:21.918009653 +0200 +@@ -34,6 +34,7 @@ + #include "mach64_drv.h" + + #include ++#include + + static struct pci_device_id pciidlist[] = { + mach64_PCI_IDS +@@ -44,7 +45,7 @@ static const struct file_operations mach + .open = drm_open, + .release = drm_release, + .unlocked_ioctl = drm_ioctl, +- .mmap = drm_mmap, ++ .mmap = drm_legacy_mmap, + .poll = drm_poll, + .llseek = noop_llseek, + }; +diff -urp linux/drivers/gpu/drm/mach64.orig/mach64_drv.h linux/drivers/gpu/drm/mach64/mach64_drv.h +--- linux/drivers/gpu/drm/mach64.orig/mach64_drv.h 2014-11-29 22:01:54.000000000 +0200 ++++ linux/drivers/gpu/drm/mach64/mach64_drv.h 2014-11-29 23:58:20.111491646 +0200 +@@ -35,6 +35,8 @@ + #ifndef __MACH64_DRV_H__ + #define __MACH64_DRV_H__ + ++#include ++ + /* General customization: + */ + +@@ -102,12 +104,12 @@ typedef struct drm_mach64_private { + u32 back_offset_pitch; + u32 depth_offset_pitch; + +- drm_local_map_t *sarea; +- drm_local_map_t *fb; +- drm_local_map_t *mmio; +- drm_local_map_t *ring_map; +- drm_local_map_t *dev_buffers; /* this is a pointer to a structure in dev */ +- drm_local_map_t *agp_textures; ++ struct drm_local_map *sarea; ++ struct drm_local_map *fb; ++ struct drm_local_map *mmio; ++ struct drm_local_map *ring_map; ++ struct drm_local_map *dev_buffers; /* this is a pointer to a structure in dev */ ++ struct drm_local_map *agp_textures; + } drm_mach64_private_t; + + extern struct drm_ioctl_desc mach64_ioctls[]; diff --git a/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.3-buildfix.patch b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.3-buildfix.patch new file mode 100644 index 0000000000..824b95525b --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.3-buildfix.patch @@ -0,0 +1,47 @@ + +This moves the .fops to a separate struct as required by kernel-3.3 + +Signed-off-by: Thomas Backlund + + b/drivers/gpu/drm/mach64/mach64_drv.c | 23 ++++++++++++----------- + 1 file changed, 12 insertions(+), 11 deletions(-) + +--- a/drivers/gpu/drm/mach64/mach64_drv.c ++++ b/drivers/gpu/drm/mach64/mach64_drv.c +@@ -39,6 +39,17 @@ static struct pci_device_id pciidlist[] + mach64_PCI_IDS + }; + ++static const struct file_operations mach64_driver_fops = { ++ .owner = THIS_MODULE, ++ .open = drm_open, ++ .release = drm_release, ++ .unlocked_ioctl = drm_ioctl, ++ .mmap = drm_mmap, ++ .poll = drm_poll, ++ .fasync = drm_fasync, ++ .llseek = noop_llseek, ++}; ++ + static struct drm_driver driver = { + .driver_features = + DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_HAVE_DMA +@@ -54,17 +65,7 @@ static struct drm_driver driver = { + .reclaim_buffers = drm_core_reclaim_buffers, + .ioctls = mach64_ioctls, + .dma_ioctl = mach64_dma_buffers, +- .fops = { +- .owner = THIS_MODULE, +- .open = drm_open, +- .release = drm_release, +- .unlocked_ioctl = drm_ioctl, +- .mmap = drm_mmap, +- .poll = drm_poll, +- .fasync = drm_fasync, +- .llseek = noop_llseek, +- }, +- ++ .fops = &mach64_driver_fops, + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, diff --git a/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.6-buildfix.patch b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.6-buildfix.patch new file mode 100644 index 0000000000..c7df6444db --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.6-buildfix.patch @@ -0,0 +1,15 @@ + +reclaim_buffers is gone in 3.6 + +Signed-off-by: Thomas Backlund + +--- linux/drivers/gpu/drm/mach64/mach64_drv.c.orig 2012-10-17 22:26:58.000000000 +0300 ++++ linux/drivers/gpu/drm/mach64/mach64_drv.c 2012-10-17 23:05:10.212566630 +0300 +@@ -62,7 +62,6 @@ static struct drm_driver driver = { + .irq_postinstall = mach64_driver_irq_postinstall, + .irq_uninstall = mach64_driver_irq_uninstall, + .irq_handler = mach64_driver_irq_handler, +- .reclaim_buffers = drm_core_reclaim_buffers, + .ioctls = mach64_ioctls, + .dma_ioctl = mach64_dma_buffers, + .fops = &mach64_driver_fops, diff --git a/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.7-buildfix.patch b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.7-buildfix.patch new file mode 100644 index 0000000000..cc1c5b2763 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-3.7-buildfix.patch @@ -0,0 +1,61 @@ +diff -Nurp linux-3.7-rc8/drivers/gpu/drm/mach64.orig/mach64_dma.c linux-3.7-rc8/drivers/gpu/drm/mach64/mach64_dma.c +--- linux-3.7-rc8/drivers/gpu/drm/mach64.orig/mach64_dma.c 2012-12-06 19:50:10.000000000 +0200 ++++ linux-3.7-rc8/drivers/gpu/drm/mach64/mach64_dma.c 2012-12-06 20:19:10.590681644 +0200 +@@ -34,8 +34,8 @@ + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +-#include "drmP.h" +-#include "drm.h" ++#include ++#include + #include "mach64_drm.h" + #include "mach64_drv.h" + +diff -Nurp linux-3.7-rc8/drivers/gpu/drm/mach64.orig/mach64_drv.c linux-3.7-rc8/drivers/gpu/drm/mach64/mach64_drv.c +--- linux-3.7-rc8/drivers/gpu/drm/mach64.orig/mach64_drv.c 2012-12-06 19:50:10.000000000 +0200 ++++ linux-3.7-rc8/drivers/gpu/drm/mach64/mach64_drv.c 2012-12-06 20:20:13.062073838 +0200 +@@ -28,12 +28,12 @@ + */ + + #include +-#include "drmP.h" +-#include "drm.h" ++#include ++#include + #include "mach64_drm.h" + #include "mach64_drv.h" + +-#include "drm_pciids.h" ++#include + + static struct pci_device_id pciidlist[] = { + mach64_PCI_IDS +diff -Nurp linux-3.7-rc8/drivers/gpu/drm/mach64.orig/mach64_irq.c linux-3.7-rc8/drivers/gpu/drm/mach64/mach64_irq.c +--- linux-3.7-rc8/drivers/gpu/drm/mach64.orig/mach64_irq.c 2012-12-06 19:50:10.000000000 +0200 ++++ linux-3.7-rc8/drivers/gpu/drm/mach64/mach64_irq.c 2012-12-06 20:20:40.192678476 +0200 +@@ -35,8 +35,8 @@ + * Leif Delgass + */ + +-#include "drmP.h" +-#include "drm.h" ++#include ++#include + #include "mach64_drm.h" + #include "mach64_drv.h" + +diff -Nurp linux-3.7-rc8/drivers/gpu/drm/mach64.orig/mach64_state.c linux-3.7-rc8/drivers/gpu/drm/mach64/mach64_state.c +--- linux-3.7-rc8/drivers/gpu/drm/mach64.orig/mach64_state.c 2012-12-06 19:50:10.000000000 +0200 ++++ linux-3.7-rc8/drivers/gpu/drm/mach64/mach64_state.c 2012-12-06 20:21:00.783137370 +0200 +@@ -30,8 +30,8 @@ + * José Fonseca + */ + +-#include "drmP.h" +-#include "drm.h" ++#include ++#include + #include "mach64_drm.h" + #include "mach64_drv.h" + diff --git a/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-fix-for-changed-drm_ioctl.patch b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-fix-for-changed-drm_ioctl.patch new file mode 100644 index 0000000000..951eabb925 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-fix-for-changed-drm_ioctl.patch @@ -0,0 +1,20 @@ +Update mach64 for changes in drm_ioctl done in 2.6.33: +"drm: convert drm_ioctl to unlocked_ioctl" (commit ed8b670) + +Signed-off-by: Herton Ronaldo Krzesinski +--- + drivers/gpu/drm/mach64/mach64_drv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff -p -up linux-2.6.33/drivers/gpu/drm/mach64/mach64_drv.c.orig linux-2.6.33/drivers/gpu/drm/mach64/mach64_drv.c +--- linux-2.6.33/drivers/gpu/drm/mach64/mach64_drv.c.orig 2010-03-16 19:27:22.517068880 -0300 ++++ linux-2.6.33/drivers/gpu/drm/mach64/mach64_drv.c 2010-03-16 19:27:54.890318416 -0300 +@@ -59,7 +59,7 @@ static struct drm_driver driver = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, +- .ioctl = drm_ioctl, ++ .unlocked_ioctl = drm_ioctl, + .mmap = drm_mmap, + .poll = drm_poll, + .fasync = drm_fasync, diff --git a/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-fix-for-changed-drm_pci_alloc.patch b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-fix-for-changed-drm_pci_alloc.patch new file mode 100644 index 0000000000..b67cecab09 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-fix-for-changed-drm_pci_alloc.patch @@ -0,0 +1,12 @@ +diff -p -up linux-2.6.32/drivers/gpu/drm/mach64/mach64_dma.c.orig linux-2.6.32/drivers/gpu/drm/mach64/mach64_dma.c +--- linux-2.6.32/drivers/gpu/drm/mach64/mach64_dma.c.orig 2010-01-06 11:35:13.784843304 -0200 ++++ linux-2.6.32/drivers/gpu/drm/mach64/mach64_dma.c 2010-01-06 11:37:50.793843502 -0200 +@@ -835,7 +835,7 @@ static int mach64_bm_dma_test(struct drm + /* FIXME: get a dma buffer from the freelist here */ + DRM_DEBUG("Allocating data memory ...\n"); + cpu_addr_dmah = +- drm_pci_alloc(dev, 0x1000, 0x1000, 0xfffffffful); ++ drm_pci_alloc(dev, 0x1000, 0x1000); + if (!cpu_addr_dmah) { + DRM_INFO("data-memory allocation failed!\n"); + return -ENOMEM; diff --git a/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-fixes.patch b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-fixes.patch new file mode 100644 index 0000000000..0ea07cd720 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-fixes.patch @@ -0,0 +1,97 @@ +Fix/cleanup mach64 drm module for building with current kernel. + +Signed-off-by: Herton Ronaldo Krzesinski + +--- + drivers/gpu/drm/mach64/mach64_dma.c | 9 +-------- + drivers/gpu/drm/mach64/mach64_drv.c | 11 +---------- + drivers/gpu/drm/mach64/mach64_state.c | 4 ++-- + 3 files changed, 4 insertions(+), 20 deletions(-) + +diff -p -up linux-2.6.28/drivers/gpu/drm/mach64/mach64_dma.c.orig linux-2.6.28/drivers/gpu/drm/mach64/mach64_dma.c +--- linux-2.6.28/drivers/gpu/drm/mach64/mach64_dma.c.orig 2008-12-10 12:19:14.000000000 -0500 ++++ linux-2.6.28/drivers/gpu/drm/mach64/mach64_dma.c 2008-12-10 13:34:19.000000000 -0500 +@@ -834,14 +834,8 @@ static int mach64_bm_dma_test(struct drm + + /* FIXME: get a dma buffer from the freelist here */ + DRM_DEBUG("Allocating data memory ...\n"); +-#ifdef __FreeBSD__ +- DRM_UNLOCK(); +-#endif + cpu_addr_dmah = + drm_pci_alloc(dev, 0x1000, 0x1000, 0xfffffffful); +-#ifdef __FreeBSD__ +- DRM_LOCK(); +-#endif + if (!cpu_addr_dmah) { + DRM_INFO("data-memory allocation failed!\n"); + return -ENOMEM; +@@ -1375,8 +1369,7 @@ int mach64_do_cleanup_dma(struct drm_dev + * may not have been called from userspace and after dev_private + * is freed, it's too late. + */ +- if (dev->irq) +- drm_irq_uninstall(dev); ++ drm_irq_uninstall(dev); + + if (dev->dev_private) { + drm_mach64_private_t *dev_priv = dev->dev_private; +diff -p -up linux-2.6.28/drivers/gpu/drm/mach64/mach64_drv.c.orig linux-2.6.28/drivers/gpu/drm/mach64/mach64_drv.c +--- linux-2.6.28/drivers/gpu/drm/mach64/mach64_drv.c.orig 2008-12-10 12:13:13.000000000 -0500 ++++ linux-2.6.28/drivers/gpu/drm/mach64/mach64_drv.c 2008-12-10 12:16:54.000000000 -0500 +@@ -38,7 +38,6 @@ static struct pci_device_id pciidlist[] + mach64_PCI_IDS + }; + +-static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); + static struct drm_driver driver = { + .driver_features = + DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_HAVE_DMA +@@ -68,8 +67,6 @@ static struct drm_driver driver = { + .pci_driver = { + .name = DRIVER_NAME, + .id_table = pciidlist, +- .probe = probe, +- .remove = __devexit_p(drm_cleanup_pci), + }, + + .name = DRIVER_NAME, +@@ -80,16 +77,10 @@ static struct drm_driver driver = { + .patchlevel = DRIVER_PATCHLEVEL, + }; + +-static int probe(struct pci_dev *pdev, const struct pci_device_id *ent) +-{ +- return drm_get_dev(pdev, ent, &driver); +-} +- +- + static int __init mach64_init(void) + { + driver.num_ioctls = mach64_max_ioctl; +- return drm_init(&driver, pciidlist); ++ return drm_init(&driver); + } + + static void __exit mach64_exit(void) +diff -p -up linux-2.6.28/drivers/gpu/drm/mach64/mach64_state.c.orig linux-2.6.28/drivers/gpu/drm/mach64/mach64_state.c +--- linux-2.6.28/drivers/gpu/drm/mach64/mach64_state.c.orig 2008-12-10 12:13:13.000000000 -0500 ++++ linux-2.6.28/drivers/gpu/drm/mach64/mach64_state.c 2008-12-10 13:38:54.000000000 -0500 +@@ -455,7 +455,7 @@ static int mach64_do_get_frames_queued(d + head = ring->head; + + start = (MACH64_MAX_QUEUED_FRAMES - +- DRM_MIN(MACH64_MAX_QUEUED_FRAMES, sarea_priv->frames_queued)); ++ min(MACH64_MAX_QUEUED_FRAMES, sarea_priv->frames_queued)); + + if (head == tail) { + sarea_priv->frames_queued = 0; +@@ -895,7 +895,7 @@ int mach64_get_param(struct drm_device * + value = mach64_do_get_frames_queued(dev_priv); + break; + case MACH64_PARAM_IRQ_NR: +- value = dev->irq; ++ value = drm_dev_to_irq(dev); + break; + default: + return -EINVAL; diff --git a/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-include-module.h.patch b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-include-module.h.patch new file mode 100644 index 0000000000..9c1163d5c1 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-include-module.h.patch @@ -0,0 +1,10 @@ +--- linux/drivers/gpu/drm/mach64/mach64_drv.c.orig 2011-12-25 00:48:42.814932355 +0200 ++++ linux/drivers/gpu/drm/mach64/mach64_drv.c 2011-12-25 00:47:43.393625260 +0200 +@@ -27,6 +27,7 @@ + * Leif Delgass + */ + ++#include + #include "drmP.h" + #include "drm.h" + #include "mach64_drm.h" diff --git a/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-linux-3.14-buildfix.patch b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-linux-3.14-buildfix.patch new file mode 100644 index 0000000000..80010d3a01 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-linux-3.14-buildfix.patch @@ -0,0 +1,102 @@ + +Fix build with kernel-3.14 + +Signed-off-by: Thomas Backlund + + drivers/gpu/drm/mach64/mach64_dma.c | 10 +++++----- + drivers/gpu/drm/mach64/mach64_drv.h | 2 +- + drivers/gpu/drm/mach64/mach64_irq.c | 2 +- + drivers/gpu/drm/mach64/mach64_state.c | 6 +++--- + 4 files changed, 10 insertions(+), 10 deletions(-) + +diff -urp linux/drivers/gpu/drm/mach64.orig/mach64_dma.c linux/drivers/gpu/drm/mach64/mach64_dma.c +--- linux/drivers/gpu/drm/mach64.orig/mach64_dma.c 2014-04-26 19:10:55.000000000 +0300 ++++ linux/drivers/gpu/drm/mach64/mach64_dma.c 2014-04-26 20:26:05.263501325 +0300 +@@ -696,9 +696,9 @@ do { \ + DRM_INFO( "ADVANCE_RING() wr=0x%06x tail=0x%06x\n", \ + _ring_write, _ring_tail ); \ + } \ +- DRM_MEMORYBARRIER(); \ ++ mb(); \ + mach64_clear_dma_eol( &_ring[(_ring_tail - 2) & _ring_mask] ); \ +- DRM_MEMORYBARRIER(); \ ++ mb(); \ + dev_priv->ring.tail = _ring_write; \ + mach64_ring_tick( dev_priv, &(dev_priv)->ring ); \ + } while (0) +@@ -912,7 +912,7 @@ static int mach64_bm_dma_test(struct drm + DRM_DEBUG(" data[%d] = 0x%08x\n", i, data[i]); + } + +- DRM_MEMORYBARRIER(); ++ mb(); + + DRM_DEBUG("waiting for idle...\n"); + if ((i = mach64_do_wait_for_idle(dev_priv))) { +@@ -1716,10 +1716,10 @@ static int mach64_dma_get_buffers(struct + + buf->file_priv = file_priv; + +- if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx, ++ if (copy_to_user(&d->request_indices[i], &buf->idx, + sizeof(buf->idx))) + return -EFAULT; +- if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total, ++ if (copy_to_user(&d->request_sizes[i], &buf->total, + sizeof(buf->total))) + return -EFAULT; + +diff -urp linux/drivers/gpu/drm/mach64.orig/mach64_drv.h linux/drivers/gpu/drm/mach64/mach64_drv.h +--- linux/drivers/gpu/drm/mach64.orig/mach64_drv.h 2014-04-26 19:10:55.000000000 +0300 ++++ linux/drivers/gpu/drm/mach64/mach64_drv.h 2014-04-26 20:28:43.693457652 +0300 +@@ -166,7 +166,7 @@ extern int mach64_get_param(struct drm_d + extern u32 mach64_get_vblank_counter(struct drm_device *dev, int crtc); + extern int mach64_enable_vblank(struct drm_device *dev, int crtc); + extern void mach64_disable_vblank(struct drm_device *dev, int crtc); +-extern irqreturn_t mach64_driver_irq_handler(DRM_IRQ_ARGS); ++extern irqreturn_t mach64_driver_irq_handler(int irq, void *arg); + extern void mach64_driver_irq_preinstall(struct drm_device *dev); + extern int mach64_driver_irq_postinstall(struct drm_device *dev); + extern void mach64_driver_irq_uninstall(struct drm_device *dev); +diff -urp linux/drivers/gpu/drm/mach64.orig/mach64_irq.c linux/drivers/gpu/drm/mach64/mach64_irq.c +--- linux/drivers/gpu/drm/mach64.orig/mach64_irq.c 2014-04-26 19:10:55.000000000 +0300 ++++ linux/drivers/gpu/drm/mach64/mach64_irq.c 2014-04-26 20:32:01.464898140 +0300 +@@ -40,7 +40,7 @@ + #include "mach64_drm.h" + #include "mach64_drv.h" + +-irqreturn_t mach64_driver_irq_handler(DRM_IRQ_ARGS) ++irqreturn_t mach64_driver_irq_handler(int irq, void *arg) + { + struct drm_device *dev = arg; + drm_mach64_private_t *dev_priv = dev->dev_private; +diff -urp linux/drivers/gpu/drm/mach64.orig/mach64_state.c linux/drivers/gpu/drm/mach64/mach64_state.c +--- linux/drivers/gpu/drm/mach64.orig/mach64_state.c 2014-04-26 19:10:55.000000000 +0300 ++++ linux/drivers/gpu/drm/mach64/mach64_state.c 2014-04-26 20:07:16.701527488 +0300 +@@ -494,7 +494,7 @@ static __inline__ int copy_from_user_ver + if (from == NULL) + return -ENOMEM; + +- if (DRM_COPY_FROM_USER(from, ufrom, bytes)) { ++ if (copy_from_user(from, ufrom, bytes)) { + kfree(from); + return -EFAULT; + } +@@ -640,7 +640,7 @@ static __inline__ int copy_from_user_bli + { + to = (u32 *)((char *)to + MACH64_HOSTDATA_BLIT_OFFSET); + +- if (DRM_COPY_FROM_USER(to, ufrom, bytes)) { ++ if (copy_from_user(to, ufrom, bytes)) { + return -EFAULT; + } + +@@ -901,7 +901,7 @@ int mach64_get_param(struct drm_device * + return -EINVAL; + } + +- if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) { ++ if (copy_to_user(param->value, &value, sizeof(int))) { + DRM_ERROR("copy_to_user\n"); + return -EFAULT; + } diff --git a/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-restore-mach64_PCI_IDS.patch b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-restore-mach64_PCI_IDS.patch new file mode 100644 index 0000000000..651d763195 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64-restore-mach64_PCI_IDS.patch @@ -0,0 +1,38 @@ +Theese got dropped in 3.12-rc + +Restore for now to get the mach64 driver to build + +TODO: Need to check mesa & drm if it's dropped there too... + +--- linux/include/drm/drm_pciids.h.orig 2013-10-13 11:05:33.000000000 +0300 ++++ linux/include/drm/drm_pciids.h 2013-10-13 14:30:43.625995248 +0300 +@@ -711,6 +711,29 @@ + {0x102b, 0x2527, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G550}, \ + {0, 0, 0} + ++#define mach64_PCI_IDS \ ++ {0x1002, 0x4749, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4742, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4744, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x474c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x474f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4752, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4753, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x474d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x474e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0, 0, 0} ++ + #define sisdrv_PCI_IDS \ + {0x1039, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1039, 0x5300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ diff --git a/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64.patch b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64.patch new file mode 100644 index 0000000000..9ab07df913 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/gpu-drm-mach64.patch @@ -0,0 +1,4144 @@ +mach64 driver from git://anongit.freedesktop.org/git/mesa/drm +head: c99566fb810c9d8cae5e9cd39d1772b55e2f514c + +--- + drivers/gpu/drm/Kconfig | 11 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/mach64/Makefile | 8 + drivers/gpu/drm/Kconfig | 11 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/mach64/Makefile | 8 + drivers/gpu/drm/mach64/mach64_dma.c | 1778 ++++++++++++++++++++++++++++++++++ + drivers/gpu/drm/mach64/mach64_drm.h | 256 ++++ + drivers/gpu/drm/mach64/mach64_drv.c | 105 ++ + drivers/gpu/drm/mach64/mach64_drv.h | 859 ++++++++++++++++ + drivers/gpu/drm/mach64/mach64_irq.c | 159 +++ + drivers/gpu/drm/mach64/mach64_state.c | 910 +++++++++++++++++ + 9 files changed, 4087 insertions(+) + +--- /dev/null ++++ b/drivers/gpu/drm/mach64/Makefile +@@ -0,0 +1,8 @@ ++# ++# Makefile for the drm device driver. This driver provides support for the ++# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. ++ ++ccflags-y = -Iinclude/drm ++mach64-y := mach64_drv.o mach64_dma.o mach64_irq.o mach64_state.o ++ ++obj-$(CONFIG_DRM_MACH64) += mach64.o +--- /dev/null ++++ b/drivers/gpu/drm/mach64/mach64_dma.c +@@ -0,0 +1,1778 @@ ++/* mach64_dma.c -- DMA support for mach64 (Rage Pro) driver -*- linux-c -*- */ ++/** ++ * \file mach64_dma.c ++ * DMA support for mach64 (Rage Pro) driver ++ * ++ * \author Gareth Hughes ++ * \author Frank C. Earl ++ * \author Leif Delgass ++ * \author José Fonseca ++ */ ++ ++/* ++ * Copyright 2000 Gareth Hughes ++ * Copyright 2002 Frank C. Earl ++ * Copyright 2002-2003 Leif Delgass ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT OWNER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER ++ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++#include "drmP.h" ++#include "drm.h" ++#include "mach64_drm.h" ++#include "mach64_drv.h" ++ ++/*******************************************************************/ ++/** \name Engine, FIFO control */ ++/*@{*/ ++ ++/** ++ * Waits for free entries in the FIFO. ++ * ++ * \note Most writes to Mach64 registers are automatically routed through ++ * command FIFO which is 16 entry deep. Prior to writing to any draw engine ++ * register one has to ensure that enough FIFO entries are available by calling ++ * this function. Failure to do so may cause the engine to lock. ++ * ++ * \param dev_priv pointer to device private data structure. ++ * \param entries number of free entries in the FIFO to wait for. ++ * ++ * \returns zero on success, or -EBUSY if the timeout (specificed by ++ * drm_mach64_private::usec_timeout) occurs. ++ */ ++int mach64_do_wait_for_fifo(drm_mach64_private_t *dev_priv, int entries) ++{ ++ int slots = 0, i; ++ ++ for (i = 0; i < dev_priv->usec_timeout; i++) { ++ slots = (MACH64_READ(MACH64_FIFO_STAT) & MACH64_FIFO_SLOT_MASK); ++ if (slots <= (0x8000 >> entries)) ++ return 0; ++ DRM_UDELAY(1); ++ } ++ ++ DRM_INFO("failed! slots=%d entries=%d\n", slots, entries); ++ return -EBUSY; ++} ++ ++/** ++ * Wait for the draw engine to be idle. ++ */ ++int mach64_do_wait_for_idle(drm_mach64_private_t *dev_priv) ++{ ++ int i, ret; ++ ++ ret = mach64_do_wait_for_fifo(dev_priv, 16); ++ if (ret < 0) ++ return ret; ++ ++ for (i = 0; i < dev_priv->usec_timeout; i++) { ++ if (!(MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE)) ++ return 0; ++ DRM_UDELAY(1); ++ } ++ ++ DRM_INFO("failed! GUI_STAT=0x%08x\n", MACH64_READ(MACH64_GUI_STAT)); ++ mach64_dump_ring_info(dev_priv); ++ return -EBUSY; ++} ++ ++/** ++ * Wait for free entries in the ring buffer. ++ * ++ * The Mach64 bus master can be configured to act as a virtual FIFO, using a ++ * circular buffer (commonly referred as "ring buffer" in other drivers) with ++ * pointers to engine commands. This allows the CPU to do other things while ++ * the graphics engine is busy, i.e., DMA mode. ++ * ++ * This function should be called before writing new entries to the ring ++ * buffer. ++ * ++ * \param dev_priv pointer to device private data structure. ++ * \param n number of free entries in the ring buffer to wait for. ++ * ++ * \returns zero on success, or -EBUSY if the timeout (specificed by ++ * drm_mach64_private_t::usec_timeout) occurs. ++ * ++ * \sa mach64_dump_ring_info() ++ */ ++int mach64_wait_ring(drm_mach64_private_t *dev_priv, int n) ++{ ++ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; ++ int i; ++ ++ for (i = 0; i < dev_priv->usec_timeout; i++) { ++ mach64_update_ring_snapshot(dev_priv); ++ if (ring->space >= n) { ++ if (i > 0) ++ DRM_DEBUG("%d usecs\n", i); ++ return 0; ++ } ++ DRM_UDELAY(1); ++ } ++ ++ /* FIXME: This is being ignored... */ ++ DRM_ERROR("failed!\n"); ++ mach64_dump_ring_info(dev_priv); ++ return -EBUSY; ++} ++ ++/** ++ * Wait until all DMA requests have been processed... ++ * ++ * \sa mach64_wait_ring() ++ */ ++static int mach64_ring_idle(drm_mach64_private_t *dev_priv) ++{ ++ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; ++ u32 head; ++ int i; ++ ++ head = ring->head; ++ i = 0; ++ while (i < dev_priv->usec_timeout) { ++ mach64_update_ring_snapshot(dev_priv); ++ if (ring->head == ring->tail && ++ !(MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE)) { ++ if (i > 0) ++ DRM_DEBUG("%d usecs\n", i); ++ return 0; ++ } ++ if (ring->head == head) { ++ ++i; ++ } else { ++ head = ring->head; ++ i = 0; ++ } ++ DRM_UDELAY(1); ++ } ++ ++ DRM_INFO("failed! GUI_STAT=0x%08x\n", MACH64_READ(MACH64_GUI_STAT)); ++ mach64_dump_ring_info(dev_priv); ++ return -EBUSY; ++} ++ ++/** ++ * Reset the the ring buffer descriptors. ++ * ++ * \sa mach64_do_engine_reset() ++ */ ++static void mach64_ring_reset(drm_mach64_private_t *dev_priv) ++{ ++ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; ++ ++ mach64_do_release_used_buffers(dev_priv); ++ ring->head_addr = ring->start_addr; ++ ring->head = ring->tail = 0; ++ ring->space = ring->size; ++ ++ MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD, ++ ring->head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB); ++ ++ dev_priv->ring_running = 0; ++} ++ ++/** ++ * Ensure the all the queued commands will be processed. ++ */ ++int mach64_do_dma_flush(drm_mach64_private_t *dev_priv) ++{ ++ /* FIXME: It's not necessary to wait for idle when flushing ++ * we just need to ensure the ring will be completely processed ++ * in finite time without another ioctl ++ */ ++ return mach64_ring_idle(dev_priv); ++} ++ ++/** ++ * Stop all DMA activity. ++ */ ++int mach64_do_dma_idle(drm_mach64_private_t *dev_priv) ++{ ++ int ret; ++ ++ /* wait for completion */ ++ if ((ret = mach64_ring_idle(dev_priv)) < 0) { ++ DRM_ERROR("failed BM_GUI_TABLE=0x%08x tail: %u\n", ++ MACH64_READ(MACH64_BM_GUI_TABLE), ++ dev_priv->ring.tail); ++ return ret; ++ } ++ ++ mach64_ring_stop(dev_priv); ++ ++ /* clean up after pass */ ++ mach64_do_release_used_buffers(dev_priv); ++ return 0; ++} ++ ++/** ++ * Reset the engine. This will stop the DMA if it is running. ++ */ ++int mach64_do_engine_reset(drm_mach64_private_t *dev_priv) ++{ ++ u32 tmp; ++ ++ DRM_DEBUG("\n"); ++ ++ /* Kill off any outstanding DMA transfers. ++ */ ++ tmp = MACH64_READ(MACH64_BUS_CNTL); ++ MACH64_WRITE(MACH64_BUS_CNTL, tmp | MACH64_BUS_MASTER_DIS); ++ ++ /* Reset the GUI engine (high to low transition). ++ */ ++ tmp = MACH64_READ(MACH64_GEN_TEST_CNTL); ++ MACH64_WRITE(MACH64_GEN_TEST_CNTL, tmp & ~MACH64_GUI_ENGINE_ENABLE); ++ /* Enable the GUI engine ++ */ ++ tmp = MACH64_READ(MACH64_GEN_TEST_CNTL); ++ MACH64_WRITE(MACH64_GEN_TEST_CNTL, tmp | MACH64_GUI_ENGINE_ENABLE); ++ ++ /* ensure engine is not locked up by clearing any FIFO or HOST errors ++ */ ++ tmp = MACH64_READ(MACH64_BUS_CNTL); ++ MACH64_WRITE(MACH64_BUS_CNTL, tmp | 0x00a00000); ++ ++ /* Once GUI engine is restored, disable bus mastering */ ++ MACH64_WRITE(MACH64_SRC_CNTL, 0); ++ ++ /* Reset descriptor ring */ ++ mach64_ring_reset(dev_priv); ++ ++ return 0; ++} ++ ++/*@}*/ ++ ++ ++/*******************************************************************/ ++/** \name Debugging output */ ++/*@{*/ ++ ++/** ++ * Dump engine registers values. ++ */ ++void mach64_dump_engine_info(drm_mach64_private_t *dev_priv) ++{ ++ DRM_INFO("\n"); ++ if (!dev_priv->is_pci) { ++ DRM_INFO(" AGP_BASE = 0x%08x\n", ++ MACH64_READ(MACH64_AGP_BASE)); ++ DRM_INFO(" AGP_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_AGP_CNTL)); ++ } ++ DRM_INFO(" ALPHA_TST_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_ALPHA_TST_CNTL)); ++ DRM_INFO("\n"); ++ DRM_INFO(" BM_COMMAND = 0x%08x\n", ++ MACH64_READ(MACH64_BM_COMMAND)); ++ DRM_INFO("BM_FRAME_BUF_OFFSET = 0x%08x\n", ++ MACH64_READ(MACH64_BM_FRAME_BUF_OFFSET)); ++ DRM_INFO(" BM_GUI_TABLE = 0x%08x\n", ++ MACH64_READ(MACH64_BM_GUI_TABLE)); ++ DRM_INFO(" BM_STATUS = 0x%08x\n", ++ MACH64_READ(MACH64_BM_STATUS)); ++ DRM_INFO(" BM_SYSTEM_MEM_ADDR = 0x%08x\n", ++ MACH64_READ(MACH64_BM_SYSTEM_MEM_ADDR)); ++ DRM_INFO(" BM_SYSTEM_TABLE = 0x%08x\n", ++ MACH64_READ(MACH64_BM_SYSTEM_TABLE)); ++ DRM_INFO(" BUS_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_BUS_CNTL)); ++ DRM_INFO("\n"); ++ /* DRM_INFO( " CLOCK_CNTL = 0x%08x\n", MACH64_READ( MACH64_CLOCK_CNTL ) ); */ ++ DRM_INFO(" CLR_CMP_CLR = 0x%08x\n", ++ MACH64_READ(MACH64_CLR_CMP_CLR)); ++ DRM_INFO(" CLR_CMP_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_CLR_CMP_CNTL)); ++ /* DRM_INFO( " CLR_CMP_MSK = 0x%08x\n", MACH64_READ( MACH64_CLR_CMP_MSK ) ); */ ++ DRM_INFO(" CONFIG_CHIP_ID = 0x%08x\n", ++ MACH64_READ(MACH64_CONFIG_CHIP_ID)); ++ DRM_INFO(" CONFIG_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_CONFIG_CNTL)); ++ DRM_INFO(" CONFIG_STAT0 = 0x%08x\n", ++ MACH64_READ(MACH64_CONFIG_STAT0)); ++ DRM_INFO(" CONFIG_STAT1 = 0x%08x\n", ++ MACH64_READ(MACH64_CONFIG_STAT1)); ++ DRM_INFO(" CONFIG_STAT2 = 0x%08x\n", ++ MACH64_READ(MACH64_CONFIG_STAT2)); ++ DRM_INFO(" CRC_SIG = 0x%08x\n", MACH64_READ(MACH64_CRC_SIG)); ++ DRM_INFO(" CUSTOM_MACRO_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_CUSTOM_MACRO_CNTL)); ++ DRM_INFO("\n"); ++ /* DRM_INFO( " DAC_CNTL = 0x%08x\n", MACH64_READ( MACH64_DAC_CNTL ) ); */ ++ /* DRM_INFO( " DAC_REGS = 0x%08x\n", MACH64_READ( MACH64_DAC_REGS ) ); */ ++ DRM_INFO(" DP_BKGD_CLR = 0x%08x\n", ++ MACH64_READ(MACH64_DP_BKGD_CLR)); ++ DRM_INFO(" DP_FRGD_CLR = 0x%08x\n", ++ MACH64_READ(MACH64_DP_FRGD_CLR)); ++ DRM_INFO(" DP_MIX = 0x%08x\n", MACH64_READ(MACH64_DP_MIX)); ++ DRM_INFO(" DP_PIX_WIDTH = 0x%08x\n", ++ MACH64_READ(MACH64_DP_PIX_WIDTH)); ++ DRM_INFO(" DP_SRC = 0x%08x\n", MACH64_READ(MACH64_DP_SRC)); ++ DRM_INFO(" DP_WRITE_MASK = 0x%08x\n", ++ MACH64_READ(MACH64_DP_WRITE_MASK)); ++ DRM_INFO(" DSP_CONFIG = 0x%08x\n", ++ MACH64_READ(MACH64_DSP_CONFIG)); ++ DRM_INFO(" DSP_ON_OFF = 0x%08x\n", ++ MACH64_READ(MACH64_DSP_ON_OFF)); ++ DRM_INFO(" DST_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_DST_CNTL)); ++ DRM_INFO(" DST_OFF_PITCH = 0x%08x\n", ++ MACH64_READ(MACH64_DST_OFF_PITCH)); ++ DRM_INFO("\n"); ++ /* DRM_INFO( " EXT_DAC_REGS = 0x%08x\n", MACH64_READ( MACH64_EXT_DAC_REGS ) ); */ ++ DRM_INFO(" EXT_MEM_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_EXT_MEM_CNTL)); ++ DRM_INFO("\n"); ++ DRM_INFO(" FIFO_STAT = 0x%08x\n", ++ MACH64_READ(MACH64_FIFO_STAT)); ++ DRM_INFO("\n"); ++ DRM_INFO(" GEN_TEST_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_GEN_TEST_CNTL)); ++ /* DRM_INFO( " GP_IO = 0x%08x\n", MACH64_READ( MACH64_GP_IO ) ); */ ++ DRM_INFO(" GUI_CMDFIFO_DATA = 0x%08x\n", ++ MACH64_READ(MACH64_GUI_CMDFIFO_DATA)); ++ DRM_INFO(" GUI_CMDFIFO_DEBUG = 0x%08x\n", ++ MACH64_READ(MACH64_GUI_CMDFIFO_DEBUG)); ++ DRM_INFO(" GUI_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_GUI_CNTL)); ++ DRM_INFO(" GUI_STAT = 0x%08x\n", ++ MACH64_READ(MACH64_GUI_STAT)); ++ DRM_INFO(" GUI_TRAJ_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_GUI_TRAJ_CNTL)); ++ DRM_INFO("\n"); ++ DRM_INFO(" HOST_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_HOST_CNTL)); ++ DRM_INFO(" HW_DEBUG = 0x%08x\n", ++ MACH64_READ(MACH64_HW_DEBUG)); ++ DRM_INFO("\n"); ++ DRM_INFO(" MEM_ADDR_CONFIG = 0x%08x\n", ++ MACH64_READ(MACH64_MEM_ADDR_CONFIG)); ++ DRM_INFO(" MEM_BUF_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_MEM_BUF_CNTL)); ++ DRM_INFO("\n"); ++ DRM_INFO(" PAT_REG0 = 0x%08x\n", ++ MACH64_READ(MACH64_PAT_REG0)); ++ DRM_INFO(" PAT_REG1 = 0x%08x\n", ++ MACH64_READ(MACH64_PAT_REG1)); ++ DRM_INFO("\n"); ++ DRM_INFO(" SC_LEFT = 0x%08x\n", MACH64_READ(MACH64_SC_LEFT)); ++ DRM_INFO(" SC_RIGHT = 0x%08x\n", ++ MACH64_READ(MACH64_SC_RIGHT)); ++ DRM_INFO(" SC_TOP = 0x%08x\n", MACH64_READ(MACH64_SC_TOP)); ++ DRM_INFO(" SC_BOTTOM = 0x%08x\n", ++ MACH64_READ(MACH64_SC_BOTTOM)); ++ DRM_INFO("\n"); ++ DRM_INFO(" SCALE_3D_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_SCALE_3D_CNTL)); ++ DRM_INFO(" SCRATCH_REG0 = 0x%08x\n", ++ MACH64_READ(MACH64_SCRATCH_REG0)); ++ DRM_INFO(" SCRATCH_REG1 = 0x%08x\n", ++ MACH64_READ(MACH64_SCRATCH_REG1)); ++ DRM_INFO(" SETUP_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_SETUP_CNTL)); ++ DRM_INFO(" SRC_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_SRC_CNTL)); ++ DRM_INFO("\n"); ++ DRM_INFO(" TEX_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_TEX_CNTL)); ++ DRM_INFO(" TEX_SIZE_PITCH = 0x%08x\n", ++ MACH64_READ(MACH64_TEX_SIZE_PITCH)); ++ DRM_INFO(" TIMER_CONFIG = 0x%08x\n", ++ MACH64_READ(MACH64_TIMER_CONFIG)); ++ DRM_INFO("\n"); ++ DRM_INFO(" Z_CNTL = 0x%08x\n", MACH64_READ(MACH64_Z_CNTL)); ++ DRM_INFO(" Z_OFF_PITCH = 0x%08x\n", ++ MACH64_READ(MACH64_Z_OFF_PITCH)); ++ DRM_INFO("\n"); ++} ++ ++#define MACH64_DUMP_CONTEXT 3 ++ ++/** ++ * Used by mach64_dump_ring_info() to dump the contents of the current buffer ++ * pointed by the ring head. ++ */ ++static void mach64_dump_buf_info(drm_mach64_private_t *dev_priv, ++ struct drm_buf *buf) ++{ ++ u32 addr = GETBUFADDR(buf); ++ u32 used = buf->used >> 2; ++ u32 sys_addr = MACH64_READ(MACH64_BM_SYSTEM_MEM_ADDR); ++ u32 *p = GETBUFPTR(buf); ++ int skipped = 0; ++ ++ DRM_INFO("buffer contents:\n"); ++ ++ while (used) { ++ u32 reg, count; ++ ++ reg = le32_to_cpu(*p++); ++ if (addr <= GETBUFADDR(buf) + MACH64_DUMP_CONTEXT * 4 || ++ (addr >= sys_addr - MACH64_DUMP_CONTEXT * 4 && ++ addr <= sys_addr + MACH64_DUMP_CONTEXT * 4) || ++ addr >= ++ GETBUFADDR(buf) + buf->used - MACH64_DUMP_CONTEXT * 4) { ++ DRM_INFO("%08x: 0x%08x\n", addr, reg); ++ } ++ addr += 4; ++ used--; ++ ++ count = (reg >> 16) + 1; ++ reg = reg & 0xffff; ++ reg = MMSELECT(reg); ++ while (count && used) { ++ if (addr <= GETBUFADDR(buf) + MACH64_DUMP_CONTEXT * 4 || ++ (addr >= sys_addr - MACH64_DUMP_CONTEXT * 4 && ++ addr <= sys_addr + MACH64_DUMP_CONTEXT * 4) || ++ addr >= ++ GETBUFADDR(buf) + buf->used - ++ MACH64_DUMP_CONTEXT * 4) { ++ DRM_INFO("%08x: 0x%04x = 0x%08x\n", addr, ++ reg, le32_to_cpu(*p)); ++ skipped = 0; ++ } else { ++ if (!skipped) { ++ DRM_INFO(" ...\n"); ++ skipped = 1; ++ } ++ } ++ p++; ++ addr += 4; ++ used--; ++ ++ reg += 4; ++ count--; ++ } ++ } ++ ++ DRM_INFO("\n"); ++} ++ ++/** ++ * Dump the ring state and contents, including the contents of the buffer being ++ * processed by the graphics engine. ++ */ ++void mach64_dump_ring_info(drm_mach64_private_t *dev_priv) ++{ ++ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; ++ int i, skipped; ++ ++ DRM_INFO("\n"); ++ ++ DRM_INFO("ring contents:\n"); ++ DRM_INFO(" head_addr: 0x%08x head: %u tail: %u\n\n", ++ ring->head_addr, ring->head, ring->tail); ++ ++ skipped = 0; ++ for (i = 0; i < ring->size / sizeof(u32); i += 4) { ++ if (i <= MACH64_DUMP_CONTEXT * 4 || ++ i >= ring->size / sizeof(u32) - MACH64_DUMP_CONTEXT * 4 || ++ (i >= ring->tail - MACH64_DUMP_CONTEXT * 4 && ++ i <= ring->tail + MACH64_DUMP_CONTEXT * 4) || ++ (i >= ring->head - MACH64_DUMP_CONTEXT * 4 && ++ i <= ring->head + MACH64_DUMP_CONTEXT * 4)) { ++ DRM_INFO(" 0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x%s%s\n", ++ (u32)(ring->start_addr + i * sizeof(u32)), ++ le32_to_cpu(((u32 *) ring->start)[i + 0]), ++ le32_to_cpu(((u32 *) ring->start)[i + 1]), ++ le32_to_cpu(((u32 *) ring->start)[i + 2]), ++ le32_to_cpu(((u32 *) ring->start)[i + 3]), ++ i == ring->head ? " (head)" : "", ++ i == ring->tail ? " (tail)" : ""); ++ skipped = 0; ++ } else { ++ if (!skipped) { ++ DRM_INFO(" ...\n"); ++ skipped = 1; ++ } ++ } ++ } ++ ++ DRM_INFO("\n"); ++ ++ if (ring->head >= 0 && ring->head < ring->size / sizeof(u32)) { ++ struct list_head *ptr; ++ u32 addr = le32_to_cpu(((u32 *) ring->start)[ring->head + 1]); ++ ++ list_for_each(ptr, &dev_priv->pending) { ++ drm_mach64_freelist_t *entry = ++ list_entry(ptr, drm_mach64_freelist_t, list); ++ struct drm_buf *buf = entry->buf; ++ ++ u32 buf_addr = GETBUFADDR(buf); ++ ++ if (buf_addr <= addr && addr < buf_addr + buf->used) ++ mach64_dump_buf_info(dev_priv, buf); ++ } ++ } ++ ++ DRM_INFO("\n"); ++ DRM_INFO(" BM_GUI_TABLE = 0x%08x\n", ++ MACH64_READ(MACH64_BM_GUI_TABLE)); ++ DRM_INFO("\n"); ++ DRM_INFO("BM_FRAME_BUF_OFFSET = 0x%08x\n", ++ MACH64_READ(MACH64_BM_FRAME_BUF_OFFSET)); ++ DRM_INFO(" BM_SYSTEM_MEM_ADDR = 0x%08x\n", ++ MACH64_READ(MACH64_BM_SYSTEM_MEM_ADDR)); ++ DRM_INFO(" BM_COMMAND = 0x%08x\n", ++ MACH64_READ(MACH64_BM_COMMAND)); ++ DRM_INFO("\n"); ++ DRM_INFO(" BM_STATUS = 0x%08x\n", ++ MACH64_READ(MACH64_BM_STATUS)); ++ DRM_INFO(" BUS_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_BUS_CNTL)); ++ DRM_INFO(" FIFO_STAT = 0x%08x\n", ++ MACH64_READ(MACH64_FIFO_STAT)); ++ DRM_INFO(" GUI_STAT = 0x%08x\n", ++ MACH64_READ(MACH64_GUI_STAT)); ++ DRM_INFO(" SRC_CNTL = 0x%08x\n", ++ MACH64_READ(MACH64_SRC_CNTL)); ++} ++ ++/*@}*/ ++ ++ ++/*******************************************************************/ ++/** \name DMA descriptor ring macros */ ++/*@{*/ ++ ++/** ++ * Add the end mark to the ring's new tail position. ++ * ++ * The bus master engine will keep processing the DMA buffers listed in the ring ++ * until it finds this mark, making it stop. ++ * ++ * \sa mach64_clear_dma_eol ++ */ ++static __inline__ void mach64_set_dma_eol(volatile u32 *addr) ++{ ++#if defined(__i386__) ++ int nr = 31; ++ ++ /* Taken from include/asm-i386/bitops.h linux header */ ++ __asm__ __volatile__("lock;" "btsl %1,%0":"=m"(*addr) ++ :"Ir"(nr)); ++#elif defined(__powerpc__) ++ u32 old; ++ u32 mask = cpu_to_le32(MACH64_DMA_EOL); ++ ++ /* Taken from the include/asm-ppc/bitops.h linux header */ ++ __asm__ __volatile__("\n\ ++1: lwarx %0,0,%3 \n\ ++ or %0,%0,%2 \n\ ++ stwcx. %0,0,%3 \n\ ++ bne- 1b":"=&r"(old), "=m"(*addr) ++ :"r"(mask), "r"(addr), "m"(*addr) ++ :"cc"); ++#elif defined(__alpha__) ++ u32 temp; ++ u32 mask = MACH64_DMA_EOL; ++ ++ /* Taken from the include/asm-alpha/bitops.h linux header */ ++ __asm__ __volatile__("1: ldl_l %0,%3\n" ++ " bis %0,%2,%0\n" ++ " stl_c %0,%1\n" ++ " beq %0,2f\n" ++ ".subsection 2\n" ++ "2: br 1b\n" ++ ".previous":"=&r"(temp), "=m"(*addr) ++ :"Ir"(mask), "m"(*addr)); ++#else ++ u32 mask = cpu_to_le32(MACH64_DMA_EOL); ++ ++ *addr |= mask; ++#endif ++} ++ ++/** ++ * Remove the end mark from the ring's old tail position. ++ * ++ * It should be called after calling mach64_set_dma_eol to mark the ring's new ++ * tail position. ++ * ++ * We update the end marks while the bus master engine is in operation. Since ++ * the bus master engine may potentially be reading from the same position ++ * that we write, we must change atomically to avoid having intermediary bad ++ * data. ++ */ ++static __inline__ void mach64_clear_dma_eol(volatile u32 *addr) ++{ ++#if defined(__i386__) ++ int nr = 31; ++ ++ /* Taken from include/asm-i386/bitops.h linux header */ ++ __asm__ __volatile__("lock;" "btrl %1,%0":"=m"(*addr) ++ :"Ir"(nr)); ++#elif defined(__powerpc__) ++ u32 old; ++ u32 mask = cpu_to_le32(MACH64_DMA_EOL); ++ ++ /* Taken from the include/asm-ppc/bitops.h linux header */ ++ __asm__ __volatile__("\n\ ++1: lwarx %0,0,%3 \n\ ++ andc %0,%0,%2 \n\ ++ stwcx. %0,0,%3 \n\ ++ bne- 1b":"=&r"(old), "=m"(*addr) ++ :"r"(mask), "r"(addr), "m"(*addr) ++ :"cc"); ++#elif defined(__alpha__) ++ u32 temp; ++ u32 mask = ~MACH64_DMA_EOL; ++ ++ /* Taken from the include/asm-alpha/bitops.h linux header */ ++ __asm__ __volatile__("1: ldl_l %0,%3\n" ++ " and %0,%2,%0\n" ++ " stl_c %0,%1\n" ++ " beq %0,2f\n" ++ ".subsection 2\n" ++ "2: br 1b\n" ++ ".previous":"=&r"(temp), "=m"(*addr) ++ :"Ir"(mask), "m"(*addr)); ++#else ++ u32 mask = cpu_to_le32(~MACH64_DMA_EOL); ++ ++ *addr &= mask; ++#endif ++} ++ ++#define RING_LOCALS \ ++ int _ring_tail, _ring_write; unsigned int _ring_mask; volatile u32 *_ring ++ ++#define RING_WRITE_OFS _ring_write ++ ++#define BEGIN_RING(n) \ ++ do { \ ++ if (MACH64_VERBOSE) { \ ++ DRM_INFO( "BEGIN_RING( %d ) \n", \ ++ (n) ); \ ++ } \ ++ if (dev_priv->ring.space <= (n) * sizeof(u32)) { \ ++ int ret; \ ++ if ((ret = mach64_wait_ring( dev_priv, (n) * sizeof(u32))) < 0 ) { \ ++ DRM_ERROR( "wait_ring failed, resetting engine\n"); \ ++ mach64_dump_engine_info( dev_priv ); \ ++ mach64_do_engine_reset( dev_priv ); \ ++ return ret; \ ++ } \ ++ } \ ++ dev_priv->ring.space -= (n) * sizeof(u32); \ ++ _ring = (u32 *) dev_priv->ring.start; \ ++ _ring_tail = _ring_write = dev_priv->ring.tail; \ ++ _ring_mask = dev_priv->ring.tail_mask; \ ++ } while (0) ++ ++#define OUT_RING( x ) \ ++do { \ ++ if (MACH64_VERBOSE) { \ ++ DRM_INFO( " OUT_RING( 0x%08x ) at 0x%x\n", \ ++ (unsigned int)(x), _ring_write ); \ ++ } \ ++ _ring[_ring_write++] = cpu_to_le32( x ); \ ++ _ring_write &= _ring_mask; \ ++} while (0) ++ ++#define ADVANCE_RING() \ ++do { \ ++ if (MACH64_VERBOSE) { \ ++ DRM_INFO( "ADVANCE_RING() wr=0x%06x tail=0x%06x\n", \ ++ _ring_write, _ring_tail ); \ ++ } \ ++ DRM_MEMORYBARRIER(); \ ++ mach64_clear_dma_eol( &_ring[(_ring_tail - 2) & _ring_mask] ); \ ++ DRM_MEMORYBARRIER(); \ ++ dev_priv->ring.tail = _ring_write; \ ++ mach64_ring_tick( dev_priv, &(dev_priv)->ring ); \ ++} while (0) ++ ++/** ++ * Queue a DMA buffer of registers writes into the ring buffer. ++ */ ++int mach64_add_buf_to_ring(drm_mach64_private_t *dev_priv, ++ drm_mach64_freelist_t *entry) ++{ ++ int bytes, pages, remainder; ++ u32 address, page; ++ int i; ++ struct drm_buf *buf = entry->buf; ++ RING_LOCALS; ++ ++ bytes = buf->used; ++ address = GETBUFADDR( buf ); ++ pages = (bytes + MACH64_DMA_CHUNKSIZE - 1) / MACH64_DMA_CHUNKSIZE; ++ ++ BEGIN_RING( pages * 4 ); ++ ++ for ( i = 0 ; i < pages-1 ; i++ ) { ++ page = address + i * MACH64_DMA_CHUNKSIZE; ++ OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_ADDR ); ++ OUT_RING( page ); ++ OUT_RING( MACH64_DMA_CHUNKSIZE | MACH64_DMA_HOLD_OFFSET ); ++ OUT_RING( 0 ); ++ } ++ ++ /* generate the final descriptor for any remaining commands in this buffer */ ++ page = address + i * MACH64_DMA_CHUNKSIZE; ++ remainder = bytes - i * MACH64_DMA_CHUNKSIZE; ++ ++ /* Save dword offset of last descriptor for this buffer. ++ * This is needed to check for completion of the buffer in freelist_get ++ */ ++ entry->ring_ofs = RING_WRITE_OFS; ++ ++ OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_ADDR ); ++ OUT_RING( page ); ++ OUT_RING( remainder | MACH64_DMA_HOLD_OFFSET | MACH64_DMA_EOL ); ++ OUT_RING( 0 ); ++ ++ ADVANCE_RING(); ++ ++ return 0; ++} ++ ++/** ++ * Queue DMA buffer controlling host data tranfers (e.g., blit). ++ * ++ * Almost identical to mach64_add_buf_to_ring. ++ */ ++int mach64_add_hostdata_buf_to_ring(drm_mach64_private_t *dev_priv, ++ drm_mach64_freelist_t *entry) ++{ ++ int bytes, pages, remainder; ++ u32 address, page; ++ int i; ++ struct drm_buf *buf = entry->buf; ++ RING_LOCALS; ++ ++ bytes = buf->used - MACH64_HOSTDATA_BLIT_OFFSET; ++ pages = (bytes + MACH64_DMA_CHUNKSIZE - 1) / MACH64_DMA_CHUNKSIZE; ++ address = GETBUFADDR( buf ); ++ ++ BEGIN_RING( 4 + pages * 4 ); ++ ++ OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_ADDR ); ++ OUT_RING( address ); ++ OUT_RING( MACH64_HOSTDATA_BLIT_OFFSET | MACH64_DMA_HOLD_OFFSET ); ++ OUT_RING( 0 ); ++ address += MACH64_HOSTDATA_BLIT_OFFSET; ++ ++ for ( i = 0 ; i < pages-1 ; i++ ) { ++ page = address + i * MACH64_DMA_CHUNKSIZE; ++ OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_HOSTDATA ); ++ OUT_RING( page ); ++ OUT_RING( MACH64_DMA_CHUNKSIZE | MACH64_DMA_HOLD_OFFSET ); ++ OUT_RING( 0 ); ++ } ++ ++ /* generate the final descriptor for any remaining commands in this buffer */ ++ page = address + i * MACH64_DMA_CHUNKSIZE; ++ remainder = bytes - i * MACH64_DMA_CHUNKSIZE; ++ ++ /* Save dword offset of last descriptor for this buffer. ++ * This is needed to check for completion of the buffer in freelist_get ++ */ ++ entry->ring_ofs = RING_WRITE_OFS; ++ ++ OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_HOSTDATA ); ++ OUT_RING( page ); ++ OUT_RING( remainder | MACH64_DMA_HOLD_OFFSET | MACH64_DMA_EOL ); ++ OUT_RING( 0 ); ++ ++ ADVANCE_RING(); ++ ++ return 0; ++} ++ ++/*@}*/ ++ ++ ++/*******************************************************************/ ++/** \name DMA test and initialization */ ++/*@{*/ ++ ++/** ++ * Perform a simple DMA operation using the pattern registers to test whether ++ * DMA works. ++ * ++ * \return zero if successful. ++ * ++ * \note This function was the testbed for many experiences regarding Mach64 ++ * DMA operation. It is left here since it so tricky to get DMA operating ++ * properly in some architectures and hardware. ++ */ ++static int mach64_bm_dma_test(struct drm_device * dev) ++{ ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ drm_dma_handle_t *cpu_addr_dmah; ++ u32 data_addr; ++ u32 *table, *data; ++ u32 expected[2]; ++ u32 src_cntl, pat_reg0, pat_reg1; ++ int i, count, failed; ++ ++ DRM_DEBUG("\n"); ++ ++ table = (u32 *) dev_priv->ring.start; ++ ++ /* FIXME: get a dma buffer from the freelist here */ ++ DRM_DEBUG("Allocating data memory ...\n"); ++#ifdef __FreeBSD__ ++ DRM_UNLOCK(); ++#endif ++ cpu_addr_dmah = ++ drm_pci_alloc(dev, 0x1000, 0x1000, 0xfffffffful); ++#ifdef __FreeBSD__ ++ DRM_LOCK(); ++#endif ++ if (!cpu_addr_dmah) { ++ DRM_INFO("data-memory allocation failed!\n"); ++ return -ENOMEM; ++ } else { ++ data = (u32 *) cpu_addr_dmah->vaddr; ++ data_addr = (u32) cpu_addr_dmah->busaddr; ++ } ++ ++ /* Save the X server's value for SRC_CNTL and restore it ++ * in case our test fails. This prevents the X server ++ * from disabling it's cache for this register ++ */ ++ src_cntl = MACH64_READ(MACH64_SRC_CNTL); ++ pat_reg0 = MACH64_READ(MACH64_PAT_REG0); ++ pat_reg1 = MACH64_READ(MACH64_PAT_REG1); ++ ++ mach64_do_wait_for_fifo(dev_priv, 3); ++ ++ MACH64_WRITE(MACH64_SRC_CNTL, 0); ++ MACH64_WRITE(MACH64_PAT_REG0, 0x11111111); ++ MACH64_WRITE(MACH64_PAT_REG1, 0x11111111); ++ ++ mach64_do_wait_for_idle(dev_priv); ++ ++ for (i = 0; i < 2; i++) { ++ u32 reg; ++ reg = MACH64_READ((MACH64_PAT_REG0 + i * 4)); ++ DRM_DEBUG("(Before DMA Transfer) reg %d = 0x%08x\n", i, reg); ++ if (reg != 0x11111111) { ++ DRM_INFO("Error initializing test registers\n"); ++ DRM_INFO("resetting engine ...\n"); ++ mach64_do_engine_reset(dev_priv); ++ DRM_INFO("freeing data buffer memory.\n"); ++ drm_pci_free(dev, cpu_addr_dmah); ++ return -EIO; ++ } ++ } ++ ++ /* fill up a buffer with sets of 2 consecutive writes starting with PAT_REG0 */ ++ count = 0; ++ ++ data[count++] = cpu_to_le32(DMAREG(MACH64_PAT_REG0) | (1 << 16)); ++ data[count++] = expected[0] = 0x22222222; ++ data[count++] = expected[1] = 0xaaaaaaaa; ++ ++ while (count < 1020) { ++ data[count++] = ++ cpu_to_le32(DMAREG(MACH64_PAT_REG0) | (1 << 16)); ++ data[count++] = 0x22222222; ++ data[count++] = 0xaaaaaaaa; ++ } ++ data[count++] = cpu_to_le32(DMAREG(MACH64_SRC_CNTL) | (0 << 16)); ++ data[count++] = 0; ++ ++ DRM_DEBUG("Preparing table ...\n"); ++ table[MACH64_DMA_FRAME_BUF_OFFSET] = cpu_to_le32(MACH64_BM_ADDR + ++ MACH64_APERTURE_OFFSET); ++ table[MACH64_DMA_SYS_MEM_ADDR] = cpu_to_le32(data_addr); ++ table[MACH64_DMA_COMMAND] = cpu_to_le32(count * sizeof(u32) ++ | MACH64_DMA_HOLD_OFFSET ++ | MACH64_DMA_EOL); ++ table[MACH64_DMA_RESERVED] = 0; ++ ++ DRM_DEBUG("table[0] = 0x%08x\n", table[0]); ++ DRM_DEBUG("table[1] = 0x%08x\n", table[1]); ++ DRM_DEBUG("table[2] = 0x%08x\n", table[2]); ++ DRM_DEBUG("table[3] = 0x%08x\n", table[3]); ++ ++ for (i = 0; i < 6; i++) { ++ DRM_DEBUG(" data[%d] = 0x%08x\n", i, data[i]); ++ } ++ DRM_DEBUG(" ...\n"); ++ for (i = count - 5; i < count; i++) { ++ DRM_DEBUG(" data[%d] = 0x%08x\n", i, data[i]); ++ } ++ ++ DRM_MEMORYBARRIER(); ++ ++ DRM_DEBUG("waiting for idle...\n"); ++ if ((i = mach64_do_wait_for_idle(dev_priv))) { ++ DRM_INFO("mach64_do_wait_for_idle failed (result=%d)\n", i); ++ DRM_INFO("resetting engine ...\n"); ++ mach64_do_engine_reset(dev_priv); ++ mach64_do_wait_for_fifo(dev_priv, 3); ++ MACH64_WRITE(MACH64_SRC_CNTL, src_cntl); ++ MACH64_WRITE(MACH64_PAT_REG0, pat_reg0); ++ MACH64_WRITE(MACH64_PAT_REG1, pat_reg1); ++ DRM_INFO("freeing data buffer memory.\n"); ++ drm_pci_free(dev, cpu_addr_dmah); ++ return i; ++ } ++ DRM_DEBUG("waiting for idle...done\n"); ++ ++ DRM_DEBUG("BUS_CNTL = 0x%08x\n", MACH64_READ(MACH64_BUS_CNTL)); ++ DRM_DEBUG("SRC_CNTL = 0x%08x\n", MACH64_READ(MACH64_SRC_CNTL)); ++ DRM_DEBUG("\n"); ++ DRM_DEBUG("data bus addr = 0x%08x\n", data_addr); ++ DRM_DEBUG("table bus addr = 0x%08x\n", dev_priv->ring.start_addr); ++ ++ DRM_DEBUG("starting DMA transfer...\n"); ++ MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD, ++ dev_priv->ring.start_addr | MACH64_CIRCULAR_BUF_SIZE_16KB); ++ ++ MACH64_WRITE(MACH64_SRC_CNTL, ++ MACH64_SRC_BM_ENABLE | MACH64_SRC_BM_SYNC | ++ MACH64_SRC_BM_OP_SYSTEM_TO_REG); ++ ++ /* Kick off the transfer */ ++ DRM_DEBUG("starting DMA transfer... done.\n"); ++ MACH64_WRITE(MACH64_DST_HEIGHT_WIDTH, 0); ++ ++ DRM_DEBUG("waiting for idle...\n"); ++ ++ if ((i = mach64_do_wait_for_idle(dev_priv))) { ++ /* engine locked up, dump register state and reset */ ++ DRM_INFO("mach64_do_wait_for_idle failed (result=%d)\n", i); ++ mach64_dump_engine_info(dev_priv); ++ DRM_INFO("resetting engine ...\n"); ++ mach64_do_engine_reset(dev_priv); ++ mach64_do_wait_for_fifo(dev_priv, 3); ++ MACH64_WRITE(MACH64_SRC_CNTL, src_cntl); ++ MACH64_WRITE(MACH64_PAT_REG0, pat_reg0); ++ MACH64_WRITE(MACH64_PAT_REG1, pat_reg1); ++ DRM_INFO("freeing data buffer memory.\n"); ++ drm_pci_free(dev, cpu_addr_dmah); ++ return i; ++ } ++ ++ DRM_DEBUG("waiting for idle...done\n"); ++ ++ /* restore SRC_CNTL */ ++ mach64_do_wait_for_fifo(dev_priv, 1); ++ MACH64_WRITE(MACH64_SRC_CNTL, src_cntl); ++ ++ failed = 0; ++ ++ /* Check register values to see if the GUI master operation succeeded */ ++ for (i = 0; i < 2; i++) { ++ u32 reg; ++ reg = MACH64_READ((MACH64_PAT_REG0 + i * 4)); ++ DRM_DEBUG("(After DMA Transfer) reg %d = 0x%08x\n", i, reg); ++ if (reg != expected[i]) { ++ failed = -1; ++ } ++ } ++ ++ /* restore pattern registers */ ++ mach64_do_wait_for_fifo(dev_priv, 2); ++ MACH64_WRITE(MACH64_PAT_REG0, pat_reg0); ++ MACH64_WRITE(MACH64_PAT_REG1, pat_reg1); ++ ++ DRM_DEBUG("freeing data buffer memory.\n"); ++ drm_pci_free(dev, cpu_addr_dmah); ++ DRM_DEBUG("returning ...\n"); ++ ++ return failed; ++} ++ ++/** ++ * Called during the DMA initialization ioctl to initialize all the necessary ++ * software and hardware state for DMA operation. ++ */ ++static int mach64_do_dma_init(struct drm_device * dev, drm_mach64_init_t * init) ++{ ++ drm_mach64_private_t *dev_priv; ++ u32 tmp; ++ int i, ret; ++ ++ DRM_DEBUG("\n"); ++ ++ dev_priv = drm_alloc(sizeof(drm_mach64_private_t), DRM_MEM_DRIVER); ++ if (dev_priv == NULL) ++ return -ENOMEM; ++ ++ memset(dev_priv, 0, sizeof(drm_mach64_private_t)); ++ ++ dev_priv->is_pci = init->is_pci; ++ ++ dev_priv->fb_bpp = init->fb_bpp; ++ dev_priv->front_offset = init->front_offset; ++ dev_priv->front_pitch = init->front_pitch; ++ dev_priv->back_offset = init->back_offset; ++ dev_priv->back_pitch = init->back_pitch; ++ ++ dev_priv->depth_bpp = init->depth_bpp; ++ dev_priv->depth_offset = init->depth_offset; ++ dev_priv->depth_pitch = init->depth_pitch; ++ ++ dev_priv->front_offset_pitch = (((dev_priv->front_pitch / 8) << 22) | ++ (dev_priv->front_offset >> 3)); ++ dev_priv->back_offset_pitch = (((dev_priv->back_pitch / 8) << 22) | ++ (dev_priv->back_offset >> 3)); ++ dev_priv->depth_offset_pitch = (((dev_priv->depth_pitch / 8) << 22) | ++ (dev_priv->depth_offset >> 3)); ++ ++ dev_priv->usec_timeout = 1000000; ++ ++ /* Set up the freelist, placeholder list and pending list */ ++ INIT_LIST_HEAD(&dev_priv->free_list); ++ INIT_LIST_HEAD(&dev_priv->placeholders); ++ INIT_LIST_HEAD(&dev_priv->pending); ++ ++ dev_priv->sarea = drm_getsarea(dev); ++ if (!dev_priv->sarea) { ++ DRM_ERROR("can not find sarea!\n"); ++ dev->dev_private = (void *)dev_priv; ++ mach64_do_cleanup_dma(dev); ++ return -EINVAL; ++ } ++ dev_priv->fb = drm_core_findmap(dev, init->fb_offset); ++ if (!dev_priv->fb) { ++ DRM_ERROR("can not find frame buffer map!\n"); ++ dev->dev_private = (void *)dev_priv; ++ mach64_do_cleanup_dma(dev); ++ return -EINVAL; ++ } ++ dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); ++ if (!dev_priv->mmio) { ++ DRM_ERROR("can not find mmio map!\n"); ++ dev->dev_private = (void *)dev_priv; ++ mach64_do_cleanup_dma(dev); ++ return -EINVAL; ++ } ++ ++ dev_priv->ring_map = drm_core_findmap(dev, init->ring_offset); ++ if (!dev_priv->ring_map) { ++ DRM_ERROR("can not find ring map!\n"); ++ dev->dev_private = (void *)dev_priv; ++ mach64_do_cleanup_dma(dev); ++ return -EINVAL; ++ } ++ ++ dev_priv->sarea_priv = (drm_mach64_sarea_t *) ++ ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); ++ ++ if (!dev_priv->is_pci) { ++ drm_core_ioremap(dev_priv->ring_map, dev); ++ if (!dev_priv->ring_map->handle) { ++ DRM_ERROR("can not ioremap virtual address for" ++ " descriptor ring\n"); ++ dev->dev_private = (void *)dev_priv; ++ mach64_do_cleanup_dma(dev); ++ return -ENOMEM; ++ } ++ dev->agp_buffer_token = init->buffers_offset; ++ dev->agp_buffer_map = ++ drm_core_findmap(dev, init->buffers_offset); ++ if (!dev->agp_buffer_map) { ++ DRM_ERROR("can not find dma buffer map!\n"); ++ dev->dev_private = (void *)dev_priv; ++ mach64_do_cleanup_dma(dev); ++ return -EINVAL; ++ } ++ /* there might be a nicer way to do this - ++ dev isn't passed all the way though the mach64 - DA */ ++ dev_priv->dev_buffers = dev->agp_buffer_map; ++ ++ drm_core_ioremap(dev->agp_buffer_map, dev); ++ if (!dev->agp_buffer_map->handle) { ++ DRM_ERROR("can not ioremap virtual address for" ++ " dma buffer\n"); ++ dev->dev_private = (void *)dev_priv; ++ mach64_do_cleanup_dma(dev); ++ return -ENOMEM; ++ } ++ dev_priv->agp_textures = ++ drm_core_findmap(dev, init->agp_textures_offset); ++ if (!dev_priv->agp_textures) { ++ DRM_ERROR("can not find agp texture region!\n"); ++ dev->dev_private = (void *)dev_priv; ++ mach64_do_cleanup_dma(dev); ++ return -EINVAL; ++ } ++ } ++ ++ dev->dev_private = (void *)dev_priv; ++ ++ dev_priv->driver_mode = init->dma_mode; ++ ++ /* changing the FIFO size from the default causes problems with DMA */ ++ tmp = MACH64_READ(MACH64_GUI_CNTL); ++ if ((tmp & MACH64_CMDFIFO_SIZE_MASK) != MACH64_CMDFIFO_SIZE_128) { ++ DRM_INFO("Setting FIFO size to 128 entries\n"); ++ /* FIFO must be empty to change the FIFO depth */ ++ if ((ret = mach64_do_wait_for_idle(dev_priv))) { ++ DRM_ERROR ++ ("wait for idle failed before changing FIFO depth!\n"); ++ mach64_do_cleanup_dma(dev); ++ return ret; ++ } ++ MACH64_WRITE(MACH64_GUI_CNTL, ((tmp & ~MACH64_CMDFIFO_SIZE_MASK) ++ | MACH64_CMDFIFO_SIZE_128)); ++ /* need to read GUI_STAT for proper sync according to docs */ ++ if ((ret = mach64_do_wait_for_idle(dev_priv))) { ++ DRM_ERROR ++ ("wait for idle failed when changing FIFO depth!\n"); ++ mach64_do_cleanup_dma(dev); ++ return ret; ++ } ++ } ++ ++ dev_priv->ring.size = 0x4000; /* 16KB */ ++ dev_priv->ring.start = dev_priv->ring_map->handle; ++ dev_priv->ring.start_addr = (u32) dev_priv->ring_map->offset; ++ ++ memset(dev_priv->ring.start, 0, dev_priv->ring.size); ++ DRM_INFO("descriptor ring: cpu addr %p, bus addr: 0x%08x\n", ++ dev_priv->ring.start, dev_priv->ring.start_addr); ++ ++ ret = 0; ++ if (dev_priv->driver_mode != MACH64_MODE_MMIO) { ++ ++ /* enable block 1 registers and bus mastering */ ++ MACH64_WRITE(MACH64_BUS_CNTL, ((MACH64_READ(MACH64_BUS_CNTL) ++ | MACH64_BUS_EXT_REG_EN) ++ & ~MACH64_BUS_MASTER_DIS)); ++ ++ /* try a DMA GUI-mastering pass and fall back to MMIO if it fails */ ++ DRM_DEBUG("Starting DMA test...\n"); ++ if ((ret = mach64_bm_dma_test(dev))) { ++ dev_priv->driver_mode = MACH64_MODE_MMIO; ++ } ++ } ++ ++ switch (dev_priv->driver_mode) { ++ case MACH64_MODE_MMIO: ++ MACH64_WRITE(MACH64_BUS_CNTL, (MACH64_READ(MACH64_BUS_CNTL) ++ | MACH64_BUS_EXT_REG_EN ++ | MACH64_BUS_MASTER_DIS)); ++ if (init->dma_mode == MACH64_MODE_MMIO) ++ DRM_INFO("Forcing pseudo-DMA mode\n"); ++ else ++ DRM_INFO ++ ("DMA test failed (ret=%d), using pseudo-DMA mode\n", ++ ret); ++ break; ++ case MACH64_MODE_DMA_SYNC: ++ DRM_INFO("DMA test succeeded, using synchronous DMA mode\n"); ++ break; ++ case MACH64_MODE_DMA_ASYNC: ++ default: ++ DRM_INFO("DMA test succeeded, using asynchronous DMA mode\n"); ++ } ++ ++ dev_priv->ring_running = 0; ++ ++ /* setup offsets for physical address of table start and end */ ++ dev_priv->ring.head_addr = dev_priv->ring.start_addr; ++ dev_priv->ring.head = dev_priv->ring.tail = 0; ++ dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1; ++ dev_priv->ring.space = dev_priv->ring.size; ++ ++ /* setup physical address and size of descriptor table */ ++ mach64_do_wait_for_fifo(dev_priv, 1); ++ MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD, ++ (dev_priv->ring. ++ head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB)); ++ ++ /* init frame counter */ ++ dev_priv->sarea_priv->frames_queued = 0; ++ for (i = 0; i < MACH64_MAX_QUEUED_FRAMES; i++) { ++ dev_priv->frame_ofs[i] = ~0; /* All ones indicates placeholder */ ++ } ++ ++ /* Allocate the DMA buffer freelist */ ++ if ((ret = mach64_init_freelist(dev))) { ++ DRM_ERROR("Freelist allocation failed\n"); ++ mach64_do_cleanup_dma(dev); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/*******************************************************************/ ++/** MMIO Pseudo-DMA (intended primarily for debugging, not performance) ++ */ ++ ++int mach64_do_dispatch_pseudo_dma(drm_mach64_private_t *dev_priv) ++{ ++ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; ++ volatile u32 *ring_read; ++ struct list_head *ptr; ++ drm_mach64_freelist_t *entry; ++ struct drm_buf *buf = NULL; ++ u32 *buf_ptr; ++ u32 used, reg, target; ++ int fifo, count, found, ret, no_idle_wait; ++ ++ fifo = count = reg = no_idle_wait = 0; ++ target = MACH64_BM_ADDR; ++ ++ if ((ret = mach64_do_wait_for_idle(dev_priv)) < 0) { ++ DRM_INFO("idle failed before pseudo-dma dispatch, resetting engine\n"); ++ mach64_dump_engine_info(dev_priv); ++ mach64_do_engine_reset(dev_priv); ++ return ret; ++ } ++ ++ ring_read = (u32 *) ring->start; ++ ++ while (ring->tail != ring->head) { ++ u32 buf_addr, new_target, offset; ++ u32 bytes, remaining, head, eol; ++ ++ head = ring->head; ++ ++ new_target = ++ le32_to_cpu(ring_read[head++]) - MACH64_APERTURE_OFFSET; ++ buf_addr = le32_to_cpu(ring_read[head++]); ++ eol = le32_to_cpu(ring_read[head]) & MACH64_DMA_EOL; ++ bytes = le32_to_cpu(ring_read[head++]) ++ & ~(MACH64_DMA_HOLD_OFFSET | MACH64_DMA_EOL); ++ head++; ++ head &= ring->tail_mask; ++ ++ /* can't wait for idle between a blit setup descriptor ++ * and a HOSTDATA descriptor or the engine will lock ++ */ ++ if (new_target == MACH64_BM_HOSTDATA ++ && target == MACH64_BM_ADDR) ++ no_idle_wait = 1; ++ ++ target = new_target; ++ ++ found = 0; ++ offset = 0; ++ list_for_each(ptr, &dev_priv->pending) { ++ entry = list_entry(ptr, drm_mach64_freelist_t, list); ++ buf = entry->buf; ++ offset = buf_addr - GETBUFADDR(buf); ++ if (offset >= 0 && offset < MACH64_BUFFER_SIZE) { ++ found = 1; ++ break; ++ } ++ } ++ ++ if (!found || buf == NULL) { ++ DRM_ERROR ++ ("Couldn't find pending buffer: head: %u tail: %u buf_addr: 0x%08x %s\n", ++ head, ring->tail, buf_addr, (eol ? "eol" : "")); ++ mach64_dump_ring_info(dev_priv); ++ mach64_do_engine_reset(dev_priv); ++ return -EINVAL; ++ } ++ ++ /* Hand feed the buffer to the card via MMIO, waiting for the fifo ++ * every 16 writes ++ */ ++ DRM_DEBUG("target: (0x%08x) %s\n", target, ++ (target == ++ MACH64_BM_HOSTDATA ? "BM_HOSTDATA" : "BM_ADDR")); ++ DRM_DEBUG("offset: %u bytes: %u used: %u\n", offset, bytes, ++ buf->used); ++ ++ remaining = (buf->used - offset) >> 2; /* dwords remaining in buffer */ ++ used = bytes >> 2; /* dwords in buffer for this descriptor */ ++ buf_ptr = (u32 *) ((char *)GETBUFPTR(buf) + offset); ++ ++ while (used) { ++ ++ if (count == 0) { ++ if (target == MACH64_BM_HOSTDATA) { ++ reg = DMAREG(MACH64_HOST_DATA0); ++ count = ++ (remaining > 16) ? 16 : remaining; ++ fifo = 0; ++ } else { ++ reg = le32_to_cpu(*buf_ptr++); ++ used--; ++ count = (reg >> 16) + 1; ++ } ++ ++ reg = reg & 0xffff; ++ reg = MMSELECT(reg); ++ } ++ while (count && used) { ++ if (!fifo) { ++ if (no_idle_wait) { ++ if ((ret = ++ mach64_do_wait_for_fifo ++ (dev_priv, 16)) < 0) { ++ no_idle_wait = 0; ++ return ret; ++ } ++ } else { ++ if ((ret = ++ mach64_do_wait_for_idle ++ (dev_priv)) < 0) { ++ return ret; ++ } ++ } ++ fifo = 16; ++ } ++ --fifo; ++ MACH64_WRITE(reg, le32_to_cpu(*buf_ptr++)); ++ used--; ++ remaining--; ++ ++ reg += 4; ++ count--; ++ } ++ } ++ ring->head = head; ++ ring->head_addr = ring->start_addr + (ring->head * sizeof(u32)); ++ ring->space += (4 * sizeof(u32)); ++ } ++ ++ if ((ret = mach64_do_wait_for_idle(dev_priv)) < 0) { ++ return ret; ++ } ++ MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD, ++ ring->head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB); ++ ++ DRM_DEBUG("completed\n"); ++ return 0; ++} ++ ++/*@}*/ ++ ++ ++/*******************************************************************/ ++/** \name DMA cleanup */ ++/*@{*/ ++ ++int mach64_do_cleanup_dma(struct drm_device * dev) ++{ ++ DRM_DEBUG("\n"); ++ ++ /* Make sure interrupts are disabled here because the uninstall ioctl ++ * may not have been called from userspace and after dev_private ++ * is freed, it's too late. ++ */ ++ if (dev->irq) ++ drm_irq_uninstall(dev); ++ ++ if (dev->dev_private) { ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ ++ if (!dev_priv->is_pci) { ++ if (dev_priv->ring_map) ++ drm_core_ioremapfree(dev_priv->ring_map, dev); ++ ++ if (dev->agp_buffer_map) { ++ drm_core_ioremapfree(dev->agp_buffer_map, dev); ++ dev->agp_buffer_map = NULL; ++ } ++ } ++ ++ mach64_destroy_freelist(dev); ++ ++ drm_free(dev_priv, sizeof(drm_mach64_private_t), ++ DRM_MEM_DRIVER); ++ dev->dev_private = NULL; ++ } ++ ++ return 0; ++} ++ ++/*@}*/ ++ ++ ++/*******************************************************************/ ++/** \name IOCTL handlers */ ++/*@{*/ ++ ++int mach64_dma_init(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ drm_mach64_init_t *init = data; ++ ++ DRM_DEBUG("\n"); ++ ++ LOCK_TEST_WITH_RETURN(dev, file_priv); ++ ++ switch (init->func) { ++ case DRM_MACH64_INIT_DMA: ++ return mach64_do_dma_init(dev, init); ++ case DRM_MACH64_CLEANUP_DMA: ++ return mach64_do_cleanup_dma(dev); ++ } ++ ++ return -EINVAL; ++} ++ ++int mach64_dma_idle(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ ++ DRM_DEBUG("\n"); ++ ++ LOCK_TEST_WITH_RETURN(dev, file_priv); ++ ++ return mach64_do_dma_idle(dev_priv); ++} ++ ++int mach64_dma_flush(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ ++ DRM_DEBUG("\n"); ++ ++ LOCK_TEST_WITH_RETURN(dev, file_priv); ++ ++ return mach64_do_dma_flush(dev_priv); ++} ++ ++int mach64_engine_reset(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ ++ DRM_DEBUG("\n"); ++ ++ LOCK_TEST_WITH_RETURN(dev, file_priv); ++ ++ return mach64_do_engine_reset(dev_priv); ++} ++ ++/*@}*/ ++ ++ ++/*******************************************************************/ ++/** \name Freelist management */ ++/*@{*/ ++ ++int mach64_init_freelist(struct drm_device * dev) ++{ ++ struct drm_device_dma *dma = dev->dma; ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ drm_mach64_freelist_t *entry; ++ struct list_head *ptr; ++ int i; ++ ++ DRM_DEBUG("adding %d buffers to freelist\n", dma->buf_count); ++ ++ for (i = 0; i < dma->buf_count; i++) { ++ if ((entry = ++ (drm_mach64_freelist_t *) ++ drm_alloc(sizeof(drm_mach64_freelist_t), ++ DRM_MEM_BUFLISTS)) == NULL) ++ return -ENOMEM; ++ memset(entry, 0, sizeof(drm_mach64_freelist_t)); ++ entry->buf = dma->buflist[i]; ++ ptr = &entry->list; ++ list_add_tail(ptr, &dev_priv->free_list); ++ } ++ ++ return 0; ++} ++ ++void mach64_destroy_freelist(struct drm_device * dev) ++{ ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ drm_mach64_freelist_t *entry; ++ struct list_head *ptr; ++ struct list_head *tmp; ++ ++ DRM_DEBUG("\n"); ++ ++ list_for_each_safe(ptr, tmp, &dev_priv->pending) { ++ list_del(ptr); ++ entry = list_entry(ptr, drm_mach64_freelist_t, list); ++ drm_free(entry, sizeof(*entry), DRM_MEM_BUFLISTS); ++ } ++ list_for_each_safe(ptr, tmp, &dev_priv->placeholders) { ++ list_del(ptr); ++ entry = list_entry(ptr, drm_mach64_freelist_t, list); ++ drm_free(entry, sizeof(*entry), DRM_MEM_BUFLISTS); ++ } ++ ++ list_for_each_safe(ptr, tmp, &dev_priv->free_list) { ++ list_del(ptr); ++ entry = list_entry(ptr, drm_mach64_freelist_t, list); ++ drm_free(entry, sizeof(*entry), DRM_MEM_BUFLISTS); ++ } ++} ++ ++/* IMPORTANT: This function should only be called when the engine is idle or locked up, ++ * as it assumes all buffers in the pending list have been completed by the hardware. ++ */ ++int mach64_do_release_used_buffers(drm_mach64_private_t *dev_priv) ++{ ++ struct list_head *ptr; ++ struct list_head *tmp; ++ drm_mach64_freelist_t *entry; ++ int i; ++ ++ if (list_empty(&dev_priv->pending)) ++ return 0; ++ ++ /* Iterate the pending list and move all buffers into the freelist... */ ++ i = 0; ++ list_for_each_safe(ptr, tmp, &dev_priv->pending) { ++ entry = list_entry(ptr, drm_mach64_freelist_t, list); ++ if (entry->discard) { ++ entry->buf->pending = 0; ++ list_del(ptr); ++ list_add_tail(ptr, &dev_priv->free_list); ++ i++; ++ } ++ } ++ ++ DRM_DEBUG("released %d buffers from pending list\n", i); ++ ++ return 0; ++} ++ ++static int mach64_do_reclaim_completed(drm_mach64_private_t *dev_priv) ++{ ++ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; ++ struct list_head *ptr; ++ struct list_head *tmp; ++ drm_mach64_freelist_t *entry; ++ u32 head, tail, ofs; ++ ++ mach64_ring_tick(dev_priv, ring); ++ head = ring->head; ++ tail = ring->tail; ++ ++ if (head == tail) { ++#if MACH64_EXTRA_CHECKING ++ if (MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE) { ++ DRM_ERROR("Empty ring with non-idle engine!\n"); ++ mach64_dump_ring_info(dev_priv); ++ return -1; ++ } ++#endif ++ /* last pass is complete, so release everything */ ++ mach64_do_release_used_buffers(dev_priv); ++ DRM_DEBUG("idle engine, freed all buffers.\n"); ++ if (list_empty(&dev_priv->free_list)) { ++ DRM_ERROR("Freelist empty with idle engine\n"); ++ return -1; ++ } ++ return 0; ++ } ++ /* Look for a completed buffer and bail out of the loop ++ * as soon as we find one -- don't waste time trying ++ * to free extra bufs here, leave that to do_release_used_buffers ++ */ ++ list_for_each_safe(ptr, tmp, &dev_priv->pending) { ++ entry = list_entry(ptr, drm_mach64_freelist_t, list); ++ ofs = entry->ring_ofs; ++ if (entry->discard && ++ ((head < tail && (ofs < head || ofs >= tail)) || ++ (head > tail && (ofs < head && ofs >= tail)))) { ++#if MACH64_EXTRA_CHECKING ++ int i; ++ ++ for (i = head; i != tail; i = (i + 4) & ring->tail_mask) ++ { ++ u32 o1 = le32_to_cpu(((u32 *) ring-> ++ start)[i + 1]); ++ u32 o2 = GETBUFADDR(entry->buf); ++ ++ if (o1 == o2) { ++ DRM_ERROR ++ ("Attempting to free used buffer: " ++ "i=%d buf=0x%08x\n", ++ i, o1); ++ mach64_dump_ring_info(dev_priv); ++ return -1; ++ } ++ } ++#endif ++ /* found a processed buffer */ ++ entry->buf->pending = 0; ++ list_del(ptr); ++ list_add_tail(ptr, &dev_priv->free_list); ++ DRM_DEBUG ++ ("freed processed buffer (head=%d tail=%d " ++ "buf ring ofs=%d).\n", ++ head, tail, ofs); ++ return 0; ++ } ++ } ++ ++ return 1; ++} ++ ++struct drm_buf *mach64_freelist_get(drm_mach64_private_t *dev_priv) ++{ ++ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; ++ drm_mach64_freelist_t *entry; ++ struct list_head *ptr; ++ int t; ++ ++ if (list_empty(&dev_priv->free_list)) { ++ if (list_empty(&dev_priv->pending)) { ++ DRM_ERROR ++ ("Couldn't get buffer - pending and free lists empty\n"); ++ t = 0; ++ list_for_each(ptr, &dev_priv->placeholders) { ++ t++; ++ } ++ DRM_INFO("Placeholders: %d\n", t); ++ return NULL; ++ } ++ ++ for (t = 0; t < dev_priv->usec_timeout; t++) { ++ int ret; ++ ++ ret = mach64_do_reclaim_completed(dev_priv); ++ if (ret == 0) ++ goto _freelist_entry_found; ++ if (ret < 0) ++ return NULL; ++ ++ DRM_UDELAY(1); ++ } ++ mach64_dump_ring_info(dev_priv); ++ DRM_ERROR ++ ("timeout waiting for buffers: ring head_addr: 0x%08x head: %d tail: %d\n", ++ ring->head_addr, ring->head, ring->tail); ++ return NULL; ++ } ++ ++ _freelist_entry_found: ++ ptr = dev_priv->free_list.next; ++ list_del(ptr); ++ entry = list_entry(ptr, drm_mach64_freelist_t, list); ++ entry->buf->used = 0; ++ list_add_tail(ptr, &dev_priv->placeholders); ++ return entry->buf; ++} ++ ++int mach64_freelist_put(drm_mach64_private_t *dev_priv, struct drm_buf *copy_buf) ++{ ++ struct list_head *ptr; ++ drm_mach64_freelist_t *entry; ++ ++#if MACH64_EXTRA_CHECKING ++ list_for_each(ptr, &dev_priv->pending) { ++ entry = list_entry(ptr, drm_mach64_freelist_t, list); ++ if (copy_buf == entry->buf) { ++ DRM_ERROR("Trying to release a pending buf\n"); ++ return -EFAULT; ++ } ++ } ++#endif ++ ptr = dev_priv->placeholders.next; ++ entry = list_entry(ptr, drm_mach64_freelist_t, list); ++ copy_buf->pending = 0; ++ copy_buf->used = 0; ++ entry->buf = copy_buf; ++ entry->discard = 1; ++ list_del(ptr); ++ list_add_tail(ptr, &dev_priv->free_list); ++ ++ return 0; ++} ++ ++/*@}*/ ++ ++ ++/*******************************************************************/ ++/** \name DMA buffer request and submission IOCTL handler */ ++/*@{*/ ++ ++static int mach64_dma_get_buffers(struct drm_device *dev, ++ struct drm_file *file_priv, ++ struct drm_dma * d) ++{ ++ int i; ++ struct drm_buf *buf; ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ ++ for (i = d->granted_count; i < d->request_count; i++) { ++ buf = mach64_freelist_get(dev_priv); ++#if MACH64_EXTRA_CHECKING ++ if (!buf) ++ return -EFAULT; ++#else ++ if (!buf) ++ return -EAGAIN; ++#endif ++ ++ buf->file_priv = file_priv; ++ ++ if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx, ++ sizeof(buf->idx))) ++ return -EFAULT; ++ if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total, ++ sizeof(buf->total))) ++ return -EFAULT; ++ ++ d->granted_count++; ++ } ++ return 0; ++} ++ ++int mach64_dma_buffers(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_device_dma *dma = dev->dma; ++ struct drm_dma *d = data; ++ int ret = 0; ++ ++ LOCK_TEST_WITH_RETURN(dev, file_priv); ++ ++ /* Please don't send us buffers. ++ */ ++ if (d->send_count != 0) { ++ DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n", ++ DRM_CURRENTPID, d->send_count); ++ return -EINVAL; ++ } ++ ++ /* We'll send you buffers. ++ */ ++ if (d->request_count < 0 || d->request_count > dma->buf_count) { ++ DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", ++ DRM_CURRENTPID, d->request_count, dma->buf_count); ++ ret = -EINVAL; ++ } ++ ++ d->granted_count = 0; ++ ++ if (d->request_count) { ++ ret = mach64_dma_get_buffers(dev, file_priv, d); ++ } ++ ++ return ret; ++} ++ ++void mach64_driver_lastclose(struct drm_device * dev) ++{ ++ mach64_do_cleanup_dma(dev); ++} ++ ++/*@}*/ +--- /dev/null ++++ b/drivers/gpu/drm/mach64/mach64_drm.h +@@ -0,0 +1,256 @@ ++/* mach64_drm.h -- Public header for the mach64 driver -*- linux-c -*- ++ * Created: Thu Nov 30 20:04:32 2000 by gareth@valinux.com ++ */ ++/* ++ * Copyright 2000 Gareth Hughes ++ * Copyright 2002 Frank C. Earl ++ * Copyright 2002-2003 Leif Delgass ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT OWNER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER ++ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: ++ * Gareth Hughes ++ * Frank C. Earl ++ * Leif Delgass ++ */ ++ ++#ifndef __MACH64_DRM_H__ ++#define __MACH64_DRM_H__ ++ ++/* WARNING: If you change any of these defines, make sure to change the ++ * defines in the Xserver file (mach64_sarea.h) ++ */ ++#ifndef __MACH64_SAREA_DEFINES__ ++#define __MACH64_SAREA_DEFINES__ ++ ++/* What needs to be changed for the current vertex buffer? ++ * GH: We're going to be pedantic about this. We want the card to do as ++ * little as possible, so let's avoid having it fetch a whole bunch of ++ * register values that don't change all that often, if at all. ++ */ ++#define MACH64_UPLOAD_DST_OFF_PITCH 0x0001 ++#define MACH64_UPLOAD_Z_OFF_PITCH 0x0002 ++#define MACH64_UPLOAD_Z_ALPHA_CNTL 0x0004 ++#define MACH64_UPLOAD_SCALE_3D_CNTL 0x0008 ++#define MACH64_UPLOAD_DP_FOG_CLR 0x0010 ++#define MACH64_UPLOAD_DP_WRITE_MASK 0x0020 ++#define MACH64_UPLOAD_DP_PIX_WIDTH 0x0040 ++#define MACH64_UPLOAD_SETUP_CNTL 0x0080 ++#define MACH64_UPLOAD_MISC 0x0100 ++#define MACH64_UPLOAD_TEXTURE 0x0200 ++#define MACH64_UPLOAD_TEX0IMAGE 0x0400 ++#define MACH64_UPLOAD_TEX1IMAGE 0x0800 ++#define MACH64_UPLOAD_CLIPRECTS 0x1000 /* handled client-side */ ++#define MACH64_UPLOAD_CONTEXT 0x00ff ++#define MACH64_UPLOAD_ALL 0x1fff ++ ++/* DMA buffer size ++ */ ++#define MACH64_BUFFER_SIZE 16384 ++ ++/* Max number of swaps allowed on the ring ++ * before the client must wait ++ */ ++#define MACH64_MAX_QUEUED_FRAMES 3U ++ ++/* Byte offsets for host blit buffer data ++ */ ++#define MACH64_HOSTDATA_BLIT_OFFSET 104 ++ ++/* Keep these small for testing. ++ */ ++#define MACH64_NR_SAREA_CLIPRECTS 8 ++ ++#define MACH64_CARD_HEAP 0 ++#define MACH64_AGP_HEAP 1 ++#define MACH64_NR_TEX_HEAPS 2 ++#define MACH64_NR_TEX_REGIONS 64 ++#define MACH64_LOG_TEX_GRANULARITY 16 ++ ++#define MACH64_TEX_MAXLEVELS 1 ++ ++#define MACH64_NR_CONTEXT_REGS 15 ++#define MACH64_NR_TEXTURE_REGS 4 ++ ++#endif /* __MACH64_SAREA_DEFINES__ */ ++ ++typedef struct { ++ unsigned int dst_off_pitch; ++ ++ unsigned int z_off_pitch; ++ unsigned int z_cntl; ++ unsigned int alpha_tst_cntl; ++ ++ unsigned int scale_3d_cntl; ++ ++ unsigned int sc_left_right; ++ unsigned int sc_top_bottom; ++ ++ unsigned int dp_fog_clr; ++ unsigned int dp_write_mask; ++ unsigned int dp_pix_width; ++ unsigned int dp_mix; ++ unsigned int dp_src; ++ ++ unsigned int clr_cmp_cntl; ++ unsigned int gui_traj_cntl; ++ ++ unsigned int setup_cntl; ++ ++ unsigned int tex_size_pitch; ++ unsigned int tex_cntl; ++ unsigned int secondary_tex_off; ++ unsigned int tex_offset; ++} drm_mach64_context_regs_t; ++ ++typedef struct drm_mach64_sarea { ++ /* The channel for communication of state information to the kernel ++ * on firing a vertex dma buffer. ++ */ ++ drm_mach64_context_regs_t context_state; ++ unsigned int dirty; ++ unsigned int vertsize; ++ ++ /* The current cliprects, or a subset thereof. ++ */ ++ struct drm_clip_rect boxes[MACH64_NR_SAREA_CLIPRECTS]; ++ unsigned int nbox; ++ ++ /* Counters for client-side throttling of rendering clients. ++ */ ++ unsigned int frames_queued; ++ ++ /* Texture memory LRU. ++ */ ++ struct drm_tex_region tex_list[MACH64_NR_TEX_HEAPS][MACH64_NR_TEX_REGIONS + ++ 1]; ++ unsigned int tex_age[MACH64_NR_TEX_HEAPS]; ++ int ctx_owner; ++} drm_mach64_sarea_t; ++ ++/* WARNING: If you change any of these defines, make sure to change the ++ * defines in the Xserver file (mach64_common.h) ++ */ ++ ++/* Mach64 specific ioctls ++ * The device specific ioctl range is 0x40 to 0x79. ++ */ ++ ++#define DRM_MACH64_INIT 0x00 ++#define DRM_MACH64_IDLE 0x01 ++#define DRM_MACH64_RESET 0x02 ++#define DRM_MACH64_SWAP 0x03 ++#define DRM_MACH64_CLEAR 0x04 ++#define DRM_MACH64_VERTEX 0x05 ++#define DRM_MACH64_BLIT 0x06 ++#define DRM_MACH64_FLUSH 0x07 ++#define DRM_MACH64_GETPARAM 0x08 ++ ++#define DRM_IOCTL_MACH64_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_MACH64_INIT, drm_mach64_init_t) ++#define DRM_IOCTL_MACH64_IDLE DRM_IO( DRM_COMMAND_BASE + DRM_MACH64_IDLE ) ++#define DRM_IOCTL_MACH64_RESET DRM_IO( DRM_COMMAND_BASE + DRM_MACH64_RESET ) ++#define DRM_IOCTL_MACH64_SWAP DRM_IO( DRM_COMMAND_BASE + DRM_MACH64_SWAP ) ++#define DRM_IOCTL_MACH64_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_MACH64_CLEAR, drm_mach64_clear_t) ++#define DRM_IOCTL_MACH64_VERTEX DRM_IOW( DRM_COMMAND_BASE + DRM_MACH64_VERTEX, drm_mach64_vertex_t) ++#define DRM_IOCTL_MACH64_BLIT DRM_IOW( DRM_COMMAND_BASE + DRM_MACH64_BLIT, drm_mach64_blit_t) ++#define DRM_IOCTL_MACH64_FLUSH DRM_IO( DRM_COMMAND_BASE + DRM_MACH64_FLUSH ) ++#define DRM_IOCTL_MACH64_GETPARAM DRM_IOWR( DRM_COMMAND_BASE + DRM_MACH64_GETPARAM, drm_mach64_getparam_t) ++ ++/* Buffer flags for clears ++ */ ++#define MACH64_FRONT 0x1 ++#define MACH64_BACK 0x2 ++#define MACH64_DEPTH 0x4 ++ ++/* Primitive types for vertex buffers ++ */ ++#define MACH64_PRIM_POINTS 0x00000000 ++#define MACH64_PRIM_LINES 0x00000001 ++#define MACH64_PRIM_LINE_LOOP 0x00000002 ++#define MACH64_PRIM_LINE_STRIP 0x00000003 ++#define MACH64_PRIM_TRIANGLES 0x00000004 ++#define MACH64_PRIM_TRIANGLE_STRIP 0x00000005 ++#define MACH64_PRIM_TRIANGLE_FAN 0x00000006 ++#define MACH64_PRIM_QUADS 0x00000007 ++#define MACH64_PRIM_QUAD_STRIP 0x00000008 ++#define MACH64_PRIM_POLYGON 0x00000009 ++ ++typedef enum _drm_mach64_dma_mode_t { ++ MACH64_MODE_DMA_ASYNC, ++ MACH64_MODE_DMA_SYNC, ++ MACH64_MODE_MMIO ++} drm_mach64_dma_mode_t; ++ ++typedef struct drm_mach64_init { ++ enum { ++ DRM_MACH64_INIT_DMA = 0x01, ++ DRM_MACH64_CLEANUP_DMA = 0x02 ++ } func; ++ ++ unsigned long sarea_priv_offset; ++ int is_pci; ++ drm_mach64_dma_mode_t dma_mode; ++ ++ unsigned int fb_bpp; ++ unsigned int front_offset, front_pitch; ++ unsigned int back_offset, back_pitch; ++ ++ unsigned int depth_bpp; ++ unsigned int depth_offset, depth_pitch; ++ ++ unsigned long fb_offset; ++ unsigned long mmio_offset; ++ unsigned long ring_offset; ++ unsigned long buffers_offset; ++ unsigned long agp_textures_offset; ++} drm_mach64_init_t; ++ ++typedef struct drm_mach64_clear { ++ unsigned int flags; ++ int x, y, w, h; ++ unsigned int clear_color; ++ unsigned int clear_depth; ++} drm_mach64_clear_t; ++ ++typedef struct drm_mach64_vertex { ++ int prim; ++ void *buf; /* Address of vertex buffer */ ++ unsigned long used; /* Number of bytes in buffer */ ++ int discard; /* Client finished with buffer? */ ++} drm_mach64_vertex_t; ++ ++typedef struct drm_mach64_blit { ++ void *buf; ++ int pitch; ++ int offset; ++ int format; ++ unsigned short x, y; ++ unsigned short width, height; ++} drm_mach64_blit_t; ++ ++typedef struct drm_mach64_getparam { ++ enum { ++ MACH64_PARAM_FRAMES_QUEUED = 0x01, ++ MACH64_PARAM_IRQ_NR = 0x02 ++ } param; ++ void *value; ++} drm_mach64_getparam_t; ++ ++#endif +--- /dev/null ++++ b/drivers/gpu/drm/mach64/mach64_drv.c +@@ -0,0 +1,105 @@ ++/* mach64_drv.c -- mach64 (Rage Pro) driver -*- linux-c -*- ++ * Created: Fri Nov 24 18:34:32 2000 by gareth@valinux.com ++ * ++ * Copyright 2000 Gareth Hughes ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * GARETH HUGHES BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER ++ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: ++ * Gareth Hughes ++ * Leif Delgass ++ */ ++ ++#include "drmP.h" ++#include "drm.h" ++#include "mach64_drm.h" ++#include "mach64_drv.h" ++ ++#include "drm_pciids.h" ++ ++static struct pci_device_id pciidlist[] = { ++ mach64_PCI_IDS ++}; ++ ++static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); ++static struct drm_driver driver = { ++ .driver_features = ++ DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_HAVE_DMA ++ | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, ++ .lastclose = mach64_driver_lastclose, ++ .get_vblank_counter = mach64_get_vblank_counter, ++ .enable_vblank = mach64_enable_vblank, ++ .disable_vblank = mach64_disable_vblank, ++ .irq_preinstall = mach64_driver_irq_preinstall, ++ .irq_postinstall = mach64_driver_irq_postinstall, ++ .irq_uninstall = mach64_driver_irq_uninstall, ++ .irq_handler = mach64_driver_irq_handler, ++ .reclaim_buffers = drm_core_reclaim_buffers, ++ .get_map_ofs = drm_core_get_map_ofs, ++ .get_reg_ofs = drm_core_get_reg_ofs, ++ .ioctls = mach64_ioctls, ++ .dma_ioctl = mach64_dma_buffers, ++ .fops = { ++ .owner = THIS_MODULE, ++ .open = drm_open, ++ .release = drm_release, ++ .ioctl = drm_ioctl, ++ .mmap = drm_mmap, ++ .poll = drm_poll, ++ .fasync = drm_fasync, ++ }, ++ .pci_driver = { ++ .name = DRIVER_NAME, ++ .id_table = pciidlist, ++ .probe = probe, ++ .remove = __devexit_p(drm_cleanup_pci), ++ }, ++ ++ .name = DRIVER_NAME, ++ .desc = DRIVER_DESC, ++ .date = DRIVER_DATE, ++ .major = DRIVER_MAJOR, ++ .minor = DRIVER_MINOR, ++ .patchlevel = DRIVER_PATCHLEVEL, ++}; ++ ++static int probe(struct pci_dev *pdev, const struct pci_device_id *ent) ++{ ++ return drm_get_dev(pdev, ent, &driver); ++} ++ ++ ++static int __init mach64_init(void) ++{ ++ driver.num_ioctls = mach64_max_ioctl; ++ return drm_init(&driver, pciidlist); ++} ++ ++static void __exit mach64_exit(void) ++{ ++ drm_exit(&driver); ++} ++ ++module_init(mach64_init); ++module_exit(mach64_exit); ++ ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE("GPL and additional rights"); +--- /dev/null ++++ b/drivers/gpu/drm/mach64/mach64_drv.h +@@ -0,0 +1,859 @@ ++/* mach64_drv.h -- Private header for mach64 driver -*- linux-c -*- ++ * Created: Fri Nov 24 22:07:58 2000 by gareth@valinux.com ++ */ ++/* ++ * Copyright 2000 Gareth Hughes ++ * Copyright 2002 Frank C. Earl ++ * Copyright 2002-2003 Leif Delgass ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT OWNER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER ++ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: ++ * Gareth Hughes ++ * Frank C. Earl ++ * Leif Delgass ++ * José Fonseca ++ */ ++ ++#ifndef __MACH64_DRV_H__ ++#define __MACH64_DRV_H__ ++ ++/* General customization: ++ */ ++ ++#define DRIVER_AUTHOR "Gareth Hughes, Leif Delgass, José Fonseca" ++ ++#define DRIVER_NAME "mach64" ++#define DRIVER_DESC "DRM module for the ATI Rage Pro" ++#define DRIVER_DATE "20060718" ++ ++#define DRIVER_MAJOR 2 ++#define DRIVER_MINOR 0 ++#define DRIVER_PATCHLEVEL 0 ++ ++/* FIXME: remove these when not needed */ ++/* Development driver options */ ++#define MACH64_EXTRA_CHECKING 0 /* Extra sanity checks for DMA/freelist management */ ++#define MACH64_VERBOSE 0 /* Verbose debugging output */ ++ ++typedef struct drm_mach64_freelist { ++ struct list_head list; /* List pointers for free_list, placeholders, or pending list */ ++ struct drm_buf *buf; /* Pointer to the buffer */ ++ int discard; /* This flag is set when we're done (re)using a buffer */ ++ u32 ring_ofs; /* dword offset in ring of last descriptor for this buffer */ ++} drm_mach64_freelist_t; ++ ++typedef struct drm_mach64_descriptor_ring { ++ void *start; /* write pointer (cpu address) to start of descriptor ring */ ++ u32 start_addr; /* bus address of beginning of descriptor ring */ ++ int size; /* size of ring in bytes */ ++ ++ u32 head_addr; /* bus address of descriptor ring head */ ++ u32 head; /* dword offset of descriptor ring head */ ++ u32 tail; /* dword offset of descriptor ring tail */ ++ u32 tail_mask; /* mask used to wrap ring */ ++ int space; /* number of free bytes in ring */ ++} drm_mach64_descriptor_ring_t; ++ ++typedef struct drm_mach64_private { ++ drm_mach64_sarea_t *sarea_priv; ++ ++ int is_pci; ++ drm_mach64_dma_mode_t driver_mode; /* Async DMA, sync DMA, or MMIO */ ++ ++ int usec_timeout; /* Timeout for the wait functions */ ++ ++ drm_mach64_descriptor_ring_t ring; /* DMA descriptor table (ring buffer) */ ++ int ring_running; /* Is bus mastering is enabled */ ++ ++ struct list_head free_list; /* Free-list head */ ++ struct list_head placeholders; /* Placeholder list for buffers held by clients */ ++ struct list_head pending; /* Buffers pending completion */ ++ ++ u32 frame_ofs[MACH64_MAX_QUEUED_FRAMES]; /* dword ring offsets of most recent frame swaps */ ++ ++ unsigned int fb_bpp; ++ unsigned int front_offset, front_pitch; ++ unsigned int back_offset, back_pitch; ++ ++ unsigned int depth_bpp; ++ unsigned int depth_offset, depth_pitch; ++ ++ atomic_t vbl_received; /**< Number of vblanks received. */ ++ ++ u32 front_offset_pitch; ++ u32 back_offset_pitch; ++ u32 depth_offset_pitch; ++ ++ drm_local_map_t *sarea; ++ drm_local_map_t *fb; ++ drm_local_map_t *mmio; ++ drm_local_map_t *ring_map; ++ drm_local_map_t *dev_buffers; /* this is a pointer to a structure in dev */ ++ drm_local_map_t *agp_textures; ++} drm_mach64_private_t; ++ ++extern struct drm_ioctl_desc mach64_ioctls[]; ++extern int mach64_max_ioctl; ++ ++ /* mach64_dma.c */ ++extern int mach64_dma_init(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int mach64_dma_idle(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int mach64_dma_flush(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int mach64_engine_reset(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int mach64_dma_buffers(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern void mach64_driver_lastclose(struct drm_device * dev); ++ ++extern int mach64_init_freelist(struct drm_device * dev); ++extern void mach64_destroy_freelist(struct drm_device * dev); ++extern struct drm_buf *mach64_freelist_get(drm_mach64_private_t * dev_priv); ++extern int mach64_freelist_put(drm_mach64_private_t * dev_priv, ++ struct drm_buf * copy_buf); ++ ++extern int mach64_do_wait_for_fifo(drm_mach64_private_t * dev_priv, ++ int entries); ++extern int mach64_do_wait_for_idle(drm_mach64_private_t * dev_priv); ++extern int mach64_wait_ring(drm_mach64_private_t * dev_priv, int n); ++extern int mach64_do_dispatch_pseudo_dma(drm_mach64_private_t * dev_priv); ++extern int mach64_do_release_used_buffers(drm_mach64_private_t * dev_priv); ++extern void mach64_dump_engine_info(drm_mach64_private_t * dev_priv); ++extern void mach64_dump_ring_info(drm_mach64_private_t * dev_priv); ++extern int mach64_do_engine_reset(drm_mach64_private_t * dev_priv); ++ ++extern int mach64_add_buf_to_ring(drm_mach64_private_t *dev_priv, ++ drm_mach64_freelist_t *_entry); ++extern int mach64_add_hostdata_buf_to_ring(drm_mach64_private_t *dev_priv, ++ drm_mach64_freelist_t *_entry); ++ ++extern int mach64_do_dma_idle(drm_mach64_private_t * dev_priv); ++extern int mach64_do_dma_flush(drm_mach64_private_t * dev_priv); ++extern int mach64_do_cleanup_dma(struct drm_device * dev); ++ ++ /* mach64_state.c */ ++extern int mach64_dma_clear(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int mach64_dma_swap(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int mach64_dma_vertex(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int mach64_dma_blit(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int mach64_get_param(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++extern u32 mach64_get_vblank_counter(struct drm_device *dev, int crtc); ++extern int mach64_enable_vblank(struct drm_device *dev, int crtc); ++extern void mach64_disable_vblank(struct drm_device *dev, int crtc); ++extern irqreturn_t mach64_driver_irq_handler(DRM_IRQ_ARGS); ++extern void mach64_driver_irq_preinstall(struct drm_device *dev); ++extern int mach64_driver_irq_postinstall(struct drm_device *dev); ++extern void mach64_driver_irq_uninstall(struct drm_device *dev); ++ ++/* ================================================================ ++ * Registers ++ */ ++ ++#define MACH64_AGP_BASE 0x0148 ++#define MACH64_AGP_CNTL 0x014c ++#define MACH64_ALPHA_TST_CNTL 0x0550 ++ ++#define MACH64_DSP_CONFIG 0x0420 ++#define MACH64_DSP_ON_OFF 0x0424 ++#define MACH64_EXT_MEM_CNTL 0x04ac ++#define MACH64_GEN_TEST_CNTL 0x04d0 ++#define MACH64_HW_DEBUG 0x047c ++#define MACH64_MEM_ADDR_CONFIG 0x0434 ++#define MACH64_MEM_BUF_CNTL 0x042c ++#define MACH64_MEM_CNTL 0x04b0 ++ ++#define MACH64_BM_ADDR 0x0648 ++#define MACH64_BM_COMMAND 0x0188 ++#define MACH64_BM_DATA 0x0648 ++#define MACH64_BM_FRAME_BUF_OFFSET 0x0180 ++#define MACH64_BM_GUI_TABLE 0x01b8 ++#define MACH64_BM_GUI_TABLE_CMD 0x064c ++# define MACH64_CIRCULAR_BUF_SIZE_16KB (0 << 0) ++# define MACH64_CIRCULAR_BUF_SIZE_32KB (1 << 0) ++# define MACH64_CIRCULAR_BUF_SIZE_64KB (2 << 0) ++# define MACH64_CIRCULAR_BUF_SIZE_128KB (3 << 0) ++# define MACH64_LAST_DESCRIPTOR (1 << 31) ++#define MACH64_BM_HOSTDATA 0x0644 ++#define MACH64_BM_STATUS 0x018c ++#define MACH64_BM_SYSTEM_MEM_ADDR 0x0184 ++#define MACH64_BM_SYSTEM_TABLE 0x01bc ++#define MACH64_BUS_CNTL 0x04a0 ++# define MACH64_BUS_MSTR_RESET (1 << 1) ++# define MACH64_BUS_APER_REG_DIS (1 << 4) ++# define MACH64_BUS_FLUSH_BUF (1 << 2) ++# define MACH64_BUS_MASTER_DIS (1 << 6) ++# define MACH64_BUS_EXT_REG_EN (1 << 27) ++ ++#define MACH64_CLR_CMP_CLR 0x0700 ++#define MACH64_CLR_CMP_CNTL 0x0708 ++#define MACH64_CLR_CMP_MASK 0x0704 ++#define MACH64_CONFIG_CHIP_ID 0x04e0 ++#define MACH64_CONFIG_CNTL 0x04dc ++#define MACH64_CONFIG_STAT0 0x04e4 ++#define MACH64_CONFIG_STAT1 0x0494 ++#define MACH64_CONFIG_STAT2 0x0498 ++#define MACH64_CONTEXT_LOAD_CNTL 0x072c ++#define MACH64_CONTEXT_MASK 0x0720 ++#define MACH64_COMPOSITE_SHADOW_ID 0x0798 ++#define MACH64_CRC_SIG 0x04e8 ++#define MACH64_CUSTOM_MACRO_CNTL 0x04d4 ++ ++#define MACH64_DP_BKGD_CLR 0x06c0 ++#define MACH64_DP_FOG_CLR 0x06c4 ++#define MACH64_DP_FGRD_BKGD_CLR 0x06e0 ++#define MACH64_DP_FRGD_CLR 0x06c4 ++#define MACH64_DP_FGRD_CLR_MIX 0x06dc ++ ++#define MACH64_DP_MIX 0x06d4 ++# define BKGD_MIX_NOT_D (0 << 0) ++# define BKGD_MIX_ZERO (1 << 0) ++# define BKGD_MIX_ONE (2 << 0) ++# define MACH64_BKGD_MIX_D (3 << 0) ++# define BKGD_MIX_NOT_S (4 << 0) ++# define BKGD_MIX_D_XOR_S (5 << 0) ++# define BKGD_MIX_NOT_D_XOR_S (6 << 0) ++# define MACH64_BKGD_MIX_S (7 << 0) ++# define BKGD_MIX_NOT_D_OR_NOT_S (8 << 0) ++# define BKGD_MIX_D_OR_NOT_S (9 << 0) ++# define BKGD_MIX_NOT_D_OR_S (10 << 0) ++# define BKGD_MIX_D_OR_S (11 << 0) ++# define BKGD_MIX_D_AND_S (12 << 0) ++# define BKGD_MIX_NOT_D_AND_S (13 << 0) ++# define BKGD_MIX_D_AND_NOT_S (14 << 0) ++# define BKGD_MIX_NOT_D_AND_NOT_S (15 << 0) ++# define BKGD_MIX_D_PLUS_S_DIV2 (23 << 0) ++# define FRGD_MIX_NOT_D (0 << 16) ++# define FRGD_MIX_ZERO (1 << 16) ++# define FRGD_MIX_ONE (2 << 16) ++# define FRGD_MIX_D (3 << 16) ++# define FRGD_MIX_NOT_S (4 << 16) ++# define FRGD_MIX_D_XOR_S (5 << 16) ++# define FRGD_MIX_NOT_D_XOR_S (6 << 16) ++# define MACH64_FRGD_MIX_S (7 << 16) ++# define FRGD_MIX_NOT_D_OR_NOT_S (8 << 16) ++# define FRGD_MIX_D_OR_NOT_S (9 << 16) ++# define FRGD_MIX_NOT_D_OR_S (10 << 16) ++# define FRGD_MIX_D_OR_S (11 << 16) ++# define FRGD_MIX_D_AND_S (12 << 16) ++# define FRGD_MIX_NOT_D_AND_S (13 << 16) ++# define FRGD_MIX_D_AND_NOT_S (14 << 16) ++# define FRGD_MIX_NOT_D_AND_NOT_S (15 << 16) ++# define FRGD_MIX_D_PLUS_S_DIV2 (23 << 16) ++ ++#define MACH64_DP_PIX_WIDTH 0x06d0 ++# define MACH64_HOST_TRIPLE_ENABLE (1 << 13) ++# define MACH64_BYTE_ORDER_MSB_TO_LSB (0 << 24) ++# define MACH64_BYTE_ORDER_LSB_TO_MSB (1 << 24) ++ ++#define MACH64_DP_SRC 0x06d8 ++# define MACH64_BKGD_SRC_BKGD_CLR (0 << 0) ++# define MACH64_BKGD_SRC_FRGD_CLR (1 << 0) ++# define MACH64_BKGD_SRC_HOST (2 << 0) ++# define MACH64_BKGD_SRC_BLIT (3 << 0) ++# define MACH64_BKGD_SRC_PATTERN (4 << 0) ++# define MACH64_BKGD_SRC_3D (5 << 0) ++# define MACH64_FRGD_SRC_BKGD_CLR (0 << 8) ++# define MACH64_FRGD_SRC_FRGD_CLR (1 << 8) ++# define MACH64_FRGD_SRC_HOST (2 << 8) ++# define MACH64_FRGD_SRC_BLIT (3 << 8) ++# define MACH64_FRGD_SRC_PATTERN (4 << 8) ++# define MACH64_FRGD_SRC_3D (5 << 8) ++# define MACH64_MONO_SRC_ONE (0 << 16) ++# define MACH64_MONO_SRC_PATTERN (1 << 16) ++# define MACH64_MONO_SRC_HOST (2 << 16) ++# define MACH64_MONO_SRC_BLIT (3 << 16) ++ ++#define MACH64_DP_WRITE_MASK 0x06c8 ++ ++#define MACH64_DST_CNTL 0x0530 ++# define MACH64_DST_X_RIGHT_TO_LEFT (0 << 0) ++# define MACH64_DST_X_LEFT_TO_RIGHT (1 << 0) ++# define MACH64_DST_Y_BOTTOM_TO_TOP (0 << 1) ++# define MACH64_DST_Y_TOP_TO_BOTTOM (1 << 1) ++# define MACH64_DST_X_MAJOR (0 << 2) ++# define MACH64_DST_Y_MAJOR (1 << 2) ++# define MACH64_DST_X_TILE (1 << 3) ++# define MACH64_DST_Y_TILE (1 << 4) ++# define MACH64_DST_LAST_PEL (1 << 5) ++# define MACH64_DST_POLYGON_ENABLE (1 << 6) ++# define MACH64_DST_24_ROTATION_ENABLE (1 << 7) ++ ++#define MACH64_DST_HEIGHT_WIDTH 0x0518 ++#define MACH64_DST_OFF_PITCH 0x0500 ++#define MACH64_DST_WIDTH_HEIGHT 0x06ec ++#define MACH64_DST_X_Y 0x06e8 ++#define MACH64_DST_Y_X 0x050c ++ ++#define MACH64_FIFO_STAT 0x0710 ++# define MACH64_FIFO_SLOT_MASK 0x0000ffff ++# define MACH64_FIFO_ERR (1 << 31) ++ ++#define MACH64_GEN_TEST_CNTL 0x04d0 ++# define MACH64_GUI_ENGINE_ENABLE (1 << 8) ++#define MACH64_GUI_CMDFIFO_DEBUG 0x0170 ++#define MACH64_GUI_CMDFIFO_DATA 0x0174 ++#define MACH64_GUI_CNTL 0x0178 ++# define MACH64_CMDFIFO_SIZE_MASK 0x00000003ul ++# define MACH64_CMDFIFO_SIZE_192 0x00000000ul ++# define MACH64_CMDFIFO_SIZE_128 0x00000001ul ++# define MACH64_CMDFIFO_SIZE_64 0x00000002ul ++#define MACH64_GUI_STAT 0x0738 ++# define MACH64_GUI_ACTIVE (1 << 0) ++#define MACH64_GUI_TRAJ_CNTL 0x0730 ++ ++#define MACH64_HOST_CNTL 0x0640 ++#define MACH64_HOST_DATA0 0x0600 ++ ++#define MACH64_ONE_OVER_AREA 0x029c ++#define MACH64_ONE_OVER_AREA_UC 0x0300 ++ ++#define MACH64_PAT_REG0 0x0680 ++#define MACH64_PAT_REG1 0x0684 ++ ++#define MACH64_SC_LEFT 0x06a0 ++#define MACH64_SC_RIGHT 0x06a4 ++#define MACH64_SC_LEFT_RIGHT 0x06a8 ++#define MACH64_SC_TOP 0x06ac ++#define MACH64_SC_BOTTOM 0x06b0 ++#define MACH64_SC_TOP_BOTTOM 0x06b4 ++ ++#define MACH64_SCALE_3D_CNTL 0x05fc ++#define MACH64_SCRATCH_REG0 0x0480 ++#define MACH64_SCRATCH_REG1 0x0484 ++#define MACH64_SECONDARY_TEX_OFF 0x0778 ++#define MACH64_SETUP_CNTL 0x0304 ++#define MACH64_SRC_CNTL 0x05b4 ++# define MACH64_SRC_BM_ENABLE (1 << 8) ++# define MACH64_SRC_BM_SYNC (1 << 9) ++# define MACH64_SRC_BM_OP_FRAME_TO_SYSTEM (0 << 10) ++# define MACH64_SRC_BM_OP_SYSTEM_TO_FRAME (1 << 10) ++# define MACH64_SRC_BM_OP_REG_TO_SYSTEM (2 << 10) ++# define MACH64_SRC_BM_OP_SYSTEM_TO_REG (3 << 10) ++#define MACH64_SRC_HEIGHT1 0x0594 ++#define MACH64_SRC_HEIGHT2 0x05ac ++#define MACH64_SRC_HEIGHT1_WIDTH1 0x0598 ++#define MACH64_SRC_HEIGHT2_WIDTH2 0x05b0 ++#define MACH64_SRC_OFF_PITCH 0x0580 ++#define MACH64_SRC_WIDTH1 0x0590 ++#define MACH64_SRC_Y_X 0x058c ++ ++#define MACH64_TEX_0_OFF 0x05c0 ++#define MACH64_TEX_CNTL 0x0774 ++#define MACH64_TEX_SIZE_PITCH 0x0770 ++#define MACH64_TIMER_CONFIG 0x0428 ++ ++#define MACH64_VERTEX_1_ARGB 0x0254 ++#define MACH64_VERTEX_1_S 0x0240 ++#define MACH64_VERTEX_1_SECONDARY_S 0x0328 ++#define MACH64_VERTEX_1_SECONDARY_T 0x032c ++#define MACH64_VERTEX_1_SECONDARY_W 0x0330 ++#define MACH64_VERTEX_1_SPEC_ARGB 0x024c ++#define MACH64_VERTEX_1_T 0x0244 ++#define MACH64_VERTEX_1_W 0x0248 ++#define MACH64_VERTEX_1_X_Y 0x0258 ++#define MACH64_VERTEX_1_Z 0x0250 ++#define MACH64_VERTEX_2_ARGB 0x0274 ++#define MACH64_VERTEX_2_S 0x0260 ++#define MACH64_VERTEX_2_SECONDARY_S 0x0334 ++#define MACH64_VERTEX_2_SECONDARY_T 0x0338 ++#define MACH64_VERTEX_2_SECONDARY_W 0x033c ++#define MACH64_VERTEX_2_SPEC_ARGB 0x026c ++#define MACH64_VERTEX_2_T 0x0264 ++#define MACH64_VERTEX_2_W 0x0268 ++#define MACH64_VERTEX_2_X_Y 0x0278 ++#define MACH64_VERTEX_2_Z 0x0270 ++#define MACH64_VERTEX_3_ARGB 0x0294 ++#define MACH64_VERTEX_3_S 0x0280 ++#define MACH64_VERTEX_3_SECONDARY_S 0x02a0 ++#define MACH64_VERTEX_3_SECONDARY_T 0x02a4 ++#define MACH64_VERTEX_3_SECONDARY_W 0x02a8 ++#define MACH64_VERTEX_3_SPEC_ARGB 0x028c ++#define MACH64_VERTEX_3_T 0x0284 ++#define MACH64_VERTEX_3_W 0x0288 ++#define MACH64_VERTEX_3_X_Y 0x0298 ++#define MACH64_VERTEX_3_Z 0x0290 ++ ++#define MACH64_Z_CNTL 0x054c ++#define MACH64_Z_OFF_PITCH 0x0548 ++ ++#define MACH64_CRTC_VLINE_CRNT_VLINE 0x0410 ++# define MACH64_CRTC_VLINE_MASK 0x000007ff ++# define MACH64_CRTC_CRNT_VLINE_MASK 0x07ff0000 ++#define MACH64_CRTC_OFF_PITCH 0x0414 ++#define MACH64_CRTC_INT_CNTL 0x0418 ++# define MACH64_CRTC_VBLANK (1 << 0) ++# define MACH64_CRTC_VBLANK_INT_EN (1 << 1) ++# define MACH64_CRTC_VBLANK_INT (1 << 2) ++# define MACH64_CRTC_VLINE_INT_EN (1 << 3) ++# define MACH64_CRTC_VLINE_INT (1 << 4) ++# define MACH64_CRTC_VLINE_SYNC (1 << 5) /* 0=even, 1=odd */ ++# define MACH64_CRTC_FRAME (1 << 6) /* 0=even, 1=odd */ ++# define MACH64_CRTC_SNAPSHOT_INT_EN (1 << 7) ++# define MACH64_CRTC_SNAPSHOT_INT (1 << 8) ++# define MACH64_CRTC_I2C_INT_EN (1 << 9) ++# define MACH64_CRTC_I2C_INT (1 << 10) ++# define MACH64_CRTC2_VBLANK (1 << 11) /* LT Pro */ ++# define MACH64_CRTC2_VBLANK_INT_EN (1 << 12) /* LT Pro */ ++# define MACH64_CRTC2_VBLANK_INT (1 << 13) /* LT Pro */ ++# define MACH64_CRTC2_VLINE_INT_EN (1 << 14) /* LT Pro */ ++# define MACH64_CRTC2_VLINE_INT (1 << 15) /* LT Pro */ ++# define MACH64_CRTC_CAPBUF0_INT_EN (1 << 16) ++# define MACH64_CRTC_CAPBUF0_INT (1 << 17) ++# define MACH64_CRTC_CAPBUF1_INT_EN (1 << 18) ++# define MACH64_CRTC_CAPBUF1_INT (1 << 19) ++# define MACH64_CRTC_OVERLAY_EOF_INT_EN (1 << 20) ++# define MACH64_CRTC_OVERLAY_EOF_INT (1 << 21) ++# define MACH64_CRTC_ONESHOT_CAP_INT_EN (1 << 22) ++# define MACH64_CRTC_ONESHOT_CAP_INT (1 << 23) ++# define MACH64_CRTC_BUSMASTER_EOL_INT_EN (1 << 24) ++# define MACH64_CRTC_BUSMASTER_EOL_INT (1 << 25) ++# define MACH64_CRTC_GP_INT_EN (1 << 26) ++# define MACH64_CRTC_GP_INT (1 << 27) ++# define MACH64_CRTC2_VLINE_SYNC (1 << 28) /* LT Pro */ /* 0=even, 1=odd */ ++# define MACH64_CRTC_SNAPSHOT2_INT_EN (1 << 29) /* LT Pro */ ++# define MACH64_CRTC_SNAPSHOT2_INT (1 << 30) /* LT Pro */ ++# define MACH64_CRTC_VBLANK2_INT (1 << 31) ++# define MACH64_CRTC_INT_ENS \ ++ ( \ ++ MACH64_CRTC_VBLANK_INT_EN | \ ++ MACH64_CRTC_VLINE_INT_EN | \ ++ MACH64_CRTC_SNAPSHOT_INT_EN | \ ++ MACH64_CRTC_I2C_INT_EN | \ ++ MACH64_CRTC2_VBLANK_INT_EN | \ ++ MACH64_CRTC2_VLINE_INT_EN | \ ++ MACH64_CRTC_CAPBUF0_INT_EN | \ ++ MACH64_CRTC_CAPBUF1_INT_EN | \ ++ MACH64_CRTC_OVERLAY_EOF_INT_EN | \ ++ MACH64_CRTC_ONESHOT_CAP_INT_EN | \ ++ MACH64_CRTC_BUSMASTER_EOL_INT_EN | \ ++ MACH64_CRTC_GP_INT_EN | \ ++ MACH64_CRTC_SNAPSHOT2_INT_EN | \ ++ 0 \ ++ ) ++# define MACH64_CRTC_INT_ACKS \ ++ ( \ ++ MACH64_CRTC_VBLANK_INT | \ ++ MACH64_CRTC_VLINE_INT | \ ++ MACH64_CRTC_SNAPSHOT_INT | \ ++ MACH64_CRTC_I2C_INT | \ ++ MACH64_CRTC2_VBLANK_INT | \ ++ MACH64_CRTC2_VLINE_INT | \ ++ MACH64_CRTC_CAPBUF0_INT | \ ++ MACH64_CRTC_CAPBUF1_INT | \ ++ MACH64_CRTC_OVERLAY_EOF_INT | \ ++ MACH64_CRTC_ONESHOT_CAP_INT | \ ++ MACH64_CRTC_BUSMASTER_EOL_INT | \ ++ MACH64_CRTC_GP_INT | \ ++ MACH64_CRTC_SNAPSHOT2_INT | \ ++ MACH64_CRTC_VBLANK2_INT | \ ++ 0 \ ++ ) ++ ++#define MACH64_DATATYPE_CI8 2 ++#define MACH64_DATATYPE_ARGB1555 3 ++#define MACH64_DATATYPE_RGB565 4 ++#define MACH64_DATATYPE_ARGB8888 6 ++#define MACH64_DATATYPE_RGB332 7 ++#define MACH64_DATATYPE_Y8 8 ++#define MACH64_DATATYPE_RGB8 9 ++#define MACH64_DATATYPE_VYUY422 11 ++#define MACH64_DATATYPE_YVYU422 12 ++#define MACH64_DATATYPE_AYUV444 14 ++#define MACH64_DATATYPE_ARGB4444 15 ++ ++#define MACH64_READ(reg) DRM_READ32(dev_priv->mmio, (reg) ) ++#define MACH64_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio, (reg), (val) ) ++ ++#define DWMREG0 0x0400 ++#define DWMREG0_END 0x07ff ++#define DWMREG1 0x0000 ++#define DWMREG1_END 0x03ff ++ ++#define ISREG0(r) (((r) >= DWMREG0) && ((r) <= DWMREG0_END)) ++#define DMAREG0(r) (((r) - DWMREG0) >> 2) ++#define DMAREG1(r) ((((r) - DWMREG1) >> 2 ) | 0x0100) ++#define DMAREG(r) (ISREG0(r) ? DMAREG0(r) : DMAREG1(r)) ++ ++#define MMREG0 0x0000 ++#define MMREG0_END 0x00ff ++ ++#define ISMMREG0(r) (((r) >= MMREG0) && ((r) <= MMREG0_END)) ++#define MMSELECT0(r) (((r) << 2) + DWMREG0) ++#define MMSELECT1(r) (((((r) & 0xff) << 2) + DWMREG1)) ++#define MMSELECT(r) (ISMMREG0(r) ? MMSELECT0(r) : MMSELECT1(r)) ++ ++/* ================================================================ ++ * DMA constants ++ */ ++ ++/* DMA descriptor field indices: ++ * The descriptor fields are loaded into the read-only ++ * BM_* system bus master registers during a bus-master operation ++ */ ++#define MACH64_DMA_FRAME_BUF_OFFSET 0 /* BM_FRAME_BUF_OFFSET */ ++#define MACH64_DMA_SYS_MEM_ADDR 1 /* BM_SYSTEM_MEM_ADDR */ ++#define MACH64_DMA_COMMAND 2 /* BM_COMMAND */ ++#define MACH64_DMA_RESERVED 3 /* BM_STATUS */ ++ ++/* BM_COMMAND descriptor field flags */ ++#define MACH64_DMA_HOLD_OFFSET (1<<30) /* Don't increment DMA_FRAME_BUF_OFFSET */ ++#define MACH64_DMA_EOL (1<<31) /* End of descriptor list flag */ ++ ++#define MACH64_DMA_CHUNKSIZE 0x1000 /* 4kB per DMA descriptor */ ++#define MACH64_APERTURE_OFFSET 0x7ff800 /* frame-buffer offset for gui-masters */ ++ ++/* ================================================================ ++ * Ring operations ++ * ++ * Since the Mach64 bus master engine requires polling, these functions end ++ * up being called frequently, hence being inline. ++ */ ++ ++static __inline__ void mach64_ring_start(drm_mach64_private_t * dev_priv) ++{ ++ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; ++ ++ DRM_DEBUG("head_addr: 0x%08x head: %d tail: %d space: %d\n", ++ ring->head_addr, ring->head, ring->tail, ring->space); ++ ++ if (mach64_do_wait_for_idle(dev_priv) < 0) { ++ mach64_do_engine_reset(dev_priv); ++ } ++ ++ if (dev_priv->driver_mode != MACH64_MODE_MMIO) { ++ /* enable bus mastering and block 1 registers */ ++ MACH64_WRITE(MACH64_BUS_CNTL, ++ (MACH64_READ(MACH64_BUS_CNTL) & ++ ~MACH64_BUS_MASTER_DIS) ++ | MACH64_BUS_EXT_REG_EN); ++ mach64_do_wait_for_idle(dev_priv); ++ } ++ ++ /* reset descriptor table ring head */ ++ MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD, ++ ring->head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB); ++ ++ dev_priv->ring_running = 1; ++} ++ ++static __inline__ void mach64_ring_resume(drm_mach64_private_t * dev_priv, ++ drm_mach64_descriptor_ring_t * ring) ++{ ++ DRM_DEBUG("head_addr: 0x%08x head: %d tail: %d space: %d\n", ++ ring->head_addr, ring->head, ring->tail, ring->space); ++ ++ /* reset descriptor table ring head */ ++ MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD, ++ ring->head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB); ++ ++ if (dev_priv->driver_mode == MACH64_MODE_MMIO) { ++ mach64_do_dispatch_pseudo_dma(dev_priv); ++ } else { ++ /* enable GUI bus mastering, and sync the bus master to the GUI */ ++ MACH64_WRITE(MACH64_SRC_CNTL, ++ MACH64_SRC_BM_ENABLE | MACH64_SRC_BM_SYNC | ++ MACH64_SRC_BM_OP_SYSTEM_TO_REG); ++ ++ /* kick off the transfer */ ++ MACH64_WRITE(MACH64_DST_HEIGHT_WIDTH, 0); ++ if (dev_priv->driver_mode == MACH64_MODE_DMA_SYNC) { ++ if ((mach64_do_wait_for_idle(dev_priv)) < 0) { ++ DRM_ERROR("idle failed, resetting engine\n"); ++ mach64_dump_engine_info(dev_priv); ++ mach64_do_engine_reset(dev_priv); ++ return; ++ } ++ mach64_do_release_used_buffers(dev_priv); ++ } ++ } ++} ++ ++/** ++ * Poll the ring head and make sure the bus master is alive. ++ * ++ * Mach64's bus master engine will stop if there are no more entries to process. ++ * This function polls the engine for the last processed entry and calls ++ * mach64_ring_resume if there is an unprocessed entry. ++ * ++ * Note also that, since we update the ring tail while the bus master engine is ++ * in operation, it is possible that the last tail update was too late to be ++ * processed, and the bus master engine stops at the previous tail position. ++ * Therefore it is important to call this function frequently. ++ */ ++static __inline__ void mach64_ring_tick(drm_mach64_private_t * dev_priv, ++ drm_mach64_descriptor_ring_t * ring) ++{ ++ DRM_DEBUG("head_addr: 0x%08x head: %d tail: %d space: %d\n", ++ ring->head_addr, ring->head, ring->tail, ring->space); ++ ++ if (!dev_priv->ring_running) { ++ mach64_ring_start(dev_priv); ++ ++ if (ring->head != ring->tail) { ++ mach64_ring_resume(dev_priv, ring); ++ } ++ } else { ++ /* GUI_ACTIVE must be read before BM_GUI_TABLE to ++ * correctly determine the ring head ++ */ ++ int gui_active = ++ MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE; ++ ++ ring->head_addr = MACH64_READ(MACH64_BM_GUI_TABLE) & 0xfffffff0; ++ ++ if (gui_active) { ++ /* If not idle, BM_GUI_TABLE points one descriptor ++ * past the current head ++ */ ++ if (ring->head_addr == ring->start_addr) { ++ ring->head_addr += ring->size; ++ } ++ ring->head_addr -= 4 * sizeof(u32); ++ } ++ ++ if (ring->head_addr < ring->start_addr || ++ ring->head_addr >= ring->start_addr + ring->size) { ++ DRM_ERROR("bad ring head address: 0x%08x\n", ++ ring->head_addr); ++ mach64_dump_ring_info(dev_priv); ++ mach64_do_engine_reset(dev_priv); ++ return; ++ } ++ ++ ring->head = (ring->head_addr - ring->start_addr) / sizeof(u32); ++ ++ if (!gui_active && ring->head != ring->tail) { ++ mach64_ring_resume(dev_priv, ring); ++ } ++ } ++} ++ ++static __inline__ void mach64_ring_stop(drm_mach64_private_t * dev_priv) ++{ ++ DRM_DEBUG("head_addr: 0x%08x head: %d tail: %d space: %d\n", ++ dev_priv->ring.head_addr, dev_priv->ring.head, ++ dev_priv->ring.tail, dev_priv->ring.space); ++ ++ /* restore previous SRC_CNTL to disable busmastering */ ++ mach64_do_wait_for_fifo(dev_priv, 1); ++ MACH64_WRITE(MACH64_SRC_CNTL, 0); ++ ++ /* disable busmastering but keep the block 1 registers enabled */ ++ mach64_do_wait_for_idle(dev_priv); ++ MACH64_WRITE(MACH64_BUS_CNTL, MACH64_READ(MACH64_BUS_CNTL) ++ | MACH64_BUS_MASTER_DIS | MACH64_BUS_EXT_REG_EN); ++ ++ dev_priv->ring_running = 0; ++} ++ ++static __inline__ void ++mach64_update_ring_snapshot(drm_mach64_private_t * dev_priv) ++{ ++ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; ++ ++ DRM_DEBUG("\n"); ++ ++ mach64_ring_tick(dev_priv, ring); ++ ++ ring->space = (ring->head - ring->tail) * sizeof(u32); ++ if (ring->space <= 0) { ++ ring->space += ring->size; ++ } ++} ++ ++/* ================================================================ ++ * DMA macros ++ * ++ * Mach64's ring buffer doesn't take register writes directly. These ++ * have to be written indirectly in DMA buffers. These macros simplify ++ * the task of setting up a buffer, writing commands to it, and ++ * queuing the buffer in the ring. ++ */ ++ ++#define DMALOCALS \ ++ drm_mach64_freelist_t *_entry = NULL; \ ++ struct drm_buf *_buf = NULL; \ ++ u32 *_buf_wptr; int _outcount ++ ++#define GETBUFPTR( __buf ) \ ++((dev_priv->is_pci) ? \ ++ ((u32 *)(__buf)->address) : \ ++ ((u32 *)((char *)dev_priv->dev_buffers->handle + (__buf)->offset))) ++ ++#define GETBUFADDR( __buf ) ((u32)(__buf)->bus_address) ++ ++#define GETRINGOFFSET() (_entry->ring_ofs) ++ ++static __inline__ int mach64_find_pending_buf_entry(drm_mach64_private_t * ++ dev_priv, ++ drm_mach64_freelist_t ** ++ entry, struct drm_buf * buf) ++{ ++ struct list_head *ptr; ++#if MACH64_EXTRA_CHECKING ++ if (list_empty(&dev_priv->pending)) { ++ DRM_ERROR("Empty pending list in \n"); ++ return -EINVAL; ++ } ++#endif ++ ptr = dev_priv->pending.prev; ++ *entry = list_entry(ptr, drm_mach64_freelist_t, list); ++ while ((*entry)->buf != buf) { ++ if (ptr == &dev_priv->pending) { ++ return -EFAULT; ++ } ++ ptr = ptr->prev; ++ *entry = list_entry(ptr, drm_mach64_freelist_t, list); ++ } ++ return 0; ++} ++ ++#define DMASETPTR( _p ) \ ++do { \ ++ _buf = (_p); \ ++ _outcount = 0; \ ++ _buf_wptr = GETBUFPTR( _buf ); \ ++} while(0) ++ ++/* FIXME: use a private set of smaller buffers for state emits, clears, and swaps? */ ++#define DMAGETPTR( file_priv, dev_priv, n ) \ ++do { \ ++ if ( MACH64_VERBOSE ) { \ ++ DRM_INFO( "DMAGETPTR( %d )\n", (n) ); \ ++ } \ ++ _buf = mach64_freelist_get( dev_priv ); \ ++ if (_buf == NULL) { \ ++ DRM_ERROR("couldn't get buffer in DMAGETPTR\n"); \ ++ return -EAGAIN; \ ++ } \ ++ if (_buf->pending) { \ ++ DRM_ERROR("pending buf in DMAGETPTR\n"); \ ++ return -EFAULT; \ ++ } \ ++ _buf->file_priv = file_priv; \ ++ _outcount = 0; \ ++ \ ++ _buf_wptr = GETBUFPTR( _buf ); \ ++} while (0) ++ ++#define DMAOUTREG( reg, val ) \ ++do { \ ++ if ( MACH64_VERBOSE ) { \ ++ DRM_INFO( " DMAOUTREG( 0x%x = 0x%08x )\n", \ ++ reg, val ); \ ++ } \ ++ _buf_wptr[_outcount++] = cpu_to_le32(DMAREG(reg)); \ ++ _buf_wptr[_outcount++] = cpu_to_le32((val)); \ ++ _buf->used += 8; \ ++} while (0) ++ ++#define DMAADVANCE( dev_priv, _discard ) \ ++ do { \ ++ struct list_head *ptr; \ ++ int ret; \ ++ \ ++ if ( MACH64_VERBOSE ) { \ ++ DRM_INFO( "DMAADVANCE() in \n" ); \ ++ } \ ++ \ ++ if (_buf->used <= 0) { \ ++ DRM_ERROR( "DMAADVANCE(): sending empty buf %d\n", \ ++ _buf->idx ); \ ++ return -EFAULT; \ ++ } \ ++ if (_buf->pending) { \ ++ /* This is a resued buffer, so we need to find it in the pending list */ \ ++ if ((ret = mach64_find_pending_buf_entry(dev_priv, &_entry, _buf))) { \ ++ DRM_ERROR( "DMAADVANCE(): couldn't find pending buf %d\n", _buf->idx ); \ ++ return ret; \ ++ } \ ++ if (_entry->discard) { \ ++ DRM_ERROR( "DMAADVANCE(): sending discarded pending buf %d\n", _buf->idx ); \ ++ return -EFAULT; \ ++ } \ ++ } else { \ ++ if (list_empty(&dev_priv->placeholders)) { \ ++ DRM_ERROR( "DMAADVANCE(): empty placeholder list\n"); \ ++ return -EFAULT; \ ++ } \ ++ ptr = dev_priv->placeholders.next; \ ++ list_del(ptr); \ ++ _entry = list_entry(ptr, drm_mach64_freelist_t, list); \ ++ _buf->pending = 1; \ ++ _entry->buf = _buf; \ ++ list_add_tail(ptr, &dev_priv->pending); \ ++ } \ ++ _entry->discard = (_discard); \ ++ if ((ret = mach64_add_buf_to_ring( dev_priv, _entry ))) \ ++ return ret; \ ++ } while (0) ++ ++#define DMADISCARDBUF() \ ++ do { \ ++ if (_entry == NULL) { \ ++ int ret; \ ++ if ((ret = mach64_find_pending_buf_entry(dev_priv, &_entry, _buf))) { \ ++ DRM_ERROR( "couldn't find pending buf %d\n", \ ++ _buf->idx ); \ ++ return ret; \ ++ } \ ++ } \ ++ _entry->discard = 1; \ ++ } while(0) ++ ++#define DMAADVANCEHOSTDATA( dev_priv ) \ ++ do { \ ++ struct list_head *ptr; \ ++ int ret; \ ++ \ ++ if ( MACH64_VERBOSE ) { \ ++ DRM_INFO( "DMAADVANCEHOSTDATA() in \n" ); \ ++ } \ ++ \ ++ if (_buf->used <= 0) { \ ++ DRM_ERROR( "DMAADVANCEHOSTDATA(): sending empty buf %d\n", _buf->idx ); \ ++ return -EFAULT; \ ++ } \ ++ if (list_empty(&dev_priv->placeholders)) { \ ++ DRM_ERROR( "empty placeholder list in DMAADVANCEHOSTDATA()\n" ); \ ++ return -EFAULT; \ ++ } \ ++ \ ++ ptr = dev_priv->placeholders.next; \ ++ list_del(ptr); \ ++ _entry = list_entry(ptr, drm_mach64_freelist_t, list); \ ++ _entry->buf = _buf; \ ++ _entry->buf->pending = 1; \ ++ list_add_tail(ptr, &dev_priv->pending); \ ++ _entry->discard = 1; \ ++ if ((ret = mach64_add_hostdata_buf_to_ring( dev_priv, _entry ))) \ ++ return ret; \ ++ } while (0) ++ ++#endif /* __MACH64_DRV_H__ */ +--- /dev/null ++++ b/drivers/gpu/drm/mach64/mach64_irq.c +@@ -0,0 +1,159 @@ ++/* mach64_irq.c -- IRQ handling for ATI Mach64 -*- linux-c -*- ++ * Created: Tue Feb 25, 2003 by Leif Delgass, based on radeon_irq.c/r128_irq.c ++ */ ++/*- ++ * Copyright (C) The Weather Channel, Inc. 2002. ++ * Copyright 2003 Leif Delgass ++ * All Rights Reserved. ++ * ++ * The Weather Channel (TM) funded Tungsten Graphics to develop the ++ * initial release of the Radeon 8500 driver under the XFree86 license. ++ * This notice must be preserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: ++ * Keith Whitwell ++ * Eric Anholt ++ * Leif Delgass ++ */ ++ ++#include "drmP.h" ++#include "drm.h" ++#include "mach64_drm.h" ++#include "mach64_drv.h" ++ ++irqreturn_t mach64_driver_irq_handler(DRM_IRQ_ARGS) ++{ ++ struct drm_device *dev = arg; ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ int status; ++ ++ status = MACH64_READ(MACH64_CRTC_INT_CNTL); ++ ++ /* VBLANK interrupt */ ++ if (status & MACH64_CRTC_VBLANK_INT) { ++ /* Mask off all interrupt ack bits before setting the ack bit, since ++ * there may be other handlers outside the DRM. ++ * ++ * NOTE: On mach64, you need to keep the enable bits set when doing ++ * the ack, despite what the docs say about not acking and enabling ++ * in a single write. ++ */ ++ MACH64_WRITE(MACH64_CRTC_INT_CNTL, ++ (status & ~MACH64_CRTC_INT_ACKS) ++ | MACH64_CRTC_VBLANK_INT); ++ ++ atomic_inc(&dev_priv->vbl_received); ++ drm_handle_vblank(dev, 0); ++ return IRQ_HANDLED; ++ } ++ return IRQ_NONE; ++} ++ ++u32 mach64_get_vblank_counter(struct drm_device * dev, int crtc) ++{ ++ const drm_mach64_private_t *const dev_priv = dev->dev_private; ++ ++ if (crtc != 0) ++ return 0; ++ ++ return atomic_read(&dev_priv->vbl_received); ++} ++ ++int mach64_enable_vblank(struct drm_device * dev, int crtc) ++{ ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL); ++ ++ if (crtc != 0) { ++ DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", ++ crtc); ++ return -EINVAL; ++ } ++ ++ DRM_DEBUG("before enable vblank CRTC_INT_CTNL: 0x%08x\n", status); ++ ++ /* Turn on VBLANK interrupt */ ++ MACH64_WRITE(MACH64_CRTC_INT_CNTL, MACH64_READ(MACH64_CRTC_INT_CNTL) ++ | MACH64_CRTC_VBLANK_INT_EN); ++ ++ return 0; ++} ++ ++void mach64_disable_vblank(struct drm_device * dev, int crtc) ++{ ++ if (crtc != 0) { ++ DRM_ERROR("tried to disable vblank on non-existent crtc %d\n", ++ crtc); ++ return; ++ } ++ ++ /* ++ * FIXME: implement proper interrupt disable by using the vblank ++ * counter register (if available). ++ */ ++} ++ ++static void mach64_disable_vblank_local(struct drm_device * dev, int crtc) ++{ ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL); ++ ++ if (crtc != 0) { ++ DRM_ERROR("tried to disable vblank on non-existent crtc %d\n", ++ crtc); ++ return; ++ } ++ ++ DRM_DEBUG("before disable vblank CRTC_INT_CTNL: 0x%08x\n", status); ++ ++ /* Disable and clear VBLANK interrupt */ ++ MACH64_WRITE(MACH64_CRTC_INT_CNTL, (status & ~MACH64_CRTC_VBLANK_INT_EN) ++ | MACH64_CRTC_VBLANK_INT); ++} ++ ++void mach64_driver_irq_preinstall(struct drm_device * dev) ++{ ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ ++ u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL); ++ ++ DRM_DEBUG("before install CRTC_INT_CTNL: 0x%08x\n", status); ++ ++ mach64_disable_vblank_local(dev, 0); ++} ++ ++int mach64_driver_irq_postinstall(struct drm_device * dev) ++{ ++ return drm_vblank_init(dev, 1); ++} ++ ++void mach64_driver_irq_uninstall(struct drm_device * dev) ++{ ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ if (!dev_priv) ++ return; ++ ++ mach64_disable_vblank_local(dev, 0); ++ ++ DRM_DEBUG("after uninstall CRTC_INT_CTNL: 0x%08x\n", ++ MACH64_READ(MACH64_CRTC_INT_CNTL)); ++} +--- /dev/null ++++ b/drivers/gpu/drm/mach64/mach64_state.c +@@ -0,0 +1,910 @@ ++/* mach64_state.c -- State support for mach64 (Rage Pro) driver -*- linux-c -*- ++ * Created: Sun Dec 03 19:20:26 2000 by gareth@valinux.com ++ */ ++/* ++ * Copyright 2000 Gareth Hughes ++ * Copyright 2002-2003 Leif Delgass ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT OWNER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER ++ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: ++ * Gareth Hughes ++ * Leif Delgass ++ * José Fonseca ++ */ ++ ++#include "drmP.h" ++#include "drm.h" ++#include "mach64_drm.h" ++#include "mach64_drv.h" ++ ++/* Interface history: ++ * ++ * 1.0 - Initial mach64 DRM ++ * ++ */ ++struct drm_ioctl_desc mach64_ioctls[] = { ++ DRM_IOCTL_DEF(DRM_MACH64_INIT, mach64_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), ++ DRM_IOCTL_DEF(DRM_MACH64_CLEAR, mach64_dma_clear, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_MACH64_SWAP, mach64_dma_swap, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_MACH64_IDLE, mach64_dma_idle, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_MACH64_RESET, mach64_engine_reset, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_MACH64_VERTEX, mach64_dma_vertex, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_MACH64_BLIT, mach64_dma_blit, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_MACH64_FLUSH, mach64_dma_flush, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_MACH64_GETPARAM, mach64_get_param, DRM_AUTH), ++}; ++ ++int mach64_max_ioctl = DRM_ARRAY_SIZE(mach64_ioctls); ++ ++/* ================================================================ ++ * DMA hardware state programming functions ++ */ ++ ++static void mach64_print_dirty(const char *msg, unsigned int flags) ++{ ++ DRM_DEBUG("%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s\n", ++ msg, ++ flags, ++ (flags & MACH64_UPLOAD_DST_OFF_PITCH) ? "dst_off_pitch, " : ++ "", ++ (flags & MACH64_UPLOAD_Z_ALPHA_CNTL) ? "z_alpha_cntl, " : "", ++ (flags & MACH64_UPLOAD_SCALE_3D_CNTL) ? "scale_3d_cntl, " : ++ "", (flags & MACH64_UPLOAD_DP_FOG_CLR) ? "dp_fog_clr, " : "", ++ (flags & MACH64_UPLOAD_DP_WRITE_MASK) ? "dp_write_mask, " : ++ "", ++ (flags & MACH64_UPLOAD_DP_PIX_WIDTH) ? "dp_pix_width, " : "", ++ (flags & MACH64_UPLOAD_SETUP_CNTL) ? "setup_cntl, " : "", ++ (flags & MACH64_UPLOAD_MISC) ? "misc, " : "", ++ (flags & MACH64_UPLOAD_TEXTURE) ? "texture, " : "", ++ (flags & MACH64_UPLOAD_TEX0IMAGE) ? "tex0 image, " : "", ++ (flags & MACH64_UPLOAD_TEX1IMAGE) ? "tex1 image, " : "", ++ (flags & MACH64_UPLOAD_CLIPRECTS) ? "cliprects, " : ""); ++} ++ ++/* Mach64 doesn't have hardware cliprects, just one hardware scissor, ++ * so the GL scissor is intersected with each cliprect here ++ */ ++/* This function returns 0 on success, 1 for no intersection, and ++ * negative for an error ++ */ ++static int mach64_emit_cliprect(struct drm_file *file_priv, ++ drm_mach64_private_t * dev_priv, ++ struct drm_clip_rect * box) ++{ ++ u32 sc_left_right, sc_top_bottom; ++ struct drm_clip_rect scissor; ++ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; ++ drm_mach64_context_regs_t *regs = &sarea_priv->context_state; ++ DMALOCALS; ++ ++ DRM_DEBUG("box=%p\n", box); ++ ++ /* Get GL scissor */ ++ /* FIXME: store scissor in SAREA as a cliprect instead of in ++ * hardware format, or do intersection client-side ++ */ ++ scissor.x1 = regs->sc_left_right & 0xffff; ++ scissor.x2 = (regs->sc_left_right & 0xffff0000) >> 16; ++ scissor.y1 = regs->sc_top_bottom & 0xffff; ++ scissor.y2 = (regs->sc_top_bottom & 0xffff0000) >> 16; ++ ++ /* Intersect GL scissor with cliprect */ ++ if (box->x1 > scissor.x1) ++ scissor.x1 = box->x1; ++ if (box->y1 > scissor.y1) ++ scissor.y1 = box->y1; ++ if (box->x2 < scissor.x2) ++ scissor.x2 = box->x2; ++ if (box->y2 < scissor.y2) ++ scissor.y2 = box->y2; ++ /* positive return means skip */ ++ if (scissor.x1 >= scissor.x2) ++ return 1; ++ if (scissor.y1 >= scissor.y2) ++ return 1; ++ ++ DMAGETPTR(file_priv, dev_priv, 2); /* returns on failure to get buffer */ ++ ++ sc_left_right = ((scissor.x1 << 0) | (scissor.x2 << 16)); ++ sc_top_bottom = ((scissor.y1 << 0) | (scissor.y2 << 16)); ++ ++ DMAOUTREG(MACH64_SC_LEFT_RIGHT, sc_left_right); ++ DMAOUTREG(MACH64_SC_TOP_BOTTOM, sc_top_bottom); ++ ++ DMAADVANCE(dev_priv, 1); ++ ++ return 0; ++} ++ ++static __inline__ int mach64_emit_state(struct drm_file *file_priv, ++ drm_mach64_private_t * dev_priv) ++{ ++ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; ++ drm_mach64_context_regs_t *regs = &sarea_priv->context_state; ++ unsigned int dirty = sarea_priv->dirty; ++ u32 offset = ((regs->tex_size_pitch & 0xf0) >> 2); ++ DMALOCALS; ++ ++ if (MACH64_VERBOSE) { ++ mach64_print_dirty(__FUNCTION__, dirty); ++ } else { ++ DRM_DEBUG("dirty=0x%08x\n", dirty); ++ } ++ ++ DMAGETPTR(file_priv, dev_priv, 17); /* returns on failure to get buffer */ ++ ++ if (dirty & MACH64_UPLOAD_MISC) { ++ DMAOUTREG(MACH64_DP_MIX, regs->dp_mix); ++ DMAOUTREG(MACH64_DP_SRC, regs->dp_src); ++ DMAOUTREG(MACH64_CLR_CMP_CNTL, regs->clr_cmp_cntl); ++ DMAOUTREG(MACH64_GUI_TRAJ_CNTL, regs->gui_traj_cntl); ++ sarea_priv->dirty &= ~MACH64_UPLOAD_MISC; ++ } ++ ++ if (dirty & MACH64_UPLOAD_DST_OFF_PITCH) { ++ DMAOUTREG(MACH64_DST_OFF_PITCH, regs->dst_off_pitch); ++ sarea_priv->dirty &= ~MACH64_UPLOAD_DST_OFF_PITCH; ++ } ++ if (dirty & MACH64_UPLOAD_Z_OFF_PITCH) { ++ DMAOUTREG(MACH64_Z_OFF_PITCH, regs->z_off_pitch); ++ sarea_priv->dirty &= ~MACH64_UPLOAD_Z_OFF_PITCH; ++ } ++ if (dirty & MACH64_UPLOAD_Z_ALPHA_CNTL) { ++ DMAOUTREG(MACH64_Z_CNTL, regs->z_cntl); ++ DMAOUTREG(MACH64_ALPHA_TST_CNTL, regs->alpha_tst_cntl); ++ sarea_priv->dirty &= ~MACH64_UPLOAD_Z_ALPHA_CNTL; ++ } ++ if (dirty & MACH64_UPLOAD_SCALE_3D_CNTL) { ++ DMAOUTREG(MACH64_SCALE_3D_CNTL, regs->scale_3d_cntl); ++ sarea_priv->dirty &= ~MACH64_UPLOAD_SCALE_3D_CNTL; ++ } ++ if (dirty & MACH64_UPLOAD_DP_FOG_CLR) { ++ DMAOUTREG(MACH64_DP_FOG_CLR, regs->dp_fog_clr); ++ sarea_priv->dirty &= ~MACH64_UPLOAD_DP_FOG_CLR; ++ } ++ if (dirty & MACH64_UPLOAD_DP_WRITE_MASK) { ++ DMAOUTREG(MACH64_DP_WRITE_MASK, regs->dp_write_mask); ++ sarea_priv->dirty &= ~MACH64_UPLOAD_DP_WRITE_MASK; ++ } ++ if (dirty & MACH64_UPLOAD_DP_PIX_WIDTH) { ++ DMAOUTREG(MACH64_DP_PIX_WIDTH, regs->dp_pix_width); ++ sarea_priv->dirty &= ~MACH64_UPLOAD_DP_PIX_WIDTH; ++ } ++ if (dirty & MACH64_UPLOAD_SETUP_CNTL) { ++ DMAOUTREG(MACH64_SETUP_CNTL, regs->setup_cntl); ++ sarea_priv->dirty &= ~MACH64_UPLOAD_SETUP_CNTL; ++ } ++ ++ if (dirty & MACH64_UPLOAD_TEXTURE) { ++ DMAOUTREG(MACH64_TEX_SIZE_PITCH, regs->tex_size_pitch); ++ DMAOUTREG(MACH64_TEX_CNTL, regs->tex_cntl); ++ DMAOUTREG(MACH64_SECONDARY_TEX_OFF, regs->secondary_tex_off); ++ DMAOUTREG(MACH64_TEX_0_OFF + offset, regs->tex_offset); ++ sarea_priv->dirty &= ~MACH64_UPLOAD_TEXTURE; ++ } ++ ++ DMAADVANCE(dev_priv, 1); ++ ++ sarea_priv->dirty &= MACH64_UPLOAD_CLIPRECTS; ++ ++ return 0; ++ ++} ++ ++/* ================================================================ ++ * DMA command dispatch functions ++ */ ++ ++static int mach64_dma_dispatch_clear(struct drm_device * dev, ++ struct drm_file *file_priv, ++ unsigned int flags, ++ int cx, int cy, int cw, int ch, ++ unsigned int clear_color, ++ unsigned int clear_depth) ++{ ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; ++ drm_mach64_context_regs_t *ctx = &sarea_priv->context_state; ++ int nbox = sarea_priv->nbox; ++ struct drm_clip_rect *pbox = sarea_priv->boxes; ++ u32 fb_bpp, depth_bpp; ++ int i; ++ DMALOCALS; ++ ++ DRM_DEBUG("\n"); ++ ++ switch (dev_priv->fb_bpp) { ++ case 16: ++ fb_bpp = MACH64_DATATYPE_RGB565; ++ break; ++ case 32: ++ fb_bpp = MACH64_DATATYPE_ARGB8888; ++ break; ++ default: ++ return -EINVAL; ++ } ++ switch (dev_priv->depth_bpp) { ++ case 16: ++ depth_bpp = MACH64_DATATYPE_RGB565; ++ break; ++ case 24: ++ case 32: ++ depth_bpp = MACH64_DATATYPE_ARGB8888; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (!nbox) ++ return 0; ++ ++ DMAGETPTR(file_priv, dev_priv, nbox * 31); /* returns on failure to get buffer */ ++ ++ for (i = 0; i < nbox; i++) { ++ int x = pbox[i].x1; ++ int y = pbox[i].y1; ++ int w = pbox[i].x2 - x; ++ int h = pbox[i].y2 - y; ++ ++ DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n", ++ pbox[i].x1, pbox[i].y1, ++ pbox[i].x2, pbox[i].y2, flags); ++ ++ if (flags & (MACH64_FRONT | MACH64_BACK)) { ++ /* Setup for color buffer clears ++ */ ++ ++ DMAOUTREG(MACH64_Z_CNTL, 0); ++ DMAOUTREG(MACH64_SCALE_3D_CNTL, 0); ++ ++ DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right); ++ DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom); ++ ++ DMAOUTREG(MACH64_CLR_CMP_CNTL, 0); ++ DMAOUTREG(MACH64_GUI_TRAJ_CNTL, ++ (MACH64_DST_X_LEFT_TO_RIGHT | ++ MACH64_DST_Y_TOP_TO_BOTTOM)); ++ ++ DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) | ++ (fb_bpp << 4) | ++ (fb_bpp << 8) | ++ (fb_bpp << 16) | ++ (fb_bpp << 28))); ++ ++ DMAOUTREG(MACH64_DP_FRGD_CLR, clear_color); ++ DMAOUTREG(MACH64_DP_WRITE_MASK, ctx->dp_write_mask); ++ DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | ++ MACH64_FRGD_MIX_S)); ++ DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR | ++ MACH64_FRGD_SRC_FRGD_CLR | ++ MACH64_MONO_SRC_ONE)); ++ ++ } ++ ++ if (flags & MACH64_FRONT) { ++ ++ DMAOUTREG(MACH64_DST_OFF_PITCH, ++ dev_priv->front_offset_pitch); ++ DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x); ++ DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w); ++ ++ } ++ ++ if (flags & MACH64_BACK) { ++ ++ DMAOUTREG(MACH64_DST_OFF_PITCH, ++ dev_priv->back_offset_pitch); ++ DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x); ++ DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w); ++ ++ } ++ ++ if (flags & MACH64_DEPTH) { ++ /* Setup for depth buffer clear ++ */ ++ DMAOUTREG(MACH64_Z_CNTL, 0); ++ DMAOUTREG(MACH64_SCALE_3D_CNTL, 0); ++ ++ DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right); ++ DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom); ++ ++ DMAOUTREG(MACH64_CLR_CMP_CNTL, 0); ++ DMAOUTREG(MACH64_GUI_TRAJ_CNTL, ++ (MACH64_DST_X_LEFT_TO_RIGHT | ++ MACH64_DST_Y_TOP_TO_BOTTOM)); ++ ++ DMAOUTREG(MACH64_DP_PIX_WIDTH, ((depth_bpp << 0) | ++ (depth_bpp << 4) | ++ (depth_bpp << 8) | ++ (depth_bpp << 16) | ++ (depth_bpp << 28))); ++ ++ DMAOUTREG(MACH64_DP_FRGD_CLR, clear_depth); ++ DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff); ++ DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | ++ MACH64_FRGD_MIX_S)); ++ DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR | ++ MACH64_FRGD_SRC_FRGD_CLR | ++ MACH64_MONO_SRC_ONE)); ++ ++ DMAOUTREG(MACH64_DST_OFF_PITCH, ++ dev_priv->depth_offset_pitch); ++ DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x); ++ DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w); ++ } ++ } ++ ++ DMAADVANCE(dev_priv, 1); ++ ++ return 0; ++} ++ ++static int mach64_dma_dispatch_swap(struct drm_device * dev, ++ struct drm_file *file_priv) ++{ ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; ++ int nbox = sarea_priv->nbox; ++ struct drm_clip_rect *pbox = sarea_priv->boxes; ++ u32 fb_bpp; ++ int i; ++ DMALOCALS; ++ ++ DRM_DEBUG("\n"); ++ ++ switch (dev_priv->fb_bpp) { ++ case 16: ++ fb_bpp = MACH64_DATATYPE_RGB565; ++ break; ++ case 32: ++ default: ++ fb_bpp = MACH64_DATATYPE_ARGB8888; ++ break; ++ } ++ ++ if (!nbox) ++ return 0; ++ ++ DMAGETPTR(file_priv, dev_priv, 13 + nbox * 4); /* returns on failure to get buffer */ ++ ++ DMAOUTREG(MACH64_Z_CNTL, 0); ++ DMAOUTREG(MACH64_SCALE_3D_CNTL, 0); ++ ++ DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16)); /* no scissor */ ++ DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16)); ++ ++ DMAOUTREG(MACH64_CLR_CMP_CNTL, 0); ++ DMAOUTREG(MACH64_GUI_TRAJ_CNTL, (MACH64_DST_X_LEFT_TO_RIGHT | ++ MACH64_DST_Y_TOP_TO_BOTTOM)); ++ ++ DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) | ++ (fb_bpp << 4) | ++ (fb_bpp << 8) | ++ (fb_bpp << 16) | (fb_bpp << 28))); ++ ++ DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff); ++ DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S)); ++ DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_BKGD_CLR | ++ MACH64_FRGD_SRC_BLIT | MACH64_MONO_SRC_ONE)); ++ ++ DMAOUTREG(MACH64_SRC_OFF_PITCH, dev_priv->back_offset_pitch); ++ DMAOUTREG(MACH64_DST_OFF_PITCH, dev_priv->front_offset_pitch); ++ ++ for (i = 0; i < nbox; i++) { ++ int x = pbox[i].x1; ++ int y = pbox[i].y1; ++ int w = pbox[i].x2 - x; ++ int h = pbox[i].y2 - y; ++ ++ DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", ++ pbox[i].x1, pbox[i].y1, pbox[i].x2, pbox[i].y2); ++ ++ DMAOUTREG(MACH64_SRC_WIDTH1, w); ++ DMAOUTREG(MACH64_SRC_Y_X, (x << 16) | y); ++ DMAOUTREG(MACH64_DST_Y_X, (x << 16) | y); ++ DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w); ++ ++ } ++ ++ DMAADVANCE(dev_priv, 1); ++ ++ if (dev_priv->driver_mode == MACH64_MODE_DMA_ASYNC) { ++ for (i = 0; i < MACH64_MAX_QUEUED_FRAMES - 1; i++) { ++ dev_priv->frame_ofs[i] = dev_priv->frame_ofs[i + 1]; ++ } ++ dev_priv->frame_ofs[i] = GETRINGOFFSET(); ++ ++ dev_priv->sarea_priv->frames_queued++; ++ } ++ ++ return 0; ++} ++ ++static int mach64_do_get_frames_queued(drm_mach64_private_t * dev_priv) ++{ ++ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; ++ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; ++ int i, start; ++ u32 head, tail, ofs; ++ ++ DRM_DEBUG("\n"); ++ ++ if (sarea_priv->frames_queued == 0) ++ return 0; ++ ++ tail = ring->tail; ++ mach64_ring_tick(dev_priv, ring); ++ head = ring->head; ++ ++ start = (MACH64_MAX_QUEUED_FRAMES - ++ DRM_MIN(MACH64_MAX_QUEUED_FRAMES, sarea_priv->frames_queued)); ++ ++ if (head == tail) { ++ sarea_priv->frames_queued = 0; ++ for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) { ++ dev_priv->frame_ofs[i] = ~0; ++ } ++ return 0; ++ } ++ ++ for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) { ++ ofs = dev_priv->frame_ofs[i]; ++ DRM_DEBUG("frame_ofs[%d] ofs: %d\n", i, ofs); ++ if (ofs == ~0 || ++ (head < tail && (ofs < head || ofs >= tail)) || ++ (head > tail && (ofs < head && ofs >= tail))) { ++ sarea_priv->frames_queued = ++ (MACH64_MAX_QUEUED_FRAMES - 1) - i; ++ dev_priv->frame_ofs[i] = ~0; ++ } ++ } ++ ++ return sarea_priv->frames_queued; ++} ++ ++/* Copy and verify a client submited buffer. ++ * FIXME: Make an assembly optimized version ++ */ ++static __inline__ int copy_from_user_vertex(u32 *to, ++ const u32 __user *ufrom, ++ unsigned long bytes) ++{ ++ unsigned long n = bytes; /* dwords remaining in buffer */ ++ u32 *from, *orig_from; ++ ++ from = drm_alloc(bytes, DRM_MEM_DRIVER); ++ if (from == NULL) ++ return -ENOMEM; ++ ++ if (DRM_COPY_FROM_USER(from, ufrom, bytes)) { ++ drm_free(from, bytes, DRM_MEM_DRIVER); ++ return -EFAULT; ++ } ++ orig_from = from; /* we'll be modifying the "from" ptr, so save it */ ++ ++ n >>= 2; ++ ++ while (n > 1) { ++ u32 data, reg, count; ++ ++ data = *from++; ++ ++ n--; ++ ++ reg = le32_to_cpu(data); ++ count = (reg >> 16) + 1; ++ if (count <= n) { ++ n -= count; ++ reg &= 0xffff; ++ ++ /* This is an exact match of Mach64's Setup Engine registers, ++ * excluding SETUP_CNTL (1_C1). ++ */ ++ if ((reg >= 0x0190 && reg < 0x01c1) || ++ (reg >= 0x01ca && reg <= 0x01cf)) { ++ *to++ = data; ++ memcpy(to, from, count << 2); ++ from += count; ++ to += count; ++ } else { ++ DRM_ERROR("Got bad command: 0x%04x\n", reg); ++ drm_free(orig_from, bytes, DRM_MEM_DRIVER); ++ return -EACCES; ++ } ++ } else { ++ DRM_ERROR ++ ("Got bad command count(=%u) dwords remaining=%lu\n", ++ count, n); ++ drm_free(orig_from, bytes, DRM_MEM_DRIVER); ++ return -EINVAL; ++ } ++ } ++ ++ drm_free(orig_from, bytes, DRM_MEM_DRIVER); ++ if (n == 0) ++ return 0; ++ else { ++ DRM_ERROR("Bad buf->used(=%lu)\n", bytes); ++ return -EINVAL; ++ } ++} ++ ++static int mach64_dma_dispatch_vertex(struct drm_device * dev, ++ struct drm_file *file_priv, ++ drm_mach64_vertex_t * vertex) ++{ ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; ++ struct drm_buf *copy_buf; ++ void *buf = vertex->buf; ++ unsigned long used = vertex->used; ++ int ret = 0; ++ int i = 0; ++ int done = 0; ++ int verify_ret = 0; ++ DMALOCALS; ++ ++ DRM_DEBUG("buf=%p used=%lu nbox=%d\n", ++ buf, used, sarea_priv->nbox); ++ ++ if (!used) ++ goto _vertex_done; ++ ++ copy_buf = mach64_freelist_get(dev_priv); ++ if (copy_buf == NULL) { ++ DRM_ERROR("couldn't get buffer\n"); ++ return -EAGAIN; ++ } ++ ++ /* Mach64's vertex data is actually register writes. To avoid security ++ * compromises these register writes have to be verified and copied from ++ * user space into a private DMA buffer. ++ */ ++ verify_ret = copy_from_user_vertex(GETBUFPTR(copy_buf), buf, used); ++ ++ if (verify_ret != 0) { ++ mach64_freelist_put(dev_priv, copy_buf); ++ goto _vertex_done; ++ } ++ ++ copy_buf->used = used; ++ ++ DMASETPTR(copy_buf); ++ ++ if (sarea_priv->dirty & ~MACH64_UPLOAD_CLIPRECTS) { ++ ret = mach64_emit_state(file_priv, dev_priv); ++ if (ret < 0) ++ return ret; ++ } ++ ++ do { ++ /* Emit the next cliprect */ ++ if (i < sarea_priv->nbox) { ++ ret = mach64_emit_cliprect(file_priv, dev_priv, ++ &sarea_priv->boxes[i]); ++ if (ret < 0) { ++ /* failed to get buffer */ ++ return ret; ++ } else if (ret != 0) { ++ /* null intersection with scissor */ ++ continue; ++ } ++ } ++ if ((i >= sarea_priv->nbox - 1)) ++ done = 1; ++ ++ /* Add the buffer to the DMA queue */ ++ DMAADVANCE(dev_priv, done); ++ ++ } while (++i < sarea_priv->nbox); ++ ++ if (!done) { ++ if (copy_buf->pending) { ++ DMADISCARDBUF(); ++ } else { ++ /* This buffer wasn't used (no cliprects), so place it ++ * back on the free list ++ */ ++ mach64_freelist_put(dev_priv, copy_buf); ++ } ++ } ++ ++_vertex_done: ++ sarea_priv->dirty &= ~MACH64_UPLOAD_CLIPRECTS; ++ sarea_priv->nbox = 0; ++ ++ return verify_ret; ++} ++ ++static __inline__ int copy_from_user_blit(u32 *to, ++ const u32 __user *ufrom, ++ unsigned long bytes) ++{ ++ to = (u32 *)((char *)to + MACH64_HOSTDATA_BLIT_OFFSET); ++ ++ if (DRM_COPY_FROM_USER(to, ufrom, bytes)) { ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++static int mach64_dma_dispatch_blit(struct drm_device * dev, ++ struct drm_file *file_priv, ++ drm_mach64_blit_t * blit) ++{ ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ int dword_shift, dwords; ++ unsigned long used; ++ struct drm_buf *copy_buf; ++ int verify_ret = 0; ++ DMALOCALS; ++ ++ /* The compiler won't optimize away a division by a variable, ++ * even if the only legal values are powers of two. Thus, we'll ++ * use a shift instead. ++ */ ++ switch (blit->format) { ++ case MACH64_DATATYPE_ARGB8888: ++ dword_shift = 0; ++ break; ++ case MACH64_DATATYPE_ARGB1555: ++ case MACH64_DATATYPE_RGB565: ++ case MACH64_DATATYPE_VYUY422: ++ case MACH64_DATATYPE_YVYU422: ++ case MACH64_DATATYPE_ARGB4444: ++ dword_shift = 1; ++ break; ++ case MACH64_DATATYPE_CI8: ++ case MACH64_DATATYPE_RGB8: ++ dword_shift = 2; ++ break; ++ default: ++ DRM_ERROR("invalid blit format %d\n", blit->format); ++ return -EINVAL; ++ } ++ ++ /* Set buf->used to the bytes of blit data based on the blit dimensions ++ * and verify the size. When the setup is emitted to the buffer with ++ * the DMA* macros below, buf->used is incremented to include the bytes ++ * used for setup as well as the blit data. ++ */ ++ dwords = (blit->width * blit->height) >> dword_shift; ++ used = dwords << 2; ++ if (used <= 0 || ++ used > MACH64_BUFFER_SIZE - MACH64_HOSTDATA_BLIT_OFFSET) { ++ DRM_ERROR("Invalid blit size: %lu bytes\n", used); ++ return -EINVAL; ++ } ++ ++ copy_buf = mach64_freelist_get(dev_priv); ++ if (copy_buf == NULL) { ++ DRM_ERROR("couldn't get buffer\n"); ++ return -EAGAIN; ++ } ++ ++ /* Copy the blit data from userspace. ++ * ++ * XXX: This is overkill. The most efficient solution would be having ++ * two sets of buffers (one set private for vertex data, the other set ++ * client-writable for blits). However that would bring more complexity ++ * and would break backward compatability. The solution currently ++ * implemented is keeping all buffers private, allowing to secure the ++ * driver, without increasing complexity at the expense of some speed ++ * transfering data. ++ */ ++ verify_ret = copy_from_user_blit(GETBUFPTR(copy_buf), blit->buf, used); ++ ++ if (verify_ret != 0) { ++ mach64_freelist_put(dev_priv, copy_buf); ++ goto _blit_done; ++ } ++ ++ copy_buf->used = used; ++ ++ /* FIXME: Use a last buffer flag and reduce the state emitted for subsequent, ++ * continuation buffers? ++ */ ++ ++ /* Blit via BM_HOSTDATA (gui-master) - like HOST_DATA[0-15], but doesn't require ++ * a register command every 16 dwords. State setup is added at the start of the ++ * buffer -- the client leaves space for this based on MACH64_HOSTDATA_BLIT_OFFSET ++ */ ++ DMASETPTR(copy_buf); ++ ++ DMAOUTREG(MACH64_Z_CNTL, 0); ++ DMAOUTREG(MACH64_SCALE_3D_CNTL, 0); ++ ++ DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16)); /* no scissor */ ++ DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16)); ++ ++ DMAOUTREG(MACH64_CLR_CMP_CNTL, 0); /* disable */ ++ DMAOUTREG(MACH64_GUI_TRAJ_CNTL, ++ MACH64_DST_X_LEFT_TO_RIGHT | MACH64_DST_Y_TOP_TO_BOTTOM); ++ ++ DMAOUTREG(MACH64_DP_PIX_WIDTH, (blit->format << 0) /* dst pix width */ ++ |(blit->format << 4) /* composite pix width */ ++ |(blit->format << 8) /* src pix width */ ++ |(blit->format << 16) /* host data pix width */ ++ |(blit->format << 28) /* scaler/3D pix width */ ++ ); ++ ++ DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff); /* enable all planes */ ++ DMAOUTREG(MACH64_DP_MIX, MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S); ++ DMAOUTREG(MACH64_DP_SRC, ++ MACH64_BKGD_SRC_BKGD_CLR ++ | MACH64_FRGD_SRC_HOST | MACH64_MONO_SRC_ONE); ++ ++ DMAOUTREG(MACH64_DST_OFF_PITCH, ++ (blit->pitch << 22) | (blit->offset >> 3)); ++ DMAOUTREG(MACH64_DST_X_Y, (blit->y << 16) | blit->x); ++ DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (blit->height << 16) | blit->width); ++ ++ DRM_DEBUG("%lu bytes\n", used); ++ ++ /* Add the buffer to the queue */ ++ DMAADVANCEHOSTDATA(dev_priv); ++ ++_blit_done: ++ return verify_ret; ++} ++ ++/* ================================================================ ++ * IOCTL functions ++ */ ++ ++int mach64_dma_clear(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; ++ drm_mach64_clear_t *clear = data; ++ int ret; ++ ++ DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); ++ ++ LOCK_TEST_WITH_RETURN(dev, file_priv); ++ ++ if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS) ++ sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS; ++ ++ ret = mach64_dma_dispatch_clear(dev, file_priv, clear->flags, ++ clear->x, clear->y, clear->w, clear->h, ++ clear->clear_color, ++ clear->clear_depth); ++ ++ /* Make sure we restore the 3D state next time. ++ */ ++ sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC); ++ return ret; ++} ++ ++int mach64_dma_swap(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; ++ int ret; ++ ++ DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); ++ ++ LOCK_TEST_WITH_RETURN(dev, file_priv); ++ ++ if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS) ++ sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS; ++ ++ ret = mach64_dma_dispatch_swap(dev, file_priv); ++ ++ /* Make sure we restore the 3D state next time. ++ */ ++ sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC); ++ return ret; ++} ++ ++int mach64_dma_vertex(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; ++ drm_mach64_vertex_t *vertex = data; ++ ++ LOCK_TEST_WITH_RETURN(dev, file_priv); ++ ++ if (!dev_priv) { ++ DRM_ERROR("called with no initialization\n"); ++ return -EINVAL; ++ } ++ ++ DRM_DEBUG("pid=%d buf=%p used=%lu discard=%d\n", ++ DRM_CURRENTPID, ++ vertex->buf, vertex->used, vertex->discard); ++ ++ if (vertex->prim < 0 || vertex->prim > MACH64_PRIM_POLYGON) { ++ DRM_ERROR("buffer prim %d\n", vertex->prim); ++ return -EINVAL; ++ } ++ ++ if (vertex->used > MACH64_BUFFER_SIZE || (vertex->used & 3) != 0) { ++ DRM_ERROR("Invalid vertex buffer size: %lu bytes\n", ++ vertex->used); ++ return -EINVAL; ++ } ++ ++ if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS) ++ sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS; ++ ++ return mach64_dma_dispatch_vertex(dev, file_priv, vertex); ++} ++ ++int mach64_dma_blit(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; ++ drm_mach64_blit_t *blit = data; ++ int ret; ++ ++ LOCK_TEST_WITH_RETURN(dev, file_priv); ++ ++ ret = mach64_dma_dispatch_blit(dev, file_priv, blit); ++ ++ /* Make sure we restore the 3D state next time. ++ */ ++ sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | ++ MACH64_UPLOAD_MISC | MACH64_UPLOAD_CLIPRECTS); ++ ++ return ret; ++} ++ ++int mach64_get_param(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ drm_mach64_private_t *dev_priv = dev->dev_private; ++ drm_mach64_getparam_t *param = data; ++ int value; ++ ++ DRM_DEBUG("\n"); ++ ++ if (!dev_priv) { ++ DRM_ERROR("called with no initialization\n"); ++ return -EINVAL; ++ } ++ ++ switch (param->param) { ++ case MACH64_PARAM_FRAMES_QUEUED: ++ /* Needs lock since it calls mach64_ring_tick() */ ++ LOCK_TEST_WITH_RETURN(dev, file_priv); ++ value = mach64_do_get_frames_queued(dev_priv); ++ break; ++ case MACH64_PARAM_IRQ_NR: ++ value = dev->irq; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) { ++ DRM_ERROR("copy_to_user\n"); ++ return -EFAULT; ++ } ++ ++ return 0; ++} +--- linux/drivers/gpu/drm/Kconfig.gpu-drm-mach64.orig 2014-03-08 18:52:34.979768492 +0200 ++++ linux/drivers/gpu/drm/Kconfig 2014-03-08 18:55:18.769681473 +0200 +@@ -130,6 +130,17 @@ config DRM_I810 + + source "drivers/gpu/drm/i915/Kconfig" + ++config DRM_MACH64 ++ tristate "ATI Rage Pro (Mach64)" ++ depends on DRM && PCI ++ help ++ Choose this option if you have an ATI Rage Pro (mach64 chipset) ++ graphics card. Example cards include: 3D Rage Pro, Xpert 98, ++ 3D Rage LT Pro, 3D Rage XL/XC, and 3D Rage Mobility (P/M, M1). ++ Cards earlier than ATI Rage Pro (e.g. Rage II) are not supported. ++ If M is selected, the module will be called mach64. AGP support for ++ this card is strongly suggested (unless you have a PCI version). ++ + config DRM_MGA + tristate "Matrox g200/g400" + depends on DRM && PCI +--- linux/drivers/gpu/drm/Makefile.gpu-drm-mach64.orig ++++ linux/drivers/gpu/drm/Makefile +@@ -38,6 +38,7 @@ obj-$(CONFIG_DRM_R128) += r128/ + obj-$(CONFIG_HSA_AMD) += amd/amdkfd/ + obj-$(CONFIG_DRM_RADEON)+= radeon/ + obj-$(CONFIG_DRM_AMDGPU)+= amd/amdgpu/ ++obj-$(CONFIG_DRM_MACH64)+= mach64/ + obj-$(CONFIG_DRM_MGA) += mga/ + obj-$(CONFIG_DRM_I810) += i810/ + obj-$(CONFIG_DRM_I915) += i915/ diff --git a/kernel/tools/perf/files/patches/mageia/hid-usbhid-IBM-BladeCenterHS20-quirk.patch b/kernel/tools/perf/files/patches/mageia/hid-usbhid-IBM-BladeCenterHS20-quirk.patch new file mode 100644 index 0000000000..d8e7fa4dea --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/hid-usbhid-IBM-BladeCenterHS20-quirk.patch @@ -0,0 +1,37 @@ +Subject: Add blacklist of usb hid modules + +IBM Blade Center HS20 can connect PS2 kerboard and mouse, It is USB emulation. +This devices need HID_QUIRK_IGNORE option. + +This patch is workaround. + +[ rediffed for 2.6.28 -- herton ] +Signed-off-by: Go Taniguchi + +--- + drivers/hid/hid-core.c | 2 ++ + drivers/hid/hid-ids.h | 2 ++ + 2 files changed, 4 insertions(+) + +--- a/drivers/hid/hid-core.c ++++ b/drivers/hid/hid-core.c +@@ -2062,6 +2062,8 @@ static const struct hid_device_id hid_ig + { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005) }, + { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006) }, + { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1007) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_IBM, 0x4001) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_IBM, 0x4002) }, + { HID_USB_DEVICE(USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_SPEAK_410) }, + { HID_USB_DEVICE(USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_SPEAK_510) }, +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -46,6 +46,8 @@ + #define USB_VENDOR_ID_AFATECH 0x15a4 + #define USB_DEVICE_ID_AFATECH_AF9016 0x9016 + ++#define USB_VENDOR_ID_IBM 0x04b3 ++ + #define USB_VENDOR_ID_AIPTEK 0x08ca + #define USB_DEVICE_ID_AIPTEK_01 0x0001 + #define USB_DEVICE_ID_AIPTEK_10 0x0010 diff --git a/kernel/tools/perf/files/patches/mageia/hp-wmi-Fix-wifi-cannot-be-hard-unblocked.patch b/kernel/tools/perf/files/patches/mageia/hp-wmi-Fix-wifi-cannot-be-hard-unblocked.patch new file mode 100644 index 0000000000..6e81741679 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/hp-wmi-Fix-wifi-cannot-be-hard-unblocked.patch @@ -0,0 +1,47 @@ +From fc8a601e1175ae351f662506030f9939cb7fdbfe Mon Sep 17 00:00:00 2001 +From: Alex Hung +Date: Mon, 13 Jun 2016 19:44:00 +0800 +Subject: [PATCH] hp-wmi: Fix wifi cannot be hard-unblocked + +Several users reported wifi cannot be unblocked as discussed in [1]. +This patch removes the use of the 2009 flag by BIOS but uses the actual +WMI function calls - it will be skipped if WMI reports unsupported. + +[1] https://bugzilla.kernel.org/show_bug.cgi?id=69131 + +Signed-off-by: Alex Hung +Tested-by: Evgenii Shatokhin +Cc: stable@vger.kernel.org +Signed-off-by: Darren Hart +--- + drivers/platform/x86/hp-wmi.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c +index 6f145f2..96ffda4 100644 +--- a/drivers/platform/x86/hp-wmi.c ++++ b/drivers/platform/x86/hp-wmi.c +@@ -718,6 +718,11 @@ static int __init hp_wmi_rfkill_setup(struct platform_device *device) + if (err) + return err; + ++ err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, &wireless, ++ sizeof(wireless), 0); ++ if (err) ++ return err; ++ + if (wireless & 0x1) { + wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, + RFKILL_TYPE_WLAN, +@@ -882,7 +887,7 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) + wwan_rfkill = NULL; + rfkill2_count = 0; + +- if (hp_wmi_bios_2009_later() || hp_wmi_rfkill_setup(device)) ++ if (hp_wmi_rfkill_setup(device)) + hp_wmi_rfkill2_setup(device); + + err = device_create_file(&device->dev, &dev_attr_display); +-- +2.9.2 + diff --git a/kernel/tools/perf/files/patches/mageia/ide-pci-sis5513-965.patch b/kernel/tools/perf/files/patches/mageia/ide-pci-sis5513-965.patch new file mode 100644 index 0000000000..9c54ab700e --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/ide-pci-sis5513-965.patch @@ -0,0 +1,23 @@ +--- + drivers/ide/sis5513.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff -p -up linux-2.6.28/drivers/ide/sis5513.c.orig linux-2.6.28/drivers/ide/sis5513.c +--- linux-2.6.28/drivers/ide/sis5513.c.orig 2008-12-08 12:41:13.000000000 -0500 ++++ linux-2.6.28/drivers/ide/sis5513.c 2008-12-08 12:51:32.000000000 -0500 +@@ -412,6 +412,15 @@ static int __devinit sis_find_family(str + pci_name(dev)); + } + } ++ else if (trueid == 0x180) { /* sis965L */ ++ u16 pci_command; ++ pci_read_config_word(dev, PCI_COMMAND, &pci_command); ++ pci_command &= ~PCI_COMMAND_INTX_DISABLE; ++ pci_write_config_word(dev, PCI_COMMAND, pci_command); ++ chipset_family = ATA_133; ++ printk(KERN_INFO DRV_NAME " %s: SiS 965 IDE UDMA133 controller\n", ++ pci_name(dev)); ++ } + } + + if (!chipset_family) { /* Belongs to pci-quirks */ diff --git a/kernel/tools/perf/files/patches/mageia/include-kbuild-export-pci_ids.patch b/kernel/tools/perf/files/patches/mageia/include-kbuild-export-pci_ids.patch new file mode 100644 index 0000000000..ebcf983291 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/include-kbuild-export-pci_ids.patch @@ -0,0 +1,19 @@ +From Thierry Vignaud (Mandriva) + +We now lacks /usr/include/linux/pci_ids.h which break ldetect build... +Can you readd it please? +Thanks +--- + include/linux/Kbuild | 1 + + 1 file changed, 1 insertion(+) + +--- linux/include/uapi/linux/Kbuild.include-kbuild-export-pci_ids.orig ++++ linux/include/uapi/linux/Kbuild +@@ -277,6 +277,7 @@ header-y += param.h + header-y += parport.h + header-y += patchkey.h + header-y += pci.h ++header-y += pci_ids.h + header-y += pci_regs.h + header-y += perf_event.h + header-y += personality.h diff --git a/kernel/tools/perf/files/patches/mageia/input-i8042-quirks-for-Fujitsu-Lifebook-A544-and-Lif.patch b/kernel/tools/perf/files/patches/mageia/input-i8042-quirks-for-Fujitsu-Lifebook-A544-and-Lif.patch new file mode 100644 index 0000000000..2ed7667194 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/input-i8042-quirks-for-Fujitsu-Lifebook-A544-and-Lif.patch @@ -0,0 +1,47 @@ +From 993b3a3f80a7842a48cd46c2b41e1b3ef6302468 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 24 Oct 2014 14:55:24 -0700 +Subject: [PATCH] Input: i8042 - quirks for Fujitsu Lifebook A544 and Lifebook + AH544 + +These models need i8042.notimeout, otherwise the touchpad will not work. + +BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=69731 +BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1111138 +Cc: stable@vger.kernel.org +Signed-off-by: Hans de Goede +Signed-off-by: Dmitry Torokhov +--- + drivers/input/serio/i8042-x86ia64io.h | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h +index a0bcbb6..aa9b299 100644 +--- a/drivers/input/serio/i8042-x86ia64io.h ++++ b/drivers/input/serio/i8042-x86ia64io.h +@@ -364,6 +364,22 @@ static const struct dmi_system_id __initconst i8042_dmi_notimeout_table[] = { + }, + }, + { ++ /* Fujitsu A544 laptop */ ++ /* https://bugzilla.redhat.com/show_bug.cgi?id=1111138 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK A544"), ++ }, ++ }, ++ { ++ /* Fujitsu AH544 laptop */ ++ /* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK AH544"), ++ }, ++ }, ++ { + /* Fujitsu U574 laptop */ + /* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */ + .matches = { +-- +2.1.2 + diff --git a/kernel/tools/perf/files/patches/mageia/intel_th-Fix-a-deadlock-in-modprobing.patch b/kernel/tools/perf/files/patches/mageia/intel_th-Fix-a-deadlock-in-modprobing.patch new file mode 100644 index 0000000000..45b63cdda5 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/intel_th-Fix-a-deadlock-in-modprobing.patch @@ -0,0 +1,95 @@ +From a36aa80f3cb2540fb1dbad6240852de4365a2e82 Mon Sep 17 00:00:00 2001 +From: Alexander Shishkin +Date: Thu, 30 Jun 2016 11:51:44 +0300 +Subject: [PATCH] intel_th: Fix a deadlock in modprobing + +Driver initialization tries to request a hub (GTH) driver module from +its probe callback, resulting in a deadlock. + +This patch solves the problem by adding a deferred work for requesting +the hub module. + +Signed-off-by: Alexander Shishkin +Cc: # 4.4.x- +--- + drivers/hwtracing/intel_th/core.c | 35 ++++++++++++++++++++++++++++++++++- + drivers/hwtracing/intel_th/intel_th.h | 3 +++ + 2 files changed, 37 insertions(+), 1 deletion(-) + +diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c +index 1be543e..0b112ae 100644 +--- a/drivers/hwtracing/intel_th/core.c ++++ b/drivers/hwtracing/intel_th/core.c +@@ -465,6 +465,38 @@ static struct intel_th_subdevice { + }, + }; + ++#ifdef CONFIG_MODULES ++static void __intel_th_request_hub_module(struct work_struct *work) ++{ ++ struct intel_th *th = container_of(work, struct intel_th, ++ request_module_work); ++ ++ request_module("intel_th_%s", th->hub->name); ++} ++ ++static int intel_th_request_hub_module(struct intel_th *th) ++{ ++ INIT_WORK(&th->request_module_work, __intel_th_request_hub_module); ++ schedule_work(&th->request_module_work); ++ ++ return 0; ++} ++ ++static void intel_th_request_hub_module_flush(struct intel_th *th) ++{ ++ flush_work(&th->request_module_work); ++} ++#else ++static inline int intel_th_request_hub_module(struct intel_th *th) ++{ ++ return -EINVAL; ++} ++ ++static inline void intel_th_request_hub_module_flush(struct intel_th *th) ++{ ++} ++#endif /* CONFIG_MODULES */ ++ + static int intel_th_populate(struct intel_th *th, struct resource *devres, + unsigned int ndevres, int irq) + { +@@ -535,7 +567,7 @@ static int intel_th_populate(struct intel_th *th, struct resource *devres, + /* need switch driver to be loaded to enumerate the rest */ + if (subdev->type == INTEL_TH_SWITCH && !req) { + th->hub = thdev; +- err = request_module("intel_th_%s", subdev->name); ++ err = intel_th_request_hub_module(th); + if (!err) + req++; + } +@@ -652,6 +684,7 @@ void intel_th_free(struct intel_th *th) + { + int i; + ++ intel_th_request_hub_module_flush(th); + for (i = 0; i < TH_SUBDEVICE_MAX; i++) + if (th->thdev[i] != th->hub) + intel_th_device_remove(th->thdev[i]); +diff --git a/drivers/hwtracing/intel_th/intel_th.h b/drivers/hwtracing/intel_th/intel_th.h +index 0df22e3..0482848 100644 +--- a/drivers/hwtracing/intel_th/intel_th.h ++++ b/drivers/hwtracing/intel_th/intel_th.h +@@ -205,6 +205,9 @@ struct intel_th { + + int id; + int major; ++#ifdef CONFIG_MODULES ++ struct work_struct request_module_work; ++#endif /* CONFIG_MODULES */ + #ifdef CONFIG_INTEL_TH_DEBUG + struct dentry *dbg; + #endif +-- +2.9.2 + diff --git a/kernel/tools/perf/files/patches/mageia/intel_th-pci-Add-Kaby-Lake-PCH-H-support.patch b/kernel/tools/perf/files/patches/mageia/intel_th-pci-Add-Kaby-Lake-PCH-H-support.patch new file mode 100644 index 0000000000..f6d4f341cf --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/intel_th-pci-Add-Kaby-Lake-PCH-H-support.patch @@ -0,0 +1,32 @@ +From 7a1a47ce35821b40f5b2ce46379ba14393bc3873 Mon Sep 17 00:00:00 2001 +From: Alexander Shishkin +Date: Tue, 28 Jun 2016 18:55:23 +0300 +Subject: [PATCH] intel_th: pci: Add Kaby Lake PCH-H support + +This adds Intel(R) Trace Hub PCI ID for Kaby Lake PCH-H. + +Signed-off-by: Alexander Shishkin +Cc: +--- + drivers/hwtracing/intel_th/pci.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/hwtracing/intel_th/pci.c b/drivers/hwtracing/intel_th/pci.c +index 5e25c7e..0bba384 100644 +--- a/drivers/hwtracing/intel_th/pci.c ++++ b/drivers/hwtracing/intel_th/pci.c +@@ -80,6 +80,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = { + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1a8e), + .driver_data = (kernel_ulong_t)0, + }, ++ { ++ /* Kaby Lake PCH-H */ ++ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa2a6), ++ .driver_data = (kernel_ulong_t)0, ++ }, + { 0 }, + }; + +-- +2.9.2 + diff --git a/kernel/tools/perf/files/patches/mageia/media-media-usbtv-prevent-access-to-free-d-resources.patch b/kernel/tools/perf/files/patches/mageia/media-media-usbtv-prevent-access-to-free-d-resources.patch new file mode 100644 index 0000000000..46e8338caf --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/media-media-usbtv-prevent-access-to-free-d-resources.patch @@ -0,0 +1,64 @@ +From 2a00932f082aff93c3a55426e0c7af6d0ec03997 Mon Sep 17 00:00:00 2001 +From: Matthew Leach +Date: Fri, 8 Jul 2016 09:04:27 -0300 +Subject: [PATCH] [media] media: usbtv: prevent access to free'd resources + +When disconnecting the usbtv device, the sound card is unregistered +from ALSA and the snd member of the usbtv struct is set to NULL. If +the usbtv snd_trigger work is running, this can cause a race condition +where the kernel will attempt to access free'd resources, shown in +[1]. + +This patch fixes the disconnection code by cancelling any snd_trigger +work before unregistering the sound card from ALSA and checking that +the snd member still exists in the work function. + +[1]: + usb 3-1.2: USB disconnect, device number 6 + BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 + IP: [] process_one_work+0x30/0x480 + PGD 405bbf067 PUD 405bbe067 PMD 0 + Call Trace: + [] worker_thread+0x48/0x4e0 + [] ? process_one_work+0x480/0x480 + [] ? process_one_work+0x480/0x480 + [] kthread+0xd8/0xf0 + [] ret_from_fork+0x22/0x40 + [] ? kthread_worker_fn+0x170/0x170 + ---[ end trace 0f3dac5c1a38e610 ]--- + +Signed-off-by: Matthew Leach +Tested-by: Peter Sutton +Cc: stable@vger.kernel.org +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/usb/usbtv/usbtv-audio.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/media/usb/usbtv/usbtv-audio.c b/drivers/media/usb/usbtv/usbtv-audio.c +index d4b4db3..1965ff1 100644 +--- a/drivers/media/usb/usbtv/usbtv-audio.c ++++ b/drivers/media/usb/usbtv/usbtv-audio.c +@@ -292,6 +292,9 @@ static void snd_usbtv_trigger(struct work_struct *work) + { + struct usbtv *chip = container_of(work, struct usbtv, snd_trigger); + ++ if (!chip->snd) ++ return; ++ + if (atomic_read(&chip->snd_stream)) + usbtv_audio_start(chip); + else +@@ -392,6 +395,8 @@ err: + + void usbtv_audio_free(struct usbtv *usbtv) + { ++ cancel_work_sync(&usbtv->snd_trigger); ++ + if (usbtv->snd && usbtv->udev) { + snd_card_free(usbtv->snd); + usbtv->snd = NULL; +-- +2.9.2 + diff --git a/kernel/tools/perf/files/patches/mageia/media-usb-pwc-lie-in-proc-usb-devices.patch b/kernel/tools/perf/files/patches/mageia/media-usb-pwc-lie-in-proc-usb-devices.patch new file mode 100644 index 0000000000..32d496e3ff --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/media-usb-pwc-lie-in-proc-usb-devices.patch @@ -0,0 +1,13 @@ +diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c +index f976df4..32c883b 100644 +--- a/drivers/media/usb/pwc/pwc-if.c ++++ b/drivers/media/usb/pwc/pwc-if.c +@@ -119,7 +119,7 @@ static void usb_pwc_disconnect(struct us + static void pwc_isoc_cleanup(struct pwc_device *pdev); + + static struct usb_driver pwc_driver = { +- .name = "Philips webcam", /* name */ ++ .name = "pwc", /* name */ + .id_table = pwc_device_table, + .probe = usb_pwc_probe, /* probe() */ + .disconnect = usb_pwc_disconnect, /* disconnect() */ diff --git a/kernel/tools/perf/files/patches/mageia/media-vb2-core-Skip-planes-array-verification-if-pb-.patch b/kernel/tools/perf/files/patches/mageia/media-vb2-core-Skip-planes-array-verification-if-pb-.patch new file mode 100644 index 0000000000..18987c08a9 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/media-vb2-core-Skip-planes-array-verification-if-pb-.patch @@ -0,0 +1,54 @@ +From 126f40298446a82116e1f92a1aaf72b8c8228fae Mon Sep 17 00:00:00 2001 +From: Sakari Ailus +Date: Wed, 11 May 2016 18:44:32 -0300 +Subject: [PATCH] [media] vb2: core: Skip planes array verification if pb is + NULL + +An earlier patch fixing an input validation issue introduced another +issue: vb2_core_dqbuf() is called with pb argument value NULL in some +cases, causing a NULL pointer dereference. Fix this by skipping the +verification as there's nothing to verify. + +Fixes: e7e0c3e26587 ("[media] videobuf2-core: Check user space planes array in dqbuf") + +Signed-off-by: David R +Signed-off-by: Sakari Ailus +Reviewed-by: Hans Verkuil +Cc: stable@vger.kernel.org # for v4.4 and later +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/v4l2-core/videobuf2-core.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c +index 9fbcb67..633fc1a 100644 +--- a/drivers/media/v4l2-core/videobuf2-core.c ++++ b/drivers/media/v4l2-core/videobuf2-core.c +@@ -1648,7 +1648,7 @@ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, + void *pb, int nonblocking) + { + unsigned long flags; +- int ret; ++ int ret = 0; + + /* + * Wait for at least one buffer to become available on the done_list. +@@ -1664,10 +1664,12 @@ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, + spin_lock_irqsave(&q->done_lock, flags); + *vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry); + /* +- * Only remove the buffer from done_list if v4l2_buffer can handle all +- * the planes. ++ * Only remove the buffer from done_list if all planes can be ++ * handled. Some cases such as V4L2 file I/O and DVB have pb ++ * == NULL; skip the check then as there's nothing to verify. + */ +- ret = call_bufop(q, verify_planes_array, *vb, pb); ++ if (pb) ++ ret = call_bufop(q, verify_planes_array, *vb, pb); + if (!ret) + list_del(&(*vb)->done_entry); + spin_unlock_irqrestore(&q->done_lock, flags); +-- +2.9.2 + diff --git a/kernel/tools/perf/files/patches/mageia/media-videobuf2-v4l2-Verify-planes-array-in-buffer-d.patch b/kernel/tools/perf/files/patches/mageia/media-videobuf2-v4l2-Verify-planes-array-in-buffer-d.patch new file mode 100644 index 0000000000..55c0acea0e --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/media-videobuf2-v4l2-Verify-planes-array-in-buffer-d.patch @@ -0,0 +1,57 @@ +From 83934b75c368f529d084815c463a7ef781dc9751 Mon Sep 17 00:00:00 2001 +From: Sakari Ailus +Date: Sun, 3 Apr 2016 16:31:03 -0300 +Subject: [PATCH] [media] videobuf2-v4l2: Verify planes array in buffer + dequeueing + +When a buffer is being dequeued using VIDIOC_DQBUF IOCTL, the exact buffer +which will be dequeued is not known until the buffer has been removed from +the queue. The number of planes is specific to a buffer, not to the queue. + +This does lead to the situation where multi-plane buffers may be requested +and queued with n planes, but VIDIOC_DQBUF IOCTL may be passed an argument +struct with fewer planes. + +__fill_v4l2_buffer() however uses the number of planes from the dequeued +videobuf2 buffer, overwriting kernel memory (the m.planes array allocated +in video_usercopy() in v4l2-ioctl.c) if the user provided fewer +planes than the dequeued buffer had. Oops! + +Fixes: b0e0e1f83de3 ("[media] media: videobuf2: Prepare to divide videobuf2") + +Signed-off-by: Sakari Ailus +Acked-by: Hans Verkuil +Cc: stable@vger.kernel.org # for v4.4 and later +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/v4l2-core/videobuf2-v4l2.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c +index 0b1b8c7..7f366f1 100644 +--- a/drivers/media/v4l2-core/videobuf2-v4l2.c ++++ b/drivers/media/v4l2-core/videobuf2-v4l2.c +@@ -74,6 +74,11 @@ static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer + return 0; + } + ++static int __verify_planes_array_core(struct vb2_buffer *vb, const void *pb) ++{ ++ return __verify_planes_array(vb, pb); ++} ++ + /** + * __verify_length() - Verify that the bytesused value for each plane fits in + * the plane length and that the data offset doesn't exceed the bytesused value. +@@ -437,6 +442,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, + } + + static const struct vb2_buf_ops v4l2_buf_ops = { ++ .verify_planes_array = __verify_planes_array_core, + .fill_user_buffer = __fill_v4l2_buffer, + .fill_vb2_buffer = __fill_vb2_buffer, + .copy_timestamp = __copy_timestamp, +-- +2.9.2 + diff --git a/kernel/tools/perf/files/patches/mageia/megaraid_sas-Do-not-fire-MR_DCMD_PD_LIST_QUERY-to-co.patch b/kernel/tools/perf/files/patches/mageia/megaraid_sas-Do-not-fire-MR_DCMD_PD_LIST_QUERY-to-co.patch new file mode 100644 index 0000000000..f6c3de354d --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/megaraid_sas-Do-not-fire-MR_DCMD_PD_LIST_QUERY-to-co.patch @@ -0,0 +1,59 @@ +From d9083160c2f6ee456ea867ea2279c1fc6124e56f Mon Sep 17 00:00:00 2001 +From: Sumit Saxena +Date: Fri, 8 Jul 2016 03:30:16 -0700 +Subject: [PATCH] megaraid_sas: Do not fire MR_DCMD_PD_LIST_QUERY to + controllers which do not support it + +There was an issue reported by Lucz Geza on Dell Perc 6i. As per issue +reported, megaraid_sas driver goes into an infinite error reporting loop +as soon as there is a change in the status of one of the +arrays (degrade, resync online etc ). Below are the error logs reported +continuously- + +Jun 25 08:49:30 ns8 kernel: [ 757.757017] megaraid_sas 0000:02:00.0: DCMD failed/not supported by firmware: megasas_get_pd_list 4115 +Jun 25 08:49:30 ns8 kernel: [ 757.778017] megaraid_sas 0000:02:00.0: DCMD failed/not supported by firmware: megasas_get_pd_list 4115 +Jun 25 08:49:30 ns8 kernel: [ 757.799017] megaraid_sas 0000:02:00.0: DCMD failed/not supported by firmware: megasas_get_pd_list 4115 +Jun 25 08:49:30 ns8 kernel: [ 757.820018] megaraid_sas 0000:02:00.0: DCMD failed/not supported by firmware: megasas_get_pd_list 4115 +Jun 25 08:49:30 ns8 kernel: [ 757.841018] megaraid_sas 0000:02:00.0: DCMD failed/not supported by firmware: megasas_get_pd_list 4115 + +This issue is very much specific to controllers which do not support +DCMD- MR_DCMD_PD_LIST_QUERY. In case of any hotplugging/rescanning of +drives, AEN thread will be scheduled by driver and fire DCMD- +MR_DCMD_PD_LIST_QUERY and if this DCMD is failed then driver will fail +this event processing and will not go ahead for further events. This +will cause infinite loop of same event getting retried infinitely and +causing above mentioned logs. + +Fix for this problem is: not to fire DCMD MR_DCMD_PD_LIST_QUERY for +controllers which do not support it and send DCMD SUCCESS status to AEN +function so that it can go ahead with other event processing. + +Reported-by: Lucz Geza +Cc: +Signed-off-by: Sumit Saxena +Reviewed-by: Tomas Henzl +Signed-off-by: Martin K. Petersen +--- + drivers/scsi/megaraid/megaraid_sas_base.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c +index f4b0690..2dab3dc 100644 +--- a/drivers/scsi/megaraid/megaraid_sas_base.c ++++ b/drivers/scsi/megaraid/megaraid_sas_base.c +@@ -4079,6 +4079,12 @@ megasas_get_pd_list(struct megasas_instance *instance) + struct MR_PD_ADDRESS *pd_addr; + dma_addr_t ci_h = 0; + ++ if (instance->pd_list_not_supported) { ++ dev_info(&instance->pdev->dev, "MR_DCMD_PD_LIST_QUERY " ++ "not supported by firmware\n"); ++ return ret; ++ } ++ + cmd = megasas_get_cmd(instance); + + if (!cmd) { +-- +2.9.2 + diff --git a/kernel/tools/perf/files/patches/mageia/mpt-vmware-fix.patch b/kernel/tools/perf/files/patches/mageia/mpt-vmware-fix.patch new file mode 100644 index 0000000000..0b90277c0c --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/mpt-vmware-fix.patch @@ -0,0 +1,49 @@ +Subject: mpt scsi modules for VMWare's emulated + +The attached patch is a workaround for a bug in VMWare's emulated LSI +Fusion SCSI HBA. The emulated firmware returns zero for the maximum +number of attached devices; the real firmware returns a positive +number. Therefore, the kernel that boots and works fine on bare metal +will fail on VMWare because this firmware value is handed to the SCSI +midlayer, which then skips the entire bus scan. + +F7 bz 241935 + +The patch below was submitted by Eric Moore of LSI to the linux-scsi +mailing list: + +http://marc.info/?l=linux-scsi&m=117432237404247 + +then immediately rejected by Christoph Hellwig, who prefers that +VMWare fix their emulation instead. + +This patch is workaround. + +--- + drivers/message/fusion/mptbase.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +--- a/drivers/message/fusion/mptbase.c ++++ b/drivers/message/fusion/mptbase.c +@@ -3051,8 +3051,19 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn + pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs); + pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets); + +- max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID : +- pfacts->MaxDevices; ++ switch (ioc->bus_type) { ++ case SAS: ++ max_id = pfacts->PortSCSIID; ++ break; ++ case FC: ++ max_id = pfacts->MaxDevices; ++ break; ++ case SPI: ++ default: ++ max_id = MPT_MAX_SCSI_DEVICES; ++ break; ++ } ++ + ioc->devices_per_bus = (max_id > 255) ? 256 : max_id; + ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256; + diff --git a/kernel/tools/perf/files/patches/mageia/net-bcma-add-PCI-ID-for-Foxconn-s-BCM43142-device.patch b/kernel/tools/perf/files/patches/mageia/net-bcma-add-PCI-ID-for-Foxconn-s-BCM43142-device.patch new file mode 100644 index 0000000000..14784de4b8 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-bcma-add-PCI-ID-for-Foxconn-s-BCM43142-device.patch @@ -0,0 +1,43 @@ +From 1bea0512c3394965de28a152149b90afd686fae5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 11 Jul 2016 23:01:36 +0200 +Subject: [PATCH] bcma: add PCI ID for Foxconn's BCM43142 device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +After discovering there are 2 very different 14e4:4365 PCI devices we +made ID tables less generic. Back then we believed there are only 2 such +devices: +1) 14e4:4365 1028:0016 with SoftMAC BCM43142 chipset +2) 14e4:4365 14e4:4365 with FullMAC BCM4366 chipset + +>From the recent report it appears there is also 14e4:4365 105b:e092 +which should be claimed by bcma. Add back support for it. + +Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=121881 +Fixes: 515b399c9a20 ("bcma: claim only 14e4:4365 PCI Dell card with SoftMAC BCM43142") +Reported-by: Igor Mammedov +Signed-off-by: Rafał Miłecki +Cc: Stable [4.6+] +Tested-by: Igor Mammedov +Signed-off-by: Kalle Valo +--- + drivers/bcma/host_pci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c +index cae5385..bd46569 100644 +--- a/drivers/bcma/host_pci.c ++++ b/drivers/bcma/host_pci.c +@@ -295,6 +295,7 @@ static const struct pci_device_id bcma_pci_bridge_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0016) }, ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_FOXCONN, 0xe092) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) }, +-- +2.9.2 + diff --git a/kernel/tools/perf/files/patches/mageia/net-brcmfmac-restore-stopping-netdev-queue-when-bus-clog.patch b/kernel/tools/perf/files/patches/mageia/net-brcmfmac-restore-stopping-netdev-queue-when-bus-clog.patch new file mode 100644 index 0000000000..6704452f04 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-brcmfmac-restore-stopping-netdev-queue-when-bus-clog.patch @@ -0,0 +1,61 @@ +From 82bc9ab6a8f577d2174a736c33f3d4ecf7d9ef47 Mon Sep 17 00:00:00 2001 +From: Arend Van Spriel +Date: Fri, 15 Jul 2016 12:16:12 +0200 +Subject: [PATCH] brcmfmac: restore stopping netdev queue when bus clogs up +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When the host-interface bus has hard time handling transmit packets +it informs higher layer about this and it would stop the netdev +queue when needed. However, since commit 9cd18359d31e ("brcmfmac: +Make FWS queueing configurable.") this was broken. With this patch +the behaviour is restored. + +Cc: stable@vger.kernel.org # v4.5, v4.6, v4.7 +Fixes: 9cd18359d31e ("brcmfmac: Make FWS queueing configurable.") +Tested-by: Per Förlin +Reviewed-by: Hante Meuleman +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Franky Lin +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + .../broadcom/brcm80211/brcmfmac/fwsignal.c | 22 +++++++++++++++++----- + 1 file changed, 17 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +index cd221ab..9f9024a 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +@@ -2469,10 +2469,22 @@ void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb) + void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked) + { + struct brcmf_fws_info *fws = drvr->fws; ++ struct brcmf_if *ifp; ++ int i; + +- fws->bus_flow_blocked = flow_blocked; +- if (!flow_blocked) +- brcmf_fws_schedule_deq(fws); +- else +- fws->stats.bus_flow_block++; ++ if (fws->avoid_queueing) { ++ for (i = 0; i < BRCMF_MAX_IFS; i++) { ++ ifp = drvr->iflist[i]; ++ if (!ifp || !ifp->ndev) ++ continue; ++ brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW, ++ flow_blocked); ++ } ++ } else { ++ fws->bus_flow_blocked = flow_blocked; ++ if (!flow_blocked) ++ brcmf_fws_schedule_deq(fws); ++ else ++ fws->stats.bus_flow_block++; ++ } + } +-- +2.9.2 + diff --git a/kernel/tools/perf/files/patches/mageia/net-ipv4-netfilter-ipt_IFWLOG-3.6-buildfix.patch b/kernel/tools/perf/files/patches/mageia/net-ipv4-netfilter-ipt_IFWLOG-3.6-buildfix.patch new file mode 100644 index 0000000000..51041b6f74 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-ipv4-netfilter-ipt_IFWLOG-3.6-buildfix.patch @@ -0,0 +1,33 @@ + +Adapt to netlink changes in 3.6 + +Signed-off-by: Thomas Backlund + +--- linux/net/ipv4/netfilter/ipt_IFWLOG.c.orig 2012-10-17 22:44:57.000000000 +0300 ++++ linux/net/ipv4/netfilter/ipt_IFWLOG.c 2012-10-17 23:17:10.012725918 +0300 +@@ -56,9 +56,9 @@ static void send_packet(const struct nl_ + return; + } + +- nlh = NLMSG_PUT(skb, 0, 0, 0, size - sizeof(*nlh)); ++ nlh = nlmsg_put(skb, 0, 0, 0, size - sizeof(*nlh), 0); + +- memcpy(NLMSG_DATA(nlh), (const void *) msg, sizeof(*msg)); ++ memcpy(nlmsg_data(nlh), (const void *) msg, sizeof(*msg)); + + NETLINK_CB(skb).pid = 0; /* from kernel */ + NETLINK_CB(skb).dst_group = IFWLOGNLGRP_DEF; +@@ -169,9 +169,11 @@ static struct xt_target ipt_IFWLOG = { + static int __init ipt_ifwlog_init(void) + { + int err; ++ struct netlink_kernel_cfg cfg = { ++ .groups = IFWLOGNLGRP_MAX, ++ }; + +- nl = netlink_kernel_create(&init_net, NETLINK_IFWLOG, IFWLOGNLGRP_MAX, +- NULL, NULL, THIS_MODULE); ++ nl = netlink_kernel_create(&init_net, NETLINK_IFWLOG, THIS_MODULE, &cfg); + if (!nl) { + PRINTR(KERN_WARNING "IFWLOG: cannot create netlink socket\n"); + return -ENOMEM; diff --git a/kernel/tools/perf/files/patches/mageia/net-netfilter-IFWLOG-2.6.35-buildfix.patch b/kernel/tools/perf/files/patches/mageia/net-netfilter-IFWLOG-2.6.35-buildfix.patch new file mode 100644 index 0000000000..99d4d0631a --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-netfilter-IFWLOG-2.6.35-buildfix.patch @@ -0,0 +1,32 @@ +--- linux-2.6.35-rc6-git-mnb0.1/net/ipv4/netfilter/ipt_IFWLOG.c.orig 2010-07-30 21:17:30.000000000 +0300 ++++ linux-2.6.35-rc6-git-mnb0.1/net/ipv4/netfilter/ipt_IFWLOG.c 2010-07-31 13:46:33.834611944 +0300 +@@ -135,7 +135,7 @@ static void ipt_IFWLOG_packet(const stru + } + + static unsigned int ipt_IFWLOG_target(struct sk_buff *skb, +- const struct xt_target_param *target_param) ++ const struct xt_action_param *target_param) + { + const struct ipt_IFWLOG_info *info = target_param->targinfo; + +@@ -144,17 +144,17 @@ static unsigned int ipt_IFWLOG_target(st + return IPT_CONTINUE; + } + +-static bool ipt_IFWLOG_checkentry(const struct xt_tgchk_param *tgchk_param) ++static int ipt_IFWLOG_checkentry(const struct xt_tgchk_param *tgchk_param) + { + const struct ipt_IFWLOG_info *info = tgchk_param->targinfo; + + if (info->prefix[sizeof(info->prefix)-1] != '\0') { + DEBUGP("IFWLOG: prefix term %i\n", + info->prefix[sizeof(info->prefix)-1]); +- return false; ++ return -EINVAL; + } + +- return true; ++ return 0; + } + + static struct xt_target ipt_IFWLOG = { diff --git a/kernel/tools/perf/files/patches/mageia/net-netfilter-IFWLOG-2.6.37-buildfix.patch b/kernel/tools/perf/files/patches/mageia/net-netfilter-IFWLOG-2.6.37-buildfix.patch new file mode 100644 index 0000000000..0ae95aa337 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-netfilter-IFWLOG-2.6.37-buildfix.patch @@ -0,0 +1,15 @@ + + net/ipv4/netfilter/ipt_IFWLOG.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-2.6.37-rc3-git1-tmb0.3/net/ipv4/netfilter/ipt_IFWLOG.c.orig 2010-11-24 21:58:36.000000000 +0200 ++++ linux-2.6.37-rc3-git1-tmb0.3/net/ipv4/netfilter/ipt_IFWLOG.c 2010-11-25 13:08:55.719379646 +0200 +@@ -141,7 +141,7 @@ static unsigned int ipt_IFWLOG_target(st + + ipt_IFWLOG_packet(skb, target_param->in, target_param->out, info); + +- return IPT_CONTINUE; ++ return XT_CONTINUE; + } + + static int ipt_IFWLOG_checkentry(const struct xt_tgchk_param *tgchk_param) diff --git a/kernel/tools/perf/files/patches/mageia/net-netfilter-IFWLOG-3.7-buildfix.patch b/kernel/tools/perf/files/patches/mageia/net-netfilter-IFWLOG-3.7-buildfix.patch new file mode 100644 index 0000000000..744e840f5a --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-netfilter-IFWLOG-3.7-buildfix.patch @@ -0,0 +1,20 @@ +--- linux-3.7-rc8/net/ipv4/netfilter/ipt_IFWLOG.c.orig 2012-12-06 19:50:10.000000000 +0200 ++++ linux-3.7-rc8/net/ipv4/netfilter/ipt_IFWLOG.c 2012-12-06 20:55:23.669152916 +0200 +@@ -60,7 +60,7 @@ static void send_packet(const struct nl_ + + memcpy(nlmsg_data(nlh), (const void *) msg, sizeof(*msg)); + +- NETLINK_CB(skb).pid = 0; /* from kernel */ ++ NETLINK_CB(skb).portid = 0; /* from kernel */ + NETLINK_CB(skb).dst_group = IFWLOGNLGRP_DEF; + + if (nl) { +@@ -173,7 +173,7 @@ static int __init ipt_ifwlog_init(void) + .groups = IFWLOGNLGRP_MAX, + }; + +- nl = netlink_kernel_create(&init_net, NETLINK_IFWLOG, THIS_MODULE, &cfg); ++ nl = netlink_kernel_create(&init_net, NETLINK_IFWLOG, &cfg); + if (!nl) { + PRINTR(KERN_WARNING "IFWLOG: cannot create netlink socket\n"); + return -ENOMEM; diff --git a/kernel/tools/perf/files/patches/mageia/net-netfilter-IFWLOG-mdv.patch b/kernel/tools/perf/files/patches/mageia/net-netfilter-IFWLOG-mdv.patch new file mode 100644 index 0000000000..5ecc015146 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-netfilter-IFWLOG-mdv.patch @@ -0,0 +1,264 @@ +ipt_IFWLOG: Mandriva changes + +This patch holds all the Mandriva changes done in ipt_IFWLOG +netfilter module. + +This work is mostly done by Thomas Backlund, Herton R. Krzesinski +and Luiz Fernando N. Capitulino. + +Signed-off-by: Luiz Fernando N. Capitulino +Signed-off-by: Herton Ronaldo Krzesinski + +--- + include/linux/netfilter_ipv4/Kbuild | 1 + include/linux/netfilter_ipv4/ipt_IFWLOG.h | 23 +++++- + net/ipv4/netfilter/ipt_IFWLOG.c | 108 +++++++++++++++--------------- + 3 files changed, 77 insertions(+), 55 deletions(-) + +diff -p -up linux-2.6.28/include/linux/netfilter_ipv4/ipt_IFWLOG.h.orig linux-2.6.28/include/linux/netfilter_ipv4/ipt_IFWLOG.h +--- linux-2.6.28/include/linux/netfilter_ipv4/ipt_IFWLOG.h.orig 2008-12-12 10:55:07.000000000 -0500 ++++ linux-2.6.28/include/linux/netfilter_ipv4/ipt_IFWLOG.h 2008-12-12 10:56:30.000000000 -0500 +@@ -1,10 +1,25 @@ +-#ifndef _IPT_IFWLOG_H +-#define _IPT_IFWLOG_H ++#ifndef _LINUX_IPT_IFWLOG_H ++#define _LINUX_IPT_IFWLOG_H + + #ifndef NETLINK_IFWLOG +-#define NETLINK_IFWLOG 19 ++#define NETLINK_IFWLOG 20 + #endif + ++#ifndef __KERNEL__ ++/* Multicast groups - backwards compatiblility for userspace */ ++#define IFWLOG_NLGRP_NONE 0x00000000 ++#define IFWLOG_NLGRP_DEF 0x00000001 /* default message group */ ++#endif ++ ++enum { ++ IFWLOGNLGRP_NONE, ++#define IFWLOGNLGRP_NONE IFWLOGNLGRP_NONE ++ IFWLOGNLGRP_DEF, ++#define IFWLOGNLGRP_DEF IFWLOGNLGRP_DEF ++ __IFWLOGNLGRP_MAX ++}; ++#define IFWLOGNLGRP_MAX (__IFWLOGNLGRP_MAX - 1) ++ + #define PREFSIZ 32 + + struct nl_msg { /* Netlink message */ +@@ -23,4 +38,4 @@ struct ipt_IFWLOG_info { + char prefix[PREFSIZ]; + }; + +-#endif /* _IPT_IFWLOG_H */ ++#endif /* _LINUX_IPT_IFWLOG_H */ +diff -p -up linux-2.6.28/net/ipv4/netfilter/ipt_IFWLOG.c.orig linux-2.6.28/net/ipv4/netfilter/ipt_IFWLOG.c +--- linux-2.6.28/net/ipv4/netfilter/ipt_IFWLOG.c.orig 2008-12-12 10:55:07.000000000 -0500 ++++ linux-2.6.28/net/ipv4/netfilter/ipt_IFWLOG.c 2008-12-12 10:57:16.000000000 -0500 +@@ -4,6 +4,14 @@ + * 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. ++ * ++ * 2007-10-10 Thomas Backlund : build fixes for 2.6.22.9 ++ * 2007-11-11 Herton Krzesinski : build fixes for 2.6.24-rc ++ * 2007-12-03 Luiz Capitulino : v1.1 ++ * - Better multicast group usage ++ * - Coding style fixes ++ * - Do not return -EINVAL by default in ipt_ifwlog_init() ++ * - Minor refinements + */ + + #include +@@ -19,12 +27,10 @@ + #include + + #include ++#include + #include + #include + +-MODULE_LICENSE("GPL"); +-MODULE_AUTHOR("Samir Bellabes "); +-MODULE_DESCRIPTION("Interactive firewall logging and module"); + + #if 0 + #define DEBUGP PRINTR +@@ -36,44 +42,41 @@ MODULE_DESCRIPTION("Interactive firewall + + static struct sock *nl; + +-#define GROUP 10 +- + /* send struct to userspace */ +-static void send_packet(struct nl_msg msg) ++static void send_packet(const struct nl_msg *msg) + { + struct sk_buff *skb = NULL; + struct nlmsghdr *nlh; ++ unsigned int size; + +- skb = alloc_skb(NLMSG_SPACE(sizeof(struct nl_msg)), GFP_ATOMIC); ++ size = NLMSG_SPACE(sizeof(*msg)); ++ skb = alloc_skb(size, GFP_ATOMIC); + if (!skb) { + PRINTR(KERN_WARNING "IFWLOG: OOM can't allocate skb\n"); +- return ; ++ return; + } + +- nlh = NLMSG_PUT(skb, 0, 0, 0, sizeof(struct nl_msg) - sizeof(*nlh)); ++ nlh = NLMSG_PUT(skb, 0, 0, 0, size - sizeof(*nlh)); + +- memcpy(NLMSG_DATA(nlh), (const void*)&msg, sizeof(struct nl_msg)); ++ memcpy(NLMSG_DATA(nlh), (const void *) msg, sizeof(*msg)); + + NETLINK_CB(skb).pid = 0; /* from kernel */ +- NETLINK_CB(skb).dst_pid = 0; /* multicast */ +- NETLINK_CB(skb).dst_group = 10; ++ NETLINK_CB(skb).dst_group = IFWLOGNLGRP_DEF; + + if (nl) { + DEBUGP(KERN_WARNING + "IFWLOG: nlmsg_len=%ld\nnlmsg_type=%d nlmsg_flags=%d\nnlmsg_seq=%ld nlmsg_pid = %ld\n", + (long)nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags, + (long)nlh->nlmsg_seq, (long)nlh->nlmsg_pid); +- DEBUGP(KERN_WARNING "prefix : %s\n", msg.prefix); ++ DEBUGP(KERN_WARNING "prefix : %s\n", msg->prefix); + +- netlink_broadcast(nl, skb, 0, 10, GFP_ATOMIC); +- return ; ++ netlink_broadcast(nl, skb, 0, IFWLOGNLGRP_DEF, GFP_ATOMIC); ++ return; + } + +- nlmsg_failure: +- if (skb) +- kfree_skb(skb); +- PRINTR(KERN_WARNING "IFWLOG: Error sending netlink packet\n"); +- return ; ++nlmsg_failure: ++ kfree_skb(skb); ++ PRINTR(KERN_WARNING "IFWLOG: Error sending netlink packet\n"); + } + + /* fill struct for userspace */ +@@ -128,73 +131,76 @@ static void ipt_IFWLOG_packet(const stru + do_gettimeofday((struct timeval *)&tv); + msg.timestamp_sec = tv.tv_sec; + +- send_packet(msg); ++ send_packet(&msg); + } + +-static unsigned int ipt_IFWLOG_target(struct sk_buff **pskb, +- const struct net_device *in, +- const struct net_device *out, +- unsigned int hooknum, +- const void *targinfo, +- void *userinfo) ++static unsigned int ipt_IFWLOG_target(struct sk_buff *skb, ++ const struct xt_target_param *target_param) + { +- const struct ipt_IFWLOG_info *info = targinfo; ++ const struct ipt_IFWLOG_info *info = target_param->targinfo; + +- ipt_IFWLOG_packet(*pskb, in, out, info); ++ ipt_IFWLOG_packet(skb, target_param->in, target_param->out, info); + + return IPT_CONTINUE; + } + +-static int ipt_IFWLOG_checkentry(const char *tablename, +- const struct ipt_entry *e, +- void *targinfo, +- unsigned int targinfosize, +- unsigned int hook_mask) ++static bool ipt_IFWLOG_checkentry(const struct xt_tgchk_param *tgchk_param) + { +- const struct ipt_IFWLOG_info *info = targinfo; ++ const struct ipt_IFWLOG_info *info = tgchk_param->targinfo; + + if (info->prefix[sizeof(info->prefix)-1] != '\0') { + DEBUGP("IFWLOG: prefix term %i\n", + info->prefix[sizeof(info->prefix)-1]); +- return 0; ++ return false; + } + +- return 1; ++ return true; + } + +-static struct ipt_target ipt_IFWLOG = { ++static struct xt_target ipt_IFWLOG = { + .name = "IFWLOG", ++ .family = AF_INET, + .target = ipt_IFWLOG_target, + .targetsize = sizeof(struct ipt_IFWLOG_info), + .checkentry = ipt_IFWLOG_checkentry, + .me = THIS_MODULE, + }; + +-static int __init init(void) ++static int __init ipt_ifwlog_init(void) + { +- nl = (struct sock*) netlink_kernel_create(NETLINK_IFWLOG, GROUP, NULL, THIS_MODULE); +- if (!nl) { +- PRINTR(KERN_WARNING "IFWLOG: cannot create netlink socket\n"); +- return -EINVAL; +- } ++ int err; + +- if (ipt_register_target(&ipt_IFWLOG)) { ++ nl = netlink_kernel_create(&init_net, NETLINK_IFWLOG, IFWLOGNLGRP_MAX, ++ NULL, NULL, THIS_MODULE); ++ if (!nl) { ++ PRINTR(KERN_WARNING "IFWLOG: cannot create netlink socket\n"); ++ return -ENOMEM; ++ } ++ ++ err = xt_register_target(&ipt_IFWLOG); ++ if (err) { + if (nl && nl->sk_socket) + sock_release(nl->sk_socket); +- return -EINVAL; ++ return err; + } + + PRINTR(KERN_INFO "IFWLOG: register target\n"); + return 0; + } + +-static void __exit fini(void) ++static void __exit ipt_ifwlog_fini(void) + { + if (nl && nl->sk_socket) +- sock_release(nl->sk_socket); ++ sock_release(nl->sk_socket); + PRINTR(KERN_INFO "IFWLOG: unregister target\n"); +- ipt_unregister_target(&ipt_IFWLOG); ++ xt_unregister_target(&ipt_IFWLOG); + } + +-module_init(init); +-module_exit(fini); ++module_init(ipt_ifwlog_init); ++module_exit(ipt_ifwlog_fini); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Samir Bellabes "); ++MODULE_AUTHOR("Luiz Capitulino "); ++MODULE_DESCRIPTION("Interactive firewall logging and module"); ++MODULE_VERSION("v1.1"); +--- linux/include/uapi/linux/netfilter_ipv4/Kbuild.net-netfilter-IFWLOG-mdv.orig ++++ linux/include/uapi/linux/netfilter_ipv4/Kbuild +@@ -2,6 +2,7 @@ header-y += ip_queue.h + header-y += ip_tables.h + header-y += ipt_CLUSTERIP.h + header-y += ipt_ECN.h ++header-y += ipt_IFWLOG.h + header-y += ipt_LOG.h + header-y += ipt_REJECT.h + header-y += ipt_TTL.h diff --git a/kernel/tools/perf/files/patches/mageia/net-netfilter-IFWLOG-remove-unused-label.patch b/kernel/tools/perf/files/patches/mageia/net-netfilter-IFWLOG-remove-unused-label.patch new file mode 100644 index 0000000000..b2c71eab0f --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-netfilter-IFWLOG-remove-unused-label.patch @@ -0,0 +1,10 @@ +--- linux-4.4/net/ipv4/netfilter/ipt_IFWLOG.c~ 2016-01-24 13:19:13.233713998 +0100 ++++ linux-4.4/net/ipv4/netfilter/ipt_IFWLOG.c 2016-01-24 20:49:10.145823623 +0100 +@@ -74,7 +74,6 @@ + return; + } + +-nlmsg_failure: + kfree_skb(skb); + PRINTR(KERN_WARNING "IFWLOG: Error sending netlink packet\n"); + } diff --git a/kernel/tools/perf/files/patches/mageia/net-netfilter-IFWLOG.patch b/kernel/tools/perf/files/patches/mageia/net-netfilter-IFWLOG.patch new file mode 100644 index 0000000000..c865442256 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-netfilter-IFWLOG.patch @@ -0,0 +1,269 @@ +--- + include/linux/netfilter_ipv4/ipt_IFWLOG.h | 26 +++ + net/ipv4/netfilter/Kconfig | 11 + + net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/ipt_IFWLOG.c | 200 ++++++++++++++++++++++++++++++ + 4 files changed, 238 insertions(+) + +--- /dev/null ++++ b/net/ipv4/netfilter/ipt_IFWLOG.c +@@ -0,0 +1,200 @@ ++/* Interactive Firewall for Mandriva ++ * Samir Bellabes ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Samir Bellabes "); ++MODULE_DESCRIPTION("Interactive firewall logging and module"); ++ ++#if 0 ++#define DEBUGP PRINTR ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++#define PRINTR(format, args...) do { if(net_ratelimit()) printk(format, ##args); } while(0) ++ ++static struct sock *nl; ++ ++#define GROUP 10 ++ ++/* send struct to userspace */ ++static void send_packet(struct nl_msg msg) ++{ ++ struct sk_buff *skb = NULL; ++ struct nlmsghdr *nlh; ++ ++ skb = alloc_skb(NLMSG_SPACE(sizeof(struct nl_msg)), GFP_ATOMIC); ++ if (!skb) { ++ PRINTR(KERN_WARNING "IFWLOG: OOM can't allocate skb\n"); ++ return ; ++ } ++ ++ nlh = NLMSG_PUT(skb, 0, 0, 0, sizeof(struct nl_msg) - sizeof(*nlh)); ++ ++ memcpy(NLMSG_DATA(nlh), (const void*)&msg, sizeof(struct nl_msg)); ++ ++ NETLINK_CB(skb).pid = 0; /* from kernel */ ++ NETLINK_CB(skb).dst_pid = 0; /* multicast */ ++ NETLINK_CB(skb).dst_group = 10; ++ ++ if (nl) { ++ DEBUGP(KERN_WARNING ++ "IFWLOG: nlmsg_len=%ld\nnlmsg_type=%d nlmsg_flags=%d\nnlmsg_seq=%ld nlmsg_pid = %ld\n", ++ (long)nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags, ++ (long)nlh->nlmsg_seq, (long)nlh->nlmsg_pid); ++ DEBUGP(KERN_WARNING "prefix : %s\n", msg.prefix); ++ ++ netlink_broadcast(nl, skb, 0, 10, GFP_ATOMIC); ++ return ; ++ } ++ ++ nlmsg_failure: ++ if (skb) ++ kfree_skb(skb); ++ PRINTR(KERN_WARNING "IFWLOG: Error sending netlink packet\n"); ++ return ; ++} ++ ++/* fill struct for userspace */ ++static void ipt_IFWLOG_packet(const struct sk_buff *skb, ++ const struct net_device *in, ++ const struct net_device *out, ++ const struct ipt_IFWLOG_info *info) ++{ ++ struct iphdr iph; ++ struct tcphdr tcph; ++ struct udphdr udph; ++ struct nl_msg msg; ++ struct iphdr _iph, *ih; ++ struct timeval tv; ++ ++ memset(&msg, 0, sizeof(struct nl_msg)); ++ ++ ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph); ++ if (ih == NULL) { ++ PRINTR(KERN_WARNING "IFWLOG: skb truncated"); ++ return; ++ } ++ ++ /* save interface name */ ++ if (in) ++ strcpy(msg.indev_name, in->name); ++ if (out) ++ strcpy(msg.outdev_name, out->name); ++ ++ /* save log-prefix */ ++ strcpy(msg.prefix, info->prefix); ++ ++ /* save ip header */ ++ skb_copy_bits(skb, 0, &iph, sizeof(iph)); ++ memcpy(&msg.ip, &iph, sizeof(struct iphdr)); ++ ++ /* save transport header */ ++ switch (iph.protocol){ ++ case IPPROTO_TCP: ++ skb_copy_bits(skb, iph.ihl*4 , &tcph, sizeof(tcph)); ++ memcpy(&msg.h.th, &tcph, sizeof(struct tcphdr)); ++ break; ++ case IPPROTO_UDP: ++ skb_copy_bits(skb, iph.ihl*4 , &udph, sizeof(udph)); ++ memcpy(&msg.h.uh, &udph, sizeof(struct udphdr)); ++ break; ++ default: ++ break; ++ } ++ ++ /* save timetamp */ ++ do_gettimeofday((struct timeval *)&tv); ++ msg.timestamp_sec = tv.tv_sec; ++ ++ send_packet(msg); ++} ++ ++static unsigned int ipt_IFWLOG_target(struct sk_buff **pskb, ++ const struct net_device *in, ++ const struct net_device *out, ++ unsigned int hooknum, ++ const void *targinfo, ++ void *userinfo) ++{ ++ const struct ipt_IFWLOG_info *info = targinfo; ++ ++ ipt_IFWLOG_packet(*pskb, in, out, info); ++ ++ return IPT_CONTINUE; ++} ++ ++static int ipt_IFWLOG_checkentry(const char *tablename, ++ const struct ipt_entry *e, ++ void *targinfo, ++ unsigned int targinfosize, ++ unsigned int hook_mask) ++{ ++ const struct ipt_IFWLOG_info *info = targinfo; ++ ++ if (info->prefix[sizeof(info->prefix)-1] != '\0') { ++ DEBUGP("IFWLOG: prefix term %i\n", ++ info->prefix[sizeof(info->prefix)-1]); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ipt_target ipt_IFWLOG = { ++ .name = "IFWLOG", ++ .target = ipt_IFWLOG_target, ++ .targetsize = sizeof(struct ipt_IFWLOG_info), ++ .checkentry = ipt_IFWLOG_checkentry, ++ .me = THIS_MODULE, ++}; ++ ++static int __init init(void) ++{ ++ nl = (struct sock*) netlink_kernel_create(NETLINK_IFWLOG, GROUP, NULL, THIS_MODULE); ++ if (!nl) { ++ PRINTR(KERN_WARNING "IFWLOG: cannot create netlink socket\n"); ++ return -EINVAL; ++ } ++ ++ if (ipt_register_target(&ipt_IFWLOG)) { ++ if (nl && nl->sk_socket) ++ sock_release(nl->sk_socket); ++ return -EINVAL; ++ } ++ ++ PRINTR(KERN_INFO "IFWLOG: register target\n"); ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ if (nl && nl->sk_socket) ++ sock_release(nl->sk_socket); ++ PRINTR(KERN_INFO "IFWLOG: unregister target\n"); ++ ipt_unregister_target(&ipt_IFWLOG); ++} ++ ++module_init(init); ++module_exit(fini); +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -331,6 +331,17 @@ config IP_NF_TARGET_TTL + (e.g. when running oldconfig). It selects + CONFIG_NETFILTER_XT_TARGET_HL. + ++config IP_NF_TARGET_IFWLOG ++ tristate 'IFWLOG target support' ++ depends on IP_NF_IPTABLES ++ help ++ This option adds a `IFWLOG' target, which is used by ++ Interactive Firewall for sending informations to a userspace ++ daemon ++ ++ If you want to compile it as a module, say M here and read ++ Documentation/modules.txt. If unsure, say `N'. ++ + # raw + specific targets + config IP_NF_RAW + tristate 'raw table support (required for NOTRACK/TRACE)' +--- /dev/null ++++ b/include/linux/netfilter_ipv4/ipt_IFWLOG.h +@@ -0,0 +1,26 @@ ++#ifndef _IPT_IFWLOG_H ++#define _IPT_IFWLOG_H ++ ++#ifndef NETLINK_IFWLOG ++#define NETLINK_IFWLOG 19 ++#endif ++ ++#define PREFSIZ 32 ++ ++struct nl_msg { /* Netlink message */ ++ long timestamp_sec; /* time packet */ ++ char indev_name[IFNAMSIZ]; /* name of the ingoing interface */ ++ char outdev_name[IFNAMSIZ]; /* name of the outgoing interface */ ++ unsigned char prefix[PREFSIZ]; /* informations on the logging reason */ ++ struct iphdr ip; ++ union { ++ struct tcphdr th; ++ struct udphdr uh; ++ } h; ++}; ++ ++struct ipt_IFWLOG_info { ++ char prefix[PREFSIZ]; ++}; ++ ++#endif /* _IPT_IFWLOG_H */ +--- linux/net/ipv4/netfilter/Makefile.net-netfilter-IFWLOG.orig 2013-10-13 11:29:08.799136037 +0300 ++++ linux/net/ipv4/netfilter/Makefile 2013-10-13 11:30:28.085842333 +0300 +@@ -44,6 +44,7 @@ obj-$(CONFIG_IP_NF_MATCH_RPFILTER) += ip + # targets + obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o + obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o ++obj-$(CONFIG_IP_NF_TARGET_IFWLOG) += ipt_IFWLOG.o + obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o + obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o + obj-$(CONFIG_IP_NF_TARGET_SYNPROXY) += ipt_SYNPROXY.o diff --git a/kernel/tools/perf/files/patches/mageia/net-netfilter-psd-2.6.35-buildfix.patch b/kernel/tools/perf/files/patches/mageia/net-netfilter-psd-2.6.35-buildfix.patch new file mode 100644 index 0000000000..218031c4a5 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-netfilter-psd-2.6.35-buildfix.patch @@ -0,0 +1,11 @@ +--- linux-2.6.35-rc6-git-mnb0.1/net/ipv4/netfilter/ipt_psd.c.orig 2010-07-30 21:17:30.000000000 +0300 ++++ linux-2.6.35-rc6-git-mnb0.1/net/ipv4/netfilter/ipt_psd.c 2010-07-31 13:29:00.623601957 +0300 +@@ -98,7 +98,7 @@ static inline int hashfunc(struct in_add + + static bool + ipt_psd_match(const struct sk_buff *pskb, +- const struct xt_match_param *match_param) ++ struct xt_action_param *match_param) + { + struct iphdr *ip_hdr; + struct tcphdr *tcp_hdr; diff --git a/kernel/tools/perf/files/patches/mageia/net-netfilter-psd-mdv.patch b/kernel/tools/perf/files/patches/mageia/net-netfilter-psd-mdv.patch new file mode 100644 index 0000000000..6bcf06ddf8 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-netfilter-psd-mdv.patch @@ -0,0 +1,233 @@ +ipt_psd: Mandriva changes + +This patch holds all the Mandriva changes done in ipt_psd +netfilter module. + +Most of the time they're just upgrades to match with new +API in the kernel. + +This work is mostly done by Thomas Backlund, Herton R. +Krzesinski and Luiz Fernando N. Capitulino. + +Signed-off-by: Luiz Fernando N. Capitulino +Signed-off-by: Herton Ronaldo Krzesinski + +--- + include/linux/netfilter_ipv4/Kbuild | 1 + net/ipv4/netfilter/Kconfig | 8 ++ + net/ipv4/netfilter/ipt_psd.c | 113 ++++++++++++++---------------------- + 3 files changed, 55 insertions(+), 67 deletions(-) + +diff -p -up linux-2.6.28/net/ipv4/netfilter/ipt_psd.c.orig linux-2.6.28/net/ipv4/netfilter/ipt_psd.c +--- linux-2.6.28/net/ipv4/netfilter/ipt_psd.c.orig 2008-12-12 11:03:05.000000000 -0500 ++++ linux-2.6.28/net/ipv4/netfilter/ipt_psd.c 2008-12-12 11:04:03.000000000 -0500 +@@ -1,21 +1,24 @@ + /* +- This is a module which is used for PSD (portscan detection) +- Derived from scanlogd v2.1 written by Solar Designer +- and LOG target module. +- +- Copyright (C) 2000,2001 astaro AG +- +- This file is distributed under the terms of the GNU General Public +- License (GPL). Copies of the GPL can be obtained from: +- ftp://prep.ai.mit.edu/pub/gnu/GPL +- +- 2000-05-04 Markus Hennig : initial +- 2000-08-18 Dennis Koslowski : first release +- 2000-12-01 Dennis Koslowski : UDP scans detection added +- 2001-01-02 Dennis Koslowski : output modified +- 2001-02-04 Jan Rekorajski : converted from target to match +- 2004-05-05 Martijn Lievaart : ported to 2.6 +-*/ ++ * This is a module which is used for PSD (portscan detection) ++ * Derived from scanlogd v2.1 written by Solar Designer ++ * and LOG target module. ++ * ++ * Copyright (C) 2000,2001 astaro AG ++ * ++ * This file is distributed under the terms of the GNU General Public ++ * License (GPL). Copies of the GPL can be obtained from: ++ * ftp://prep.ai.mit.edu/pub/gnu/GPL ++ * ++ * 2000-05-04 Markus Hennig : initial ++ * 2000-08-18 Dennis Koslowski : first release ++ * 2000-12-01 Dennis Koslowski : UDP scans detection added ++ * 2001-01-02 Dennis Koslowski : output modified ++ * 2001-02-04 Jan Rekorajski : converted from target to match ++ * 2004-05-05 Martijn Lievaart : ported to 2.6 ++ * 2007-10-10 Thomas Backlund : 2.6.22 update ++ * 2007-11-14 Luiz Capitulino : 2.6.22 API usage fixes ++ * 2007-11-26 Herton Ronaldo Krzesinski : switch xt_match->match to bool ++ */ + + #include + #include +@@ -54,7 +57,7 @@ struct port { + */ + struct host { + struct host *next; /* Next entry with the same hash */ +- clock_t timestamp; /* Last update time */ ++ unsigned long timestamp; /* Last update time */ + struct in_addr src_addr; /* Source address */ + struct in_addr dest_addr; /* Destination address */ + unsigned short src_port; /* Source port */ +@@ -93,33 +96,29 @@ static inline int hashfunc(struct in_add + return hash & (HASH_SIZE - 1); + } + +-static int ++static bool + ipt_psd_match(const struct sk_buff *pskb, +- const struct net_device *in, +- const struct net_device *out, +- const void *matchinfo, +- int offset, +- int *hotdrop) ++ const struct xt_match_param *match_param) + { + struct iphdr *ip_hdr; + struct tcphdr *tcp_hdr; + struct in_addr addr; + u_int16_t src_port,dest_port; + u_int8_t tcp_flags, proto; +- clock_t now; ++ unsigned long now; + struct host *curr, *last, **head; + int hash, index, count; + + /* Parameters from userspace */ +- const struct ipt_psd_info *psdinfo = matchinfo; ++ const struct ipt_psd_info *psdinfo = match_param->matchinfo; + + /* IP header */ +- ip_hdr = pskb->nh.iph; ++ ip_hdr = ipip_hdr(pskb); + + /* Sanity check */ + if (ntohs(ip_hdr->frag_off) & IP_OFFSET) { + DEBUGP("PSD: sanity check failed\n"); +- return 0; ++ return false; + } + + /* TCP or UDP ? */ +@@ -127,7 +126,7 @@ ipt_psd_match(const struct sk_buff *pskb + + if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) { + DEBUGP("PSD: protocol not supported\n"); +- return 0; ++ return false; + } + + /* Get the source address, source & destination ports, and TCP flags */ +@@ -151,7 +150,7 @@ ipt_psd_match(const struct sk_buff *pskb + * them spoof us. [DHCP needs this feature - HW] */ + if (!addr.s_addr) { + DEBUGP("PSD: spoofed source address (0.0.0.0)\n"); +- return 0; ++ return false; + } + + /* Use jiffies here not to depend on someone setting the time while we're +@@ -298,46 +297,26 @@ ipt_psd_match(const struct sk_buff *pskb + + out_no_match: + spin_unlock(&state.lock); +- return 0; ++ return false; + + out_match: + spin_unlock(&state.lock); +- return 1; ++ DEBUGP("PSD: Dropping packets from "NIPQUAD_FMT" \n", ++ NIPQUAD(curr->src_addr.s_addr)); ++ return true; + } + +-static int ipt_psd_checkentry(const char *tablename, +- const struct ipt_ip *e, +- void *matchinfo, +- unsigned int matchsize, +- unsigned int hook_mask) +-{ +-/* const struct ipt_psd_info *psdinfo = targinfo;*/ +- +- /* we accept TCP only */ +-/* if (e->ip.proto != IPPROTO_TCP) { */ +-/* DEBUGP("PSD: specified protocol may be TCP only\n"); */ +-/* return 0; */ +-/* } */ +- +- if (matchsize != IPT_ALIGN(sizeof(struct ipt_psd_info))) { +- DEBUGP("PSD: matchsize %u != %u\n", +- matchsize, +- IPT_ALIGN(sizeof(struct ipt_psd_info))); +- return 0; +- } +- +- return 1; +-} +- +-static struct ipt_match ipt_psd_reg = { +- .name = "psd", +- .match = ipt_psd_match, +- .checkentry = ipt_psd_checkentry, +- .me = THIS_MODULE }; ++static struct xt_match ipt_psd_reg = { ++ .name = "psd", ++ .family = AF_INET, ++ .match = ipt_psd_match, ++ .matchsize = sizeof(struct ipt_psd_info), ++ .me = THIS_MODULE ++}; + +-static int __init init(void) ++static int __init ipt_psd_init(void) + { +- if (ipt_register_match(&ipt_psd_reg)) ++ if (xt_register_match(&ipt_psd_reg)) + return -EINVAL; + + memset(&state, 0, sizeof(state)); +@@ -348,11 +327,11 @@ static int __init init(void) + return 0; + } + +-static void __exit fini(void) ++static void __exit ipt_psd_fini(void) + { +- ipt_unregister_match(&ipt_psd_reg); ++ xt_unregister_match(&ipt_psd_reg); + printk("netfilter PSD unloaded - (c) astaro AG\n"); + } + +-module_init(init); +-module_exit(fini); ++module_init(ipt_psd_init); ++module_exit(ipt_psd_fini); +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -193,6 +193,14 @@ config IP_NF_MATCH_ECN + (e.g. when running oldconfig). It selects + CONFIG_NETFILTER_XT_MATCH_ECN. + ++config IP_NF_MATCH_PSD ++ tristate 'Port scanner detection support' ++ depends on NETFILTER_ADVANCED ++ help ++ Module used for PSD (portscan detection). ++ ++ To compile it as a module, choose M here. If unsure, say N. ++ + config IP_NF_MATCH_RPFILTER + tristate '"rpfilter" reverse path filter match support' + depends on NETFILTER_ADVANCED +--- linux/include/uapi/linux/netfilter_ipv4/Kbuild.orig ++++ linux/include/uapi/linux/netfilter_ipv4/Kbuild +@@ -8,4 +8,5 @@ header-y += ipt_REJECT.h + header-y += ipt_TTL.h + header-y += ipt_ah.h + header-y += ipt_ecn.h ++header-y += ipt_psd.h + header-y += ipt_ttl.h diff --git a/kernel/tools/perf/files/patches/mageia/net-netfilter-psd.patch b/kernel/tools/perf/files/patches/mageia/net-netfilter-psd.patch new file mode 100644 index 0000000000..8ec326ff2a --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-netfilter-psd.patch @@ -0,0 +1,420 @@ +--- + include/linux/netfilter_ipv4/ipt_psd.h | 40 +++ + net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/ipt_psd.c | 358 +++++++++++++++++++++++++++++++++ + 3 files changed, 399 insertions(+) + +--- /dev/null ++++ b/net/ipv4/netfilter/ipt_psd.c +@@ -0,0 +1,358 @@ ++/* ++ This is a module which is used for PSD (portscan detection) ++ Derived from scanlogd v2.1 written by Solar Designer ++ and LOG target module. ++ ++ Copyright (C) 2000,2001 astaro AG ++ ++ This file is distributed under the terms of the GNU General Public ++ License (GPL). Copies of the GPL can be obtained from: ++ ftp://prep.ai.mit.edu/pub/gnu/GPL ++ ++ 2000-05-04 Markus Hennig : initial ++ 2000-08-18 Dennis Koslowski : first release ++ 2000-12-01 Dennis Koslowski : UDP scans detection added ++ 2001-01-02 Dennis Koslowski : output modified ++ 2001-02-04 Jan Rekorajski : converted from target to match ++ 2004-05-05 Martijn Lievaart : ported to 2.6 ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Dennis Koslowski "); ++ ++#define HF_DADDR_CHANGING 0x01 ++#define HF_SPORT_CHANGING 0x02 ++#define HF_TOS_CHANGING 0x04 ++#define HF_TTL_CHANGING 0x08 ++ ++/* ++ * Information we keep per each target port ++ */ ++struct port { ++ u_int16_t number; /* port number */ ++ u_int8_t proto; /* protocol number */ ++ u_int8_t and_flags; /* tcp ANDed flags */ ++ u_int8_t or_flags; /* tcp ORed flags */ ++}; ++ ++/* ++ * Information we keep per each source address. ++ */ ++struct host { ++ struct host *next; /* Next entry with the same hash */ ++ clock_t timestamp; /* Last update time */ ++ struct in_addr src_addr; /* Source address */ ++ struct in_addr dest_addr; /* Destination address */ ++ unsigned short src_port; /* Source port */ ++ int count; /* Number of ports in the list */ ++ int weight; /* Total weight of ports in the list */ ++ struct port ports[SCAN_MAX_COUNT - 1]; /* List of ports */ ++ unsigned char tos; /* TOS */ ++ unsigned char ttl; /* TTL */ ++ unsigned char flags; /* HF_ flags bitmask */ ++}; ++ ++/* ++ * State information. ++ */ ++static struct { ++ spinlock_t lock; ++ struct host list[LIST_SIZE]; /* List of source addresses */ ++ struct host *hash[HASH_SIZE]; /* Hash: pointers into the list */ ++ int index; /* Oldest entry to be replaced */ ++} state; ++ ++/* ++ * Convert an IP address into a hash table index. ++ */ ++static inline int hashfunc(struct in_addr addr) ++{ ++ unsigned int value; ++ int hash; ++ ++ value = addr.s_addr; ++ hash = 0; ++ do { ++ hash ^= value; ++ } while ((value >>= HASH_LOG)); ++ ++ return hash & (HASH_SIZE - 1); ++} ++ ++static int ++ipt_psd_match(const struct sk_buff *pskb, ++ const struct net_device *in, ++ const struct net_device *out, ++ const void *matchinfo, ++ int offset, ++ int *hotdrop) ++{ ++ struct iphdr *ip_hdr; ++ struct tcphdr *tcp_hdr; ++ struct in_addr addr; ++ u_int16_t src_port,dest_port; ++ u_int8_t tcp_flags, proto; ++ clock_t now; ++ struct host *curr, *last, **head; ++ int hash, index, count; ++ ++ /* Parameters from userspace */ ++ const struct ipt_psd_info *psdinfo = matchinfo; ++ ++ /* IP header */ ++ ip_hdr = pskb->nh.iph; ++ ++ /* Sanity check */ ++ if (ntohs(ip_hdr->frag_off) & IP_OFFSET) { ++ DEBUGP("PSD: sanity check failed\n"); ++ return 0; ++ } ++ ++ /* TCP or UDP ? */ ++ proto = ip_hdr->protocol; ++ ++ if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) { ++ DEBUGP("PSD: protocol not supported\n"); ++ return 0; ++ } ++ ++ /* Get the source address, source & destination ports, and TCP flags */ ++ ++ addr.s_addr = ip_hdr->saddr; ++ ++ tcp_hdr = (struct tcphdr*)((u_int32_t *)ip_hdr + ip_hdr->ihl); ++ ++ /* Yep, it´s dirty */ ++ src_port = tcp_hdr->source; ++ dest_port = tcp_hdr->dest; ++ ++ if (proto == IPPROTO_TCP) { ++ tcp_flags = *((u_int8_t*)tcp_hdr + 13); ++ } ++ else { ++ tcp_flags = 0x00; ++ } ++ ++ /* We're using IP address 0.0.0.0 for a special purpose here, so don't let ++ * them spoof us. [DHCP needs this feature - HW] */ ++ if (!addr.s_addr) { ++ DEBUGP("PSD: spoofed source address (0.0.0.0)\n"); ++ return 0; ++ } ++ ++ /* Use jiffies here not to depend on someone setting the time while we're ++ * running; we need to be careful with possible return value overflows. */ ++ now = jiffies; ++ ++ spin_lock(&state.lock); ++ ++ /* Do we know this source address already? */ ++ count = 0; ++ last = NULL; ++ if ((curr = *(head = &state.hash[hash = hashfunc(addr)]))) ++ do { ++ if (curr->src_addr.s_addr == addr.s_addr) break; ++ count++; ++ if (curr->next) last = curr; ++ } while ((curr = curr->next)); ++ ++ if (curr) { ++ ++ /* We know this address, and the entry isn't too old. Update it. */ ++ if (now - curr->timestamp <= (psdinfo->delay_threshold*HZ)/100 && ++ time_after_eq(now, curr->timestamp)) { ++ ++ /* Just update the appropriate list entry if we've seen this port already */ ++ for (index = 0; index < curr->count; index++) { ++ if (curr->ports[index].number == dest_port) { ++ curr->ports[index].proto = proto; ++ curr->ports[index].and_flags &= tcp_flags; ++ curr->ports[index].or_flags |= tcp_flags; ++ goto out_no_match; ++ } ++ } ++ ++ /* TCP/ACK and/or TCP/RST to a new port? This could be an outgoing connection. */ ++ if (proto == IPPROTO_TCP && (tcp_hdr->ack || tcp_hdr->rst)) ++ goto out_no_match; ++ ++ /* Packet to a new port, and not TCP/ACK: update the timestamp */ ++ curr->timestamp = now; ++ ++ /* Logged this scan already? Then drop the packet. */ ++ if (curr->weight >= psdinfo->weight_threshold) ++ goto out_match; ++ ++ /* Specify if destination address, source port, TOS or TTL are not fixed */ ++ if (curr->dest_addr.s_addr != ip_hdr->daddr) ++ curr->flags |= HF_DADDR_CHANGING; ++ if (curr->src_port != src_port) ++ curr->flags |= HF_SPORT_CHANGING; ++ if (curr->tos != ip_hdr->tos) ++ curr->flags |= HF_TOS_CHANGING; ++ if (curr->ttl != ip_hdr->ttl) ++ curr->flags |= HF_TTL_CHANGING; ++ ++ /* Update the total weight */ ++ curr->weight += (ntohs(dest_port) < 1024) ? ++ psdinfo->lo_ports_weight : psdinfo->hi_ports_weight; ++ ++ /* Got enough destination ports to decide that this is a scan? */ ++ /* Then log it and drop the packet. */ ++ if (curr->weight >= psdinfo->weight_threshold) ++ goto out_match; ++ ++ /* Remember the new port */ ++ if (curr->count < SCAN_MAX_COUNT) { ++ curr->ports[curr->count].number = dest_port; ++ curr->ports[curr->count].proto = proto; ++ curr->ports[curr->count].and_flags = tcp_flags; ++ curr->ports[curr->count].or_flags = tcp_flags; ++ curr->count++; ++ } ++ ++ goto out_no_match; ++ } ++ ++ /* We know this address, but the entry is outdated. Mark it unused, and ++ * remove from the hash table. We'll allocate a new entry instead since ++ * this one might get re-used too soon. */ ++ curr->src_addr.s_addr = 0; ++ if (last) ++ last->next = last->next->next; ++ else if (*head) ++ *head = (*head)->next; ++ last = NULL; ++ } ++ ++ /* We don't need an ACK from a new source address */ ++ if (proto == IPPROTO_TCP && tcp_hdr->ack) ++ goto out_no_match; ++ ++ /* Got too many source addresses with the same hash value? Then remove the ++ * oldest one from the hash table, so that they can't take too much of our ++ * CPU time even with carefully chosen spoofed IP addresses. */ ++ if (count >= HASH_MAX && last) last->next = NULL; ++ ++ /* We're going to re-use the oldest list entry, so remove it from the hash ++ * table first (if it is really already in use, and isn't removed from the ++ * hash table already because of the HASH_MAX check above). */ ++ ++ /* First, find it */ ++ if (state.list[state.index].src_addr.s_addr) ++ head = &state.hash[hashfunc(state.list[state.index].src_addr)]; ++ else ++ head = &last; ++ last = NULL; ++ if ((curr = *head)) ++ do { ++ if (curr == &state.list[state.index]) break; ++ last = curr; ++ } while ((curr = curr->next)); ++ ++ /* Then, remove it */ ++ if (curr) { ++ if (last) ++ last->next = last->next->next; ++ else if (*head) ++ *head = (*head)->next; ++ } ++ ++ /* Get our list entry */ ++ curr = &state.list[state.index++]; ++ if (state.index >= LIST_SIZE) state.index = 0; ++ ++ /* Link it into the hash table */ ++ head = &state.hash[hash]; ++ curr->next = *head; ++ *head = curr; ++ ++ /* And fill in the fields */ ++ curr->timestamp = now; ++ curr->src_addr = addr; ++ curr->dest_addr.s_addr = ip_hdr->daddr; ++ curr->src_port = src_port; ++ curr->count = 1; ++ curr->weight = (ntohs(dest_port) < 1024) ? ++ psdinfo->lo_ports_weight : psdinfo->hi_ports_weight; ++ curr->ports[0].number = dest_port; ++ curr->ports[0].proto = proto; ++ curr->ports[0].and_flags = tcp_flags; ++ curr->ports[0].or_flags = tcp_flags; ++ curr->tos = ip_hdr->tos; ++ curr->ttl = ip_hdr->ttl; ++ ++out_no_match: ++ spin_unlock(&state.lock); ++ return 0; ++ ++out_match: ++ spin_unlock(&state.lock); ++ return 1; ++} ++ ++static int ipt_psd_checkentry(const char *tablename, ++ const struct ipt_ip *e, ++ void *matchinfo, ++ unsigned int matchsize, ++ unsigned int hook_mask) ++{ ++/* const struct ipt_psd_info *psdinfo = targinfo;*/ ++ ++ /* we accept TCP only */ ++/* if (e->ip.proto != IPPROTO_TCP) { */ ++/* DEBUGP("PSD: specified protocol may be TCP only\n"); */ ++/* return 0; */ ++/* } */ ++ ++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_psd_info))) { ++ DEBUGP("PSD: matchsize %u != %u\n", ++ matchsize, ++ IPT_ALIGN(sizeof(struct ipt_psd_info))); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ipt_match ipt_psd_reg = { ++ .name = "psd", ++ .match = ipt_psd_match, ++ .checkentry = ipt_psd_checkentry, ++ .me = THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ if (ipt_register_match(&ipt_psd_reg)) ++ return -EINVAL; ++ ++ memset(&state, 0, sizeof(state)); ++ ++ spin_lock_init(&(state.lock)); ++ ++ printk("netfilter PSD loaded - (c) astaro AG\n"); ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_match(&ipt_psd_reg); ++ printk("netfilter PSD unloaded - (c) astaro AG\n"); ++} ++ ++module_init(init); ++module_exit(fini); +--- /dev/null ++++ b/include/linux/netfilter_ipv4/ipt_psd.h +@@ -0,0 +1,40 @@ ++#ifndef _IPT_PSD_H ++#define _IPT_PSD_H ++ ++#include ++#include ++ ++/* ++ * High port numbers have a lower weight to reduce the frequency of false ++ * positives, such as from passive mode FTP transfers. ++ */ ++#define PORT_WEIGHT_PRIV 3 ++#define PORT_WEIGHT_HIGH 1 ++ ++/* ++ * Port scan detection thresholds: at least COUNT ports need to be scanned ++ * from the same source, with no longer than DELAY ticks between ports. ++ */ ++#define SCAN_MIN_COUNT 7 ++#define SCAN_MAX_COUNT (SCAN_MIN_COUNT * PORT_WEIGHT_PRIV) ++#define SCAN_WEIGHT_THRESHOLD SCAN_MAX_COUNT ++#define SCAN_DELAY_THRESHOLD (300) /* old usage of HZ here was erroneously and broke under uml */ ++ ++/* ++ * Keep track of up to LIST_SIZE source addresses, using a hash table of ++ * HASH_SIZE entries for faster lookups, but limiting hash collisions to ++ * HASH_MAX source addresses per the same hash value. ++ */ ++#define LIST_SIZE 0x100 ++#define HASH_LOG 9 ++#define HASH_SIZE (1 << HASH_LOG) ++#define HASH_MAX 0x10 ++ ++struct ipt_psd_info { ++ unsigned int weight_threshold; ++ unsigned int delay_threshold; ++ unsigned short lo_ports_weight; ++ unsigned short hi_ports_weight; ++}; ++ ++#endif /*_IPT_PSD_H*/ +--- a/net/ipv4/netfilter/Makefile ++++ b/net/ipv4/netfilter/Makefile +@@ -49,6 +49,7 @@ + + # matches + obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o ++obj-$(CONFIG_IP_NF_MATCH_PSD) += ipt_psd.o + obj-$(CONFIG_IP_NF_MATCH_RPFILTER) += ipt_rpfilter.o + + # targets diff --git a/kernel/tools/perf/files/patches/mageia/net-sis190-fix-list-usage.patch b/kernel/tools/perf/files/patches/mageia/net-sis190-fix-list-usage.patch new file mode 100644 index 0000000000..eda13d1d32 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-sis190-fix-list-usage.patch @@ -0,0 +1,30 @@ +--- + drivers/net/ethernet/sis/sis190.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- linux/drivers/net/ethernet/sis/sis190.c.net-sis190-fix-list-usage.orig ++++ linux/drivers/net/ethernet/sis/sis190.c +@@ -1252,6 +1252,7 @@ static u16 sis190_default_phy(struct net + struct sis190_private *tp = netdev_priv(dev); + struct mii_if_info *mii_if = &tp->mii_if; + void __iomem *ioaddr = tp->mmio_addr; ++ struct list_head *l; + u16 status; + + phy_home = phy_default = phy_lan = NULL; +@@ -1280,9 +1281,12 @@ static u16 sis190_default_phy(struct net + phy_default = phy_home; + else if (phy_lan) + phy_default = phy_lan; +- else +- phy_default = list_first_entry(&tp->first_phy, +- struct sis190_phy, list); ++ else { ++ l = &tp->first_phy; ++ l = l->next; ++ phy_default = list_first_entry(l, struct sis190_phy, list); ++ ++ } + } + + if (mii_if->phy_id != phy_default->phy_id) { diff --git a/kernel/tools/perf/files/patches/mageia/net-wireless-iwlwifi-add-new-8260-PCI-IDs.patch b/kernel/tools/perf/files/patches/mageia/net-wireless-iwlwifi-add-new-8260-PCI-IDs.patch new file mode 100644 index 0000000000..3b78306034 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-wireless-iwlwifi-add-new-8260-PCI-IDs.patch @@ -0,0 +1,42 @@ +From: Luca Coelho +Subject: [PATCH 13/56] iwlwifi: add new 8260 PCI IDs +Date: Wed, 6 Jul 2016 13:40:08 +0300 + +From: Oren Givon + +Add 3 new 8260 series PCI IDs: + - (0x24F3, 0x10B0) + - (0x24F3, 0xD0B0) + - (0x24F3, 0xB0B0) + +CC: [4.1+] +Signed-off-by: Oren Givon +Signed-off-by: David Spinadel +Signed-off-by: Luca Coelho +--- + drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +index a588b05..1cae19d 100644 +--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c ++++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +@@ -433,6 +433,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { + /* 8000 Series */ + {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x1010, iwl8260_2ac_cfg)}, ++ {IWL_PCI_DEVICE(0x24F3, 0x10B0, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0130, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x1130, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0132, iwl8260_2ac_cfg)}, +@@ -454,6 +455,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { + {IWL_PCI_DEVICE(0x24F3, 0xD010, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0xC050, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0xD050, iwl8260_2ac_cfg)}, ++ {IWL_PCI_DEVICE(0x24F3, 0xD0B0, iwl8260_2ac_cfg)}, ++ {IWL_PCI_DEVICE(0x24F3, 0xB0B0, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x8010, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x8110, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x9010, iwl8260_2ac_cfg)}, +-- +2.8.1 diff --git a/kernel/tools/perf/files/patches/mageia/net-wireless-iwlwifi-add-new-8265.patch b/kernel/tools/perf/files/patches/mageia/net-wireless-iwlwifi-add-new-8265.patch new file mode 100644 index 0000000000..56eb2464e3 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-wireless-iwlwifi-add-new-8265.patch @@ -0,0 +1,48 @@ +From: Luca Coelho +Subject: [PATCH 14/56] iwlwifi: add new 8265 +Date: Wed, 6 Jul 2016 13:40:09 +0300 + +From: Oren Givon + +Add 6 new 8265 series PCI IDs: + - (0x24FD, 0x1130) + - (0x24FD, 0x0130) + - (0x24FD, 0x0910) + - (0x24FD, 0x0930) + - (0x24FD, 0x0950) + - (0x24FD, 0x0850) + +CC: [4.6+] +Signed-off-by: Oren Givon +Signed-off-by: David Spinadel +Signed-off-by: Luca Coelho +--- + drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +index 1cae19d..6f020e4 100644 +--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c ++++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +@@ -484,6 +484,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { + {IWL_PCI_DEVICE(0x24FD, 0x0010, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x0110, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x1110, iwl8265_2ac_cfg)}, ++ {IWL_PCI_DEVICE(0x24FD, 0x1130, iwl8265_2ac_cfg)}, ++ {IWL_PCI_DEVICE(0x24FD, 0x0130, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x1010, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x0050, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x0150, iwl8265_2ac_cfg)}, +@@ -494,6 +496,10 @@ static const struct pci_device_id iwl_hw_card_ids[] = { + {IWL_PCI_DEVICE(0x24FD, 0x0810, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x9110, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x8130, iwl8265_2ac_cfg)}, ++ {IWL_PCI_DEVICE(0x24FD, 0x0910, iwl8265_2ac_cfg)}, ++ {IWL_PCI_DEVICE(0x24FD, 0x0930, iwl8265_2ac_cfg)}, ++ {IWL_PCI_DEVICE(0x24FD, 0x0950, iwl8265_2ac_cfg)}, ++ {IWL_PCI_DEVICE(0x24FD, 0x0850, iwl8265_2ac_cfg)}, + + /* 9000 Series */ + {IWL_PCI_DEVICE(0x2526, 0x0000, iwl9260_2ac_cfg)}, +-- +2.8.1 diff --git a/kernel/tools/perf/files/patches/mageia/net-wireless-iwlwifi-pcie-enable-interrupts-before-releasing-the-NICs-CPU.patch b/kernel/tools/perf/files/patches/mageia/net-wireless-iwlwifi-pcie-enable-interrupts-before-releasing-the-NICs-CPU.patch new file mode 100644 index 0000000000..b7b37825ac --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-wireless-iwlwifi-pcie-enable-interrupts-before-releasing-the-NICs-CPU.patch @@ -0,0 +1,58 @@ +From: Luca Coelho +Subject: [PATCH 28/56] iwlwifi: pcie: enable interrupts before releasing the NIC's CPU +Date: Wed, 6 Jul 2016 13:40:23 +0300 + +From: Emmanuel Grumbach + +The NIC's CPU gets started after the firmware has been +written to its memory. The first thing it does is to +send an interrupt to let the driver know that it is +running. In order to get that interrupt, the driver needs +to make sure it is not masked. Of course, the interrupt +needs to be enabled in the driver before the CPU starts to +run. +I mistakenly inversed those two steps leading to races +which prevented the driver from getting the alive interrupt +from the firmware. +Fix that. + +Cc: [4.5+] +Fixes: a6bd005fe92 ("iwlwifi: pcie: fix RF-Kill vs. firmware load race") +Signed-off-by: Emmanuel Grumbach +Signed-off-by: Luca Coelho +--- + drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +index 3badebb..ac623c3 100644 +--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c ++++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +@@ -801,6 +801,8 @@ static int iwl_pcie_load_cpu_sections_8000(struct iwl_trans *trans, + + *first_ucode_section = last_read_idx; + ++ iwl_enable_interrupts(trans); ++ + if (cpu == 1) + iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFF); + else +@@ -980,6 +982,8 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, + iwl_pcie_apply_destination(trans); + } + ++ iwl_enable_interrupts(trans); ++ + /* release CPU reset */ + iwl_write32(trans, CSR_RESET, 0); + +@@ -1215,7 +1219,6 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, + ret = iwl_pcie_load_given_ucode_8000(trans, fw); + else + ret = iwl_pcie_load_given_ucode(trans, fw); +- iwl_enable_interrupts(trans); + + /* re-check RF-Kill state since we may have missed the interrupt */ + hw_rfkill = iwl_is_rfkill_set(trans); +-- +2.8.1 diff --git a/kernel/tools/perf/files/patches/mageia/net-wireless-iwlwifi-pcie-fix-a-race-in-firmware-loading-flow.patch b/kernel/tools/perf/files/patches/mageia/net-wireless-iwlwifi-pcie-fix-a-race-in-firmware-loading-flow.patch new file mode 100644 index 0000000000..4ea2eee8dc --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-wireless-iwlwifi-pcie-fix-a-race-in-firmware-loading-flow.patch @@ -0,0 +1,195 @@ +From: Luca Coelho +Subject: [PATCH 48/56] iwlwifi: pcie: fix a race in firmware loading flow +Date: Wed, 6 Jul 2016 13:40:43 +0300 + +From: Emmanuel Grumbach + +Upon firmware load interrupt (FH_TX), the ISR re-enables the +firmware load interrupt only to avoid races with other +flows as described in the commit below. When the firmware +is completely loaded, the thread that is loading the +firmware will enable all the interrupts to make sure that +the driver gets the ALIVE interrupt. +The problem with that is that the thread that is loading +the firmware is actually racing against the ISR and we can +get to the following situation: + +CPU0 CPU1 +iwl_pcie_load_given_ucode + ... + iwl_pcie_load_firmware_chunk + wait_for_interrupt + + ISR handles CSR_INT_BIT_FH_TX + ISR wakes up the thread on CPU0 + /* enable all the interrupts + * to get the ALIVE interrupt + */ + iwl_enable_interrupts + ISR re-enables CSR_INT_BIT_FH_TX only + /* start the firmware */ + iwl_write32(trans, CSR_RESET, 0); + +BUG! ALIVE interrupt will never arrive since it has been +masked by CPU1. + +In order to fix that, change the ISR to first check if +STATUS_INT_ENABLED is set. If so, re-enable all the +interrupts. If STATUS_INT_ENABLED is clear, then we can +check what specific interrupt happened and re-enable only +that specific interrupt (RFKILL or FH_TX). + +All the credit for the analysis goes to Kirtika who did the +actual debugging work. + +Cc: [4.5+] +Fixes: a6bd005fe92 ("iwlwifi: pcie: fix RF-Kill vs. firmware load race") +Signed-off-by: Luca Coelho +--- + drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 21 +++++++++++++++++++-- + drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 16 +++++++++------- + drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 8 -------- + 3 files changed, 28 insertions(+), 17 deletions(-) + +diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +index f684b9d..54af3da 100644 +--- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h ++++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +@@ -500,7 +500,7 @@ void iwl_pcie_dump_csr(struct iwl_trans *trans); + /***************************************************** + * Helpers + ******************************************************/ +-static inline void iwl_disable_interrupts(struct iwl_trans *trans) ++static inline void _iwl_disable_interrupts(struct iwl_trans *trans) + { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + +@@ -523,7 +523,16 @@ static inline void iwl_disable_interrupts(struct iwl_trans *trans) + IWL_DEBUG_ISR(trans, "Disabled interrupts\n"); + } + +-static inline void iwl_enable_interrupts(struct iwl_trans *trans) ++static inline void iwl_disable_interrupts(struct iwl_trans *trans) ++{ ++ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); ++ ++ spin_lock(&trans_pcie->irq_lock); ++ _iwl_disable_interrupts(trans); ++ spin_unlock(&trans_pcie->irq_lock); ++} ++ ++static inline void _iwl_enable_interrupts(struct iwl_trans *trans) + { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + +@@ -546,6 +555,14 @@ static inline void iwl_enable_interrupts(struct iwl_trans *trans) + } + } + ++static inline void iwl_enable_interrupts(struct iwl_trans *trans) ++{ ++ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); ++ ++ spin_lock(&trans_pcie->irq_lock); ++ _iwl_enable_interrupts(trans); ++ spin_unlock(&trans_pcie->irq_lock); ++} + static inline void iwl_enable_hw_int_msk_msix(struct iwl_trans *trans, u32 msk) + { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); +diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +index 0296c29..45f1b7e 100644 +--- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c ++++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +@@ -1535,7 +1535,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) + * have anything to service + */ + if (test_bit(STATUS_INT_ENABLED, &trans->status)) +- iwl_enable_interrupts(trans); ++ _iwl_enable_interrupts(trans); + spin_unlock(&trans_pcie->irq_lock); + lock_map_release(&trans->sync_cmd_lockdep_map); + return IRQ_NONE; +@@ -1727,15 +1727,17 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) + inta & ~trans_pcie->inta_mask); + } + ++ spin_lock(&trans_pcie->irq_lock); ++ /* only Re-enable all interrupt if disabled by irq */ ++ if (test_bit(STATUS_INT_ENABLED, &trans->status)) ++ _iwl_enable_interrupts(trans); + /* we are loading the firmware, enable FH_TX interrupt only */ +- if (handled & CSR_INT_BIT_FH_TX) ++ else if (handled & CSR_INT_BIT_FH_TX) + iwl_enable_fw_load_int(trans); +- /* only Re-enable all interrupt if disabled by irq */ +- else if (test_bit(STATUS_INT_ENABLED, &trans->status)) +- iwl_enable_interrupts(trans); + /* Re-enable RF_KILL if it occurred */ + else if (handled & CSR_INT_BIT_RF_KILL) + iwl_enable_rfkill_int(trans); ++ spin_unlock(&trans_pcie->irq_lock); + + out: + lock_map_release(&trans->sync_cmd_lockdep_map); +@@ -1799,7 +1801,7 @@ void iwl_pcie_reset_ict(struct iwl_trans *trans) + return; + + spin_lock(&trans_pcie->irq_lock); +- iwl_disable_interrupts(trans); ++ _iwl_disable_interrupts(trans); + + memset(trans_pcie->ict_tbl, 0, ICT_SIZE); + +@@ -1815,7 +1817,7 @@ void iwl_pcie_reset_ict(struct iwl_trans *trans) + trans_pcie->use_ict = true; + trans_pcie->ict_index = 0; + iwl_write32(trans, CSR_INT, trans_pcie->inta_mask); +- iwl_enable_interrupts(trans); ++ _iwl_enable_interrupts(trans); + spin_unlock(&trans_pcie->irq_lock); + } + +diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +index 3b7a414..9e953a4 100644 +--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c ++++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +@@ -1037,9 +1037,7 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) + was_hw_rfkill = iwl_is_rfkill_set(trans); + + /* tell the device to stop sending interrupts */ +- spin_lock(&trans_pcie->irq_lock); + iwl_disable_interrupts(trans); +- spin_unlock(&trans_pcie->irq_lock); + + /* device going down, Stop using ICT table */ + iwl_pcie_disable_ict(trans); +@@ -1083,9 +1081,7 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) + * the time, unless the interrupt is ACKed even if the interrupt + * should be masked. Re-ACK all the interrupts here. + */ +- spin_lock(&trans_pcie->irq_lock); + iwl_disable_interrupts(trans); +- spin_unlock(&trans_pcie->irq_lock); + + /* clear all status bits */ + clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); +@@ -1578,15 +1574,11 @@ static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans) + mutex_lock(&trans_pcie->mutex); + + /* disable interrupts - don't enable HW RF kill interrupt */ +- spin_lock(&trans_pcie->irq_lock); + iwl_disable_interrupts(trans); +- spin_unlock(&trans_pcie->irq_lock); + + iwl_pcie_apm_stop(trans, true); + +- spin_lock(&trans_pcie->irq_lock); + iwl_disable_interrupts(trans); +- spin_unlock(&trans_pcie->irq_lock); + + iwl_pcie_disable_ict(trans); + +-- +2.8.1 + diff --git a/kernel/tools/perf/files/patches/mageia/pci-add-ALI-M5229-ide-compatibility-mode-quirk.patch b/kernel/tools/perf/files/patches/mageia/pci-add-ALI-M5229-ide-compatibility-mode-quirk.patch new file mode 100644 index 0000000000..47e1a2f5a3 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/pci-add-ALI-M5229-ide-compatibility-mode-quirk.patch @@ -0,0 +1,60 @@ +PCI: Add ALI M5229 comaptibility mode quirk + +The libata driver will not work with an M5229 set into native IDE +mode (the old drivers/pci one does) if the M5229 does not provide +it's own IRQ. + +The M5229 implementation embedded into the ALI M1543 uses the +M1543's ISA PIC to provide the interrupts and thus does not have +an valid PCI IRQ set. This quirk detects the abscence of IRQ and +sets the M5229 back into compatibility mode to use IRQs 14 and 15 +so that libata works correctly. + +Note, I belive that the check for an valid interrupt line is +correct, I only have an M5229 in an ALI M1543 to check this +on. It would be useful to confirm that a M5229 with an valid IRQ +does not trigger this quirk. + +Signed-off-by: Ben Dooks + +--- + drivers/pci/quirks.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -964,6 +964,34 @@ static void __devinit quirk_svwks_csb5id + } + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide); + ++/* Some systems set the ALI M5229 in the ALI M1543 bridge to native mode, ++ * which cannot be supported by the pata_ali.c driver (the old drivers/ide ++ * makes a compatibility effort to change the IDE interrupts). ++ */ ++static void __devinit quirk_ali_ide_compatibility(struct pci_dev *pdev) ++{ ++ u8 tmp; ++ ++ /* pdev->irq and pdev->pin have yet to be initialised, so check ++ * by reading from the configuration header to see if we've got ++ * a valid interrupt line. */ ++ ++ pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp); ++ if (tmp != 0xff) ++ return; ++ ++ pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp); ++ if (tmp & 0x5) { ++ dev_info(&pdev->dev, "quirk: changing to IDE compatibility mode\n"); ++ ++ tmp &= ~0x05; ++ pdev->class &= ~0x05; ++ pci_write_config_byte(pdev, PCI_CLASS_PROG, tmp); ++ } ++} ++ ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, quirk_ali_ide_compatibility); ++ + /* + * Intel 82801CAM ICH3-M datasheet says IDE modes must be the same + */ diff --git a/kernel/tools/perf/files/patches/mageia/pci-quirks-drop-devinit-exit.patch b/kernel/tools/perf/files/patches/mageia/pci-quirks-drop-devinit-exit.patch new file mode 100644 index 0000000000..c8eeeda073 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/pci-quirks-drop-devinit-exit.patch @@ -0,0 +1,11 @@ +--- ./drivers/pci/quirks.c.orig 2013-01-16 18:13:57.000000000 +0200 ++++ ./drivers/pci/quirks.c 2013-01-16 18:42:24.331008402 +0200 +@@ -1083,7 +1083,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SE + * which cannot be supported by the pata_ali.c driver (the old drivers/ide + * makes a compatibility effort to change the IDE interrupts). + */ +-static void __devinit quirk_ali_ide_compatibility(struct pci_dev *pdev) ++static void quirk_ali_ide_compatibility(struct pci_dev *pdev) + { + u8 tmp; + diff --git a/kernel/tools/perf/files/patches/mageia/pinctrl-cherryview-prevent-concurrent-access-to-GPIO.patch b/kernel/tools/perf/files/patches/mageia/pinctrl-cherryview-prevent-concurrent-access-to-GPIO.patch new file mode 100644 index 0000000000..cccb9fd623 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/pinctrl-cherryview-prevent-concurrent-access-to-GPIO.patch @@ -0,0 +1,339 @@ +From 0bd50d719b004110e791800450ad204399100a86 Mon Sep 17 00:00:00 2001 +From: Dan O'Donovan +Date: Fri, 10 Jun 2016 13:23:34 +0100 +Subject: [PATCH] pinctrl: cherryview: prevent concurrent access to GPIO + controllers + +Due to a silicon issue on the Atom X5-Z8000 "Cherry Trail" processor +series, a common lock must be used to prevent concurrent accesses +across the 4 GPIO controllers managed by this driver. + +See Intel Atom Z8000 Processor Series Specification Update +(Rev. 005), errata #CHT34, for further information. + +Cc: stable +Signed-off-by: Dan O'Donovan +Acked-by: Mika Westerberg +Signed-off-by: Linus Walleij +--- + drivers/pinctrl/intel/pinctrl-cherryview.c | 80 ++++++++++++++++-------------- + 1 file changed, 44 insertions(+), 36 deletions(-) + +diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c +index ac4f564..bf65c94 100644 +--- a/drivers/pinctrl/intel/pinctrl-cherryview.c ++++ b/drivers/pinctrl/intel/pinctrl-cherryview.c +@@ -160,7 +160,6 @@ struct chv_pin_context { + * @pctldev: Pointer to the pin controller device + * @chip: GPIO chip in this pin controller + * @regs: MMIO registers +- * @lock: Lock to serialize register accesses + * @intr_lines: Stores mapping between 16 HW interrupt wires and GPIO + * offset (in GPIO number space) + * @community: Community this pinctrl instance represents +@@ -174,7 +173,6 @@ struct chv_pinctrl { + struct pinctrl_dev *pctldev; + struct gpio_chip chip; + void __iomem *regs; +- raw_spinlock_t lock; + unsigned intr_lines[16]; + const struct chv_community *community; + u32 saved_intmask; +@@ -657,6 +655,17 @@ static const struct chv_community *chv_communities[] = { + &southeast_community, + }; + ++/* ++ * Lock to serialize register accesses ++ * ++ * Due to a silicon issue, a shared lock must be used to prevent ++ * concurrent accesses across the 4 GPIO controllers. ++ * ++ * See Intel Atom Z8000 Processor Series Specification Update (Rev. 005), ++ * errata #CHT34, for further information. ++ */ ++static DEFINE_RAW_SPINLOCK(chv_lock); ++ + static void __iomem *chv_padreg(struct chv_pinctrl *pctrl, unsigned offset, + unsigned reg) + { +@@ -718,13 +727,13 @@ static void chv_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, + u32 ctrl0, ctrl1; + bool locked; + +- raw_spin_lock_irqsave(&pctrl->lock, flags); ++ raw_spin_lock_irqsave(&chv_lock, flags); + + ctrl0 = readl(chv_padreg(pctrl, offset, CHV_PADCTRL0)); + ctrl1 = readl(chv_padreg(pctrl, offset, CHV_PADCTRL1)); + locked = chv_pad_locked(pctrl, offset); + +- raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ raw_spin_unlock_irqrestore(&chv_lock, flags); + + if (ctrl0 & CHV_PADCTRL0_GPIOEN) { + seq_puts(s, "GPIO "); +@@ -787,14 +796,14 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function, + + grp = &pctrl->community->groups[group]; + +- raw_spin_lock_irqsave(&pctrl->lock, flags); ++ raw_spin_lock_irqsave(&chv_lock, flags); + + /* Check first that the pad is not locked */ + for (i = 0; i < grp->npins; i++) { + if (chv_pad_locked(pctrl, grp->pins[i])) { + dev_warn(pctrl->dev, "unable to set mode for locked pin %u\n", + grp->pins[i]); +- raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ raw_spin_unlock_irqrestore(&chv_lock, flags); + return -EBUSY; + } + } +@@ -837,7 +846,7 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function, + pin, altfunc->mode, altfunc->invert_oe ? "" : "not "); + } + +- raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ raw_spin_unlock_irqrestore(&chv_lock, flags); + + return 0; + } +@@ -851,13 +860,13 @@ static int chv_gpio_request_enable(struct pinctrl_dev *pctldev, + void __iomem *reg; + u32 value; + +- raw_spin_lock_irqsave(&pctrl->lock, flags); ++ raw_spin_lock_irqsave(&chv_lock, flags); + + if (chv_pad_locked(pctrl, offset)) { + value = readl(chv_padreg(pctrl, offset, CHV_PADCTRL0)); + if (!(value & CHV_PADCTRL0_GPIOEN)) { + /* Locked so cannot enable */ +- raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ raw_spin_unlock_irqrestore(&chv_lock, flags); + return -EBUSY; + } + } else { +@@ -897,7 +906,7 @@ static int chv_gpio_request_enable(struct pinctrl_dev *pctldev, + chv_writel(value, reg); + } + +- raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ raw_spin_unlock_irqrestore(&chv_lock, flags); + + return 0; + } +@@ -911,13 +920,13 @@ static void chv_gpio_disable_free(struct pinctrl_dev *pctldev, + void __iomem *reg; + u32 value; + +- raw_spin_lock_irqsave(&pctrl->lock, flags); ++ raw_spin_lock_irqsave(&chv_lock, flags); + + reg = chv_padreg(pctrl, offset, CHV_PADCTRL0); + value = readl(reg) & ~CHV_PADCTRL0_GPIOEN; + chv_writel(value, reg); + +- raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ raw_spin_unlock_irqrestore(&chv_lock, flags); + } + + static int chv_gpio_set_direction(struct pinctrl_dev *pctldev, +@@ -929,7 +938,7 @@ static int chv_gpio_set_direction(struct pinctrl_dev *pctldev, + unsigned long flags; + u32 ctrl0; + +- raw_spin_lock_irqsave(&pctrl->lock, flags); ++ raw_spin_lock_irqsave(&chv_lock, flags); + + ctrl0 = readl(reg) & ~CHV_PADCTRL0_GPIOCFG_MASK; + if (input) +@@ -938,7 +947,7 @@ static int chv_gpio_set_direction(struct pinctrl_dev *pctldev, + ctrl0 |= CHV_PADCTRL0_GPIOCFG_GPO << CHV_PADCTRL0_GPIOCFG_SHIFT; + chv_writel(ctrl0, reg); + +- raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ raw_spin_unlock_irqrestore(&chv_lock, flags); + + return 0; + } +@@ -963,10 +972,10 @@ static int chv_config_get(struct pinctrl_dev *pctldev, unsigned pin, + u16 arg = 0; + u32 term; + +- raw_spin_lock_irqsave(&pctrl->lock, flags); ++ raw_spin_lock_irqsave(&chv_lock, flags); + ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); + ctrl1 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL1)); +- raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ raw_spin_unlock_irqrestore(&chv_lock, flags); + + term = (ctrl0 & CHV_PADCTRL0_TERM_MASK) >> CHV_PADCTRL0_TERM_SHIFT; + +@@ -1040,7 +1049,7 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin, + unsigned long flags; + u32 ctrl0, pull; + +- raw_spin_lock_irqsave(&pctrl->lock, flags); ++ raw_spin_lock_irqsave(&chv_lock, flags); + ctrl0 = readl(reg); + + switch (param) { +@@ -1063,7 +1072,7 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin, + pull = CHV_PADCTRL0_TERM_20K << CHV_PADCTRL0_TERM_SHIFT; + break; + default: +- raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ raw_spin_unlock_irqrestore(&chv_lock, flags); + return -EINVAL; + } + +@@ -1081,7 +1090,7 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin, + pull = CHV_PADCTRL0_TERM_20K << CHV_PADCTRL0_TERM_SHIFT; + break; + default: +- raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ raw_spin_unlock_irqrestore(&chv_lock, flags); + return -EINVAL; + } + +@@ -1089,12 +1098,12 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin, + break; + + default: +- raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ raw_spin_unlock_irqrestore(&chv_lock, flags); + return -EINVAL; + } + + chv_writel(ctrl0, reg); +- raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ raw_spin_unlock_irqrestore(&chv_lock, flags); + + return 0; + } +@@ -1160,9 +1169,9 @@ static int chv_gpio_get(struct gpio_chip *chip, unsigned offset) + unsigned long flags; + u32 ctrl0, cfg; + +- raw_spin_lock_irqsave(&pctrl->lock, flags); ++ raw_spin_lock_irqsave(&chv_lock, flags); + ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); +- raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ raw_spin_unlock_irqrestore(&chv_lock, flags); + + cfg = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK; + cfg >>= CHV_PADCTRL0_GPIOCFG_SHIFT; +@@ -1180,7 +1189,7 @@ static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value) + void __iomem *reg; + u32 ctrl0; + +- raw_spin_lock_irqsave(&pctrl->lock, flags); ++ raw_spin_lock_irqsave(&chv_lock, flags); + + reg = chv_padreg(pctrl, pin, CHV_PADCTRL0); + ctrl0 = readl(reg); +@@ -1192,7 +1201,7 @@ static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value) + + chv_writel(ctrl0, reg); + +- raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ raw_spin_unlock_irqrestore(&chv_lock, flags); + } + + static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +@@ -1202,9 +1211,9 @@ static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset) + u32 ctrl0, direction; + unsigned long flags; + +- raw_spin_lock_irqsave(&pctrl->lock, flags); ++ raw_spin_lock_irqsave(&chv_lock, flags); + ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); +- raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ raw_spin_unlock_irqrestore(&chv_lock, flags); + + direction = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK; + direction >>= CHV_PADCTRL0_GPIOCFG_SHIFT; +@@ -1242,14 +1251,14 @@ static void chv_gpio_irq_ack(struct irq_data *d) + int pin = chv_gpio_offset_to_pin(pctrl, irqd_to_hwirq(d)); + u32 intr_line; + +- raw_spin_lock(&pctrl->lock); ++ raw_spin_lock(&chv_lock); + + intr_line = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); + intr_line &= CHV_PADCTRL0_INTSEL_MASK; + intr_line >>= CHV_PADCTRL0_INTSEL_SHIFT; + chv_writel(BIT(intr_line), pctrl->regs + CHV_INTSTAT); + +- raw_spin_unlock(&pctrl->lock); ++ raw_spin_unlock(&chv_lock); + } + + static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask) +@@ -1260,7 +1269,7 @@ static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask) + u32 value, intr_line; + unsigned long flags; + +- raw_spin_lock_irqsave(&pctrl->lock, flags); ++ raw_spin_lock_irqsave(&chv_lock, flags); + + intr_line = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); + intr_line &= CHV_PADCTRL0_INTSEL_MASK; +@@ -1273,7 +1282,7 @@ static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask) + value |= BIT(intr_line); + chv_writel(value, pctrl->regs + CHV_INTMASK); + +- raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ raw_spin_unlock_irqrestore(&chv_lock, flags); + } + + static void chv_gpio_irq_mask(struct irq_data *d) +@@ -1307,7 +1316,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d) + unsigned long flags; + u32 intsel, value; + +- raw_spin_lock_irqsave(&pctrl->lock, flags); ++ raw_spin_lock_irqsave(&chv_lock, flags); + intsel = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); + intsel &= CHV_PADCTRL0_INTSEL_MASK; + intsel >>= CHV_PADCTRL0_INTSEL_SHIFT; +@@ -1322,7 +1331,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d) + irq_set_handler_locked(d, handler); + pctrl->intr_lines[intsel] = offset; + } +- raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ raw_spin_unlock_irqrestore(&chv_lock, flags); + } + + chv_gpio_irq_unmask(d); +@@ -1338,7 +1347,7 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned type) + unsigned long flags; + u32 value; + +- raw_spin_lock_irqsave(&pctrl->lock, flags); ++ raw_spin_lock_irqsave(&chv_lock, flags); + + /* + * Pins which can be used as shared interrupt are configured in +@@ -1387,7 +1396,7 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned type) + else if (type & IRQ_TYPE_LEVEL_MASK) + irq_set_handler_locked(d, handle_level_irq); + +- raw_spin_unlock_irqrestore(&pctrl->lock, flags); ++ raw_spin_unlock_irqrestore(&chv_lock, flags); + + return 0; + } +@@ -1499,7 +1508,6 @@ static int chv_pinctrl_probe(struct platform_device *pdev) + if (i == ARRAY_SIZE(chv_communities)) + return -ENODEV; + +- raw_spin_lock_init(&pctrl->lock); + pctrl->dev = &pdev->dev; + + #ifdef CONFIG_PM_SLEEP +-- +2.9.2 + diff --git a/kernel/tools/perf/files/patches/mageia/platform-x86-add-shuttle-wmi-driver.patch b/kernel/tools/perf/files/patches/mageia/platform-x86-add-shuttle-wmi-driver.patch new file mode 100644 index 0000000000..02f8979192 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/platform-x86-add-shuttle-wmi-driver.patch @@ -0,0 +1,1437 @@ + + Documentation/ABI/testing/sysfs-platform-shuttle-wmi | 72 + + MAINTAINERS | 6 + drivers/platform/x86/Kconfig | 15 + drivers/platform/x86/Makefile | 1 + drivers/platform/x86/shuttle-wmi.c | 1297 +++++++++++++++++++ + 5 files changed, 1391 insertions(+) + +diff -Nurp linux-3.14.2/Documentation/ABI/testing/sysfs-platform-shuttle-wmi linux-3.14.2-shuttle/Documentation/ABI/testing/sysfs-platform-shuttle-wmi +--- linux-3.14.2/Documentation/ABI/testing/sysfs-platform-shuttle-wmi 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.14.2-shuttle/Documentation/ABI/testing/sysfs-platform-shuttle-wmi 2014-04-26 18:33:26.867761088 +0300 +@@ -0,0 +1,72 @@ ++What: /sys/devices/platform/shuttle_wmi/lcd_auto_adjust ++Date: December 2010 ++KernelVersion: 2.6.36 ++Contact: "Herton Ronaldo Krzesinski" ++Description: ++ This is a write only option (accepts any single value, eg. ++ "echo 1 > lcd_auto_adjust") that starts LCD auto-adjust ++ function, if the machine has this function enabled. Some ++ shuttle machines have LCD attached to analog VGA connector, ++ so uses/needs auto-adjust. ++ ++What: /sys/devices/platform/shuttle_wmi/model_name ++Date: December 2010 ++KernelVersion: 2.6.36 ++Contact: "Herton Ronaldo Krzesinski" ++Description: ++ This is a read only attribute which outputs a string with model ++ name of the machine. When shuttle-wmi can't determine which ++ model it is, "Unknown" is returned. Otherwise, the possible ++ models are "Shuttle MA", "Shuttle DA18IE", "Shuttle DA18IM", ++ "Shuttle X50 V2", "Positivo A14IE01", "Positivo P13", ++ "Positivo P14". ++ ++What: /sys/devices/platform/shuttle_wmi/panel_set_default ++Date: December 2010 ++KernelVersion: 2.6.36 ++Contact: "Herton Ronaldo Krzesinski" ++Description: ++ This is a write only option (accepts any single value, eg. ++ "echo 1 > panel_set_default"). Probably resets panel/lcd to ++ default configuration, function not explained in shuttle wmi ++ documentation. It also starts an auto adjust and color adjust ++ cycle. The function should only work in shuttle machines with ++ LCD attached to an analog VGA connector. ++ ++What: /sys/devices/platform/shuttle_wmi/powersave ++Date: December 2010 ++KernelVersion: 2.6.36 ++Contact: "Herton Ronaldo Krzesinski" ++Description: ++ Control powersave state. 1 means on, 0 means off. ++ When enabled, it basically forces the cpu to stay on powersave ++ state (only works if cpu has P-states support, it is similar to ++ powersave governor in cpufreq) when machine is only running on ++ battery. If not running on battery, this function isn't expected ++ to work, any attempt to enable this returns -EIO. ++ ++What: /sys/devices/platform/shuttle_wmi/touchpad_off ++Date: December 2010 ++KernelVersion: 2.6.36 ++Contact: "Herton Ronaldo Krzesinski" ++Description: ++ Control touchpad state. 1 means off, 0 means on. ++ ++What: /sys/devices/platform/shuttle_wmi/webcam ++Date: December 2010 ++KernelVersion: 2.6.36 ++Contact: "Herton Ronaldo Krzesinski" ++Description: ++ Control webcam state. 1 means on, 0 means off. ++ ++What: /sys/devices/platform/shuttle_wmi/white_balance ++Date: December 2010 ++KernelVersion: 2.6.36 ++Contact: "Herton Ronaldo Krzesinski" ++Description: ++ This is a write only option (accepts any single value, eg. ++ "echo 1 > white_balance"). Probably triggers an automatic ++ white balance adjustment for lcd, function not explained in ++ shuttle wmi documentation. It also starts an auto adjust and ++ color adjust cycle. The function should only work in shuttle ++ machines with LCD attached to an analog VGA connector. +diff -Nurp linux-3.14.2/drivers/platform/x86/Kconfig linux-3.14.2-shuttle/drivers/platform/x86/Kconfig +--- linux-3.14.2/drivers/platform/x86/Kconfig 2014-03-31 06:40:15.000000000 +0300 ++++ linux-3.14.2-shuttle/drivers/platform/x86/Kconfig 2014-04-26 18:33:26.867761088 +0300 +@@ -811,6 +811,21 @@ config INTEL_SMARTCONNECT + This driver checks to determine whether the device has Intel Smart + Connect enabled, and if so disables it. + ++config SHUTTLE_WMI ++ tristate "Shuttle WMI Extras Driver" ++ depends on ACPI_WMI ++ depends on BACKLIGHT_CLASS_DEVICE ++ depends on RFKILL ++ depends on INPUT ++ select INPUT_SPARSEKMAP ++ ---help--- ++ This is a driver for the WMI interface present on some Shuttle ++ machines. It adds controls for wireless, bluetooth and 3g radios, ++ webcam switch, backlight controls, among others. ++ ++ If you have a Shuttle machine with ACPI-WMI interface say Y or M ++ here. ++ + config PVPANIC + tristate "pvpanic device support" + depends on ACPI +diff -Nurp linux-3.14.2/drivers/platform/x86/Makefile linux-3.14.2-shuttle/drivers/platform/x86/Makefile +--- linux-3.15/drivers/platform/x86/Makefile ++++ linux-3.15-shuttle/drivers/platform/x86/Makefile +@@ -53,6 +53,7 @@ obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10 + obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o + obj-$(CONFIG_INTEL_RST) += intel-rst.o + obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o ++obj-$(CONFIG_SHUTTLE_WMI) += shuttle-wmi.o + + obj-$(CONFIG_PVPANIC) += pvpanic.o + obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o +diff -Nurp linux-3.14.2/drivers/platform/x86/shuttle-wmi.c linux-3.14.2-shuttle/drivers/platform/x86/shuttle-wmi.c +--- linux-3.14.2/drivers/platform/x86/shuttle-wmi.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.14.2-shuttle/drivers/platform/x86/shuttle-wmi.c 2014-04-26 18:33:26.868761096 +0300 +@@ -0,0 +1,1297 @@ ++/* ++ * ACPI-WMI driver for Shuttle WMI interface ++ * ++ * Copyright (c) 2010 Herton Ronaldo Krzesinski ++ * ++ * Development of this driver was funded by Positivo Informatica S.A. ++ * Parts of the driver were based on some WMI documentation provided by Shuttle ++ * ++ * 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. ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Herton Ronaldo Krzesinski"); ++MODULE_DESCRIPTION("Shuttle WMI Extras Driver"); ++MODULE_LICENSE("GPL"); ++ ++#define SHUTTLE_WMI_SETGET_GUID "abbc0f6f-8ea1-11d1-00a0-c90629100000" ++#define SHUTTLE_WMI_EVENT_GUID "abbc0f72-8ea1-11d1-00a0-c90629100000" ++MODULE_ALIAS("wmi:"SHUTTLE_WMI_SETGET_GUID); ++MODULE_ALIAS("wmi:"SHUTTLE_WMI_EVENT_GUID); ++ ++#define CMD_WRITEEC 0x00 ++#define CMD_READEC 0x01 ++#define CMD_SCMD 0x02 ++#define CMD_INT15 0x03 ++#define CMD_HWSW 0x07 ++#define CMD_LCTRL 0x09 ++#define CMD_CUTLVDS 0x11 ++#define CMD_MA 0x18 ++#define CMD_DA18IE 0x19 ++#define CMD_DA18IM 0x20 ++ ++#define ECRAM_ER0 0x443 ++#define ECRAM_ER1 0x45a ++#define ECRAM_ER2 0x47b ++#define ECRAM_ER3 0x758 ++#define ECRAM_ER4 0x759 ++ ++struct shuttle_ecram { ++ unsigned short addr; ++ u32 mask; ++}; ++ ++struct shuttle_state { ++ struct shuttle_ecram ecram; ++ struct device_attribute *dev_attr; ++}; ++ ++static struct shuttle_state state_powersave = { ++ .ecram = { ++ .addr = ECRAM_ER3, ++ .mask = 0x10, ++ }, ++}; ++ ++static struct shuttle_state state_touchpad_off = { ++ .ecram = { ++ .addr = ECRAM_ER2, ++ .mask = 0x02, ++ }, ++}; ++ ++static struct shuttle_state state_webcam = { ++ .ecram = { ++ .addr = ECRAM_ER2, ++ .mask = 0x10, ++ }, ++}; ++ ++struct shuttle_rfkill { ++ struct rfkill *rfk; ++ enum rfkill_type type; ++ struct shuttle_ecram ecram_state; ++ struct shuttle_ecram ecram_present; ++ /* lists of rf state switch notification codes */ ++ u32 rf_on[3]; ++ u32 rf_off[3]; ++}; ++ ++static struct shuttle_rfkill srfk_3g = { ++ .type = RFKILL_TYPE_WWAN, ++ .ecram_state = { ++ .addr = ECRAM_ER2, ++ .mask = 0x40, ++ }, ++ .rf_on = { 0x10, 0x29 }, ++ .rf_off = { 0x11, 0x2a }, ++}; ++ ++static struct shuttle_rfkill srfk_bluetooth = { ++ .type = RFKILL_TYPE_BLUETOOTH, ++ .ecram_state = { ++ .addr = ECRAM_ER2, ++ .mask = 0x20, ++ }, ++ .rf_on = { 0x0c, 0x29 }, ++ .rf_off = { 0x0d, 0x2a }, ++}; ++ ++static struct shuttle_rfkill srfk_wlan = { ++ .type = RFKILL_TYPE_WLAN, ++ .ecram_state = { ++ .addr = ECRAM_ER2, ++ .mask = 0x80, ++ }, ++ .ecram_present = { ++ .addr = ECRAM_ER1, ++ .mask = 0x80, ++ }, ++ .rf_on = { 0x08 }, ++ .rf_off = { 0x09 }, ++}; ++ ++enum fn_type { ++ FN_CMD, ++ FN_CMD_DEBUG, ++ FN_RFKILL, ++ FN_STATE ++}; ++ ++struct shuttle_fn_map { ++ char *name; ++ enum fn_type type; ++ unsigned short cmd; ++ unsigned short arg; ++ unsigned short fn; ++ void *data; ++}; ++ ++static struct shuttle_fn_map unknown_fn_map[] = { ++ { "fn_f1", FN_CMD_DEBUG, CMD_SCMD, 0, 0x01, NULL }, ++ { "fn_f2", FN_CMD_DEBUG, CMD_SCMD, 0, 0x02, NULL }, ++ { "fn_f3", FN_CMD_DEBUG, CMD_SCMD, 0, 0x03, NULL }, ++ { "fn_f4", FN_CMD_DEBUG, CMD_SCMD, 0, 0x04, NULL }, ++ { "fn_f5", FN_CMD_DEBUG, CMD_SCMD, 0, 0x05, NULL }, ++ { "fn_f6", FN_CMD_DEBUG, CMD_SCMD, 0, 0x06, NULL }, ++ { "fn_f7", FN_CMD_DEBUG, CMD_SCMD, 0, 0x07, NULL }, ++ { "fn_f8", FN_CMD_DEBUG, CMD_SCMD, 0, 0x08, NULL }, ++ { "fn_f9", FN_CMD_DEBUG, CMD_SCMD, 0, 0x09, NULL }, ++ { "fn_f10", FN_CMD_DEBUG, CMD_SCMD, 0, 0x0a, NULL }, ++ { "fn_f11", FN_CMD_DEBUG, CMD_SCMD, 0, 0x0b, NULL }, ++ { "fn_f12", FN_CMD_DEBUG, CMD_SCMD, 0, 0x0c, NULL }, ++ { "fn_f13", FN_CMD_DEBUG, CMD_SCMD, 0, 0x0d, NULL }, ++ { "fn_f14", FN_CMD_DEBUG, CMD_SCMD, 0, 0x0e, NULL }, ++ { "fn_f15", FN_CMD_DEBUG, CMD_SCMD, 0, 0x0f, NULL }, ++ { "lcd_auto_adjust", FN_CMD, CMD_SCMD, 0, 0x81, NULL }, ++ { "lightbar_brightness_down", FN_CMD_DEBUG, CMD_LCTRL, 1, 0x00, NULL }, ++ { "lightbar_brightness_up", FN_CMD_DEBUG, CMD_LCTRL, 1, 0x01, NULL }, ++ { "panel_set_default", FN_CMD, CMD_SCMD, 0, 0x83, NULL }, ++ { "video_output_on", FN_CMD_DEBUG, CMD_CUTLVDS, 0, 0x01, NULL}, ++ { "video_output_off", FN_CMD_DEBUG, CMD_CUTLVDS, 0, 0x00, NULL}, ++ { "white_balance", FN_CMD, CMD_SCMD, 0, 0x82, NULL }, ++ { } ++}; ++ ++static struct shuttle_fn_map fn_map_1[] = { ++ { "brightness_down", FN_CMD_DEBUG, CMD_SCMD, 0, 0x0b, NULL }, ++ { "brightness_up", FN_CMD_DEBUG, CMD_SCMD, 0, 0x0c, NULL }, ++ { "lcd_auto_adjust", FN_CMD, CMD_SCMD, 0, 0x81, NULL }, ++ { "lightbar_brightness_down", FN_CMD_DEBUG, CMD_LCTRL, 1, 0x00, NULL }, ++ { "lightbar_brightness_up", FN_CMD_DEBUG, CMD_LCTRL, 1, 0x01, NULL }, ++ { "panel_set_default", FN_CMD, CMD_SCMD, 0, 0x83, NULL }, ++ { "powersave", FN_STATE, CMD_SCMD, 0, 0x02, &state_powersave }, ++ { "shuttle_3g", FN_RFKILL, CMD_SCMD, 0, 0x05, &srfk_3g }, ++ { "shuttle_bluetooth", FN_RFKILL, CMD_SCMD, 0, 0x0d, &srfk_bluetooth }, ++ { "shuttle_wlan", FN_RFKILL, CMD_SCMD, 0, 0x04, &srfk_wlan }, ++ { "sleep", FN_CMD_DEBUG, CMD_SCMD, 0, 0x01, NULL }, ++ { "sound_mute", FN_CMD_DEBUG, CMD_SCMD, 0, 0x08, NULL }, ++ { "switch_video", FN_CMD_DEBUG, CMD_SCMD, 0, 0x03, NULL }, ++ { "touchpad_off", FN_STATE, CMD_SCMD, 0, 0x06, &state_touchpad_off }, ++ { "volume_down", FN_CMD_DEBUG, CMD_SCMD, 0, 0x09, NULL }, ++ { "volume_up", FN_CMD_DEBUG, CMD_SCMD, 0, 0x0a, NULL }, ++ { "video_output_on", FN_CMD_DEBUG, CMD_CUTLVDS, 0, 0x01, NULL}, ++ { "video_output_off", FN_CMD_DEBUG, CMD_CUTLVDS, 0, 0x00, NULL}, ++ { "webcam", FN_STATE, CMD_SCMD, 0, 0x07, &state_webcam }, ++ { "white_balance", FN_CMD, CMD_SCMD, 0, 0x82, NULL }, ++ { } ++}; ++ ++static struct shuttle_fn_map fn_map_2[] = { ++ { "brightness_down", FN_CMD_DEBUG, CMD_SCMD, 0, 0x08, NULL }, ++ { "brightness_up", FN_CMD_DEBUG, CMD_SCMD, 0, 0x09, NULL }, ++ { "video_output", FN_CMD_DEBUG, CMD_SCMD, 0, 0x02, NULL }, ++ { "video_output_on", FN_CMD_DEBUG, CMD_CUTLVDS, 0, 0x01, NULL}, ++ { "video_output_off", FN_CMD_DEBUG, CMD_CUTLVDS, 0, 0x00, NULL}, ++ { "shuttle_wlan", FN_RFKILL, CMD_SCMD, 0, 0x0b, &srfk_wlan }, ++ { "sleep", FN_CMD_DEBUG, CMD_SCMD, 0, 0x03, NULL }, ++ { "sound_mute", FN_CMD_DEBUG, CMD_SCMD, 0, 0x04, NULL }, ++ { "switch_video", FN_CMD_DEBUG, CMD_SCMD, 0, 0x07, NULL }, ++ { "touchpad_off", FN_STATE, CMD_SCMD, 0, 0x01, &state_touchpad_off }, ++ { "volume_down", FN_CMD_DEBUG, CMD_SCMD, 0, 0x05, NULL }, ++ { "volume_up", FN_CMD_DEBUG, CMD_SCMD, 0, 0x06, NULL }, ++ { "webcam", FN_STATE, CMD_SCMD, 0, 0x0a, &state_webcam }, ++ { } ++}; ++ ++struct shuttle_backlight { ++ u8 ec_addr; ++ struct shuttle_fn_map *fn_bl_down; ++ struct shuttle_fn_map *fn_bl_up; ++}; ++ ++static struct shuttle_backlight common_bl_desc = { ++ .ec_addr = 0x79, ++}; ++ ++static struct shuttle_backlight quirk_bl_desc = { ++ .ec_addr = 0x79, ++ .fn_bl_down = &fn_map_1[0], ++ .fn_bl_up = &fn_map_1[1], ++}; ++ ++struct shuttle_id { ++ unsigned char cmd_id; ++ const char *model_name; ++ struct shuttle_backlight *bl_desc; ++ struct shuttle_fn_map *fn_map; ++}; ++ ++static struct shuttle_id shuttle_ids[] = { ++ { CMD_MA, "Shuttle MA", &common_bl_desc, fn_map_1 }, ++ { CMD_DA18IE, "Shuttle DA18IE", &quirk_bl_desc, fn_map_1 }, ++ { CMD_DA18IM, "Shuttle DA18IM", &common_bl_desc, fn_map_1 } ++}; ++ ++static struct shuttle_id id_unknown = { ++ .model_name = "Unknown", ++ .fn_map = unknown_fn_map, ++}; ++ ++static struct shuttle_id shuttle_dmi_id; ++ ++static int shuttle_dmi_matched(const struct dmi_system_id *dmi) ++{ ++ shuttle_dmi_id.model_name = dmi->ident; ++ shuttle_dmi_id.bl_desc = &common_bl_desc; ++ shuttle_dmi_id.fn_map = dmi->driver_data; ++ return 1; ++} ++ ++static struct dmi_system_id shuttle_dmi_ids[] = { ++ { ++ .callback = shuttle_dmi_matched, ++ .ident = "Shuttle X50 V2", ++ .matches = { ++ DMI_MATCH(DMI_PRODUCT_NAME, "X50-V2"), ++ }, ++ .driver_data = fn_map_1, ++ }, ++ { ++ .callback = shuttle_dmi_matched, ++ .ident = "Positivo A14IE01", ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "POSITIVO"), ++ DMI_MATCH(DMI_BOARD_NAME, "A14IE01"), ++ }, ++ .driver_data = fn_map_2, ++ }, ++ { ++ .callback = shuttle_dmi_matched, ++ .ident = "Positivo P13", ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "POSITIVO"), ++ DMI_MATCH(DMI_BOARD_NAME, "P13"), ++ }, ++ .driver_data = fn_map_2, ++ }, ++ { ++ .callback = shuttle_dmi_matched, ++ .ident = "Positivo P14", ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "POSITIVO"), ++ DMI_MATCH(DMI_BOARD_NAME, "P14"), ++ }, ++ .driver_data = fn_map_2, ++ }, ++ {} ++}; ++ ++static struct dmi_system_id __devinitdata shuttle_quirk_bl_dmi_ids[] = { ++ { ++ .ident = "Positivo M13", ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "POSITIVO"), ++ DMI_MATCH(DMI_BOARD_NAME, "M13"), ++ }, ++ }, ++ { ++ .ident = "Positivo M14", ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "POSITIVO"), ++ DMI_MATCH(DMI_BOARD_NAME, "M14"), ++ }, ++ }, ++ { ++ .ident = "Positivo A14IM01", ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "POSITIVO"), ++ DMI_MATCH(DMI_BOARD_NAME, "A14IM01"), ++ }, ++ }, ++ { ++ .ident = "Positivo J14IM21", ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "POSITIVO"), ++ DMI_MATCH(DMI_BOARD_NAME, "J14IM21"), ++ }, ++ }, ++ {} ++}; ++ ++struct shuttle_wmi { ++ struct platform_device *pdev; ++ struct shuttle_id *id; ++ struct dentry *dbg_root; ++ struct attribute_group *attr_group; ++ struct input_dev *inputdev; ++ struct backlight_device *bd; ++}; ++ ++struct shuttle_cmd { ++ u16 param2; ++ u16 param1; ++ u8 arg; ++ u8 cmd; ++ u16 hdr; ++}; ++ ++static int wmi_setget_mtd(struct shuttle_cmd *scmd, u32 *res) ++{ ++ acpi_status status; ++ union acpi_object *obj; ++ struct acpi_buffer input; ++ static DEFINE_MUTEX(mtd_lock); ++ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; ++ ++ input.length = sizeof(struct shuttle_cmd); ++ scmd->hdr = 0xec00; ++ input.pointer = (u8 *) scmd; ++ ++ /* We must serialize access to wmi_evaluate_method: the wmi interface ++ * functions in the bios save its parameters on a common shared buffer, ++ * which gets overwritten on parallel calls with unpredicted results; ++ * AML code doesn't have any locking, so we must do this here */ ++ mutex_lock(&mtd_lock); ++ status = wmi_evaluate_method(SHUTTLE_WMI_SETGET_GUID, 0, 2, ++ &input, &output); ++ mutex_unlock(&mtd_lock); ++ if (ACPI_FAILURE(status)) ++ return -1; ++ ++ obj = output.pointer; ++ if (obj) { ++ if (obj->type == ACPI_TYPE_INTEGER) { ++ if (res) ++ *res = obj->integer.value; ++ } else { ++ pr_err("Unsupported object returned (%s)", __func__); ++ res = NULL; ++ } ++ kfree(obj); ++ } else { ++ if (res) { ++ pr_warning("No result from WMI method (%s)", __func__); ++ res = NULL; ++ } ++ } ++ ++ return (res) ? 0 : 1; ++} ++ ++static int wmi_ec_cmd(unsigned char cmd, unsigned char arg, ++ unsigned short param1, unsigned short param2, ++ u32 *res) ++{ ++ struct shuttle_cmd scmd = { ++ .cmd = cmd, ++ .arg = arg, ++ .param1 = param1, ++ .param2 = param2 ++ }; ++ ++ return wmi_setget_mtd(&scmd, res); ++} ++ ++static int wmi_ec_state(struct shuttle_ecram *ecram) ++{ ++ u32 val; ++ ++ if (wmi_ec_cmd(CMD_READEC, 0, 0, ecram->addr, &val)) ++ return -EIO; ++ return (val & ecram->mask) ? 1 : 0; ++} ++ ++static int rfkill_common_set_block(void *data, bool blocked) ++{ ++ int sw; ++ struct shuttle_fn_map *fn_map = data; ++ struct shuttle_rfkill *srfk = fn_map->data; ++ ++ sw = wmi_ec_state(&srfk->ecram_state); ++ if (sw < 0) ++ return sw; ++ ++ if (blocked == sw) ++ wmi_ec_cmd(fn_map->cmd, fn_map->arg, 0, fn_map->fn, NULL); ++ else ++ return 0; ++ ++ sw = wmi_ec_state(&srfk->ecram_state); ++ if (sw < 0) ++ return sw; ++ ++ return (sw != blocked) ? 0 : -EIO; ++} ++ ++static const struct rfkill_ops rfkill_common_ops = { ++ .set_block = rfkill_common_set_block, ++}; ++ ++static void pr_possible_dev_state(void) ++{ ++ static bool pr; ++ u32 val; ++ ++ if (!pr) { ++ pr = true; ++ pr_info("need to unblock some rfkills to check device" ++ " presence\n"); ++ if (!wmi_ec_cmd(CMD_READEC, 0, 0, ECRAM_ER1, &val)) ++ pr_info("possible device present state at address" ++ " 0x%04x is 0x%08x\n", ECRAM_ER1, val); ++ } ++} ++ ++static int shuttle_rfkill_init(struct shuttle_fn_map *fn_map, ++ struct device *dev) ++{ ++ int rc; ++ struct shuttle_rfkill *srfk = fn_map->data; ++ ++ /* Try to detect if device controlled by this rfkill is present, to ++ * avoid having an rfkill switch when not needed */ ++ if (srfk->ecram_present.mask && srfk->ecram_present.addr) { ++ /* we have an address to read to check if device is present */ ++ rc = wmi_ec_state(&srfk->ecram_present); ++ if (rc <= 0) ++ return rc; ++ ++ rc = wmi_ec_state(&srfk->ecram_state); ++ if (rc < 0) ++ return rc; ++ } else { ++ /* print only once the possible value of devices presence, for ++ * extra information (useful to check if really device presence ++ * is or isn't available at usual ECRAM_ER1 address) */ ++ pr_possible_dev_state(); ++ ++ /* no address/mask to check, detect if device is available by ++ * trying to enable it, in case it's disabled */ ++ rc = wmi_ec_state(&srfk->ecram_state); ++ if (rc < 0) ++ return rc; ++ if (!rc) { ++ if (rfkill_common_set_block(fn_map, false)) ++ return 0; ++ ++ /* after check, reset to initial setting; should be ++ * unlikely this returns with error, but really check if ++ * we could reset to initial blocked setting, otherwise ++ * don't make it a fatal error and assume rfkill not ++ * blocked */ ++ if (rfkill_common_set_block(fn_map, true)) ++ rc = 1; ++ } ++ } ++ ++ srfk->rfk = rfkill_alloc(fn_map->name, dev, srfk->type, ++ &rfkill_common_ops, fn_map); ++ if (!srfk->rfk) ++ return -ENOMEM; ++ ++ rfkill_init_sw_state(srfk->rfk, !rc); ++ ++ rc = rfkill_register(srfk->rfk); ++ if (rc) { ++ rfkill_destroy(srfk->rfk); ++ srfk->rfk = NULL; ++ return rc; ++ } ++ ++ return 0; ++} ++ ++static void shuttle_rfkill_remove(struct shuttle_fn_map *fn_map) ++{ ++ struct shuttle_rfkill *srfk = fn_map->data; ++ ++ if (srfk->rfk) { ++ rfkill_unregister(srfk->rfk); ++ rfkill_destroy(srfk->rfk); ++ srfk->rfk = NULL; ++ } ++} ++ ++static int shuttle_rfkill_resume(struct device *dev) ++{ ++ struct shuttle_fn_map *fn_map; ++ struct shuttle_rfkill *srfk; ++ int rc; ++ struct platform_device *pdev = to_platform_device(dev); ++ struct shuttle_wmi *priv = platform_get_drvdata(pdev); ++ ++ for (fn_map = priv->id->fn_map; fn_map->name; fn_map++) { ++ if (fn_map->type != FN_RFKILL) ++ continue; ++ ++ srfk = fn_map->data; ++ if (srfk->rfk) { ++ rc = wmi_ec_state(&srfk->ecram_state); ++ if (rc < 0) ++ return rc; ++ rfkill_set_sw_state(srfk->rfk, rc); ++ } ++ } ++ return 0; ++} ++ ++static bool set_rfkill_sw(u32 *list, u32 code, struct rfkill *rfk, bool blocked) ++{ ++ while (*list) { ++ if (*list == code) { ++ rfkill_set_sw_state(rfk, blocked); ++ return true; ++ } ++ list++; ++ } ++ return false; ++} ++ ++static bool notify_switch_rfkill(struct shuttle_wmi *priv, u32 code) ++{ ++ struct shuttle_fn_map *fn_map; ++ struct shuttle_rfkill *srfk; ++ struct rfkill *rfk; ++ bool res = false; ++ ++ for (fn_map = priv->id->fn_map; fn_map->name; fn_map++) { ++ if (fn_map->type != FN_RFKILL) ++ continue; ++ ++ srfk = fn_map->data; ++ rfk = srfk->rfk; ++ if (!rfk) ++ continue; ++ ++ /* check if notification code means radio turned on, looking ++ * at list_on array of "on" notification codes for this rfkill; ++ * if code is in this list, we notify rfkill core (set_rfkill_sw ++ * does the check, notification and returns true) and we can ++ * skip to next rfkill on the list (some notification codes are ++ * shared, firmware may want to turn on two radios at same time, ++ * so we must check all rfkills with this code) */ ++ if (set_rfkill_sw(srfk->rf_on, code, rfk, false)) { ++ res = true; ++ continue; ++ } ++ ++ /* same as above, but we check the list_off to see if ++ * notification code means radio turned off */ ++ if (set_rfkill_sw(srfk->rf_off, code, rfk, true)) ++ res = true; ++ } ++ /* if we found that notification code was indeed a radio on/off event, ++ * return true here */ ++ return res; ++} ++ ++static bool notify_switch_attr(struct platform_device *pdev, u32 code) ++{ ++ int i; ++ struct shuttle_switch { ++ u32 switch_on; ++ u32 switch_off; ++ char *sys_attr; ++ }; ++ static const struct shuttle_switch codes[] = { ++ { 0x04, 0x05, "touchpad_off" }, ++ { 0x12, 0x13, "webcam" }, ++ { 0x31, 0x32, "powersave" } ++ }; ++ ++ for (i = 0; i < ARRAY_SIZE(codes); i++) { ++ if (codes[i].switch_on == code || codes[i].switch_off == code) { ++ sysfs_notify(&pdev->dev.kobj, NULL, codes[i].sys_attr); ++ return true; ++ } ++ } ++ return false; ++} ++ ++static void shuttle_wmi_notify(u32 value, void *data) ++{ ++ acpi_status status; ++ union acpi_object *obj; ++ u8 type; ++ u32 code; ++ struct acpi_buffer res = { ACPI_ALLOCATE_BUFFER, NULL }; ++ struct shuttle_wmi *priv = data; ++ ++ status = wmi_get_event_data(value, &res); ++ if (status != AE_OK) { ++ pr_warning("unable to retrieve wmi event status" ++ " (error=0x%x)\n", status); ++ return; ++ } ++ ++ obj = (union acpi_object *) res.pointer; ++ if (!obj) ++ return; ++ if (obj->type != ACPI_TYPE_INTEGER) { ++ pr_info("unknown object returned in wmi event\n"); ++ goto notify_exit; ++ } ++ ++ type = (obj->integer.value >> 24) & 0xFF; ++ switch (type) { ++ case 0: /* OSD/Scancode event */ ++ code = obj->integer.value & 0xFFFFFF; ++ ++ /* update rfkill switches */ ++ if (notify_switch_rfkill(priv, code)) ++ break; ++ ++ /* send notification on state switch attributes */ ++ if (notify_switch_attr(priv->pdev, code)) ++ break; ++ ++ if (priv->bd && (code == 0x14 || code == 0x15)) { ++ backlight_force_update(priv->bd, ++ BACKLIGHT_UPDATE_HOTKEY); ++ break; ++ } ++ ++ if (!sparse_keymap_report_event(priv->inputdev, code, 1, true)) ++ pr_info("unhandled scancode (0x%06x)\n", code); ++ break; ++ case 1: /* Power management event */ ++ /* Events not used. ++ * Possible values for obj->integer.value: ++ * 0x01000000 - silent mode ++ * 0x01010000 - brightness sync */ ++ case 2: /* i-PowerXross event */ ++ /* i-PowerXross is a overclocking feature, not ++ * implemented, there are no further details, possible ++ * values for obj->integer.value in documentation: ++ * 0x02000000 - idle mode ++ * 0x02010000 - action mode ++ * 0x02020000 - entry s3 */ ++ break; ++ case 0xec: /* Lost event */ ++ if (printk_ratelimit()) ++ pr_warning("lost event because of buggy BIOS"); ++ break; ++ default: ++ pr_info("unknown wmi notification type (0x%02x)\n", type); ++ } ++ ++notify_exit: ++ kfree(obj); ++} ++ ++static const struct key_entry shuttle_wmi_keymap[] = { ++ { KE_IGNORE, 0x14, { KEY_BRIGHTNESSUP } }, ++ { KE_IGNORE, 0x15, { KEY_BRIGHTNESSDOWN } }, ++ { KE_KEY, 0x16, { KEY_FASTFORWARD } }, ++ { KE_KEY, 0x17, { KEY_REWIND } }, ++ { KE_KEY, 0x18, { KEY_F13 } }, /* OSD Beep */ ++ { KE_KEY, 0x2b, { KEY_F14 } }, /* OSD menu 1 */ ++ { KE_KEY, 0x2c, { KEY_F15 } }, /* OSD menu 2 */ ++ { KE_KEY, 0x2d, { KEY_F16 } }, /* OSD menu 3 */ ++ { KE_KEY, 0x2e, { KEY_F17 } }, /* OSD menu 4 */ ++ { KE_KEY, 0x33, { KEY_F18 } }, /* Update OSD bar status */ ++ { KE_KEY, 0x90, { KEY_WWW } }, ++ { KE_KEY, 0x95, { KEY_PREVIOUSSONG } }, ++ { KE_KEY, 0xa0, { KEY_PROG1 } }, /* Call OSD software */ ++ { KE_KEY, 0xa1, { KEY_VOLUMEDOWN } }, ++ { KE_KEY, 0xa3, { KEY_MUTE } }, ++ { KE_KEY, 0xb2, { KEY_VOLUMEUP } }, ++ { KE_KEY, 0xb4, { KEY_PLAYPAUSE } }, ++ { KE_KEY, 0xbb, { KEY_STOPCD } }, ++ { KE_KEY, 0xc8, { KEY_MAIL } }, ++ { KE_KEY, 0xcd, { KEY_NEXTSONG } }, ++ { KE_KEY, 0xd0, { KEY_MEDIA } }, ++ ++ /* Known non hotkey events don't handled, that we don't care or ++ * which we must ignore */ ++ { KE_IGNORE, 0x01, }, /* Caps Lock toggled */ ++ { KE_IGNORE, 0x02, }, /* Num Lock toggled */ ++ { KE_IGNORE, 0x03, }, /* Scroll Lock toggled */ ++ { KE_IGNORE, 0x06, }, /* Downclock/Silent on */ ++ { KE_IGNORE, 0x07, }, /* Downclock/Silent off */ ++ { KE_IGNORE, 0x0a, }, /* WiMax on */ ++ { KE_IGNORE, 0x0b, }, /* WiMax off */ ++ { KE_IGNORE, 0x0e, }, /* RF on */ ++ { KE_IGNORE, 0x0f, }, /* RF off */ ++ { KE_IGNORE, 0x1a, }, /* Auto Brightness on */ ++ { KE_IGNORE, 0x1b, }, /* Auto Brightness off */ ++ { KE_IGNORE, 0x1c, }, /* Auto-KB Brightness on */ ++ { KE_IGNORE, 0x1d, }, /* Auto-KB Brightness off */ ++ { KE_IGNORE, 0x1e, }, /* Light Bar Brightness up */ ++ { KE_IGNORE, 0x1f, }, /* Light Bar Brightness down */ ++ { KE_IGNORE, 0x20, }, /* China Telecom AP enable */ ++ { KE_IGNORE, 0x21, }, /* China Mobile AP enable */ ++ { KE_IGNORE, 0x22, }, /* Huawei AP enable */ ++ { KE_IGNORE, 0x23, }, /* Docking in */ ++ { KE_IGNORE, 0x24, }, /* Docking out */ ++ { KE_IGNORE, 0x25, }, /* Device no function */ ++ { KE_IGNORE, 0x26, }, /* i-PowerXross OverClocking */ ++ { KE_IGNORE, 0x27, }, /* i-PowerXross PowerSaving */ ++ { KE_IGNORE, 0x28, }, /* i-PowerXross off */ ++ { KE_IGNORE, 0x2f, }, /* Optimus on */ ++ { KE_IGNORE, 0x30, }, /* Optimus off */ ++ { KE_IGNORE, 0x91, }, /* ICO 2 on */ ++ { KE_IGNORE, 0x92, }, /* ICO 2 off */ ++ ++ { KE_END, 0 } ++}; ++ ++static int shuttle_wmi_input_init(struct shuttle_wmi *priv) ++{ ++ struct input_dev *input; ++ int rc; ++ ++ input = input_allocate_device(); ++ if (!input) ++ return -ENOMEM; ++ ++ input->name = "Shuttle WMI hotkeys"; ++ input->phys = KBUILD_MODNAME "/input0"; ++ input->id.bustype = BUS_HOST; ++ ++ rc = sparse_keymap_setup(input, shuttle_wmi_keymap, NULL); ++ if (rc) ++ goto err_free_dev; ++ ++ rc = input_register_device(input); ++ if (rc) ++ goto err_free_keymap; ++ ++ priv->inputdev = input; ++ return 0; ++ ++err_free_keymap: ++ sparse_keymap_free(input); ++err_free_dev: ++ input_free_device(input); ++ return rc; ++} ++ ++static void shuttle_wmi_input_remove(struct shuttle_wmi *priv) ++{ ++ struct input_dev *input = priv->inputdev; ++ ++ sparse_keymap_free(input); ++ input_unregister_device(input); ++} ++ ++static int shuttle_wmi_get_bl(struct backlight_device *bd) ++{ ++ u8 val; ++ int rc; ++ struct shuttle_wmi *priv = bl_get_data(bd); ++ struct shuttle_backlight *sbl = priv->id->bl_desc; ++ ++ rc = ec_read(sbl->ec_addr, &val); ++ if (rc) ++ return rc; ++ return val & 7; ++} ++ ++static int shuttle_wmi_update_bl(struct backlight_device *bd) ++{ ++ int rc, steps; ++ u8 val; ++ struct shuttle_fn_map *fn_down, *fn_up; ++ struct shuttle_wmi *priv = bl_get_data(bd); ++ struct shuttle_backlight *sbl = priv->id->bl_desc; ++ ++ fn_down = sbl->fn_bl_down; ++ fn_up = sbl->fn_bl_up; ++ if (!fn_down || !fn_up) { ++ rc = ec_write(sbl->ec_addr, bd->props.brightness); ++ if (rc) ++ return rc; ++ } else { ++ /* change brightness by steps, this is a quirk for shuttle ++ * machines which don't accept direct write to ec for this */ ++ rc = ec_read(sbl->ec_addr, &val); ++ if (rc) ++ return rc; ++ steps = bd->props.brightness - (val & 7); ++ while (steps > 0) { ++ wmi_ec_cmd(fn_up->cmd, fn_up->arg, 0, fn_up->fn, NULL); ++ steps--; ++ } ++ while (steps < 0) { ++ wmi_ec_cmd(fn_down->cmd, fn_down->arg, 0, fn_down->fn, ++ NULL); ++ steps++; ++ } ++ } ++ ++ wmi_ec_cmd(CMD_CUTLVDS, 0, 0, ++ (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0, ++ NULL); ++ ++ return 0; ++} ++ ++static const struct backlight_ops shuttle_wmi_bl_ops = { ++ .get_brightness = shuttle_wmi_get_bl, ++ .update_status = shuttle_wmi_update_bl, ++}; ++ ++static int shuttle_wmi_backlight_init(struct shuttle_wmi *priv) ++{ ++ int rc; ++ u8 val; ++ struct backlight_properties props; ++ struct backlight_device *bd; ++ struct shuttle_backlight *sbl = priv->id->bl_desc; ++ ++ rc = ec_read(sbl->ec_addr, &val); ++ if (rc) ++ return rc; ++ memset(&props, 0, sizeof(struct backlight_properties)); ++ props.max_brightness = 7; ++ props.brightness = val & 7; ++ props.power = FB_BLANK_UNBLANK; ++ ++ bd = backlight_device_register(KBUILD_MODNAME, &priv->pdev->dev, priv, ++ &shuttle_wmi_bl_ops, &props); ++ if (IS_ERR(bd)) ++ return PTR_ERR(bd); ++ priv->bd = bd; ++ return 0; ++} ++ ++static void shuttle_wmi_backlight_exit(struct shuttle_wmi *priv) ++{ ++ if (priv->bd) ++ backlight_device_unregister(priv->bd); ++} ++ ++static ssize_t store_fn_cmd(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct shuttle_wmi *priv = platform_get_drvdata(pdev); ++ struct shuttle_fn_map *fn_map; ++ ++ for (fn_map = priv->id->fn_map; fn_map->name; fn_map++) { ++ if (fn_map->name == attr->attr.name) { ++ wmi_ec_cmd(fn_map->cmd, fn_map->arg, 0, fn_map->fn, ++ NULL); ++ return count; ++ } ++ } ++ return -EIO; ++} ++ ++static int set_fn_cmd_debug(void *data, u64 val) ++{ ++ struct shuttle_fn_map *fn_map = data; ++ ++ wmi_ec_cmd(fn_map->cmd, fn_map->arg, 0, fn_map->fn, NULL); ++ /* we don't know yet how many brightness values or maximum brightness ++ * values for lightbar, for now print possible brightness value change ++ * to aid in discovering these */ ++ if (fn_map->cmd == CMD_LCTRL) { ++ u32 val; ++ if (!wmi_ec_cmd(CMD_READEC, 0, 0, ECRAM_ER4, &val)) ++ pr_info("possible lightbar brightness change to value" ++ " 0x%08x\n", val); ++ } ++ return 0; ++} ++DEFINE_SIMPLE_ATTRIBUTE(fops_fn_cmd_debug, NULL, set_fn_cmd_debug, "%llu"); ++ ++static ssize_t show_fn_state(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct shuttle_fn_map *fn_map; ++ struct shuttle_state *state; ++ int sw; ++ struct platform_device *pdev = to_platform_device(dev); ++ struct shuttle_wmi *priv = platform_get_drvdata(pdev); ++ ++ for (fn_map = priv->id->fn_map; fn_map->name; fn_map++) { ++ if (fn_map->name != attr->attr.name) ++ continue; ++ ++ state = fn_map->data; ++ sw = wmi_ec_state(&state->ecram); ++ if (sw < 0) ++ return sw; ++ return sprintf(buf, "%d\n", sw); ++ } ++ return -EIO; ++} ++ ++static ssize_t store_fn_state(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int enable, sw; ++ struct shuttle_fn_map *fn_map; ++ struct shuttle_state *state; ++ struct platform_device *pdev = to_platform_device(dev); ++ struct shuttle_wmi *priv = platform_get_drvdata(pdev); ++ ++ if (sscanf(buf, "%i", &enable) != 1) ++ return -EINVAL; ++ ++ for (fn_map = priv->id->fn_map; fn_map->name; fn_map++) { ++ if (fn_map->name != attr->attr.name) ++ continue; ++ ++ state = fn_map->data; ++ sw = wmi_ec_state(&state->ecram); ++ if (sw < 0) ++ return sw; ++ enable = enable ? 1 : 0; ++ if (enable != sw) { ++ wmi_ec_cmd(fn_map->cmd, fn_map->arg, 0, fn_map->fn, ++ NULL); ++ sw = wmi_ec_state(&state->ecram); ++ if (sw < 0) ++ return sw; ++ if (enable != sw) ++ return -EIO; ++ } ++ return count; ++ } ++ return -EIO; ++} ++ ++static void shuttle_fn_exit(struct shuttle_wmi *priv) ++{ ++ struct shuttle_fn_map *fn_map; ++ struct dentry *dbg_entry; ++ struct shuttle_state *state; ++ ++ if (priv->attr_group) { ++ sysfs_remove_group(&priv->pdev->dev.kobj, priv->attr_group); ++ kfree(priv->attr_group->attrs); ++ kfree(priv->attr_group); ++ priv->attr_group = NULL; ++ } ++ ++ fn_map = priv->id->fn_map; ++ while (fn_map->name) { ++ switch (fn_map->type) { ++ case FN_CMD: ++ kfree(fn_map->data); ++ fn_map->data = NULL; ++ break; ++ case FN_CMD_DEBUG: ++ dbg_entry = fn_map->data; ++ if (dbg_entry) { ++ debugfs_remove(dbg_entry); ++ fn_map->data = NULL; ++ } ++ break; ++ case FN_RFKILL: ++ shuttle_rfkill_remove(fn_map); ++ break; ++ case FN_STATE: ++ state = fn_map->data; ++ kfree(state->dev_attr); ++ state->dev_attr = NULL; ++ break; ++ } ++ fn_map++; ++ } ++} ++ ++static struct device_attribute *new_dev_attr(struct shuttle_fn_map *fn_map) ++{ ++ struct device_attribute *dev_attr; ++ ++ dev_attr = kzalloc(sizeof(struct device_attribute), GFP_KERNEL); ++ if (!dev_attr) ++ return NULL; ++ dev_attr->attr.name = fn_map->name; ++ return dev_attr; ++} ++ ++static int shuttle_fn_init(struct shuttle_wmi *priv) ++{ ++ struct shuttle_fn_map *fn_map; ++ struct device_attribute *dev_attr; ++ struct dentry *dbg_entry; ++ struct shuttle_state *state; ++ struct attribute **attr; ++ int nattr = 0; ++ int rc = -ENOMEM; ++ ++ fn_map = priv->id->fn_map; ++ while (fn_map->name) { ++ switch (fn_map->type) { ++ case FN_CMD: ++ dev_attr = new_dev_attr(fn_map); ++ if (!dev_attr) ++ goto fn_init_err; ++ dev_attr->attr.mode = 0200; ++ dev_attr->store = store_fn_cmd; ++ fn_map->data = dev_attr; ++ nattr++; ++ break; ++ case FN_CMD_DEBUG: ++ dbg_entry = debugfs_create_file(fn_map->name, 0200, ++ priv->dbg_root, fn_map, ++ &fops_fn_cmd_debug); ++ if (!dbg_entry) ++ goto fn_init_err; ++ fn_map->data = dbg_entry; ++ break; ++ case FN_RFKILL: ++ rc = shuttle_rfkill_init(fn_map, &priv->pdev->dev); ++ if (rc) ++ goto fn_init_err; ++ break; ++ case FN_STATE: ++ dev_attr = new_dev_attr(fn_map); ++ if (!dev_attr) ++ goto fn_init_err; ++ dev_attr->attr.mode = 0644; ++ dev_attr->show = show_fn_state; ++ dev_attr->store = store_fn_state; ++ state = fn_map->data; ++ state->dev_attr = dev_attr; ++ nattr++; ++ break; ++ } ++ fn_map++; ++ } ++ ++ /* create array of sysfs attributes (FN_CMD and FN_STATE types) */ ++ if (nattr > 0) { ++ priv->attr_group = kzalloc(sizeof(struct attribute_group), ++ GFP_KERNEL); ++ if (!priv->attr_group) ++ goto fn_init_err; ++ priv->attr_group->attrs = kzalloc(sizeof(struct attribute *) * ++ (nattr + 1), GFP_KERNEL); ++ if (!priv->attr_group->attrs) ++ goto fn_attrs_err; ++ attr = priv->attr_group->attrs; ++ fn_map = priv->id->fn_map; ++ while (fn_map->name) { ++ if (fn_map->type == FN_CMD) { ++ dev_attr = fn_map->data; ++ *attr = &dev_attr->attr; ++ attr++; ++ } else if (fn_map->type == FN_STATE) { ++ state = fn_map->data; ++ *attr = &state->dev_attr->attr; ++ attr++; ++ } ++ fn_map++; ++ } ++ rc = sysfs_create_group(&priv->pdev->dev.kobj, ++ priv->attr_group); ++ if (rc) ++ goto fn_grp_err; ++ } ++ ++ return 0; ++ ++fn_grp_err: ++ kfree(priv->attr_group->attrs); ++fn_attrs_err: ++ kfree(priv->attr_group); ++ priv->attr_group = NULL; ++fn_init_err: ++ shuttle_fn_exit(priv); ++ return rc; ++} ++ ++static int __devinit shuttle_wmi_probe(struct platform_device *pdev) ++{ ++ struct shuttle_wmi *priv; ++ int rc, i; ++ acpi_status status; ++ u32 val; ++ ++ priv = kzalloc(sizeof(struct shuttle_wmi), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ priv->pdev = pdev; ++ platform_set_drvdata(pdev, priv); ++ ++ for (i = 0; i < ARRAY_SIZE(shuttle_ids); i++) { ++ rc = wmi_ec_cmd(shuttle_ids[i].cmd_id, 0, 0, 0, &val); ++ if (!rc && val == 1) { ++ priv->id = &shuttle_ids[i]; ++ break; ++ } ++ } ++ /* If we can't identify the system using a WMI command, try using a DMI ++ * match, otherwise set id to unknown model */ ++ if (i == ARRAY_SIZE(shuttle_ids)) { ++ if (dmi_check_system(shuttle_dmi_ids)) ++ priv->id = &shuttle_dmi_id; ++ else ++ priv->id = &id_unknown; ++ } ++ ++ /* Process backlight quirks for some models based on DA18IM */ ++ if (priv->id->cmd_id == CMD_DA18IM) { ++ if (dmi_check_system(shuttle_quirk_bl_dmi_ids)) ++ priv->id->bl_desc = &quirk_bl_desc; ++ } ++ ++ priv->dbg_root = debugfs_create_dir(KBUILD_MODNAME, NULL); ++ if (!priv->dbg_root) { ++ rc = -ENOMEM; ++ goto err_debugfs; ++ } ++ ++ rc = shuttle_fn_init(priv); ++ if (rc) ++ goto err_fn; ++ ++ rc = shuttle_wmi_input_init(priv); ++ if (rc) ++ goto err_input; ++ ++ status = wmi_install_notify_handler(SHUTTLE_WMI_EVENT_GUID, ++ shuttle_wmi_notify, priv); ++ if (ACPI_FAILURE(status)) { ++ rc = -EIO; ++ goto err_notify; ++ } ++ ++ if (!acpi_video_backlight_support()) { ++ rc = shuttle_wmi_backlight_init(priv); ++ if (rc) ++ goto err_backlight; ++ } ++ return 0; ++ ++err_backlight: ++ wmi_remove_notify_handler(SHUTTLE_WMI_EVENT_GUID); ++err_notify: ++ shuttle_wmi_input_remove(priv); ++err_input: ++ shuttle_fn_exit(priv); ++err_fn: ++ debugfs_remove(priv->dbg_root); ++err_debugfs: ++ kfree(priv); ++ return rc; ++} ++ ++static int __devexit shuttle_wmi_remove(struct platform_device *pdev) ++{ ++ struct shuttle_wmi *priv = platform_get_drvdata(pdev); ++ ++ shuttle_wmi_backlight_exit(priv); ++ wmi_remove_notify_handler(SHUTTLE_WMI_EVENT_GUID); ++ shuttle_wmi_input_remove(priv); ++ shuttle_fn_exit(priv); ++ debugfs_remove(priv->dbg_root); ++ kfree(priv); ++ return 0; ++} ++ ++static int shuttle_wmi_resume(struct device *dev) ++{ ++ return shuttle_rfkill_resume(dev); ++} ++ ++static const struct dev_pm_ops shuttle_wmi_pm_ops = { ++ .restore = shuttle_wmi_resume, ++ .resume = shuttle_wmi_resume, ++}; ++ ++static struct platform_driver shuttle_wmi_driver = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .owner = THIS_MODULE, ++ .pm = &shuttle_wmi_pm_ops, ++ }, ++ .probe = shuttle_wmi_probe, ++ .remove = __devexit_p(shuttle_wmi_remove), ++}; ++ ++static struct platform_device *shuttle_wmi_device; ++ ++static ssize_t show_model_name(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct shuttle_wmi *priv = platform_get_drvdata(pdev); ++ ++ return sprintf(buf, "%s\n", priv->id->model_name); ++} ++ ++static DEVICE_ATTR(model_name, 0444, show_model_name, NULL); ++ ++static struct attribute *shuttle_platform_attributes[] = { ++ &dev_attr_model_name.attr, ++ NULL ++}; ++ ++static struct attribute_group shuttle_attribute_group = { ++ .attrs = shuttle_platform_attributes ++}; ++ ++static int __init shuttle_wmi_init(void) ++{ ++ int rc; ++ u32 val; ++ ++ if (!wmi_has_guid(SHUTTLE_WMI_SETGET_GUID) || ++ !wmi_has_guid(SHUTTLE_WMI_EVENT_GUID)) { ++ pr_err("Required WMI GUID not available\n"); ++ return -ENODEV; ++ } ++ ++ /* Check that we are really on a shuttle BIOS */ ++ rc = wmi_ec_cmd(CMD_INT15, 0, 0, 0, &val); ++ if (rc || val != 0x534c) { ++ pr_err("Shuttle WMI device not found or unsupported" ++ " (val=0x%08x)\n", val); ++ return -ENODEV; ++ } ++ ++ rc = platform_driver_register(&shuttle_wmi_driver); ++ if (rc) ++ goto err_driver_register; ++ shuttle_wmi_device = platform_device_alloc(KBUILD_MODNAME, -1); ++ if (!shuttle_wmi_device) { ++ rc = -ENOMEM; ++ goto err_device_alloc; ++ } ++ rc = platform_device_add(shuttle_wmi_device); ++ if (rc) ++ goto err_device_add; ++ ++ rc = sysfs_create_group(&shuttle_wmi_device->dev.kobj, ++ &shuttle_attribute_group); ++ if (rc) ++ goto err_sysfs; ++ ++ return 0; ++ ++err_sysfs: ++ platform_device_del(shuttle_wmi_device); ++err_device_add: ++ platform_device_put(shuttle_wmi_device); ++err_device_alloc: ++ platform_driver_unregister(&shuttle_wmi_driver); ++err_driver_register: ++ return rc; ++} ++ ++static void __exit shuttle_wmi_exit(void) ++{ ++ sysfs_remove_group(&shuttle_wmi_device->dev.kobj, ++ &shuttle_attribute_group); ++ platform_device_unregister(shuttle_wmi_device); ++ platform_driver_unregister(&shuttle_wmi_driver); ++} ++ ++module_init(shuttle_wmi_init); ++module_exit(shuttle_wmi_exit); +diff -Nurp linux-4.6/MAINTAINERS linux-4.6-shuttle/MAINTAINERS +--- linux-4.6/MAINTAINERS ++++ linux-4.6-shuttle/MAINTAINERS +@@ -10130,6 +10130,12 @@ S: Orphan + F: drivers/media/platform/sh_vou.c + F: include/media/drv-intf/sh_vou.h + ++SHUTTLE WMI EXTRAS DRIVER ++M: Herton Ronaldo Krzesinski ++L: platform-driver-x86@vger.kernel.org ++S: Maintained ++F: drivers/platform/x86/shuttle-wmi.c ++ + SIMPLE FIRMWARE INTERFACE (SFI) + M: Len Brown + L: sfi-devel@simplefirmware.org diff --git a/kernel/tools/perf/files/patches/mageia/platform-x86-shuttle-wmi-4.2-buildfix.patch b/kernel/tools/perf/files/patches/mageia/platform-x86-shuttle-wmi-4.2-buildfix.patch new file mode 100644 index 0000000000..ee0d5849a3 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/platform-x86-shuttle-wmi-4.2-buildfix.patch @@ -0,0 +1,19 @@ +--- linux/drivers/platform/x86/shuttle-wmi.c.orig 2015-09-30 00:51:13.000000000 +0300 ++++ linux/drivers/platform/x86/shuttle-wmi.c 2015-09-30 02:04:20.808458393 +0300 +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + MODULE_AUTHOR("Herton Ronaldo Krzesinski"); + MODULE_DESCRIPTION("Shuttle WMI Extras Driver"); +@@ -1161,7 +1162,7 @@ static int shuttle_wmi_probe(struct plat + goto err_notify; + } + +- if (!acpi_video_backlight_support()) { ++ if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { + rc = shuttle_wmi_backlight_init(priv); + if (rc) + goto err_backlight; diff --git a/kernel/tools/perf/files/patches/mageia/platform-x86-shuttle-wmi-drop-devinit-exit.patch b/kernel/tools/perf/files/patches/mageia/platform-x86-shuttle-wmi-drop-devinit-exit.patch new file mode 100644 index 0000000000..171286414e --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/platform-x86-shuttle-wmi-drop-devinit-exit.patch @@ -0,0 +1,38 @@ +--- ./drivers/platform/x86/shuttle-wmi.c.orig 2013-01-16 18:13:57.000000000 +0200 ++++ ./drivers/platform/x86/shuttle-wmi.c 2013-01-16 18:41:13.676433242 +0200 +@@ -294,7 +294,7 @@ static struct dmi_system_id shuttle_dmi_ + {} + }; + +-static struct dmi_system_id __devinitdata shuttle_quirk_bl_dmi_ids[] = { ++static struct dmi_system_id shuttle_quirk_bl_dmi_ids[] = { + { + .ident = "Positivo M13", + .matches = { +@@ -1105,7 +1105,7 @@ fn_init_err: + return rc; + } + +-static int __devinit shuttle_wmi_probe(struct platform_device *pdev) ++static int shuttle_wmi_probe(struct platform_device *pdev) + { + struct shuttle_wmi *priv; + int rc, i; +@@ -1181,7 +1181,7 @@ err_debugfs: + return rc; + } + +-static int __devexit shuttle_wmi_remove(struct platform_device *pdev) ++static int shuttle_wmi_remove(struct platform_device *pdev) + { + struct shuttle_wmi *priv = platform_get_drvdata(pdev); + +@@ -1211,7 +1211,7 @@ static struct platform_driver shuttle_wm + .pm = &shuttle_wmi_pm_ops, + }, + .probe = shuttle_wmi_probe, +- .remove = __devexit_p(shuttle_wmi_remove), ++ .remove = shuttle_wmi_remove, + }; + + static struct platform_device *shuttle_wmi_device; diff --git a/kernel/tools/perf/files/patches/mageia/scsi-megaraid-new-sysfs-name.patch b/kernel/tools/perf/files/patches/mageia/scsi-megaraid-new-sysfs-name.patch new file mode 100644 index 0000000000..c750150fe6 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/scsi-megaraid-new-sysfs-name.patch @@ -0,0 +1,15 @@ +--- + drivers/scsi/megaraid/megaraid_mbox.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-3.8-rc3-mga0.1/drivers/scsi/megaraid/megaraid_mbox.c.scsi-megaraid-new-sysfs-name.orig 2013-01-10 08:17:11.000000000 +0200 ++++ linux-3.8-rc3-mga0.1/drivers/scsi/megaraid/megaraid_mbox.c 2013-01-10 08:30:19.908301909 +0200 +@@ -302,7 +302,7 @@ MODULE_DEVICE_TABLE(pci, pci_id_table_g) + + + static struct pci_driver megaraid_pci_driver = { +- .name = "megaraid", ++ .name = "megaraid_mbox", + .id_table = pci_id_table_g, + .probe = megaraid_probe_one, + .remove = megaraid_detach_one, diff --git a/kernel/tools/perf/files/patches/mageia/scsi-ppscsi-2.6.2.patch b/kernel/tools/perf/files/patches/mageia/scsi-ppscsi-2.6.2.patch new file mode 100644 index 0000000000..bf7be4ba71 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/scsi-ppscsi-2.6.2.patch @@ -0,0 +1,5083 @@ +--- + drivers/scsi/Kconfig | 36 + + drivers/scsi/Makefile | 10 + drivers/scsi/epsa2.c | 507 +++++++++++++++++++ + drivers/scsi/epst.c | 478 ++++++++++++++++++ + drivers/scsi/onscsi.c | 544 ++++++++++++++++++++ + drivers/scsi/ppscsi.c | 1294 +++++++++++++++++++++++++++++++++++++++++++++++++ + drivers/scsi/ppscsi.h | 356 +++++++++++++ + drivers/scsi/sparcsi.c | 389 ++++++++++++++ + drivers/scsi/t348.c | 318 ++++++++++++ + drivers/scsi/t358.c | 394 ++++++++++++++ + drivers/scsi/vpi0.c | 276 ++++++++++ + drivers/scsi/vpi2.c | 418 +++++++++++++++ + 12 files changed, 5020 insertions(+) + +--- /dev/null ++++ b/drivers/scsi/vpi2.c +@@ -0,0 +1,418 @@ ++/* ++ vpi2.c (c) 1995-1999 Grant Guenther ++ (c) 1997-1999 David Campbell ++ (c) 2000 Tim Waugh ++ ++ This is the ppSCSI protocol module for the Iomega VPI2 adapter ++ found in the newer ZIP-100 drives. ++ ++*/ ++ ++#error "This doesn't work yet." ++ ++#define VPI2_VERSION "0.91" ++ ++#define PPSC_BASE ++#define PPSC_HA_MODULE ++ ++#include "ppscsi.h" ++ ++static char vpi2_map[256]; /* status bits permutation */ ++ ++static void vpi2_init (PHA *pha) ++{ ++ ++/* *** No MSG line on the VPI2 ! *** */ /* tmw: is this true for VPI2? */ ++ ++/* { REQ, BSY, MSG, CD, IO} */ ++ ++ char key[5] = {0x80,0x40,0x00,0x20,0x10}; ++ ++ ppsc_make_map(vpi2_map,key,0); ++ sprintf(pha->ident,"vpi2 %s (%s) ",VPI2_VERSION,PPSC_H_VERSION); ++} ++ ++#define j44(a,b) ((a&0xf0)|((b>>4)&0x0f)) ++ ++#define CST(v) w2(0xc);w0(v);w2(4);w2(6);w2(4);w2(0xc); ++#define DST(v) w2(0xc);w0(v);w2(0xc);w2(0xe);w2(0xc);w2(4);w2(0xc); ++ ++static inline int imm_cpp (PHA *pha, unsigned char b) ++{ ++ unsigned char s1, s2, s3; ++ ++ w2(0xc); ++ udelay(2); /* 1 usec - infinite */ ++ w0(0xaa); ++ udelay(10); /* 7 usec - infinite */ ++ w0(0x55); ++ udelay(10); /* 7 usec - infinite */ ++ w0(0x00); ++ udelay(10); /* 7 usec - infinite */ ++ w0(0xff); ++ udelay(10); /* 7 usec - infinite */ ++ s1 = r1() & 0xb8; ++ w0(0x87); ++ udelay(10); /* 7 usec - infinite */ ++ s2 = r1() & 0xb8; ++ w0(0x78); ++ udelay(10); ++ s3 = r1() & 0x38; ++ /* ++ * Values for b are: ++ * 0000 00aa Assign address aa to current device ++ * 0010 00aa Select device aa in EPP Winbond mode ++ * 0010 10aa Select device aa in EPP mode ++ * 0011 xxxx Deselect all devices ++ * 0110 00aa Test device aa ++ * 1101 00aa Select device aa in ECP mode ++ * 1110 00aa Select device aa in Compatible mode ++ */ ++ w0(b); ++ udelay(2); /* 1 usec - infinite */ ++ w2(0x0c); ++ udelay(10); /* 7 usec - infinite */ ++ w2(0x0d); ++ udelay(2); /* 1 usec - infinite */ ++ w2(0x0c); ++ udelay(10); /* 7 usec - infinite */ ++ w0(0xff); ++ udelay(10); /* 7 usec - infinite */ ++ ++ /* ++ * The following table is electrical pin values. ++ * (BSY is inverted at the CTR register) ++ * ++ * BSY ACK POut SEL Fault ++ * S1 0 X 1 1 1 ++ * S2 1 X 0 1 1 ++ * S3 L X 1 1 S ++ * ++ * L => Last device in chain ++ * S => Selected ++ * ++ * Observered values for S1,S2,S3 are: ++ * Disconnect => f8/58/78 ++ * Connect => f8/58/70 ++ */ ++ if ((s1 == 0xb8) && (s2 == 0x18) && (s3 == 0x30)) ++ return 1; /* Connected */ ++ if ((s1 == 0xb8) && (s2 == 0x18) && (s3 == 0x38)) ++ return 0; /* Disconnected */ ++ ++ return -1; /* No device present */ ++} ++ ++static inline int do_vpi2_connect (PHA *pha) ++{ ++ pha->saved_r0 = r0(); ++ pha->saved_r2 = r2(); ++ ++ imm_cpp(pha, 0xe0); /* Select device 0 in compatible mode */ ++ imm_cpp(pha, 0x30); /* Disconnect all devices */ ++ ++ if (pha->mode >= 2) ++ /* Select device 0 in EPP mode */ ++ return imm_cpp (pha, 0x28); ++ ++ /* Select device 0 in compatible mode */ ++ return imm_cpp (pha, 0xe0); ++} ++ ++static void vpi2_connect (PHA *pha) ++{ ++ printk ("--> vpi2_connect\n"); ++ do_vpi2_connect (pha); ++ printk ("<--\n"); ++} ++ ++static void vpi2_disconnect (PHA *pha) ++{ ++ printk ("--> vpi2_disconnect\n"); ++ imm_cpp (pha, 0x30); /* Disconnect all devices */ ++ ++ w2(pha->saved_r2); ++ w0(pha->saved_r0); ++ printk ("<--\n"); ++} ++ ++ ++/* There are no data-transfer tests available, just this simple ++ check that we are talking to a VPI2. */ ++static int vpi2_test_proto (PHA *pha) ++{ ++ int e = 1; ++ ++ printk ("--> vpi2_test_proto\n"); ++ if (do_vpi2_connect(pha) == 1) ++ e--; ++ ++ vpi2_disconnect (pha); ++ printk ("<-- %d\n", e); ++ return e; ++} ++ ++static int vpi2_select (PHA *pha, int initiator, int target) ++{ ++ printk ("--> vpi2_select\n"); ++ w2(0xc); ++ if (r1() & 0x08) { ++ printk ("<-- -1 (busy)\n"); ++ return -1; /* bus busy */ ++ } ++ ++ /* ++ * Now assert the SCSI ID (HOST and TARGET) on the data bus ++ */ ++ w2(0x4); ++ w0(0x80 | (1 << target)); ++ udelay (1); ++ ++ /* ++ * Deassert SELIN first followed by STROBE ++ */ ++ w2(0xc); ++ w2(0xd); ++ ++ printk ("<-- 0\n"); ++ return 0; ++ ++} ++ ++static int vpi2_test_select (PHA *pha) ++{ ++ int val = r1() & 0x08; ++ printk ("--> vpi2_test_select\n<-- %d\n", val); ++ return val; /* BSY asserted ? */ ++} ++ ++static void vpi2_select_finish (PHA *pha) ++{ ++ printk ("--> vpi2_select_finish\n<--\n"); ++ w2(0xc); ++} ++ ++static void vpi2_deselect (PHA *pha) ++{ ++ printk ("--> vpi2_deselect\n<--\n"); ++ w2(0xc); ++} ++ ++static int vpi2_get_bus_status (PHA *pha) ++{ ++ int val; ++ printk ("--> vpi2_get_bus_status\n"); ++ w2(0xc); ++ val = vpi2_map[r1()]; ++ printk ("<-- %d\n", val); ++ return val; ++} ++ ++/* These functions are inlined so the C optimiser can move the switches ++ outside of loops where possible, am I dreaming ? */ ++ ++static inline int vpi2_read (PHA *pha, int first) ++{ ++ int l, h; ++ ++ printk ("--> vpi2_read\n<--\n"); ++ ++ switch (pha->mode) { ++ ++ case 0: if (first) w2(4); ++ w2(0x6); h = r1(); ++ w2(0x5); l = r1(); w2(4); ++ return j44(h,l); ++ ++ case 1: if (first) w2(0x25); ++ w2(0x26); ++ l = r0(); ++ w2(0x25); ++ return l; ++ ++ case 2: if (first) w2(0x24); ++ return r4(); ++ ++ default: return -1; ++ ++ } ++} ++ ++static inline void vpi2_write (PHA *pha, int v, int first ) ++{ ++ static int alternate; ++ ++ printk ("--> vpi2_write\n"); ++ ++ switch (pha->mode) { ++ ++ case 0: ++ case 1: ++ if (first) { ++ w2(0xc); ++ alternate = 0; ++ } ++ w0(v); ++ if (alternate) ++ w2(0x0); ++ else ++ w2(0x5); ++ alternate = 1 - alternate; ++ break; ++ ++ case 2: if (first) w2(0x4); ++ w4(v); ++ break; ++ ++ } ++ printk ("<--\n"); ++} ++ ++static void vpi2_slow_start (PHA *pha, char *val) ++{ ++ int r; ++ ++ printk ("--> vpi2_slow_start\n"); ++ ++ w2(0xc); ++ ++ r = (r1() & 0x10); ++ ++ if (r) *val = vpi2_read(pha,1); ++ else vpi2_write(pha,*val,1); ++ ++ printk ("<--\n"); ++} ++ ++static int vpi2_slow_done (PHA *pha) ++{ ++ printk ("--> vpi2_slow_done\n<--\n"); ++ return 1; /* vpi2 does its own REQ/ACK handshaking */ ++} ++ ++static void vpi2_slow_end (PHA *pha) ++{ ++ printk ("--> vpi2_slow_end\n<--\n"); ++ w2(0xc); ++} ++ ++static void vpi2_start_block (PHA *pha, int rd) ++{ ++ printk ("--> vpi2_start_block\n<--\n"); ++ pha->priv_flag = rd; ++} ++ ++static int vpi2_transfer_ready (PHA *pha) ++{ ++ int b; ++ ++ printk ("--> vpi2_transfer_ready\n<--\n"); ++ b = vpi2_get_bus_status(pha); ++ if ((b & PPSC_PH_STAT) == PPSC_PH_STAT) return -1; ++ if (b == (PPSC_REQ|PPSC_BSY| pha->priv_flag)) return 128; ++ return 0; ++} ++ ++static int vpi2_transfer_block (PHA *pha, char * buf, int buflen, int rd) ++{ ++ int k, n, i; ++ ++ printk ("--> vpi2_transfer_block\n"); ++ k = 0; ++ while (k < buflen) { ++ n = vpi2_transfer_ready(pha); ++ if (n <= 0 ) break; ++ if (n > (buflen-k)) n = buflen-k; ++ for (i=0;i vpi2_transfer_done\n<-- 1\n"); ++ return 1; ++} ++ ++static void vpi2_end_block (PHA *pha, int rd) ++{ ++ printk ("--> vpi2_end_block\n<--\n"); ++ w2(0xc); ++} ++ ++static void vpi2_reset_bus (PHA *pha) ++{ ++ printk ("--> vpi2_reset_bus\n<--\n"); ++ w2(0xc); ++ w0(0x40); w2(8); udelay(60); ++ w2(0xc); ++} ++ ++/* Make these correspond to the actual modes supported by the adapter */ ++ ++static char *(mode_strings[3]) = {"Nybble","PS/2","EPP"}; ++ ++static struct ppsc_protocol vpi2_psp = { ++ ++ {&host0,&host1,&host2,&host3}, /* params */ ++ &host_structs, /* hosts */ ++ 3, /* num_modes */ ++ 2, /* epp_first */ ++ 1, /* default_delay */ ++ 0, /* can_message */ ++ 16, /* sg_tablesize */ ++ mode_strings, ++ vpi2_init, ++ NULL, ++ vpi2_connect, ++ vpi2_disconnect, ++ vpi2_test_proto, ++ vpi2_select, ++ vpi2_test_select, ++ vpi2_select_finish, ++ vpi2_deselect, ++ vpi2_get_bus_status, ++ vpi2_slow_start, ++ vpi2_slow_done, ++ vpi2_slow_end, ++ vpi2_start_block, ++ vpi2_transfer_block, ++ vpi2_transfer_ready, ++ vpi2_transfer_done, ++ vpi2_end_block, ++ vpi2_reset_bus ++}; ++ ++int vpi2_detect (struct scsi_host_template *tpnt) ++{ ++ int val; ++ printk ("--> vpi2_detect\n"); ++ val = ppsc_detect( &vpi2_psp, tpnt, verbose); ++ printk ("<-- %d\n", val); ++ return val; ++} ++ ++#ifdef MODULE ++ ++struct scsi_host_template driver_template = PPSC_TEMPLATE(vpi2); ++ ++#include "scsi_module.c" ++ ++MODULE_LICENSE("GPL"); ++ ++#else ++ ++void vpi2_setup (char *str, int *ints) ++{ ++ printk ("--> vpi2_setup\n"); ++ ppsc_gen_setup(stt,4,str); ++ printk ("<--\n"); ++} ++ ++#endif ++ ++/* end of vpi2.c */ +--- /dev/null ++++ b/drivers/scsi/vpi0.c +@@ -0,0 +1,276 @@ ++/* ++ vpi0.c (c) 1995-1999 Grant Guenther ++ (c) 1997-1999 David Campbell ++ ++ This is the ppSCSI protocol module for the Iomega VPI0 adapter ++ found in the original ZIP-100 drives and the Jaz Traveller. ++ ++*/ ++ ++#define VPI0_VERSION "0.91" ++ ++#define PPSC_BASE ++#define PPSC_HA_MODULE ++ ++#include "ppscsi.h" ++ ++static char vpi0_map[256]; /* status bits permutation */ ++ ++static void vpi0_init (PHA *pha) ++{ ++ ++/* *** No MSG line on the VPI0 ! *** */ ++ ++/* { REQ, BSY, MSG, CD, IO} */ ++ ++ char key[5] = {0x80,0x40,0x00,0x20,0x10}; ++ ++ ppsc_make_map(vpi0_map,key,0); ++ sprintf(pha->ident,"vpi0 %s (%s) ",VPI0_VERSION,PPSC_H_VERSION); ++} ++ ++#define j44(a,b) ((a&0xf0)|((b>>4)&0x0f)) ++ ++#define CST(v) w2(0xc);w0(v);w2(4);w2(6);w2(4);w2(0xc); ++#define DST(v) w2(0xc);w0(v);w2(0xc);w2(0xe);w2(0xc);w2(4);w2(0xc); ++ ++static void vpi0_connect (PHA *pha) ++{ ++ pha->saved_r0 = r0(); ++ pha->saved_r2 = r2(); ++ ++ CST(0); CST(0x3c); CST(0x20); ++ if (pha->mode >= 2) { CST(0xcf) } else { CST(0x8f) } ++} ++ ++static void vpi0_disconnect (PHA *pha) ++{ ++ DST(0); DST(0x3c); DST(0x20); DST(0xf); ++ ++ w2(pha->saved_r2); ++ w0(pha->saved_r0); ++} ++ ++ ++/* There are no data-transfer tests available, just this simple ++ check that we are talking to a VPI0. */ ++static int vpi0_test_proto (PHA *pha) ++{ ++ int e = 2; ++ ++ vpi0_connect(pha); ++ w2(0xe); ++ if ((r1() & 8) == 8) e--; ++ w2(0xc); ++ if ((r1() & 8) == 0) e--; ++ vpi0_disconnect(pha); ++ return e; ++} ++ ++static int vpi0_select (PHA *pha, int initiator, int target) ++{ ++ w2(0xc); ++ if (r1() & 0x40) return -1; /* bus busy */ ++ ++ w0(1<mode) { ++ ++ case 0: if (first) w2(4); ++ h = r1(); w2(6); ++ l = r1(); w2(4); ++ return j44(h,l); ++ ++ case 1: if (first) w2(0x25); ++ l = r0(); ++ w2(0x27); w2(0x25); ++ return l; ++ ++ case 2: if (first) w2(0x24); ++ return r4(); ++ ++ default: return -1; ++ ++ } ++} ++ ++static inline void vpi0_write (PHA *pha, int v, int first ) ++{ ++ switch (pha->mode) { ++ ++ case 0: ++ case 1: if (first) w2(0xc); ++ w0(v); w2(0xe); w2(0xc); ++ break; ++ ++ case 2: if (first) w2(0x4); ++ w4(v); ++ break; ++ ++ } ++} ++ ++static void vpi0_slow_start (PHA *pha, char *val) ++{ ++ int r; ++ ++ w2(0xc); ++ ++ r = (r1() & 0x10); ++ ++ if (r) *val = vpi0_read(pha,1); ++ else vpi0_write(pha,*val,1); ++ ++} ++ ++static int vpi0_slow_done (PHA *pha) ++{ ++ return 1; /* vpi0 does its own REQ/ACK handshaking */ ++} ++ ++static void vpi0_slow_end (PHA *pha) ++{ ++ w2(0xc); ++} ++ ++static void vpi0_start_block (PHA *pha, int rd) ++{ ++ pha->priv_flag = rd; ++} ++ ++static int vpi0_transfer_ready (PHA *pha) ++{ ++ int b; ++ ++ b = vpi0_get_bus_status(pha); ++ if ((b & PPSC_PH_STAT) == PPSC_PH_STAT) return -1; ++ if (b == (PPSC_REQ|PPSC_BSY| pha->priv_flag)) return 128; ++ return 0; ++} ++ ++static int vpi0_transfer_block (PHA *pha, char * buf, int buflen, int rd) ++{ ++ int k, n, i; ++ ++ k = 0; ++ while (k < buflen) { ++ n = vpi0_transfer_ready(pha); ++ if (n <= 0 ) break; ++ if (n > (buflen-k)) n = buflen-k; ++ for (i=0;i ++ ++ This is the low-level protocol module for the Adaptec APA-348 ++ (aka Trantor T348) parallel port SCSI adapter. It forms part ++ of the 'ppSCSI' suite of drivers. ++ ++*/ ++ ++#define T348_VERSION "0.92" ++ ++#define PPSC_BASE ++#define PPSC_HA_MODULE ++ ++#include "ppscsi.h" ++ ++#define j44(a,b) (((a<<1)&0xf0)+((b>>3)&0x0f)) ++ ++static char t348_map[256]; /* status bits permutation */ ++ ++static void t348_init (PHA *pha) ++{ ++ ++/* { REQ, BSY, MSG, CD, IO} */ ++ ++ char key[5] = {0x20,0x40,0x10,0x08,0x04}; ++ ++ ppsc_make_map(t348_map,key,0); ++ sprintf(pha->ident,"t348 %s (%s), Adaptec APA-348", ++ T348_VERSION,PPSC_H_VERSION); ++} ++ ++static void t348_write_regr (PHA *pha, int regr, int value) ++{ ++ w0(0x40+regr); w2(1); w2(0); w0(value); w2(8); w2(0); ++} ++ ++static int t348_read_regr (PHA *pha, int regr) ++{ ++ int s,a,b; ++ ++ w0(0x10+regr); s = r2(); w2(s|1); w2(s); w2(8); ++ w0(0x80); a = r1(); w0(0); b = r1(); w2(0); ++ return j44(a,b); ++} ++ ++static void t348_connect (PHA *pha) ++{ ++ int t; ++ ++ pha->saved_r0 = r0(); ++ w0(0); ++ t = r2(); ++ w2(t%16); w0(0xfe); w2(t%4); w2((t%4)+8); w2(0); ++ pha->saved_r2 = t; ++} ++ ++static void t348_disconnect (PHA *pha) ++{ ++ w0(0x71); w2(1); w2(0); ++ w0(pha->saved_r0); ++ w2(pha->saved_r2); ++} ++ ++static int t348_test_proto (PHA *pha) ++{ ++ int k, e, a, b; ++ int wnt[3] = {0x6c, 0x55, 0xaa}; ++ ++ e = 0; ++ ++ t348_connect(pha); ++ ++ switch (pha->mode) { ++ ++ case 0: w0(0x70); w2(1); w2(0); w0(0); ++ for (k=0;k<3;k++) { ++ w2(8); a = r1(); w2(0); ++ w2(8); w2(8); w2(8); w2(8); w2(8); ++ b = r1(); w2(0); ++ if (j44(b,a) != wnt[k]) e++; ++ } ++ break; ++ ++ case 1: w0(0x50); w2(1); w2(0); ++ for (k=0;k<3;k++) { ++ w2(0xe0); w2(0xe8); ++ if (r0() != wnt[k]) e++; ++ w2(0xe0); w2(0xe8); ++ } ++ ++ } ++ ++ t348_disconnect(pha); ++ ++ return e; ++} ++ ++/* The T348 appears to contain a NCR 5380 core. The following ++ functions use the 5380 registers. See NCR5380.h for clues. ++*/ ++ ++#define WR(r,v) t348_write_regr(pha,r,v) ++#define RR(r) (t348_read_regr(pha,r)) ++ ++static int t348_select (PHA *pha, int initiator, int target) ++{ ++ WR(3,0); WR(1,1); ++ WR(0,(1 << initiator)); WR(2,1); udelay(100); ++ if (RR(1) != 0x41) { ++ WR(1,0); ++ return -1; ++ } ++ ++ WR(1,5); WR(0,(1 << initiator)|(1 << target)); ++ WR(2,0); WR(2,0); WR(2,0); ++ return 0; ++} ++ ++static int t348_test_select (PHA *pha) ++{ ++ return ((RR(4) & 0x42) == 0x42); ++} ++ ++static void t348_select_finish (PHA *pha) ++{ ++ WR(3,2); WR(1,5); WR(1,1); ++} ++ ++static void t348_deselect (PHA *pha) ++{ ++ WR(1,0); ++} ++ ++static int t348_get_bus_status (PHA *pha) ++{ ++ int s; ++ ++ s = RR(4); ++ return t348_map[s]; ++} ++ ++static void t348_slow_start (PHA *pha, char *val) ++{ ++ int ph, io; ++ ++ ph = ((RR(4)>>2)&7); ++ io = (ph & 1); ++ ++ WR(3,ph); ++ WR(1,1-io); ++ if (io) *val = RR(0); else WR(0,*val); ++ WR(1,0x10+(1-io)); ++} ++ ++static int t348_slow_done (PHA *pha) ++{ ++ return ((RR(4) & 0x20) == 0); ++} ++ ++static void t348_slow_end (PHA *pha) ++{ ++ int io; ++ ++ io = ((RR(4)>>2)&1); ++ ++ WR(1,1-io); ++} ++ ++static void t348_start_block (PHA *pha, int rd) ++{ ++ if (rd) { ++ ++ WR(3,1); WR(1,0); ++ WR(2,2); WR(7,3); ++ WR(3,1); WR(1,0); ++ ++ switch (pha->mode) { ++ ++ case 0: w0(0x31); w2(1); w2(0); w0(0x80); w2(8); ++ break; ++ ++ case 1: w0(0x21); w2(1); w2(0); w2(0xe8); ++ break; ++ } ++ ++ } else { ++ ++ WR(3,0); WR(1,1); ++ WR(2,2); WR(5,0); ++ WR(3,0); WR(1,1); ++ ++ w0(0x61); w2(1); w2(0); ++ } ++} ++ ++static int t348_transfer_ready (PHA *pha) ++{ ++ if (r1() & 0x80) return 1; ++ ++ if (pha->data_dir == 0) return 0; ++ return -1; ++} ++ ++static int t348_transfer_block (PHA *pha, char * buf, int buflen, int rd) ++{ ++ int k, a, b; ++ ++ k = 0; ++ while (k < buflen) { ++ ++ if (t348_transfer_ready(pha) <= 0) break; ++ ++ if (rd) { ++ switch(pha->mode) { ++ ++ case 0: a = r1(); w0(0); b = r1(); w0(0xc0); ++ buf[k++] = j44(a,b); ++ a = r1(); w0(0x40); b = r1(); w0(0x80); ++ buf[k++] = j44(a,b); ++ break; ++ ++ case 1: buf[k++] = r0(); w2(0xea); ++ buf[k++] = r0(); w2(0xe8); ++ break; ++ } ++ ++ } else { ++ ++ w0(buf[k++]); w2(2); ++ w0(buf[k++]); w2(0); ++ } ++ ++ } ++ ++ return k; ++} ++ ++static int t348_transfer_done (PHA *pha) ++{ ++ return 1; ++} ++ ++static void t348_end_block (PHA *pha, int rd) ++{ ++ w2(0); ++ WR(2,0); ++} ++ ++ ++static void t348_reset_bus (PHA *pha) ++{ ++ WR(1,1); WR(3,0); ++ WR(2,0); ++ WR(1,0x80); udelay(60); ++ WR(1,0); ++ WR(2,0); ++ WR(1,1); WR(3,0); ++ WR(2,0); ++} ++ ++static char *(mode_strings[2]) = {"Nybble","PS/2"}; ++ ++static struct ppsc_protocol t348_psp = { ++ ++ {&host0,&host1,&host2,&host3}, /* params */ ++ &host_structs, /* hosts */ ++ 2, /* num_modes */ ++ 2, /* epp_first */ ++ 1, /* default_delay */ ++ 1, /* can_message */ ++ 0, /* sg_tablesize */ ++ mode_strings, ++ t348_init, ++ NULL, ++ t348_connect, ++ t348_disconnect, ++ t348_test_proto, ++ t348_select, ++ t348_test_select, ++ t348_select_finish, ++ t348_deselect, ++ t348_get_bus_status, ++ t348_slow_start, ++ t348_slow_done, ++ t348_slow_end, ++ t348_start_block, ++ t348_transfer_block, ++ t348_transfer_ready, ++ t348_transfer_done, ++ t348_end_block, ++ t348_reset_bus ++}; ++ ++int t348_detect (struct scsi_host_template *tpnt) ++{ ++ return ppsc_detect( &t348_psp, tpnt, verbose); ++} ++ ++#ifdef MODULE ++ ++struct scsi_host_template driver_template = PPSC_TEMPLATE(t348); ++ ++#include "scsi_module.c" ++ ++MODULE_LICENSE("GPL"); ++ ++#else ++ ++void t348_setup (char *str, int *ints) ++{ ++ ppsc_gen_setup(stt,4,str); ++} ++ ++#endif ++ ++/* end of t348.c */ ++ +--- /dev/null ++++ b/drivers/scsi/t358.c +@@ -0,0 +1,394 @@ ++/* ++ t358.c (c) 1997-1999 Grant Guenther ++ ++ This is the low-level protocol module for the Adaptec APA-358 ++ (aka Trantor T358) parallel port SCSI adapter. It forms part ++ of the 'ppSCSI' suite of drivers. ++ ++*/ ++ ++#define T358_VERSION "0.91" ++ ++#define PPSC_BASE ++#define PPSC_HA_MODULE ++ ++#include "ppscsi.h" ++ ++#define j44(a,b) (((a<<1)&0xf0)+((b>>3)&0x0f)) ++ ++static char t358_map[256]; /* status bits permutation */ ++ ++static void t358_init (PHA *pha) ++{ ++ ++/* { REQ, BSY, MSG, CD, IO} */ ++ ++ char key[5] = {0x20,0x40,0x10,0x08,0x04}; ++ ++ ppsc_make_map(t358_map,key,0); ++ sprintf(pha->ident,"t358 %s (%s), Adaptec APA-358", ++ T358_VERSION,PPSC_H_VERSION); ++} ++ ++static void t358_write_regr (PHA *pha, int regr, int value) ++{ ++ int x; ++ ++ switch (pha->mode) { ++ ++ case 0: ++ case 1: w0(regr); x = r2(); w2(1); w2(9); w2(0); w2(0); ++ w0(value); w2(1); w2(3); w2(0); w2(x); ++ break; ++ ++ case 2: w2(0xc0); w3(regr); w4(value); ++ break; ++ ++ } ++} ++ ++static int t358_read_regr (PHA *pha, int regr) ++{ ++ int h, l; ++ ++ switch (pha->mode) { ++ ++ case 0: w0(regr); w2(1); w2(9); w2(0); w2(0); ++ w0(0x80); w2(2); h = r1(); ++ w0(0); l = r1(); w2(0); ++ return j44(h,l); ++ ++ case 1: w0(regr); h = r2(); w2(1); w2(9); w2(0); w2(0); ++ w2(0xe2); l = r0(); w2(h); ++ return l; ++ ++ case 2: h = r2(); w2(0xe0); w3(regr); w2(0xe0); ++ l = r4(); w2(h); ++ return l; ++ } ++ ++ return 0; ++} ++ ++static void t358_read_block (PHA *pha, char *buf, int len) ++{ ++ int k, h, l; ++ ++ switch (pha->mode) { ++ ++ case 0: w0(0x10); w2(1); w2(9); w2(0); w2(0); ++ for (k=0;kmode) { ++ ++ case 0: ++ case 1: w0(0x10); x = r2(); ++ w2(1); w2(9); w2(0); w2(0); ++ for (k=0;ksaved_r0 = r0(); ++ w0(0); ++ pha->saved_r2 = r2(); ++ b = pha->saved_r2 % 4; ++ w0(0xf7); w2(b+4); w2(b); w2(b+8); w2(b); w2(0); ++ ++ if (pha->mode) { w0(0x80); w2(1); w2(9); w2(1); w2(0); } ++ else { w0(0xa0); w2(1); w2(9); w2(0); } ++} ++ ++static void t358_disconnect (PHA *pha) ++{ ++ w0(pha->saved_r0); ++ w2(pha->saved_r2); ++} ++ ++static int t358_test_proto (PHA *pha) ++{ ++ int h, l, a, b; ++ int j = 0, k = 0, e = 0; ++ ++ t358_connect(pha); ++ ++ switch (pha->mode) { ++ ++ case 0: w0(0x80); w2(8); h = r1(); w0(0); l = r1(); ++ w2(0); w2(8); a = r1(); w0(0); b = r1(); w2(0); ++ k = j44(h,l); j = j44(a,b); ++ break; ++ ++ case 1: w2(0xe0); w0(0); w2(0xe8); k = r0(); ++ w2(0xe0); w2(0xe8); j = r0(); w2(0xe0); ++ break; ++ ++ case 2: w0(0xa0); w2(1); w2(9); w2(0); ++ w0(0x80); w2(8); h = r1(); w0(0); l = r1(); ++ w2(0); w2(8); a = r1(); w0(0); b = r1(); w2(0); ++ k = j44(h,l); j = j44(a,b); ++ w0(0x80); w2(1); w2(9); w2(1); w2(0); ++ ++ } ++ ++ if (V_PROBE) printk("%s: Signature: %x %x\n",pha->device,k,j); ++ ++ if ((k != 0xe8) || (j != 0xff)) e++; ++ ++ t358_disconnect(pha); ++ ++ if (!e) { ++ ++ t358_connect(pha); ++ ++ for (j=0;j<256;j++) { ++ t358_write_regr(pha,0,j); ++ k = t358_read_regr(pha,0); ++ if (k != j) e++; ++ } ++ ++ t358_disconnect(pha); ++ ++ } ++ ++ return e; ++} ++ ++/* The T358 appears to contain a NCR 53c400 core. Check NCR5380.h ++ for hints about the regrs ... */ ++ ++#define WR(r,v) t358_write_regr(pha,r+8,v) ++#define RR(r) (t358_read_regr(pha,r+8)) ++ ++static int t358_select (PHA *pha, int initiator, int target) ++{ ++ WR(3,0); WR(1,1); ++ WR(0,(1 << initiator)); WR(2,1); udelay(100); ++ if (RR(1) != 0x41) { ++ WR(1,0); ++ return -1; ++ } ++ ++ WR(1,5); WR(0,(1 << initiator)|(1 << target)); ++ WR(2,0); WR(2,0); WR(2,0); ++ return 0; ++} ++ ++static int t358_test_select (PHA *pha) ++{ ++ return ((RR(4) & 0x42) == 0x42); ++} ++ ++static void t358_select_finish (PHA *pha) ++{ ++ WR(3,2); WR(1,5); WR(1,1); ++} ++ ++static void t358_deselect (PHA *pha) ++{ ++ WR(1,0); ++} ++ ++static int t358_get_bus_status (PHA *pha) ++{ ++ int s; ++ ++ s = RR(4); ++ return t358_map[s]; ++} ++ ++static void t358_slow_start (PHA *pha, char *val) ++{ ++ int ph, io; ++ ++ ph = ((RR(4)>>2)&7); ++ io = (ph & 1); ++ ++ WR(3,ph); ++ WR(1,1-io); ++ if (io) *val = RR(0); else WR(0,*val); ++ WR(1,0x10+(1-io)); ++} ++ ++static int t358_slow_done (PHA *pha) ++{ ++ return ((RR(4) & 0x20) == 0); ++} ++ ++static void t358_slow_end (PHA *pha) ++{ ++ int io; ++ ++ io = ((RR(4)>>2)&1); ++ ++ WR(1,1-io); ++} ++ ++static void t358_start_block (PHA *pha, int rd) ++{ ++ if (rd) { ++ WR(3,1); WR(1,0); ++ WR(2,2); ++ WR(0x10,0x40); WR(2,0); WR(2,0xa); ++ WR(3,1); WR(1,0); WR(7,3); ++ } else { ++ WR(3,0); WR(1,1); ++ WR(2,2); ++ WR(0x10,0); WR(2,0); WR(2,0xa); ++ WR(3,0); WR(1,1); WR(5,0); ++ } ++ WR(0x11,pha->tlen/128); ++} ++ ++static int t358_transfer_ready (PHA *pha) ++{ ++ int r; ++ ++ r = RR(0x10); ++ ++ if (!(r & 4)) return 128; /* 4 is host buffer not ready */ ++ ++ if (r & 1) return -1; /* last block transferred */ ++ ++ return 0; ++} ++ ++static int t358_transfer_block (PHA *pha, char * buf, int buflen, int rd) ++{ ++ int k, n; ++ ++ k = 0; ++ while (k < buflen) { ++ ++ n = t358_transfer_ready(pha); ++ ++ if (n <= 0) break; ++ ++ if (n > (buflen - k)) n = buflen - k; ++ ++ if (rd) t358_read_block(pha,buf,n); ++ else t358_write_block(pha,buf,n); ++ ++ k += n; buf += n; ++ ++ } ++ ++ return k; ++} ++ ++static int t358_transfer_done (PHA *pha) ++{ ++ if (RR(0x10) & 1) return 1; /* last block transferred */ ++ return 0; ++} ++ ++static void t358_end_block (PHA *pha, int rd) ++{ ++ WR(2,0); ++} ++ ++ ++static void t358_reset_bus (PHA *pha) ++{ ++ WR(1,1); WR(3,0); ++ WR(2,0); ++ WR(1,0x80); udelay(60); ++ WR(1,0); ++ WR(2,0); ++ WR(1,1); WR(3,0); ++ WR(2,0); ++} ++ ++static char *(mode_strings[3]) = {"Nybble","PS/2","EPP"}; ++ ++static struct ppsc_protocol t358_psp = { ++ ++ {&host0,&host1,&host2,&host3}, /* params */ ++ &host_structs, /* hosts */ ++ 3, /* num_modes */ ++ 2, /* epp_first */ ++ 1, /* default_delay */ ++ 1, /* can_message */ ++ 16, /* sg_tablesize */ ++ mode_strings, ++ t358_init, ++ NULL, ++ t358_connect, ++ t358_disconnect, ++ t358_test_proto, ++ t358_select, ++ t358_test_select, ++ t358_select_finish, ++ t358_deselect, ++ t358_get_bus_status, ++ t358_slow_start, ++ t358_slow_done, ++ t358_slow_end, ++ t358_start_block, ++ t358_transfer_block, ++ t358_transfer_ready, ++ t358_transfer_done, ++ t358_end_block, ++ t358_reset_bus ++}; ++ ++int t358_detect (struct scsi_host_template *tpnt ) ++{ ++ return ppsc_detect( &t358_psp, tpnt, verbose); ++} ++ ++#ifdef MODULE ++ ++struct scsi_host_template driver_template = PPSC_TEMPLATE(t358); ++ ++#include "scsi_module.c" ++ ++MODULE_LICENSE("GPL"); ++ ++#else ++ ++void t358_setup (char *str, int *ints) ++{ ++ ppsc_gen_setup(stt,4,str); ++} ++ ++#endif ++ ++/* end of t358.c */ ++ +--- a/drivers/scsi/Makefile ++++ b/drivers/scsi/Makefile +@@ -129,6 +129,16 @@ obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libisc + + obj-$(CONFIG_ARM) += arm/ + ++obj-$(CONFIG_PPSCSI) += ppscsi.o ++obj-$(CONFIG_PPSCSI_T348) += t348.o ++obj-$(CONFIG_PPSCSI_T358) += t358.o ++obj-$(CONFIG_PPSCSI_ONSCSI) += onscsi.o ++obj-$(CONFIG_PPSCSI_EPSA2) += epsa2.o ++obj-$(CONFIG_PPSCSI_EPST) += epst.o ++obj-$(CONFIG_PPSCSI_VPI0) += vpi0.o ++obj-$(CONFIG_PPSCSI_VPI2) += vpi2.o ++obj-$(CONFIG_PPSCSI_SPARCSI) += sparcsi.o ++ + obj-$(CONFIG_CHR_DEV_ST) += st.o + obj-$(CONFIG_CHR_DEV_OSST) += osst.o + obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o +--- /dev/null ++++ b/drivers/scsi/epst.c +@@ -0,0 +1,478 @@ ++/* ++ epst.c (c) 1996-1999 Grant Guenther ++ ++ This is the ppSCSI protocol module for the Shuttle ++ Technologies EPST parallel port SCSI adapter. ++ ++*/ ++ ++#define EPST_VERSION "0.92" ++ ++#define PPSC_BASE ++#define PPSC_HA_MODULE ++ ++#include "ppscsi.h" ++ ++#define EPST_VER_CODE 0xb2 ++ ++#define j44(a,b) (((a>>4)&0x0f)+(b&0xf0)) ++#define j53(a,b) (((a>>3)&0x1f)+((b<<4)&0xe0)) ++ ++static char epst_map[256]; /* status bits permutation */ ++ ++static void epst_init (PHA *pha) ++{ ++ ++/* { REQ, BSY, MSG, CD, IO} */ ++ ++ char key[5] = {0x20,0x40,0x04,0x02,0x01}; ++ ++ ppsc_make_map(epst_map,key,0); ++ sprintf(pha->ident,"epst %s (%s), Shuttle EPST", ++ EPST_VERSION,PPSC_H_VERSION); ++} ++ ++static void epst_write_regr (PHA *pha, int regr, int value) ++{ ++ switch (pha->mode) { ++ ++ case 0: ++ case 1: ++ case 2: w0(0x60+regr); w2(1); w0(value); w2(4); ++ break; ++ ++ case 3: ++ case 4: ++ case 5: w3(0x40+regr); w4(value); ++ break; ++ ++ } ++} ++ ++static int epst_read_regr (PHA *pha, int regr) ++{ ++ int a, b; ++ ++ switch (pha->mode) { ++ ++ case 0: w0(regr); w2(1); w2(3); ++ a = r1(); w2(4); b = r1(); ++ return j44(a,b); ++ ++ case 1: w0(0x40+regr); w2(1); w2(4); ++ a = r1(); b = r2(); w0(0xff); ++ return j53(a,b); ++ ++ case 2: w0(0x20+regr); w2(1); w2(0x25); ++ a = r0(); w2(4); ++ return a; ++ ++ case 3: ++ case 4: ++ case 5: w3(regr); w2(0x24); a = r4(); ++ return a; ++ ++ } ++ ++ return -1; ++} ++ ++/* for performance reasons, these block transfer functions make ++ some assumptions about the behaviour of the SCSI devices. In ++ particular, DMA transfers are assumed not to stall within the ++ last few bytes of a block ... ++*/ ++ ++static int epst_read_block (PHA *pha, char *buf, int len) ++{ ++ int t, k, p, a, b; ++ ++ k = 0; ++ ++ switch (pha->mode) { ++ ++ case 0: w0(7); w2(1); w2(3); w0(0xff); ++ p = 1; ++ while (k < len) { ++ w2(6+p); a = r1(); ++ if (a & 8) b = a; else { w2(4+p); b = r1(); } ++ buf[k++] = j44(a,b); ++ p = 1 - p; ++ if (!(k % 16)) { ++ w0(0xfe); t = r1(); w0(0xff); ++ if (t & 8) break; ++ } ++ } ++ w0(0); w2(4); ++ break; ++ ++ case 1: w0(0x47); w2(1); w2(5); w0(0xff); ++ p = 0; ++ while (k < len) { ++ a = r1(); b = r2(); ++ buf[k++] = j53(a,b); ++ w2(4+p); ++ p = 1 - p; ++ if (!(k % 16)) { ++ w0(0xfe); t = r1(); w0(0xff); ++ if (t & 8) break; ++ } ++ } ++ w0(0); w2(4); ++ break; ++ ++ case 2: w0(0x27); w2(1); ++ p = 1; ++ while (k < len) { ++ w2(0x24+p); ++ buf[k++] = r0(); ++ p = 1 - p; ++ if ((!(k % 16)) && (r1() & 8)) break; ++ } ++ w2(6); w2(4); ++ break; ++ ++ case 3: w3(0x80); w2(0x24); ++ while (k < len) { ++ buf[k++] = r4(); ++ if ((!(k % 16)) && (r1() & 8)) break; ++ } ++ w2(4); ++ break; ++ ++ case 4: w3(0x80); w2(0x24); ++ while (k < len) { ++ if ((len - k) > 1) { ++ *((u16 *)(&buf[k])) = r4w(); ++ k += 2; ++ } else { ++ buf[k++] = r4(); ++ } ++ if ((!(k % 16)) && (r1() & 8)) break; ++ } ++ w2(4); ++ break; ++ ++ case 5: w3(0x80); w2(0x24); ++ while (k < len) { ++ if ((len - k) > 3) { ++ *((u32 *)(&buf[k])) = r4l(); ++ k += 4; ++ } else { ++ buf[k++] = r4(); ++ } ++ if ((!(k % 16)) && (r1() & 8)) break; ++ } ++ w2(4); ++ break; ++ } ++ ++ return k; ++} ++ ++static int epst_write_block (PHA *pha, char *buf, int len) ++{ ++ int p, k; ++ ++ k = 0; ++ ++ switch (pha->mode) { ++ ++ case 0: ++ case 1: ++ case 2: w0(0x67); w2(1); ++ p = 1; ++ while (k < len) { ++ w2(4+p); ++ w0(buf[k++]); ++ p = 1 - p; ++ if ((!(k % 16)) && (r1() & 8)) break; ++ } ++ w2(5); w2(7); w2(4); ++ break; ++ ++ case 3: w3(0xc0); ++ while (k < len) { ++ w4(buf[k++]); ++ if ((!(k % 16)) && (r1() & 8)) break; ++ } ++ w2(4); ++ break; ++ ++ case 4: w3(0xc0); ++ while (k < len) { ++ if ((len - k) > 1) { ++ w4w(*((u16 *)(&buf[k]))); ++ k += 2; ++ } else { ++ w4(buf[k++]); ++ } ++ if ((!(k % 16)) && (r1() & 8)) break; ++ } ++ w2(4); ++ break; ++ ++ case 5: w3(0xc0); ++ while (k < len) { ++ if ((len - k) > 3) { ++ w4l(*((u32 *)(&buf[k]))); ++ k += 4; ++ } else { ++ w4(buf[k++]); ++ } ++ if ((!(k % 16)) && (r1() & 8)) break; ++ } ++ w2(4); ++ break; ++ } ++ ++ return k; ++} ++ ++#define WR(r,v) epst_write_regr(pha,r,v) ++#define RR(r) (epst_read_regr(pha,r)) ++ ++#define CPP(x) w2(4);w0(0x22);w0(0xaa);w0(0x55);w0(0);w0(0xff);\ ++ w0(0x87);w0(0x78);w0(x);w2(5);w2(4);w0(0xff); ++ ++static void epst_connect (PHA *pha) ++{ ++ w2(4); ++ CPP(0x40); CPP(0xe0); ++ w0(0); w2(1); w2(3); w2(4); ++ ++ if (pha->mode >= 3) { ++ w0(0); w2(1); w2(3); w2(4); w2(0xc); ++ w0(0x40); w2(6); w2(7); w2(4); ++ } ++ ++ WR(0x1d,0x20); WR(0x1d,0); /* clear the ring buffer */ ++ WR(0xa,0x1e); /* set up PDMA */ ++ WR(0xc,4); /* enable status bits */ ++ WR(8,2); /* deglitch timing */ ++} ++ ++static void epst_disconnect (PHA *pha) ++{ ++ CPP(0x30); w2(4); ++ CPP(0x40); w2(4); ++} ++ ++#define Wsr(r,v) WR(0x18+r,v) ++#define Rsr(r) (RR(0x18+r)) ++ ++static int epst_test_proto (PHA *pha) ++{ ++ int i, j, e; ++ char wb[16], rb[16]; ++ ++ e = 0; ++ ++ epst_connect(pha); ++ i = RR(0xb); ++ if (V_PROBE) printk("%s: version code reads: 0x%x\n",pha->device,i); ++ epst_disconnect(pha); ++ ++ if (i != EPST_VER_CODE) return 1; ++ ++ epst_connect(pha); ++ ++ for (j=0;j<200;j++) { ++ for (i=0;i<16;i++) { wb[i] = i+j; rb[i] = i+j+6; } ++ Wsr(5,1); ++ epst_write_block(pha,wb,16); ++ Wsr(5,0x11); ++ epst_read_block(pha,rb,16); ++ for (i=0;i<16;i++) if (wb[i] != rb[i]) e++; ++ } ++ ++ epst_disconnect(pha); ++ ++ if (V_FULL) ++ printk("%s: test port 0x%x mode %d errors %d\n", ++ pha->device,pha->port,pha->mode,e); ++ ++ return e; ++} ++ ++/* The EPST contains a core SCSI controller that is very ++ similar to the NCR 5380. Some bits have been shuffled ++ around, but the basic structure is the same. ++*/ ++ ++static int epst_select (PHA *pha, int initiator, int target) ++{ ++ Wsr(4,(1< ++ ++ This is the low-level protocol module for the WBS-11A parallel ++ port SCSI adapter. This adapter has been marketed by LinkSys ++ as the "ParaSCSI+" and by Shining Technologies as the "SparCSI". ++ The device is constructed from the KBIC-951A ISA replicator ++ chip from KingByte and the NCR 5380. ++ ++*/ ++ ++#define SPARCSI_VERSION "0.91" ++ ++#define PPSC_BASE ++#define PPSC_HA_MODULE ++ ++#include "ppscsi.h" ++ ++#define r12w() (delay_p,inw(pha->port+1)&0xffff) ++ ++#define j44(a,b) ((((a>>4)&0x0f)|(b&0xf0))^0x88) ++#define j53(w) (((w>>3)&0x1f)|((w>>4)&0xe0)) ++ ++static char sparcsi_map[256]; /* status bits permutation */ ++ ++static void sparcsi_init (PHA *pha) ++{ ++ ++/* { REQ, BSY, MSG, CD, IO} */ ++ ++ char key[5] = {0x20,0x40,0x10,0x08,0x04}; ++ ++ ppsc_make_map(sparcsi_map,key,0); ++ sprintf(pha->ident,"sparcsi %s (%s), WBS-11A", ++ SPARCSI_VERSION,PPSC_H_VERSION); ++} ++ ++static void sparcsi_write_regr (PHA *pha, int regr, int value) ++{ ++ switch (pha->mode) { ++ ++ case 0: ++ case 1: ++ case 2: w0(regr|0x10); w2(4); w2(6); w2(4); ++ w0(value); w2(5); w2(4); ++ break; ++ ++ case 3: w0(0x20); w2(4); w2(6); w2(4); w3(regr); ++ w4(value); w2(4); w2(0); w2(4); ++ break; ++ ++ } ++} ++ ++static int sparcsi_read_regr (PHA *pha, int regr) ++{ ++ int a, b; ++ ++ switch (pha->mode) { ++ ++ case 0: w0(regr|0x18); w2(4); w2(6); w2(4); w2(5); ++ a = r1(); w0(0x58); b = r1(); w2(4); ++ return j44(a,b); ++ ++ case 1: w0(regr|0x58); w2(4); w2(6); w2(4); w2(5); ++ a = r12w(); w2(4); ++ return j53(a); ++ ++ case 2: w0(regr|0x98); w2(4); w2(6); w2(4); w2(0xa5); ++ a = r0(); w2(4); ++ return a; ++ ++ case 3: w0(0x20); w2(4); w2(6); w2(4); w3(regr); ++ w2(0xe4); a = r4(); w2(4); w2(0); w2(4); ++ return a; ++ ++ } ++ return -1; ++} ++ ++static void sparcsi_read_block (PHA *pha, char *buf, int len) ++{ ++ int k, a, b; ++ ++ switch (pha->mode) { ++ ++ case 0: w0(8); w2(4); w2(6); w2(4); ++ for (k=0;kmode) { ++ ++ case 0: ++ case 1: ++ case 2: w0(0); w2(4); w2(6); w2(4); ++ for(k=0;ksaved_r0 = r0(); ++ pha->saved_r2 = r2(); ++ w2(4); ++} ++ ++static void sparcsi_disconnect (PHA *pha) ++{ ++ w0(pha->saved_r0); ++ w2(pha->saved_r2); ++} ++ ++#define WR(r,v) sparcsi_write_regr(pha,r,v) ++#define RR(r) (sparcsi_read_regr(pha,r)) ++ ++static int sparcsi_test_proto (PHA *pha) ++{ ++ int k, e; ++ ++ e = 0; ++ ++ sparcsi_connect(pha); ++ ++ if (!pha->private[0]) { /* reset the SCSI bus on first sight */ ++ ++ if (V_FULL) printk("%s: SCSI reset ...\n",pha->device); ++ ++ WR(1,0x80); udelay(60); ++ WR(1,0); ++ scsi_sleep(5*HZ); ++ pha->private[0] = 1; ++ } ++ ++ WR(1,0); ++ WR(1,1); ++ ++ if (V_PROBE) ++ printk("%s: 5380 regrs [4]=%x [5]=%x\n",pha->device,RR(4),RR(5)); ++ ++ for (k=0;k<256;k++) { ++ WR(0,k); ++ if (RR(0) != k) e++; ++ WR(0,255-k); ++ if (RR(0) != (255-k)) e++; ++ } ++ ++ WR(1,0); ++ ++ sparcsi_disconnect(pha); ++ ++ return e; ++} ++ ++static int sparcsi_select (PHA *pha, int initiator, int target) ++{ ++ WR(3,0); WR(1,1); ++ WR(0,(1 << initiator)); WR(2,1); udelay(100); ++ if (RR(1) != 0x41) { ++ WR(1,0); ++ return -1; ++ } ++ ++ WR(1,5); WR(0,(1 << initiator)|(1 << target)); ++ WR(2,0); WR(2,0); WR(2,0); ++ return 0; ++} ++ ++static int sparcsi_test_select (PHA *pha) ++{ ++ return ((RR(4) & 0x42) == 0x42); ++} ++ ++static void sparcsi_select_finish (PHA *pha) ++{ ++ WR(3,2); WR(1,5); WR(1,1); ++} ++ ++static void sparcsi_deselect (PHA *pha) ++{ ++ WR(1,0); ++} ++ ++static int sparcsi_get_bus_status (PHA *pha) ++{ ++ int s; ++ ++ s = RR(4); ++ return sparcsi_map[s]; ++} ++ ++static void sparcsi_slow_start (PHA *pha, char *val) ++{ ++ int ph, io; ++ ++ ph = ((RR(4)>>2)&7); ++ io = (ph & 1); ++ ++ WR(3,ph); ++ WR(1,1-io); ++ if (io) *val = RR(0); else WR(0,*val); ++ WR(1,0x10+(1-io)); ++} ++ ++static int sparcsi_slow_done (PHA *pha) ++{ ++ return ((RR(4) & 0x20) == 0); ++} ++ ++static void sparcsi_slow_end (PHA *pha) ++{ ++ int io; ++ ++ io = ((RR(4)>>2)&1); ++ ++ WR(1,1-io); ++} ++ ++static void sparcsi_start_block (PHA *pha, int rd) ++{ ++ if (rd) { ++ ++ WR(3,1); WR(1,0); ++ WR(2,2); WR(7,3); ++ WR(3,1); WR(1,0); ++ ++ } else { ++ ++ WR(3,0); WR(1,1); ++ WR(2,2); WR(5,0); ++ WR(3,0); WR(1,1); ++ ++ } ++ pha->priv_flag = rd; ++} ++ ++static int sparcsi_transfer_ready (PHA *pha) ++{ ++ int chunk; ++ ++ chunk = 512; ++ if ((pha->data_count == 0) && (!pha->priv_flag)) chunk++; ++ ++ if (r1() & 0x40) return chunk; ++ if (!(RR(5) & 8)) return -1; ++ return 0; ++} ++ ++static int sparcsi_transfer_block (PHA *pha, char * buf, int buflen, int rd) ++{ ++ int k, n; ++ ++ k = 0; ++ while (k < buflen) { ++ ++ n = sparcsi_transfer_ready(pha); ++ ++ if (n <= 0) break; ++ ++ if (n > (buflen - k)) n = buflen - k; ++ ++ if (rd) sparcsi_read_block(pha,buf,n); ++ else sparcsi_write_block(pha,buf,n); ++ ++ k += n; buf += n; ++ } ++ ++ return k; ++} ++ ++static int sparcsi_transfer_done (PHA *pha) ++{ ++ return 1; ++} ++ ++static void sparcsi_end_block (PHA *pha, int rd) ++{ ++ char buf[2] = {0,0}; ++ ++ if (!rd) sparcsi_write_block(pha,buf,1); ++ ++ WR(2,0); ++} ++ ++static void sparcsi_reset_bus (PHA *pha) ++{ ++ WR(1,1); WR(3,0); ++ WR(2,0); ++ WR(1,0x80); udelay(60); ++ WR(1,0); ++ WR(2,0); ++ WR(1,1); WR(3,0); ++ WR(2,0); ++} ++ ++static char *(mode_strings[4]) = {"Nybble","KBIC 5/3","PS/2","EPP"}; ++ ++static struct ppsc_protocol sparcsi_psp = { ++ ++ {&host0,&host1,&host2,&host3}, /* params */ ++ &host_structs, /* hosts */ ++ 4, /* num_modes */ ++ 3, /* epp_first */ ++ 1, /* default_delay */ ++ 1, /* can_message */ ++ 16, /* sg_tablesize */ ++ mode_strings, ++ sparcsi_init, ++ NULL, ++ sparcsi_connect, ++ sparcsi_disconnect, ++ sparcsi_test_proto, ++ sparcsi_select, ++ sparcsi_test_select, ++ sparcsi_select_finish, ++ sparcsi_deselect, ++ sparcsi_get_bus_status, ++ sparcsi_slow_start, ++ sparcsi_slow_done, ++ sparcsi_slow_end, ++ sparcsi_start_block, ++ sparcsi_transfer_block, ++ sparcsi_transfer_ready, ++ sparcsi_transfer_done, ++ sparcsi_end_block, ++ sparcsi_reset_bus ++}; ++ ++int sparcsi_detect (Scsi_Host_Template *tpnt) ++{ ++ return ppsc_detect( &sparcsi_psp, tpnt, verbose); ++} ++ ++#ifdef MODULE ++ ++Scsi_Host_Template driver_template = PPSC_TEMPLATE(sparcsi); ++ ++#include "scsi_module.c" ++ ++MODULE_LICENSE("GPL"); ++ ++#else ++ ++void sparcsi_setup (char *str, int *ints) ++{ ++ ppsc_gen_setup(stt,4,str); ++} ++ ++#endif ++ ++/* end of sparcsi.c */ ++ +--- /dev/null ++++ b/drivers/scsi/epsa2.c +@@ -0,0 +1,507 @@ ++/* ++ epsa2.c (c) 1996-1999 Grant Guenther ++ ++ This is the ppSCSI protocol module for the Shuttle ++ Technologies EPSA2 parallel port SCSI adapter. EPSA2 is ++ a predecessor to the EPST. It uses slightly different ++ command encoding and has a less elaborate internal register ++ model. ++ ++*/ ++ ++#define EPSA2_VERSION "0.91" ++ ++#define PPSC_BASE ++#define PPSC_HA_MODULE ++ ++#include "ppscsi.h" ++ ++#define EPSA2_VER_CODE 0xb1 ++ ++#define j44(a,b) (((a>>4)&0x0f)+(b&0xf0)) ++#define j53(a,b) (((a>>3)&0x1f)+((b<<4)&0xe0)) ++ ++static char epsa2_map[256]; /* status bits permutation */ ++ ++static void epsa2_init( PHA *pha) ++{ ++ ++/* { REQ, BSY, MSG, CD, IO} */ ++ ++ char key[5] = {0x20,0x40,0x04,0x02,0x01}; ++ ++ ppsc_make_map(epsa2_map,key,0); ++ sprintf(pha->ident,"epsa2 %s (%s), Shuttle EPSA2", ++ EPSA2_VERSION,PPSC_H_VERSION); ++} ++ ++static void epsa2_write_regr (PHA *pha, int regr, int value) ++{ ++ switch (pha->mode) { ++ ++ case 0: ++ case 1: ++ case 2: w0(0x70+regr); w2(1); w0(value); w2(4); ++ break; ++ ++ case 3: ++ case 4: ++ case 5: w3(0x40+regr); w4(value); w2(4); ++ break; ++ ++ } ++} ++ ++static int epsa2_read_regr (PHA *pha, int regr) ++{ ++ int a, b; ++ ++ switch (pha->mode) { ++ ++ case 0: w0(0x40+regr); w2(1); w2(3); ++ a = r1(); w2(4); b = r1(); ++ return j44(a,b); ++ ++ case 1: w0(0x60+regr); w2(1); w2(4); ++ a = r1(); b = r2(); w0(0xff); ++ return j53(a,b); ++ ++ case 2: w0(0x50+regr); w2(1); w2(0x25); ++ a = r0(); w2(4); ++ return a; ++ ++ case 3: ++ case 4: ++ case 5: w3(regr); w2(0x24); a = r4(); w2(4); ++ return a; ++ ++ } ++ ++ return -1; ++} ++ ++/* for performance reasons, these block transfer functions make ++ some assumptions about the behaviour of the SCSI devices. In ++ particular, DMA transfers are assumed not to stall within the ++ last few bytes of a block ... ++*/ ++ ++static int epsa2_read_block (PHA *pha, char *buf, int len) ++{ ++ int t, k, p, a, b; ++ ++ k = 0; ++ ++ switch (pha->mode) { ++ ++ case 0: w0(7); w2(1); w2(3); w0(0xff); ++ p = 1; ++ while (k < len) { ++ w2(6+p); a = r1(); ++ if (a & 8) b = a; else { w2(4+p); b = r1(); } ++ buf[k++] = j44(a,b); ++ p = 1 - p; ++ if (!(k % 16)) { ++ w0(0xfe); t = r1(); w0(0xff); ++ if (t & 8) break; ++ } ++ } ++ w0(0); w2(4); ++ break; ++ ++ case 1: w0(0x27); w2(1); w2(5); w0(0xff); ++ p = 0; ++ while (k < len) { ++ a = r1(); b = r2(); ++ buf[k++] = j53(a,b); ++ w2(4+p); ++ p = 1 - p; ++ if (!(k % 16)) { ++ w0(0xfe); t = r1(); w0(0xff); ++ if (t & 8) break; ++ } ++ } ++ w0(0); w2(4); ++ break; ++ ++ case 2: w0(0x17); w2(1); ++ p = 1; ++ while (k < len) { ++ w2(0x24+p); ++ buf[k++] = r0(); ++ p = 1 - p; ++ if ((!(k % 16)) && (r1() & 8)) break; ++ } ++ w2(6); w2(4); ++ break; ++ ++ case 3: w3(6); w2(0x24); ++ while (k < len) { ++ buf[k++] = r4(); ++ if ((!(k % 16)) && (r1() & 8)) break; ++ } ++ w2(4); ++ break; ++ ++ case 4: w3(6); w2(0x24); ++ while (k < len) { ++ if ((len - k) > 1) { ++ *((u16 *)(&buf[k])) = r4w(); ++ k += 2; ++ } else { ++ buf[k++] = r4(); ++ } ++ if ((!(k % 16)) && (r1() & 8)) break; ++ } ++ w2(4); ++ break; ++ ++ case 5: w3(6); w2(0x24); ++ while (k < len) { ++ if ((len - k) > 3) { ++ *((u32 *)(&buf[k])) = r4l(); ++ k += 4; ++ } else { ++ buf[k++] = r4(); ++ } ++ if ((!(k % 16)) && (r1() & 8)) break; ++ } ++ w2(4); ++ break; ++ } ++ ++ return k; ++} ++ ++static int epsa2_write_block (PHA *pha, char *buf, int len) ++{ ++ int p, k; ++ ++ k = 0; ++ ++ switch (pha->mode) { ++ ++ case 0: ++ case 1: ++ case 2: w0(0x37); w2(1); ++ p = 1; ++ while (k < len) { ++ w2(4+p); ++ w0(buf[k++]); ++ p = 1 - p; ++ if ((!(k % 16)) && (r1() & 8)) break; ++ } ++ w2(5); w2(7); w2(4); ++ break; ++ ++ case 3: w3(0x46); ++ while (k < len) { ++ w4(buf[k++]); ++ if ((!(k % 16)) && (r1() & 8)) break; ++ } ++ w2(4); ++ break; ++ ++ case 4: w3(0x46); ++ while (k < len) { ++ if ((len - k) > 1) { ++ w4w(*((u16 *)(&buf[k]))); ++ k += 2; ++ } else { ++ w4(buf[k++]); ++ } ++ if ((!(k % 16)) && (r1() & 8)) break; ++ } ++ w2(4); ++ break; ++ ++ case 5: w3(0x46); ++ while (k < len) { ++ if ((len - k) > 3) { ++ w4l(*((u32 *)(&buf[k]))); ++ k += 4; ++ } else { ++ w4(buf[k++]); ++ } ++ if ((!(k % 16)) && (r1() & 8)) break; ++ } ++ w2(4); ++ break; ++ } ++ ++ return k; ++} ++ ++#define WR(r,v) epsa2_write_regr(pha,r,v) ++#define RR(r) (epsa2_read_regr(pha,r)) ++ ++#define CPP(x) w2(4);w0(0x22);w0(0xaa);w0(0x55);w0(0);w0(0xff);\ ++ w0(0x87);w0(0x78);w0(x);w2(5);w2(4);w0(0xff); ++ ++static void epsa2_connect (PHA *pha) ++{ ++ CPP(0x40); CPP(0xe0); ++ ++ w0(0x73); w2(1); w0(0); w2(4); ++ w0(0x72); w2(1); w0(0x40); w2(4); ++ ++ w0(0); w2(1); w2(4); ++ ++ CPP(0x50); CPP(0x48); ++ ++ switch (pha->mode) { ++ ++ case 0: WR(7,0x82); ++ break; ++ ++ case 1: ++ case 2: WR(7,0xa2); ++ break; ++ ++ case 3: ++ case 4: ++ case 5: CPP(0x30); CPP(0x20); ++ WR(7,0xa3); ++ break; ++ } ++ ++ w2(4); ++} ++ ++static void epsa2_disconnect (PHA *pha) ++{ ++ switch (pha->mode) { ++ ++ case 0: WR(7,2); WR(2,0); ++ break; ++ ++ case 1: ++ case 2: WR(7,0x22); WR(2,0); ++ break; ++ ++ case 3: ++ case 4: ++ case 5: WR(7,0x23); w2(4); ++ w0(0x72); w2(1); w0(0); w2(4); ++ break; ++ } ++ ++ CPP(0x30); CPP(0x40); ++} ++ ++static int epsa2_test_proto (PHA *pha) ++{ ++ int i, j, e; ++ char wb[16], rb[16]; ++ ++ e = 0; ++ ++ epsa2_connect(pha); ++ i = RR(7); ++ if (V_PROBE) printk("%s: version code reads: 0x%x\n",pha->device,i); ++ epsa2_disconnect(pha); ++ ++ if (i != EPSA2_VER_CODE) return 1; ++ ++ epsa2_connect(pha); ++ ++ for (j=0;j<200;j++) { ++ for (i=0;i<16;i++) { wb[i] = i+j; rb[i] = i+j+6; } ++ WR(5,1); ++ epsa2_write_block(pha,wb,16); ++ udelay(100); ++ WR(5,0x11); ++ epsa2_read_block(pha,rb,16); ++ for (i=0;i<16;i++) if (wb[i] != rb[i]) e++; ++ } ++ ++ epsa2_disconnect(pha); ++ ++ if (V_FULL) ++ printk("%s: test port 0x%x mode %d errors %d\n", ++ pha->device,pha->port,pha->mode,e); ++ ++ return e; ++} ++ ++/* The EPSA2 contains a core SCSI controller that is very ++ similar to the NCR 5380. Some bits have been shuffled ++ around, but the basic structure is the same. ++*/ ++ ++static int epsa2_select (PHA *pha, int initiator, int target) ++{ ++ WR(4,(1< ++ (C) 2000 Tim Waugh ++ Under the terms of the GNU general public license. ++ ++ This is the common code shared by the PPSCSI family of ++ low-level drivers for parallel port SCSI host adapters. ++ ++ ++ To use one of the ppSCSI drivers, you must first have this module ++ built-in to your kernel, or loaded. Then, you can load the ++ appropriate protocol module. All protocol modules accept the ++ same parameters: ++ ++ verbose=N determines the logging level where N= ++ 0 only serious errors are logged ++ 1 report progress messages while probing adapters ++ 2 log the scsi commands sent to adapters ++ 3 basic debugging information ++ 4 full debugging (generates lots of output) ++ ++ hostN=,,,,, ++ ++ sets per-host-adapter parameters where ++ ++ N is between 0 and 3, each protocol can ++ support up to four separate adapters. ++ ++ The parport for this adapter, eg: ++ 0 for parport0. ++ ++ Protocol dependent mode number. Usually ++ probed to determine the fastest available ++ mode. ++ ++ microseconds of delay per port access. ++ Default is protocol dependent. ++ ++ Determines this host's ability to load ++ the system. Default 0. Set to 1 or 2 ++ to reduce load at the expense of device ++ performance. ++ ++ scatter-gather table size. ++ ++ bit mask of targets on which to force ++ all commands to use explicit REQ/ACK ++ handshaking, rather than adapter buffers. ++ ++*/ ++ ++#define PPSC_VERSION "0.92" ++ ++#define PPSC_BASE ++#include "ppscsi.h" ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define PPSC_GEN_TMO 40*HZ ++#define PPSC_SELECT_TMO HZ/10 ++#define PPSC_PROBE_TMO HZ/2 ++#define PPSC_RESET_TMO 4*HZ ++#define PPSC_SLOW_LOOPS 30 ++#define PPSC_BUSY_SNOOZE HZ; ++ ++#define PPSC_DEF_NICE 0 ++#define PPSC_INITIATOR 7 ++ ++spinlock_t ppsc_spinlock = SPIN_LOCK_UNLOCKED; ++ ++static char ppsc_bulk_map[256]; ++ ++struct ppsc_port_list_struct { ++ struct parport *port; ++ struct ppsc_port_list_struct *next; ++}; ++static struct ppsc_port_list_struct *ppsc_port_list; ++ ++/* ppsc_attach and ppsc_detach are for keeping a list of currently ++ * available ports, held under a mutex. We do this rather than ++ * using parport_enumerate because it stops a load of races. ++ */ ++ ++static void ppsc_attach (struct parport *port) ++{ ++ struct ppsc_port_list_struct *add; ++ ++ add = kmalloc (sizeof (struct ppsc_port_list_struct), GFP_KERNEL); ++ if (!add) { ++ printk (KERN_WARNING "ppscsi: memory squeeze\n"); ++ return; ++ } ++ ++ add->port = parport_get_port (port); ++ add->next = ppsc_port_list; ++ wmb (); ++ ppsc_port_list = add; ++} ++ ++static void ppsc_detach (struct parport *port) ++{ ++ /* Do nothing. We have a reference to the port already, so ++ * it won't go away. We'll clean up the port list when we ++ * unload. */ ++} ++ ++static struct parport_driver ppsc_driver = { ++ name: "ppscsi", ++ attach: ppsc_attach, ++ detach: ppsc_detach ++}; ++ ++void ppsc_make_map (char map[256], char key[5], int inv) ++{ ++ int i, j; ++ ++ for (i=0;i<256;i++) { ++ map[i] = 0; ++ for (j=0;j<5;j++) ++ map[i] = (map[i] << 1) | ((i & key[j]) != inv*key[j]); ++ } ++} ++ ++void ppsc_gen_setup (STT t[], int n, char *ss) ++{ ++ int j, k, sgn; ++ ++ k = 0; ++ for (j=0;jcontinuation = continuation; ++ pha->ready = ready; ++ if (timeout) ++ pha->timeout = jiffies + timeout; ++ else pha->timeout = pha->then + pha->tmo; ++ ++ if (!pha->nice && !pha->wq_active) { ++#ifdef HAVE_DISABLE_HLT ++ disable_hlt(); ++#endif ++ pha->wq_active = 1; ++ schedule_work (&pha->wq); ++ } ++ ++ if (!pha->timer_active) { ++ pha->timer_active = 1; ++ pha->timer.expires = jiffies + ((pha->nice>0)?(pha->nice-1):0); ++ add_timer(&pha->timer); ++ } ++ ++ spin_unlock_irqrestore(&ppsc_spinlock,flags); ++} ++ ++static void ppsc_tq_int (void *data) ++{ ++ void (*con)(PHA *); ++ unsigned long flags; ++ PHA *pha = (PHA *)data; ++ ++ spin_lock_irqsave(&ppsc_spinlock,flags); ++ ++ con = pha->continuation; ++ ++#ifdef HAVE_DISABLE_HLT ++ enable_hlt(); ++#endif ++ ++ pha->wq_active = 0; ++ ++ if (!con) { ++ spin_unlock_irqrestore(&ppsc_spinlock,flags); ++ return; ++ } ++ pha->timedout = time_after_eq (jiffies, pha->timeout); ++ if (!pha->ready || pha->ready(pha) || pha->timedout) { ++ pha->continuation = NULL; ++ spin_unlock_irqrestore(&ppsc_spinlock,flags); ++ con(pha); ++ return; ++ } ++ ++#ifdef HAVE_DISABLE_HLT ++ disable_hlt(); ++#endif ++ ++ pha->wq_active = 1; ++ schedule_work (&pha->wq); ++ spin_unlock_irqrestore(&ppsc_spinlock,flags); ++} ++ ++static void ppsc_timer_int (unsigned long data) ++{ ++ void (*con)(PHA *); ++ unsigned long flags; ++ PHA *pha = (PHA *)data; ++ ++ spin_lock_irqsave(&ppsc_spinlock,flags); ++ ++ con = pha->continuation; ++ pha->timer_active = 0; ++ if (!con) { ++ spin_unlock_irqrestore(&ppsc_spinlock,flags); ++ return; ++ } ++ pha->timedout = time_after_eq (jiffies, pha->timeout); ++ if (!pha->ready || pha->ready(pha) || pha->timedout) { ++ pha->continuation = NULL; ++ spin_unlock_irqrestore(&ppsc_spinlock,flags); ++ con(pha); ++ return; ++ } ++ pha->timer_active = 1; ++ pha->timer.expires = jiffies + ((pha->nice>0)?(pha->nice-1):0); ++ add_timer(&pha->timer); ++ spin_unlock_irqrestore(&ppsc_spinlock,flags); ++} ++ ++static void ppsc_wake_up( void *p) ++{ ++ PHA *pha = (PHA *) p; ++ unsigned long flags; ++ void (*cont)(PHA *) = NULL; ++ ++ spin_lock_irqsave(&ppsc_spinlock,flags); ++ ++ if (pha->claim_cont && ++ !parport_claim(pha->pardev)) { ++ cont = pha->claim_cont; ++ pha->claim_cont = NULL; ++ pha->claimed = 1; ++ } ++ ++ spin_unlock_irqrestore(&ppsc_spinlock,flags); ++ ++ wake_up(&(pha->parq)); ++ ++ if (cont) cont(pha); ++} ++ ++void ppsc_do_claimed (PHA *pha, void(*cont)(PHA *)) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ppsc_spinlock,flags); ++ ++ if (!parport_claim(pha->pardev)) { ++ pha->claimed = 1; ++ spin_unlock_irqrestore(&ppsc_spinlock,flags); ++ cont(pha); ++ } else { ++ pha->claim_cont = cont; ++ spin_unlock_irqrestore(&ppsc_spinlock,flags); ++ } ++} ++ ++static void ppsc_claim (PHA *pha) ++{ ++ if (pha->claimed) return; ++ pha->claimed = 1; ++ ++ wait_event (pha->parq, !parport_claim (pha->pardev)); ++} ++ ++static void ppsc_unclaim (PHA *pha) ++{ ++ pha->claimed = 0; ++ parport_release(pha->pardev); ++} ++ ++static void ppsc_unregister_parport (PHA *pha) ++{ ++ parport_unregister_device(pha->pardev); ++ pha->pardev = NULL; ++} ++ ++static int ppsc_register_parport (PHA *pha, int verbose) ++{ ++ struct ppsc_port_list_struct *ports; ++ struct parport *port = NULL; ++ ++ ports = ppsc_port_list; ++ while((ports)&&(ports->port->number != pha->port)) ++ ports = ports->next; ++ if (ports) { ++ port = ports->port; ++ pha->pardev = parport_register_device(port, pha->device, ++ NULL, ppsc_wake_up, NULL, ++ 0, (void *)pha); ++ } else { ++ printk (KERN_DEBUG "%s: no such device: parport%d\n", ++ pha->device, pha->port); ++ return 1; ++ } ++ ++ if (!pha->pardev) { ++ printk (KERN_DEBUG "%s: couldn't register device\n", ++ pha->device); ++ return 1; ++ } ++ ++ init_waitqueue_head (&pha->parq); ++ ++ /* For now, cache the port base address. Won't need this ++ after transition to parport_xxx_yyy. */ ++ pha->port = port->base; ++ ++ if (verbose) ++ printk("%s: 0x%x is %s\n",pha->device,pha->port, ++ port->name); ++ pha->parname = port->name; ++ return 0; ++} ++ ++/* Here's the actual core SCSI stuff ... */ ++ ++#define PPSC_FAIL(err,msg) { ppsc_fail_command(pha,err,msg); return; } ++ ++static void ppsc_start (PHA *pha); ++static void ppsc_select_intr (PHA *pha); ++static void ppsc_engine (PHA *pha); ++static void ppsc_transfer (PHA *pha); ++static void ppsc_transfer_done (PHA *pha); ++static int ppsc_slow (PHA *pha, char *val); ++static void ppsc_slow_done (PHA *pha); ++static void ppsc_cleanup (PHA *pha); ++static void ppsc_fail_command (PHA *pha, int err_code, char *msg); ++static int ppsc_ready (PHA *pha); ++ ++/* synchronous interface is deprecated, but we maintain it for ++ internal use. It just starts an asynchronous command and waits ++ for it to complete. ++*/ ++ ++int ppsc_command (struct scsi_cmnd *cmd) ++{ ++ PHA *pha = (PHA *) cmd->device->host->hostdata[0]; ++ ++ pha->cur_cmd = cmd; ++ pha->done = NULL; ++ pha->then = jiffies; ++ ++ ppsc_do_claimed(pha,ppsc_start); ++ ++ while (pha->cur_cmd) scsi_sleep(1); ++ ++ return cmd->result; ++} ++ ++int ppsc_queuecommand (struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) ++{ ++ PHA *pha = (PHA *) cmd->device->host->hostdata[0]; ++ ++ if (pha->cur_cmd) { ++ printk("%s: Driver is busy\n",pha->device); ++ return 0; ++ } ++ ++ pha->cur_cmd = cmd; ++ pha->done = done; ++ pha->then = jiffies; ++ ++ ppsc_do_claimed(pha,ppsc_start); ++ ++ return 0; ++} ++ ++static void ppsc_arb_fail (PHA *pha) ++{ ++ PPSC_FAIL(DID_BUS_BUSY,"Arbitration failure"); ++} ++ ++static void ppsc_start (PHA *pha) ++{ ++ int k, r, b, bf; ++ struct scatterlist *p; ++ ++ pha->last_phase = PPSC_PH_NONE; ++ pha->return_code = (DID_OK << 16); ++ pha->overflow = 0; ++ pha->protocol_error = 0; ++ pha->cmd_count = 0; ++ ++ k = pha->cur_cmd->cmnd[0]; ++ bf = ppsc_bulk_map[k]; ++ ++ bf &= (!((1<cur_cmd->device->id) & pha->slow_targets)); ++ ++ r = pha->cur_cmd->use_sg; ++ if (r) { ++ b = 0; ++ p = (struct scatterlist *)pha->cur_cmd->request_buffer; ++ for (k=0;klength; ++ p++; ++ } ++ } else { ++ b = pha->cur_cmd->request_bufflen; ++ } ++ ++ bf &= (b > 127); ++ ++ if (V_DEBUG) ++ printk("%s: Target %d, bl=%d us=%d bf=%d cm=%x\n", ++ pha->device,pha->cur_cmd->device->id,b,r,bf,k); ++ ++ pha->bulk = bf; ++ pha->tlen = b; ++ ++ pha->proto->connect(pha); ++ ++ r = 0; ++ while (r++ < 5) { ++ k = pha->proto->select(pha,PPSC_INITIATOR,pha->cur_cmd->device->id); ++ if (k != -1) break; ++ udelay(200); ++ } ++ ++ if (k == -1) { ++ ppsc_set_intr(pha,ppsc_arb_fail,NULL,1); ++ return; ++ } ++ ++ ppsc_set_intr(pha,ppsc_select_intr,pha->proto->test_select, ++ PPSC_SELECT_TMO); ++} ++ ++static void ppsc_select_intr (PHA *pha) ++{ ++ if (!pha->proto->test_select(pha)) { ++ pha->return_code = DID_NO_CONNECT << 16; ++ ppsc_cleanup(pha); ++ return; ++ } ++ if (pha->proto->select_finish) ++ pha->proto->select_finish(pha); ++ ++ if (V_FULL) ++ printk("%s: selected target\n",pha->device); ++ ++ pha->timedout = 0; ++ ppsc_engine(pha); ++} ++ ++static void ppsc_update_sg (PHA *pha) ++{ ++ if ((!pha->cur_len) && pha->sg_count) { ++ pha->sg_count--; ++ pha->sg_list++; ++ pha->cur_buf = page_address(pha->sg_list->page) + pha->sg_list->offset; ++ pha->cur_len = pha->sg_list->length; ++ } ++} ++ ++static void ppsc_engine (PHA *pha) ++{ ++ int phase, i; ++ char *sb; ++ ++ while (1) { ++ if ((pha->last_phase == PPSC_PH_MSGIN) || ++ ((pha->last_phase == PPSC_PH_STAT) ++ && (!pha->proto->can_message))) { ++ pha->return_code |= (pha->status_byte & STATUS_MASK) ++ | (pha->message_byte << 8); ++ ppsc_cleanup(pha); ++ return; ++ } ++ ++ phase = pha->proto->get_bus_status(pha); ++ ++ if (pha->abort_flag) ++ PPSC_FAIL(DID_ABORT,"Command aborted"); ++ ++ if (pha->protocol_error) ++ PPSC_FAIL(DID_ERROR,"Adapter protocol failure"); ++ ++ if (!(phase & PPSC_BSY)) { ++ if (pha->last_phase == PPSC_PH_STAT) { ++ if (V_DEBUG) printk("%s: No msg phase ?\n", pha->device); ++ pha->return_code |= (pha->status_byte & STATUS_MASK); ++ ppsc_cleanup(pha); ++ return; ++ } ++ PPSC_FAIL(DID_ERROR,"Unexpected bus free"); ++ } ++ ++ if (!(phase & PPSC_REQ)) { ++ if (pha->timedout) ++ PPSC_FAIL(DID_TIME_OUT,"Pseudo-interrupt timeout"); ++ ppsc_set_intr(pha,ppsc_engine,ppsc_ready,0); ++ return; ++ } ++ ++ switch (phase) { ++ ++ case PPSC_PH_CMD: ++ ++ if (phase != pha->last_phase) { ++ if (pha->last_phase != PPSC_PH_NONE) ++ PPSC_FAIL(DID_ERROR,"Phase sequence error 1"); ++ pha->cmd_count = 0; ++ if (V_TRACE) { ++ printk("%s: Command to %d (%d): ", ++ pha->device, pha->cur_cmd->device->id, ++ pha->cur_cmd->cmd_len); ++ for (i=0;icur_cmd->cmd_len;i++) ++ printk("%2x ",pha->cur_cmd->cmnd[i]); ++ printk("\n"); ++ } ++ } ++ ++ pha->last_phase = phase; ++ ++ if (pha->cmd_count >= pha->cur_cmd->cmd_len) ++ PPSC_FAIL(DID_ERROR,"Command buffer overrun"); ++ ++ if (!ppsc_slow(pha,&(pha->cur_cmd->cmnd[pha->cmd_count++]))) ++ return; ++ ++ break; ++ ++ case PPSC_PH_READ: ++ case PPSC_PH_WRITE: ++ ++ if (phase != pha->last_phase) { ++ if (pha->last_phase != PPSC_PH_CMD) ++ PPSC_FAIL(DID_ERROR,"Phase sequence error 2"); ++ pha->data_dir = phase & PPSC_IO; ++ pha->data_count = 0; ++ ++ pha->sg_count = pha->cur_cmd->use_sg; ++ if (pha->sg_count) { ++ pha->sg_count--; ++ pha->sg_list = ++ (struct scatterlist *)pha->cur_cmd->request_buffer; ++ pha->cur_buf = page_address(pha->sg_list->page) + pha->sg_list->offset; ++ pha->cur_len = pha->sg_list->length; ++ } else { ++ pha->cur_buf = pha->cur_cmd->request_buffer; ++ pha->cur_len = pha->cur_cmd->request_bufflen; ++ } ++ ++ pha->last_phase = phase; ++ ++ } ++ ++ if ((pha->bulk) && (pha->cur_len > 0 )) { ++ pha->proto->start_block(pha,pha->data_dir); ++ ppsc_transfer(pha); ++ return; ++ } ++ ++ ppsc_update_sg(pha); ++ ++ if (!pha->cur_len) { ++ pha->cur_len = 1; ++ pha->cur_buf = (char *)&i; ++ i = 0x5a; ++ pha->overflow++; ++ } ++ ++ pha->cur_len--; ++ pha->data_count++; ++ ++ if (!ppsc_slow(pha,pha->cur_buf++)) return; ++ ++ break; ++ ++ case PPSC_PH_STAT: ++ ++ if ((pha->last_phase != PPSC_PH_CMD) && ++ (pha->last_phase != PPSC_PH_READ) && ++ (pha->last_phase != PPSC_PH_WRITE)) ++ PPSC_FAIL(DID_ERROR,"Phase sequence error 3"); ++ ++ if ((pha->last_phase != PPSC_PH_CMD) && ++ (V_DEBUG)) { ++ printk("%s: %s%s %d bytes\n", ++ pha->device, ++ pha->bulk?"":"slow ", ++ pha->data_dir?"read":"write", ++ pha->data_count); ++ ++ if (pha->cur_cmd->cmnd[0] == REQUEST_SENSE) { ++ ++ sb = (char *)pha->cur_cmd->request_buffer; ++ printk("%s: Sense key: %x ASC: %x ASCQ: %x\n", ++ pha->device, sb[2] & 0xff, ++ sb[12] & 0xff, sb[13] & 0xff); ++ } ++ } ++ ++ if (pha->overflow) ++ printk("%s: WARNING: data %s overran by %d/%d bytes\n", ++ pha->device,pha->data_dir?"read":"write", ++ pha->overflow,pha->data_count); ++ ++ pha->last_phase = phase; ++ ++ if (!ppsc_slow(pha,&pha->status_byte)) return; ++ ++ break; ++ ++ case PPSC_PH_MSGIN: ++ ++ if (pha->last_phase != PPSC_PH_STAT) ++ PPSC_FAIL(DID_ERROR,"Phase sequence error 4"); ++ ++ pha->last_phase = phase; ++ ++ if (V_FULL) ++ printk("%s: status = %x\n",pha->device,pha->status_byte); ++ ++ if (!ppsc_slow(pha,&pha->message_byte)) return; ++ ++ break; ++ ++ default: ++ ++ PPSC_FAIL(DID_ERROR,"Unexpected bus phase"); ++ ++ } ++ } ++} ++ ++static void ppsc_transfer (PHA *pha) ++{ ++ int i, j; ++ ++ if (pha->timedout) ++ PPSC_FAIL(DID_TIME_OUT,"PDMA timeout"); ++ ++ while(1) { ++ ++ if (!(j=pha->proto->transfer_ready(pha))) { ++ ppsc_set_intr(pha,ppsc_transfer, ++ pha->proto->transfer_ready,0); ++ return; ++ } ++ ++ if (j < 0) { ++ if (V_DEBUG) ++ printk("%s: short transfer\n",pha->device); ++ ppsc_set_intr(pha,ppsc_transfer_done, ++ pha->proto->transfer_done,0); ++ return; ++ } ++ ++ i = pha->proto->transfer_block(pha,pha->cur_buf, ++ pha->cur_len,pha->data_dir); ++ ++ if (V_FULL) ++ printk("%s: Fragment %d\n",pha->device,i); ++ ++ if ((i < 0) || (i > pha->cur_len)) ++ PPSC_FAIL(DID_ERROR,"Block transfer error"); ++ ++ pha->cur_len -= i; ++ pha->cur_buf += i; ++ pha->data_count += i; ++ ++ ppsc_update_sg(pha); ++ ++ if (pha->cur_len == 0 ) { ++ ppsc_set_intr(pha,ppsc_transfer_done, ++ pha->proto->transfer_done,0); ++ return; ++ } ++ } ++} ++ ++static void ppsc_transfer_done (PHA *pha) ++{ ++ if (pha->timedout) PPSC_FAIL(DID_TIME_OUT,"PDMA done timeout"); ++ ++ pha->proto->end_block(pha,pha->data_dir); ++ ppsc_engine(pha); ++} ++ ++static int ppsc_slow (PHA *pha, char *val) ++{ ++ int k; ++ ++ pha->proto->slow_start(pha,val); ++ ++ k = 0; ++ while (k++ < PPSC_SLOW_LOOPS) ++ if (pha->proto->slow_done(pha)) { ++ pha->proto->slow_end(pha); ++ return 1; ++ } ++ ++ ppsc_set_intr(pha,ppsc_slow_done,pha->proto->slow_done,0); ++ return 0; ++} ++ ++static void ppsc_slow_done (PHA *pha) ++{ ++ int k; ++ ++ if (pha->timedout) PPSC_FAIL(DID_TIME_OUT,"PIO timeout"); ++ ++ pha->proto->slow_end(pha); ++ ++ k = 0; ++ while (k++ < PPSC_SLOW_LOOPS) ++ if (ppsc_ready(pha)) break; ++ ++ ppsc_engine(pha); ++} ++ ++static void ppsc_try_again (unsigned long data ) ++{ ++ PHA *pha = (PHA *)data; ++ ++ ppsc_do_claimed(pha,ppsc_start); ++} ++ ++static void ppsc_cleanup (PHA *pha) ++{ ++ struct scsi_cmnd *cmd; ++ void (*done)(struct scsi_cmnd *); ++ unsigned long saved_flags; ++ ++ pha->tot_bytes += pha->data_count; ++ ++ cmd = pha->cur_cmd; ++ done = pha->done; ++ cmd->result = pha->return_code; ++ pha->cur_cmd = 0; ++ ++ pha->proto->deselect(pha); ++ pha->proto->disconnect(pha); ++ ++ if (V_FULL) printk("%s: releasing parport\n",pha->device); ++ ++ ppsc_unclaim(pha); ++ ++ if (pha->abort_flag) { ++ ++ if (V_DEBUG) printk("%s: command aborted !\n",pha->device); ++ ++ return; /* kill the thread */ ++ } ++ ++ if (V_DEBUG) ++ printk("%s: Command status %08x last phase %o\n", ++ pha->device,cmd->result,pha->last_phase); ++ ++ if (status_byte(pha->return_code) == BUSY) { ++ ++ pha->cur_cmd = cmd; ++ ++ if (V_FULL) ++ printk("%s: BUSY, sleeping before retry ...\n", ++ pha->device); ++ ++ init_timer (&pha->sleeper); ++ pha->sleeper.data = (unsigned long) pha; ++ pha->sleeper.function = ppsc_try_again; ++ pha->sleeper.expires = jiffies + PPSC_BUSY_SNOOZE; ++ add_timer(&pha->sleeper); ++ ++ return; ++ ++ } ++ ++ pha->tot_cmds++; ++ ++ if ((cmd->cmnd[0] != REQUEST_SENSE) && ++ (status_byte(pha->return_code) == CHECK_CONDITION)) { ++ ++ if (V_FULL) ++ printk("%s: Requesting sense data\n",pha->device); ++ ++ cmd->cmnd[0] = REQUEST_SENSE; ++ cmd->cmnd[1] &= 0xe0; ++ cmd->cmnd[2] = 0; ++ cmd->cmnd[3] = 0; ++ cmd->cmnd[4] = sizeof(cmd->sense_buffer); ++ cmd->cmnd[5] = 0; ++ cmd->cmd_len = 6; ++ cmd->use_sg = 0; ++ cmd->request_buffer = (char *) cmd->sense_buffer; ++ cmd->request_bufflen = sizeof(cmd->sense_buffer); ++ ++ pha->cur_cmd = cmd; ++ ppsc_do_claimed(pha,ppsc_start); ++ ++ return; ++ } ++ ++ if (done) { ++ ++ spin_lock_irqsave(pha->host_ptr->host_lock,saved_flags); ++ done(cmd); ++ spin_unlock_irqrestore(pha->host_ptr->host_lock,saved_flags); ++ ++ } ++ ++} ++ ++static void ppsc_fail_command (PHA *pha, int err_code, char *msg) ++{ ++ int bs; ++ ++ pha->tot_errs++; ++ ++ bs = pha->proto->get_bus_status(pha); ++ ++ pha->return_code = err_code << 16; ++ if (!pha->quiet) ++ printk("%s: %s, bs=%o cb=%d db=%d bu=%d sg=%d " ++ "rd=%d lp=%o pe=%d cc=%d\n", ++ pha->device, msg, bs, ++ pha->cmd_count, pha->data_count, ++ pha->bulk, pha->sg_count, pha->data_dir, ++ pha->last_phase, pha->protocol_error, pha->tot_cmds); ++ ++ ppsc_cleanup(pha); ++} ++ ++static int ppsc_ready (PHA *pha) ++{ ++ int bs; ++ ++ if (pha->abort_flag || pha->protocol_error) return 1; ++ bs = pha->proto->get_bus_status(pha); ++ ++ if ( (bs & (PPSC_REQ|PPSC_BSY)) != PPSC_BSY) return 1; ++ ++ return 0; ++} ++ ++int ppsc_abort (struct scsi_cmnd * cmd) ++{ ++ PHA *pha = (PHA *)cmd->device->host->hostdata[0]; ++ ++ printk("%s: Command abort not supported\n",pha->device); ++ return FAILED; ++} ++ ++static void ppsc_reset_pha (PHA *pha) ++{ ++ if (!pha->proto->reset_bus) { ++ printk("%s: No reset method available\n",pha->device); ++ return; ++ } ++ ++ ppsc_claim(pha); ++ pha->proto->connect(pha); ++ pha->proto->reset_bus(pha); ++ scsi_sleep(4*HZ); ++ pha->proto->disconnect(pha); ++ ppsc_unclaim(pha); ++ ++ if (!pha->quiet) printk("%s: Bus reset\n",pha->device); ++} ++ ++int ppsc_reset (struct scsi_cmnd * cmd) ++{ ++ PHA *pha = (PHA *)cmd->device->host->hostdata[0]; ++ int k = 0; ++ ++ if (!pha->proto->reset_bus) ++ return FAILED; ++ ++ if (pha->cur_cmd) ++ pha->abort_flag = PPSC_DO_RESET; ++ ++ while (pha->cur_cmd && (k < PPSC_RESET_TMO)) { ++ scsi_sleep(HZ/10); ++ k += HZ/10; ++ } ++ ++ if (pha->cur_cmd) { ++ printk("%s: Driver won't give up for reset\n",pha->device); ++ return FAILED; ++ } ++ ++ ppsc_reset_pha(pha); ++ ++ return SUCCESS; ++} ++ ++#define PROCIN(n,var) \ ++ if ((length>n+1)&&(strncmp(buffer,#var"=",n+1)==0)) { \ ++ pha->var = simple_strtoul(buffer+n+1,NULL,0); \ ++ return length; \ ++ } ++ ++#define PROCOUT(fmt,val) len+=sprintf(buffer+len,fmt"\n",val); ++ ++int ppsc_proc_info(struct Scsi_Host *p, char *buffer, char **start, off_t offset, ++ int length, int inout) ++{ ++ int len = 0; ++ PHA *pha; ++ ++ if (!p) return 0; /* should never happen */ ++ pha = (PHA *)p->hostdata[0]; ++ ++ if (inout) { ++ ++ PROCIN(4,mode); ++ PROCIN(5,delay); ++ PROCIN(7,verbose); ++ PROCIN(10,abort_flag); ++ PROCIN(4,nice); ++ ++ return (-EINVAL); ++ } ++ ++ PROCOUT("ident: %s",pha->ident); ++ PROCOUT("base port: 0x%03x",pha->port); ++ PROCOUT("mode: %d",pha->mode); ++ if (pha->proto->mode_names) ++ PROCOUT("mode name: %s",pha->proto->mode_names[pha->mode]); ++ PROCOUT("delay: %d",pha->delay); ++ PROCOUT("nice: %d",pha->nice); ++ PROCOUT("verbose: %d",pha->verbose); ++ PROCOUT("quiet: %d",pha->quiet); ++ PROCOUT("tot_cmds: %d",pha->tot_cmds); ++ PROCOUT("tot_bytes: %ld",pha->tot_bytes); ++ PROCOUT("tot_errs: %d",pha->tot_errs); ++ ++ if (pha->pardev) { ++ PROCOUT("parport device: %s",pha->parname); ++ PROCOUT("claimed: %d",pha->claimed); ++ } ++ if (V_DEBUG) { ++ PROCOUT("then: %ld",pha->then); ++ PROCOUT("timeout: %ld",pha->timeout); ++ PROCOUT("now: %ld",jiffies); ++ PROCOUT("timer active: %d",pha->timer_active); ++ PROCOUT("wq_active: %d",pha->wq_active); ++ PROCOUT("abort_flag: %d",pha->abort_flag); ++ PROCOUT("return_code: %08x",pha->return_code); ++ PROCOUT("last_phase: %o",pha->last_phase); ++ PROCOUT("cmd_count: %d",pha->cmd_count); ++ PROCOUT("data_count: %d",pha->data_count); ++ PROCOUT("data_dir: %d",pha->data_dir); ++ PROCOUT("bulk: %d",pha->bulk); ++ PROCOUT("tlen: %d",pha->tlen); ++ PROCOUT("overflow: %d",pha->overflow); ++ } ++ ++ if (offset > len) return 0; ++ ++ *start = buffer+offset; len -= offset; ++ if (len > length) len = length; ++ return len; ++} ++ ++int ppsc_biosparam (struct scsi_device * sdev, struct block_device *bdev, sector_t capacity, int ip[]) ++{ ++ ip[0] = 0x40; ++ ip[1] = 0x20; ++ ip[2] = (capacity +1) / (ip[0] * ip[1]); ++ if (ip[2] > 1024) { ++ ip[0] = 0xff; ++ ip[1] = 0x3f; ++ ip[2] = (capacity +1) / (ip[0] * ip[1]); ++ if (ip[2] > 1023) ++ ip[2] = 1023; ++ } ++ return 0; ++} ++ ++static int ppsc_inquire (PHA *pha, int target, char *buf) ++{ ++ char inq[6] = {0x12,0,0,0,36,0}; ++ int i; ++ struct scsi_cmnd cmd; ++ struct scsi_device dev; ++ ++ dev.host = pha->host_ptr; ++ dev.id = target; ++ cmd.device = &dev; ++ cmd.cmd_len = 6; ++ for (i=0;i<6;i++) cmd.cmnd[i] = inq[i]; ++ cmd.use_sg = 0; ++ cmd.request_buffer = buf; ++ cmd.request_bufflen = 36; ++ ++ return ppsc_command(&cmd); ++} ++ ++static void ppsc_test_mode (PHA *pha, int mode) ++{ ++ int i, t, s, e, f, g, ok, old_mode; ++ char ibuf[38]; ++ ++ if ((mode >= pha->proto->epp_first) && ++ !(pha->pardev->port->modes & PARPORT_MODE_EPP)) ++ return; ++ ++ old_mode = pha->mode; ++ pha->mode = mode; ++ ++ e = -1; f = -1; g = 0; ++ ++ if (pha->proto->test_proto) { ++ ppsc_claim(pha); ++ e = pha->proto->test_proto(pha); ++ ppsc_unclaim(pha); ++ } ++ ++ if (e <= 0) { ++ f = 0; ++ for (t=0;t<8;t++) { ++ s = ppsc_inquire(pha,t,ibuf); ++ if (s == DID_NO_CONNECT << 16) continue; ++ if (s) { ++ f++; ++ break; ++ } ++ if (V_FULL) { ++ for (i=0;i<36;i++) ++ if ((ibuf[i] < ' ') || (ibuf[i] >= '~')) ibuf[i] = '.'; ++ ibuf[36] = 0; ++ printk("%s: port 0x%x mode %d targ %d: %s\n", ++ pha->device,pha->port,mode,t,ibuf); ++ } ++ g++; ++ } ++ if (f) ppsc_reset_pha(pha); ++ } ++ ++ ok = (e<=0) && (f == 0); ++ ++ if (!ok) pha->mode = old_mode; ++ ++ if (V_PROBE) printk("%s: port 0x%3x mode %d test %s (%d,%d,%d)\n", ++ pha->device,pha->port,mode,ok?"passed":"failed",e,f,g); ++} ++ ++ ++int ppsc_release_pha (PHA *pha) ++{ ++ if (pha->proto->release) pha->proto->release(pha); ++ ++ ppsc_unregister_parport(pha); ++ ++ /* MOD_DEC_USE_COUNT; */ ++ ++ return 0; ++} ++ ++ ++int ppsc_detect (PSP *proto, Scsi_Host_Template *tpnt, int verbose) ++{ ++ int i, m, p, d, n, s, z; ++ struct ppsc_port_list_struct *next_port = NULL; /* shut gcc up */ ++ int user_specified = 1; ++ PHA *pha; ++ int host_count = 0; ++ struct Scsi_Host *hreg; ++ ++ m = 0; ++ for (i=0;i<4;i++) if ((*proto->params[i])[PPSC_PARM_PORT] != -1) m++; ++ ++ if (!m) { ++ /* Just take parports from the list as they come. */ ++ next_port = ppsc_port_list; ++ user_specified = 0; ++ } ++ ++ tpnt->this_id = PPSC_INITIATOR; ++ ++ for (i=0;i<4;i++) { ++ if (!user_specified) { ++ if (!next_port) ++ break; ++ ++ p = next_port->port->number; ++ next_port = next_port->next; ++ } ++ else { ++ p = (*proto->params[i])[PPSC_PARM_PORT]; ++ if (p < 0) ++ continue; ++ } ++ ++ m = (*proto->params[i])[PPSC_PARM_MODE]; ++ n = (*proto->params[i])[PPSC_PARM_NICE]; ++ if (n == -1) n = PPSC_DEF_NICE; ++ d = (*proto->params[i])[PPSC_PARM_DLY]; ++ if (d == -1) d = proto->default_delay; ++ s = (*proto->params[i])[PPSC_PARM_SGTS]; ++ if (s == -1) s = proto->default_sg_tablesize; ++ z = (*proto->params[i])[PPSC_PARM_SLOW]; ++ if (z == -1) z = 0; ++ ++ /* MOD_INC_USE_COUNT; */ ++ ++ pha = &(((*proto->hosts)[i])); ++ ++ pha->proto = proto; ++ ++ pha->port = p; ++ pha->delay = d; ++ pha->nice = n; ++ ++ d = sizeof(pha->device)-3; ++ p = strlen(tpnt->name); ++ if (p > d) p = d; ++ for (n=0;ndevice[n] = tpnt->name[n]; ++ pha->device[p] = '.'; ++ pha->device[p+1] = '0' + i; ++ pha->device[p+2] = 0; ++ ++ INIT_WORK(&pha->wq, ppsc_tq_int, pha); ++ ++ init_timer (&pha->timer); ++ pha->timer.data = (unsigned long) pha; ++ pha->timer.function = ppsc_timer_int; ++ ++ init_waitqueue_head (&pha->parq); ++ pha->pardev = NULL; ++ pha->claimed = 0; ++ pha->claim_cont = NULL; ++ pha->timer_active = 0; ++ pha->wq_active = 0; ++ pha->timedout = 0; ++ ++ pha->cur_cmd = NULL; ++ pha->done = NULL; ++ pha->abort_flag = 0; ++ pha->protocol_error = 0; ++ pha->tot_errs = 0; ++ pha->tot_cmds = 0; ++ pha->tot_bytes = 0; ++ ++ for (n=0;n<8;n++) pha->private[n] = 0; ++ ++ pha->slow_targets = z; ++ ++ if (ppsc_register_parport(pha,verbose)) { ++ /* MOD_DEC_USE_COUNT; */ ++ continue; ++ } ++ ++ pha->proto->init(pha); ++ ++ pha->verbose = verbose; ++ pha->quiet = 1; /* no errors until probe over */ ++ if (V_FULL) pha->quiet = 0; /* unless we want them ... */ ++ ++ pha->tmo = PPSC_PROBE_TMO; ++ ++ hreg = scsi_register(tpnt,sizeof(PHA*)); ++ hreg->dma_channel = -1; ++ hreg->n_io_port = 0; ++ hreg->unique_id = (int) pha; /* What should we put in here??? */ ++ hreg->sg_tablesize = s; ++ hreg->hostdata[0]=(unsigned long)pha; /* Will be our pointer */ ++ ++ pha->host_ptr = hreg; ++ ++ pha->mode = -1; ++ ++ if (m == -1) for (m=0;mnum_modes;m++) ++ ppsc_test_mode(pha,m); ++ else ppsc_test_mode(pha,m); ++ ++ if (pha->mode != -1) { ++ ++ pha->quiet = 0; /* enable PPSC_FAIL msgs */ ++ pha->tmo = PPSC_GEN_TMO; ++ host_count++; ++ ++ printk("%s: %s at 0x%3x mode %d (%s) dly %d nice %d sg %d\n", ++ pha->device, ++ pha->ident, ++ pha->port, ++ pha->mode, ++ (pha->proto->mode_names)? ++ pha->proto->mode_names[pha->mode]:"", ++ pha->delay, ++ pha->nice, ++ hreg->sg_tablesize); ++ ++ } else { ++ ++ scsi_unregister(hreg); ++ ppsc_release_pha(pha); ++ ++ } ++ } ++ return host_count; ++} ++ ++int ppsc_release (struct Scsi_Host *host) ++{ ++ PHA *pha = (PHA *) host->hostdata[0]; ++ ++ return ppsc_release_pha(pha); ++} ++ ++int ppsc_initialise (void) ++{ ++ int i; ++ ++ for (i=0;i<256;i++) ppsc_bulk_map[i] = 0; ++ ++/* commands marked in this map will use pseudo-DMA transfers, while ++ the rest will use the slow handshaking. ++*/ ++ ++ ppsc_bulk_map[READ_6] = 1; ++ ppsc_bulk_map[READ_10] = 1; ++ ppsc_bulk_map[READ_BUFFER] = 1; ++ ppsc_bulk_map[WRITE_6] = 1; ++ ppsc_bulk_map[WRITE_10] = 1; ++ ppsc_bulk_map[WRITE_BUFFER] = 1; ++ ++ if (parport_register_driver (&ppsc_driver)) { ++ printk (KERN_WARNING "ppscsi: couldn't register driver\n"); ++ return -EIO; ++ } ++ ++ printk("ppSCSI %s (%s) installed\n",PPSC_VERSION,PPSC_H_VERSION); ++ return 0; ++} ++ ++#ifdef MODULE ++ ++int init_module (void) ++{ ++ return ppsc_initialise(); ++} ++ ++void cleanup_module (void) ++{ ++ struct ppsc_port_list_struct *ports, *next; ++ parport_unregister_driver (&ppsc_driver); ++ for (ports = ppsc_port_list; ports; ports = next) { ++ next = ports->next; ++ parport_put_port (ports->port); ++ kfree (ports); ++ } ++} ++ ++MODULE_LICENSE("GPL"); ++ ++#endif ++ ++EXPORT_SYMBOL(ppsc_make_map); ++EXPORT_SYMBOL(ppsc_queuecommand); ++EXPORT_SYMBOL(ppsc_abort); ++EXPORT_SYMBOL(ppsc_reset); ++EXPORT_SYMBOL(ppsc_proc_info); ++EXPORT_SYMBOL(ppsc_biosparam); ++EXPORT_SYMBOL(ppsc_detect); ++EXPORT_SYMBOL(ppsc_release); ++ ++/* end of ppscsi.c */ +--- /dev/null ++++ b/drivers/scsi/ppscsi.h +@@ -0,0 +1,356 @@ ++#ifndef _PPSC_H ++#define _PPSC_H ++ ++/* ++ ppscsi.h (c) 1999 Grant Guenther ++ Under the terms of the GNU public license. ++ ++ This header file defines a common interface for constructing ++ low-level SCSI drivers for parallel port SCSI adapters. ++ ++*/ ++ ++#define PPSC_H_VERSION "0.92" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "scsi.h" ++#include "hosts.h" ++ ++ ++/* ppscsi global functions */ ++ ++extern void ppsc_make_map( char map[256], char key[5], int inv); ++ ++extern int ppsc_proc_info(struct Scsi_Host *, char *,char **,off_t,int,int); ++extern int ppsc_command(struct scsi_cmnd *); ++extern int ppsc_queuecommand(struct scsi_cmnd *, void (* done)(struct scsi_cmnd *)); ++extern int ppsc_abort(struct scsi_cmnd *); ++extern int ppsc_reset(struct scsi_cmnd *); ++extern int ppsc_biosparam(struct scsi_device *, struct block_device *, sector_t capacity, int[]); ++extern int ppsc_release(struct Scsi_Host *); ++ ++#ifndef PPSC_BASE ++ ++/* imports for hosts.c */ ++ ++#ifdef CONFIG_PPSCSI_T348 ++extern int t348_detect( Scsi_Host_Template *); ++#endif ++ ++#ifdef CONFIG_PPSCSI_T358 ++extern int t358_detect( Scsi_Host_Template *); ++#endif ++ ++#ifdef CONFIG_PPSCSI_ONSCSI ++extern int onscsi_detect( Scsi_Host_Template *); ++#endif ++ ++#ifdef CONFIG_PPSCSI_EPST ++extern int epst_detect( Scsi_Host_Template *); ++#endif ++ ++#ifdef CONFIG_PPSCSI_EPSA2 ++extern int epsa2_detect( Scsi_Host_Template *); ++#endif ++ ++#ifdef CONFIG_PPSCSI_VPI0 ++extern int vpi0_detect( Scsi_Host_Template *); ++#endif ++ ++#ifdef CONFIG_PPSCSI_SPARCSI ++extern int sparcsi_detect( Scsi_Host_Template *); ++#endif ++ ++#endif ++ ++#define PPSC_TEMPLATE(proto){ \ ++ .name = #proto, \ ++ .detect = proto##_detect, \ ++ .release = ppsc_release, \ ++ .proc_name = #proto, \ ++ .proc_info = ppsc_proc_info, \ ++ .queuecommand = ppsc_queuecommand, \ ++ .eh_abort_handler = ppsc_abort, \ ++ .eh_bus_reset_handler = ppsc_reset, \ ++ .eh_host_reset_handler = ppsc_reset, \ ++ .bios_param = ppsc_biosparam, \ ++ .can_queue = 1, \ ++ .sg_tablesize = SG_NONE, \ ++ .cmd_per_lun = 1, \ ++ .use_clustering = DISABLE_CLUSTERING \ ++} ++ ++/* types used by the actual driver modules */ ++ ++#ifdef PPSC_BASE ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++struct setup_tab_t { ++ ++ char *tag; /* variable name */ ++ int size; /* number of elements in array */ ++ int *iv; /* pointer to variable */ ++}; ++ ++typedef struct setup_tab_t STT; ++ ++extern void ppsc_gen_setup( STT t[], int n, char *ss ); ++ ++typedef struct ppsc_host_adapter PHA; ++ ++struct ppsc_host_adapter { ++ ++ char ident[80]; /* Adapter name and version info */ ++ ++ char device[12]; /* device name for messages */ ++ ++ struct Scsi_Host *host_ptr; /* SCSI host structure */ ++ struct ppsc_protocol *proto; /* adapter protocol */ ++ ++ int port; /* parallel port base address */ ++ int mode; /* transfer mode in use */ ++ int delay; /* parallel port settling delay */ ++ int saved_r0; /* saved port state */ ++ int saved_r2; /* saved port state */ ++ ++ int reserved; /* number of ports reserved */ ++ int tmo; /* default command timeout */ ++ int verbose; /* logging level */ ++ int quiet; /* do not log PPSC_FAIL msgs */ ++ ++ int slow_targets; /* bit mask for disabling block mode */ ++ ++ wait_queue_head_t parq; /* semaphore for parport sharing */ ++ struct pardevice *pardev; /* pointer to pardevice */ ++ const char *parname; /* parport name */ ++ int claimed; /* parport has been claimed */ ++ void (*claim_cont)(PHA *); /* continuation for parport wait */ ++ ++ void (*continuation)(PHA *); /* next "interrupt" handler */ ++ int (*ready)(PHA *); /* current ready test */ ++ unsigned long then; /* jiffies at start of last wait */ ++ unsigned long timeout; /* when to timeout this wait */ ++ int timedout; /* timeout was seen */ ++ int timer_active; /* we're using a timer */ ++ int wq_active; /* we have a task queued */ ++ int nice; /* tune the CPU load */ ++ struct timer_list timer; /* timer queue element */ ++ struct work_struct wq; /* task queue element */ ++ ++ int private[8]; /* for the protocol layer, if needed */ ++ char *priv_ptr; ++ int priv_flag; ++ ++ struct scsi_cmnd *cur_cmd; /* current command on this host */ ++ void (*done)(struct scsi_cmnd *); /* current "done" function */ ++ ++ int overflow; /* excess bytes transferred */ ++ int bulk; /* should we use block mode ? */ ++ int tlen; /* total transfer length */ ++ int abort_flag; /* abort=1 reset=2 requested */ ++ int return_code; /* build return value here */ ++ ++ struct scatterlist *sg_list; /* current fragment, if any */ ++ int sg_count; /* remaining fragments */ ++ char *cur_buf; /* current buffer pointer */ ++ int cur_len; /* remaining bytes in buffer */ ++ ++ struct timer_list sleeper; /* for BUSY handling */ ++ ++ int last_phase; /* to detect phase changes */ ++ char message_byte; ++ char status_byte; ++ ++ int cmd_count; /* bytes of command transfered */ ++ int data_count; /* bytes of data transferred */ ++ int data_dir; /* direction of transfer */ ++ ++ int tot_cmds; /* number of commands processed */ ++ long tot_bytes; /* total bytes transferred */ ++ int tot_errs; /* number of failed commands */ ++ ++ int protocol_error; /* Some protocols can set this ++ != zero to signal a fatal error ++ we report it and expect to die ++ */ ++}; ++ ++/* constants for 'verbose' */ ++ ++#define PPSC_VERB_NORMAL 0 ++#define PPSC_VERB_PROBE 1 ++#define PPSC_VERB_TRACE 2 ++#define PPSC_VERB_DEBUG 3 ++#define PPSC_VERB_FULL 4 ++ ++#define V_PROBE (pha->verbose >= PPSC_VERB_PROBE) ++#define V_TRACE (pha->verbose >= PPSC_VERB_TRACE) ++#define V_DEBUG (pha->verbose >= PPSC_VERB_DEBUG) ++#define V_FULL (pha->verbose >= PPSC_VERB_FULL) ++ ++/* constants for abort_flag */ ++ ++#define PPSC_DO_ABORT 1 ++#define PPSC_DO_RESET 2 ++ ++ ++struct ppsc_protocol { ++ ++ int (*params[4])[8]; /* hostN tuning parameters */ ++ ++ PHA (*hosts)[4]; /* actual PHA structs */ ++ ++ int num_modes; /* number of modes*/ ++ int epp_first; /* modes >= this use 8 ports */ ++ int default_delay; /* delay parameter if not specified */ ++ ++ int can_message; /* adapter can send/rcv SCSI msgs */ ++ int default_sg_tablesize; /* sg_tablesize if not specified */ ++ ++ char **mode_names; /* printable names of comm. modes */ ++ ++/* first two functions are NOT called with the port claimed. */ ++ ++ void (*init)(PHA *); /* (pha) ++ protocol initialisation ++ should fill in pha->ident */ ++ void (*release)(PHA *); /* (pha) optional ++ protocol no longer in use */ ++ void (*connect)(PHA *); /* (pha) ++ connect to adapter */ ++ void (*disconnect)(PHA *); /* (pha) ++ release adapter */ ++ int (*test_proto)(PHA *); /* (pha) optional ++ test protocol in current settings, ++ returns error count */ ++ int (*select)(PHA *,int,int); /* (pha,initiator,target) ++ start artibration and selection ++ 0 = OK, -1 = arb. failed */ ++ int (*test_select)(PHA *); /* (pha) ++ test for selection to complete ++ 1 = OK, 0 try again */ ++ void (*select_finish)(PHA *); /* (pha) optional ++ called after successful select */ ++ void (*deselect)(PHA *); /* (pha) ++ release SCSI bus */ ++ int (*get_bus_status)(PHA *); /* (pha) ++ return (REQ,BSY,MSG,C/D,I/O) */ ++ void (*slow_start)(PHA *,char *); /* (pha,byte) ++ start transfer of one byte using ++ explicit handshaking */ ++ int (*slow_done)(PHA *); /* (pha) ++ has the device acked the byte ? */ ++ void (*slow_end)(PHA *); /* (pha) ++ shut down the slow transfer */ ++ void (*start_block)(PHA *,int); /* (pha,read) ++ start data transfer */ ++ int (*transfer_block)(PHA *,char *,int,int); ++ /* (pha,buf,len,read) ++ transfer as much as possible and ++ return count of bytes ++ can return -1 if error detected */ ++ int (*transfer_ready)(PHA *pha);/* (pha) ++ can we go again yet ? ++ >0 = yes, 0 = try again, -1 = done */ ++ int (*transfer_done)(PHA *pha); /* (pha) ++ has all data been flushed ? ++ 1 = yes, 0 = try again */ ++ void (*end_block)(PHA *,int); /* (pha,read) ++ shut down block transfer */ ++ void (*reset_bus)(PHA *); /* (pha) optional ++ reset SCSI bus if possible */ ++ ++}; ++ ++/* constants for the params array */ ++ ++#define PPSC_PARM_PORT 0 ++#define PPSC_PARM_MODE 1 ++#define PPSC_PARM_DLY 2 ++#define PPSC_PARM_NICE 3 ++#define PPSC_PARM_SGTS 4 ++#define PPSC_PARM_SLOW 5 ++ ++/* constants for get_bus_status */ ++ ++#define PPSC_REQ 16 ++#define PPSC_BSY 8 ++#define PPSC_MSG 4 ++#define PPSC_CD 2 ++#define PPSC_IO 1 ++ ++/* phases */ ++ ++#define PPSC_PH_NONE 0 ++#define PPSC_PH_WRITE (PPSC_REQ|PPSC_BSY) ++#define PPSC_PH_READ (PPSC_PH_WRITE|PPSC_IO) ++#define PPSC_PH_CMD (PPSC_PH_WRITE|PPSC_CD) ++#define PPSC_PH_STAT (PPSC_PH_READ|PPSC_CD) ++#define PPSC_PH_MSGIN (PPSC_PH_STAT|PPSC_MSG) ++ ++typedef struct ppsc_protocol PSP; ++ ++extern int ppsc_detect( PSP *, Scsi_Host_Template *, int); ++ ++#ifdef PPSC_HA_MODULE ++ ++static int verbose = PPSC_VERB_NORMAL; ++ ++static int host0[8] = {-1,-1,-1,-1,-1,-1,-1,-1}; ++static int host1[8] = {-1,-1,-1,-1,-1,-1,-1,-1}; ++static int host2[8] = {-1,-1,-1,-1,-1,-1,-1,-1}; ++static int host3[8] = {-1,-1,-1,-1,-1,-1,-1,-1}; ++ ++#ifndef MODULE ++ ++static STT stt[4] = { {"host0",8,host0}, ++ {"host1",8,host1}, ++ {"host2",8,host2}, ++ {"host3",8,host3} }; ++#endif ++ ++MODULE_PARM(host0,"1-8i"); ++MODULE_PARM(host1,"1-8i"); ++MODULE_PARM(host2,"1-8i"); ++MODULE_PARM(host3,"1-8i"); ++MODULE_PARM(verbose,"i"); ++ ++static struct ppsc_host_adapter host_structs[4]; ++ ++#define delay_p (pha->delay?udelay(pha->delay):0) ++#define out_p(offs,byte) outb(byte,pha->port+offs); delay_p; ++#define in_p(offs) (delay_p,inb(pha->port+offs)) ++ ++#define w0(byte) do {out_p(0,byte);} while (0) ++#define r0() (in_p(0) & 0xff) ++#define w1(byte) do {out_p(1,byte);} while (0) ++#define r1() (in_p(1) & 0xff) ++#define w2(byte) do {out_p(2,byte);} while (0) ++#define r2() (in_p(2) & 0xff) ++#define w3(byte) do {out_p(3,byte);} while (0) ++#define w4(byte) do {out_p(4,byte);} while (0) ++#define r4() (in_p(4) & 0xff) ++#define w4w(data) do {outw(data,pha->port+4); delay_p;} while (0) ++#define w4l(data) do {outl(data,pha->port+4); delay_p;} while (0) ++#define r4w() (delay_p,inw(pha->port+4)&0xffff) ++#define r4l() (delay_p,inl(pha->port+4)&0xffffffff) ++ ++#endif /* PPSC_HA_MODULE */ ++#endif /* PPSC_BASE */ ++#endif /* _PPSC_H */ ++ ++/* end of ppscsi.h */ ++ +--- /dev/null ++++ b/drivers/scsi/onscsi.c +@@ -0,0 +1,544 @@ ++/* ++ onscsi.c (c) 1999 Grant Guenther ++ ++ This is the ppSCSI protocol module for the OnSpec 90c26 ++ in its SCSI adapter mode. ++*/ ++ ++#define ONSCSI_VERSION "0.91" ++ ++#define PPSC_BASE ++#define PPSC_HA_MODULE ++ ++#include "ppscsi.h" ++ ++#define ONSCSI_REP_COUNT 256 ++ ++#define TOGL pha->private[0] ++ ++static char onscsi_map[256]; /* status bits permutation */ ++ ++static void onscsi_init (PHA *pha) ++{ ++ ++/* { REQ, BSY, MSG, CD, IO} */ ++ ++ char key[5] = {0x10,0x01,0x20,0x40,0x80}; ++ ++ ppsc_make_map(onscsi_map,key,0); ++ sprintf(pha->ident,"onscsi %s (%s), OnSpec 90c26", ++ ONSCSI_VERSION,PPSC_H_VERSION); ++} ++ ++#define j44(a,b) ((b&0xf0)|((a>>4)&0x0f)) ++ ++#define CMD(x) w0(x);w2(5);w2(0xd);w2(5);w2(0xd);w2(5);w2(4); ++#define VAL(v) w0(v);w2(5);w2(7);w2(5);w2(4); ++ ++static inline void onscsi_opcode (PHA *pha, int x ) ++{ ++ if (pha->mode < 2) { ++ CMD(x); ++ } else { ++ w3(x); ++ } ++} ++ ++#define OP(x) onscsi_opcode(pha,x) ++#define FULLBYTE (pha->mode > 0) ++ ++static void onscsi_write_regr (PHA *pha, int r, int v) ++{ ++ onscsi_opcode(pha,r); ++ ++ if (pha->mode < 2) { ++ VAL(v); ++ } else { ++ w2(5); w4(v); w2(4); ++ } ++} ++ ++static inline int onscsi_read_nybble (PHA *pha) ++{ ++ int a, b; ++ ++ w2(6); a = r1(); w2(4); ++ w2(6); b = r1(); w2(4); ++ ++ return j44(a,b); ++} ++ ++static int onscsi_read_regr (PHA *pha, int r) ++{ ++ int v = -1; ++ ++ onscsi_opcode(pha,r); ++ ++ switch (pha->mode) { ++ ++ case 0: v = onscsi_read_nybble(pha); ++ break; ++ ++ case 1: w2(0x26); v = r0(); w2(4); ++ break; ++ ++ case 2: ++ case 3: ++ case 4: w2(0x24); v = r4(); w2(4); ++ break; ++ ++ } ++ ++ return v; ++} ++ ++#define RR(r) onscsi_read_regr(pha,r) ++#define WR(r,v) onscsi_write_regr(pha,r,v) ++ ++static void onscsi_write_block (PHA *pha, char *buf, int n) ++{ ++ int i; ++ ++ w2(5+TOGL); ++ ++ switch (pha->mode) { ++ ++ case 0: ++ case 1: for (i=0;imode) { ++ ++ case 0: w2(4); ++ for (i=0;isaved_r0 = r0(); ++ pha->saved_r2 = r2(); ++ ++ CPP(0x20,4); ++ ++ CMD(2); VAL(0); ++ CMD(2); VAL(FULLBYTE); ++ ++ WR(2,FULLBYTE); ++} ++ ++static void onscsi_disconnect (PHA *pha) ++{ ++ WR(3,0); WR(7,0x48); ++ OP(4); ++ CPP(0x30,pha->saved_r2); ++ ++ w0(pha->saved_r0); ++ w2(pha->saved_r2); ++} ++ ++static int onscsi_test_proto (PHA *pha) ++{ ++ int i, k, j; ++ char wbuf[16], rbuf[16]; ++ int e = 0; ++ ++ pha->saved_r0 = r0(); ++ pha->saved_r2 = r2(); ++ ++ CPP(0x30,pha->saved_r2); ++ CPP(0x0,pha->saved_r2); ++ ++ w0(0xfe);w0(0xaa);w0(0x55);w0(0);w0(0xff); ++ i = ((r1() & 0xf0) << 4); w0(0x87); ++ i |= (r1() & 0xf0); w0(0x78); ++ w0(0x20);w2(5); ++ i |= ((r1() & 0xf0) >> 4); ++ w2(4);w0(0xff); ++ ++ if (V_PROBE) printk("%s: signature 0x%x\n",pha->device,i); ++ ++ if (i == 0xb5f) { ++ ++ CMD(2); VAL(FULLBYTE); ++ ++ w2(4); w2(0xc); udelay(100); w2(4); udelay(100); ++ ++ CMD(2); VAL(0); ++ CMD(2); VAL(FULLBYTE); ++ ++ WR(2,FULLBYTE); ++ ++ k = RR(4); ++ ++ if (V_PROBE) ++ printk("%s: OnSpec 90c26 version %x\n",pha->device,k); ++ } ++ ++ CPP(0x30,pha->saved_r2); ++ ++ w0(pha->saved_r0); ++ w2(pha->saved_r2); ++ ++ if (i != 0xb5f) return 1; ++ ++ onscsi_connect(pha); ++ ++ for (k=0;kmode == 0) WR(2,0x30); ++ if (pha->mode == 1) WR(2,0x10); ++ ++ WR(3,0); WR(7,0x48); ++ ++ WR(3,1); WR(7,0x48); OP(5); ++ TOGL = 0; ++ onscsi_write_block(pha,wbuf,16); ++ w2(4); ++ ++ if (pha->mode == 0) WR(2,0); ++ if (pha->mode == 1) WR(2,0x11); ++ ++ WR(3,5); WR(7,0x48); OP(5); ++ TOGL = 0; ++ onscsi_read_block(pha,rbuf,16); ++ w2(4); ++ ++ for (j=0;j<16;j++) ++ if (rbuf[j] != wbuf[j]) e++; ++ ++ } ++ ++ onscsi_disconnect(pha); ++ ++#ifdef EXPERIMENT ++ ++ /* enable this to see how the buffer status bits work */ ++ ++ if (pha->mode == 2) { ++ ++ onscsi_connect(pha); ++ ++ WR(3,0); WR(7,0x48); ++ WR(3,1); WR(7,0x48); OP(5); ++ w2(5); ++ ++ for (k=0;k<16;k++) { ++ j = r1(); w4(k); ++ printk("%2x:%d ",j,k); ++ } ++ printk("\n"); ++ ++ w2(4); WR(3,5); WR(7,0x48); OP(5); ++ w2(0x24); ++ ++ for (k=0;k<16;k++) { ++ j = r1(); ++ printk("%2x:%d ",j,r4()); ++ } ++ printk("\n"); ++ ++ w2(4); ++ ++ onscsi_disconnect(pha); ++ } ++ ++ if (pha->mode == 1) { ++ ++ onscsi_connect(pha); ++ ++ WR(2,0x11); ++ WR(3,0); WR(7,0x48); ++ WR(3,1); WR(7,0x48); OP(5); ++ w2(5); i = 0; ++ ++ for (k=0;k<16;k++) { ++ j = r1(); w0(k); i = 2 - i; w2(5+i); ++ printk("%2x:%d ",j,k); ++ } ++ printk("%2x.\n",r1()); ++ ++ w2(4); ++ ++ WR(2,0x11); ++ WR(3,0); WR(7,0x48); ++ WR(3,5); WR(7,0x48); OP(5); ++ w2(0x24); i = 0; ++ ++ printk("%2x ",r1()); ++ for (k=0;k<16;k++) { ++ i = 2 - i; w2(0x24+i); j = r1(); ++ printk("%2x:%d ",j,r0()); ++ } ++ printk("\n"); ++ ++ w2(4); ++ ++ onscsi_disconnect(pha); ++ } ++ ++#endif ++ ++ if (V_FULL) ++ printk("%s: test port 0x%x mode %d errors %d\n", ++ pha->device,pha->port,pha->mode,e); ++ ++ return e; ++} ++ ++static int onscsi_select (PHA *pha, int initiator, int target) ++{ ++ WR(1,0); ++ WR(2,0x80+FULLBYTE); ++ if (RR(1) != 0) return -1; ++ WR(0,((1 << initiator) | (1 << target))); ++ WR(1,2); ++ return 0; ++} ++ ++static int onscsi_test_select (PHA *pha) ++{ ++ return ((RR(1) & 3) == 3); ++} ++ ++static void onscsi_select_finish (PHA *pha) ++{ ++ WR(1,0); ++} ++ ++static void onscsi_deselect (PHA *pha) ++{ ++ WR(1,0); ++ /* WR(2,0x20+FULLBYTE); */ ++ WR(2,FULLBYTE); ++ WR(3,0); WR(7,0x48); ++} ++ ++static int onscsi_get_bus_status (PHA *pha) ++{ ++ WR(2,0x20+FULLBYTE); ++ return onscsi_map[RR(1)]; ++} ++ ++static void onscsi_slow_start (PHA *pha, char *val) ++{ ++ pha->priv_flag = (RR(1) & 0x80); ++ pha->priv_ptr = val; ++ ++ if (pha->priv_flag) WR(2,0x20); else WR(2,0x21); ++ ++ OP(0); ++ ++ if (pha->priv_flag) { ++ w2(6); ++ } else { ++ w0(*val); w2(5); w2(7); ++ } ++} ++ ++static int onscsi_slow_done (PHA *pha) ++{ ++ return (!(r1() & 8)); ++} ++ ++static void onscsi_slow_end (PHA *pha) ++{ ++ if (pha->priv_flag) { ++ *pha->priv_ptr = onscsi_read_nybble(pha); ++ } else { ++ w2(5); w2(4); ++ } ++} ++ ++static void onscsi_start_block (PHA *pha, int rd) ++{ ++ pha->priv_flag = rd; ++ ++ if (rd) { ++ WR(3,5); WR(7,0x48); ++ if (pha->mode == 1) WR(2,0x31); ++ OP(5); ++ w2(5); w0(0xff); w2(4); ++ } else { ++ WR(3,1); WR(7,0x48); ++ if (pha->mode == 1) WR(2,0x31); ++ OP(5); ++ } ++ TOGL = 0; ++} ++ ++static int onscsi_transfer_done (PHA *pha) ++{ ++ int x; ++ ++ if (pha->priv_flag) return 1; ++ ++ if (pha->mode == 0) { WR(2,0x20); OP(5); } ++ x = r1(); x = r1(); ++ if (pha->mode == 0) { WR(2,0x30); OP(5); } ++ ++ if ((x & 0xf0) == 0x80) return 16; ++ return 0; ++} ++ ++static int onscsi_transfer_ready (PHA *pha) ++{ ++ int x; ++ ++ if (pha->priv_flag) { ++ x = r1(); x = r1(); ++ if ((x & 0xf0) == 0xf0) return 16; ++ if ((x & 0xf0) == 0xb0) return 8; ++ if ((x & 0xf0) == 0x90) return 1; ++ if ((x & 0xf8) == 0x88) return -1; ++ if ((x & 0xf8) == 0x08) return -1; ++ if ((x & 0xf8) == 0x0) return 1; ++ ++ if ((x & 0xf8) != 0x80) printk("DEBUG: %x\n",x); ++ ++ return 0; ++ } ++ ++ return onscsi_transfer_done(pha); ++} ++ ++ ++static int onscsi_transfer_block (PHA *pha, char * buf, int buflen, int rd) ++{ ++ int k, b; ++ ++ k = 0; ++ while ( k < buflen) { ++ ++ if ((b=onscsi_transfer_ready(pha)) <= 0) break; ++ if (b > (buflen-k)) b = buflen-k; ++ ++ if (rd) onscsi_read_block(pha,buf,b); ++ else onscsi_write_block(pha,buf,b); ++ ++ k += b; buf += b; ++ } ++ ++ return k; ++} ++ ++static void onscsi_end_block (PHA *pha, int rd) ++{ ++ w2(4); WR(3,0); WR(7,0x48); ++} ++ ++static void onscsi_reset_bus (PHA *pha) ++{ ++ WR(2,2); ++ udelay(500); ++ WR(2,0); ++ WR(2,FULLBYTE); ++} ++ ++static char *(mode_strings[5]) = {"Nybble","PS/2","EPP","EPP-16","EPP-32"}; ++ ++static struct ppsc_protocol onscsi_psp = { ++ ++ {&host0,&host1,&host2,&host3}, /* params */ ++ &host_structs, /* hosts */ ++ 5, /* num_modes */ ++ 2, /* epp_first */ ++ 1, /* default_delay */ ++ 1, /* can_message */ ++ 16, /* sg_tablesize */ ++ mode_strings, ++ onscsi_init, ++ NULL, /* release */ ++ onscsi_connect, ++ onscsi_disconnect, ++ onscsi_test_proto, ++ onscsi_select, ++ onscsi_test_select, ++ onscsi_select_finish, ++ onscsi_deselect, ++ onscsi_get_bus_status, ++ onscsi_slow_start, ++ onscsi_slow_done, ++ onscsi_slow_end, ++ onscsi_start_block, ++ onscsi_transfer_block, ++ onscsi_transfer_ready, ++ onscsi_transfer_done, ++ onscsi_end_block, ++ onscsi_reset_bus ++}; ++ ++int onscsi_detect (struct scsi_host_template *tpnt ) ++{ ++ return ppsc_detect( &onscsi_psp, tpnt, verbose); ++} ++ ++#ifdef MODULE ++ ++struct scsi_host_template driver_template = PPSC_TEMPLATE(onscsi); ++ ++#include "scsi_module.c" ++ ++MODULE_LICENSE("GPL"); ++ ++#else ++ ++void onscsi_setup (char *str, int *ints) ++{ ++ ppsc_gen_setup(stt,4,str); ++} ++ ++#endif ++ ++/* end of onscsi.c */ +--- linux-2.6.31-rc3-git5.mnb1/drivers/scsi/Kconfig.scsi-ppscsi-2.6.2.orig 2009-07-22 01:11:12.000000000 +0300 ++++ linux-2.6.31-rc3-git5.mnb1/drivers/scsi/Kconfig 2009-07-22 21:54:04.000000000 +0300 +@@ -1062,6 +1062,42 @@ config SCSI_IZIP_SLOW_CTR + + Generally, saying N is fine. + ++config PPSCSI ++ tristate "Parallel Port SCSI adapters" ++ depends on SCSI && PARPORT ++ ++config PPSCSI_T348 ++ tristate "Adaptec APA-348 adapter" ++ depends on PPSCSI ++ ++config PPSCSI_T358 ++ tristate "Adaptec APA-358 adapter" ++ depends on PPSCSI ++ ++config PPSCSI_VPI0 ++ tristate "Iomega VPI0 adapter" ++ depends on PPSCSI ++ ++config PPSCSI_VPI2 ++ tristate "Iomega VPI2 adapter (EXPERIMENTAL)" ++ depends on PPSCSI && EXPERIMENTAL ++ ++config PPSCSI_ONSCSI ++ tristate "OnSpec 90c26 adapter" ++ depends on PPSCSI ++ ++config PPSCSI_SPARCSI ++ tristate "Shining SparSCI adapter" ++ depends on PPSCSI ++ ++config PPSCSI_EPSA2 ++ tristate "Shuttle EPSA-2 adapter" ++ depends on PPSCSI ++ ++config PPSCSI_EPST ++ tristate "Shuttle EPST adapter" ++ depends on PPSCSI ++ + config SCSI_NCR53C406A + tristate "NCR53c406a SCSI support" + depends on ISA && SCSI diff --git a/kernel/tools/perf/files/patches/mageia/scsi-ppscsi-3.0-buildfix.patch b/kernel/tools/perf/files/patches/mageia/scsi-ppscsi-3.0-buildfix.patch new file mode 100644 index 0000000000..c0be53e272 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/scsi-ppscsi-3.0-buildfix.patch @@ -0,0 +1,19 @@ + +fix build with 3.0 + +Signed-off-by: Thomas Backlund + + drivers/scsi/ppscsi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/scsi/ppscsi.c.orig 2011-07-15 02:37:27.000000000 +0300 ++++ a/drivers/scsi/ppscsi.c 2011-07-15 13:44:29.514928985 +0300 +@@ -72,7 +72,7 @@ + #define PPSC_DEF_NICE 0 + #define PPSC_INITIATOR 7 + +-spinlock_t ppsc_spinlock = SPIN_LOCK_UNLOCKED; ++DEFINE_SPINLOCK(ppsc_spinlock); + + static char ppsc_bulk_map[256]; + diff --git a/kernel/tools/perf/files/patches/mageia/scsi-ppscsi-mdvbz45393.patch b/kernel/tools/perf/files/patches/mageia/scsi-ppscsi-mdvbz45393.patch new file mode 100644 index 0000000000..2e919ea621 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/scsi-ppscsi-mdvbz45393.patch @@ -0,0 +1,31 @@ +Fix for https://qa.mandriva.com/show_bug.cgi?id=45393 + +cmnd field of struct scsi_cmnd changed after commit "[SCSI] Let +scsi_cmnd->cmnd use request->cmd buffer" +(64a87b244b9297667ca80264aab849a36f494884) + +Signed-off-by: Herton Ronaldo Krzesinski + +--- + drivers/scsi/ppscsi.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/scsi/ppscsi.c ++++ b/drivers/scsi/ppscsi.c +@@ -1009,7 +1009,6 @@ int ppsc_biosparam (struct scsi_device * + static int ppsc_inquire (PHA *pha, int target, char *buf) + { + char inq[6] = {0x12,0,0,0,36,0}; +- int i; + struct scsi_cmnd cmd; + struct scsi_device dev; + +@@ -1017,7 +1016,7 @@ static int ppsc_inquire (PHA *pha, int t + dev.id = target; + cmd.device = &dev; + cmd.cmd_len = 6; +- for (i=0;i<6;i++) cmd.cmnd[i] = inq[i]; ++ cmd.cmnd = inq; + cmd.sdb.table.nents = 0; + cmd.sdb.table.sgl = (void *) buf; + cmd.sdb.length = 36; diff --git a/kernel/tools/perf/files/patches/mageia/scsi-ppscsi-sg-helper-update.patch b/kernel/tools/perf/files/patches/mageia/scsi-ppscsi-sg-helper-update.patch new file mode 100644 index 0000000000..defdcefebe --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/scsi-ppscsi-sg-helper-update.patch @@ -0,0 +1,36 @@ +Update ppscsi for 2.6.24 changes. + +Signed-off-by: Herton Ronaldo Krzesinski + +--- + drivers/scsi/ppscsi.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/scsi/ppscsi.c ++++ b/drivers/scsi/ppscsi.c +@@ -58,6 +58,7 @@ + #include + #include + #include ++#include + + #include + +@@ -484,7 +485,7 @@ static void ppsc_update_sg (PHA *pha) + if ((!pha->cur_len) && pha->sg_count) { + pha->sg_count--; + pha->sg_list++; +- pha->cur_buf = page_address(pha->sg_list->page) + pha->sg_list->offset; ++ pha->cur_buf = sg_virt(pha->sg_list); + pha->cur_len = pha->sg_list->length; + } + } +@@ -571,7 +572,7 @@ static void ppsc_engine (PHA *pha) + pha->sg_count--; + pha->sg_list = + (struct scatterlist *)pha->cur_cmd->request_buffer; +- pha->cur_buf = page_address(pha->sg_list->page) + pha->sg_list->offset; ++ pha->cur_buf = sg_virt(pha->sg_list); + pha->cur_len = pha->sg_list->length; + } else { + pha->cur_buf = pha->cur_cmd->request_buffer; diff --git a/kernel/tools/perf/files/patches/mageia/scsi-ppscsi-update-for-scsi_data_buffer.patch b/kernel/tools/perf/files/patches/mageia/scsi-ppscsi-update-for-scsi_data_buffer.patch new file mode 100644 index 0000000000..496326e311 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/scsi-ppscsi-update-for-scsi_data_buffer.patch @@ -0,0 +1,88 @@ +Update ppscsi for "[SCSI] implement scsi_data_buffer" change on Linux 2.6.25 +(commit 30b0c37b27485a9cb897bfe3824f6f517b8c80d6) + +Signed-off-by: Herton Ronaldo Krzesinski + +--- + drivers/scsi/ppscsi.c | 30 +++++++++++++++--------------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +--- a/drivers/scsi/ppscsi.c ++++ b/drivers/scsi/ppscsi.c +@@ -424,16 +424,16 @@ static void ppsc_start (PHA *pha) + + bf &= (!((1<cur_cmd->device->id) & pha->slow_targets)); + +- r = pha->cur_cmd->use_sg; ++ r = scsi_sg_count(pha->cur_cmd); + if (r) { + b = 0; +- p = (struct scatterlist *)pha->cur_cmd->request_buffer; ++ p = scsi_sglist(pha->cur_cmd); + for (k=0;klength; + p++; + } + } else { +- b = pha->cur_cmd->request_bufflen; ++ b = scsi_bufflen(pha->cur_cmd); + } + + bf &= (b > 127); +@@ -567,16 +567,16 @@ static void ppsc_engine (PHA *pha) + pha->data_dir = phase & PPSC_IO; + pha->data_count = 0; + +- pha->sg_count = pha->cur_cmd->use_sg; ++ pha->sg_count = scsi_sg_count(pha->cur_cmd); + if (pha->sg_count) { + pha->sg_count--; +- pha->sg_list = +- (struct scatterlist *)pha->cur_cmd->request_buffer; ++ pha->sg_list = scsi_sglist(pha->cur_cmd); + pha->cur_buf = sg_virt(pha->sg_list); + pha->cur_len = pha->sg_list->length; + } else { +- pha->cur_buf = pha->cur_cmd->request_buffer; +- pha->cur_len = pha->cur_cmd->request_bufflen; ++ pha->cur_buf = ++ (char *)pha->cur_cmd->sdb.table.sgl; ++ pha->cur_len = scsi_bufflen(pha->cur_cmd); + } + + pha->last_phase = phase; +@@ -622,7 +622,7 @@ static void ppsc_engine (PHA *pha) + + if (pha->cur_cmd->cmnd[0] == REQUEST_SENSE) { + +- sb = (char *)pha->cur_cmd->request_buffer; ++ sb = (char *)pha->cur_cmd->sdb.table.sgl; + printk("%s: Sense key: %x ASC: %x ASCQ: %x\n", + pha->device, sb[2] & 0xff, + sb[12] & 0xff, sb[13] & 0xff); +@@ -819,9 +819,9 @@ static void ppsc_cleanup (PHA *pha) + cmd->cmnd[4] = sizeof(cmd->sense_buffer); + cmd->cmnd[5] = 0; + cmd->cmd_len = 6; +- cmd->use_sg = 0; +- cmd->request_buffer = (char *) cmd->sense_buffer; +- cmd->request_bufflen = sizeof(cmd->sense_buffer); ++ cmd->sdb.table.nents = 0; ++ cmd->sdb.table.sgl = (void *) cmd->sense_buffer; ++ cmd->sdb.length = sizeof(cmd->sense_buffer); + + pha->cur_cmd = cmd; + ppsc_do_claimed(pha,ppsc_start); +@@ -1018,9 +1018,9 @@ static int ppsc_inquire (PHA *pha, int t + cmd.device = &dev; + cmd.cmd_len = 6; + for (i=0;i<6;i++) cmd.cmnd[i] = inq[i]; +- cmd.use_sg = 0; +- cmd.request_buffer = buf; +- cmd.request_bufflen = 36; ++ cmd.sdb.table.nents = 0; ++ cmd.sdb.table.sgl = (void *) buf; ++ cmd.sdb.length = 36; + + return ppsc_command(&cmd); + } diff --git a/kernel/tools/perf/files/patches/mageia/scsi-ppscsi_fixes.patch b/kernel/tools/perf/files/patches/mageia/scsi-ppscsi_fixes.patch new file mode 100644 index 0000000000..acc011e989 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/scsi-ppscsi_fixes.patch @@ -0,0 +1,226 @@ +--- + drivers/scsi/Makefile | 2 +- + drivers/scsi/ppscsi.c | 22 ++++++++++++---------- + drivers/scsi/ppscsi.h | 34 ++++++++++++++++++---------------- + drivers/scsi/sparcsi.c | 6 +++--- + 4 files changed, 34 insertions(+), 30 deletions(-) + +--- a/drivers/scsi/ppscsi.c ++++ b/drivers/scsi/ppscsi.c +@@ -57,6 +57,7 @@ + #include + #include + #include ++#include + + #include + +@@ -95,7 +96,8 @@ static void ppsc_attach (struct parport + return; + } + +- add->port = parport_get_port (port); ++ atomic_inc(&port->ref_count); ++ add->port = port; + add->next = ppsc_port_list; + wmb (); + ppsc_port_list = add; +@@ -187,11 +189,11 @@ static void ppsc_set_intr (PHA *pha, voi + spin_unlock_irqrestore(&ppsc_spinlock,flags); + } + +-static void ppsc_tq_int (void *data) ++static void ppsc_tq_int (struct work_struct *work) + { + void (*con)(PHA *); + unsigned long flags; +- PHA *pha = (PHA *)data; ++ PHA *pha = container_of(work, PHA, wq); + + spin_lock_irqsave(&ppsc_spinlock,flags); + +@@ -377,7 +379,7 @@ int ppsc_command (struct scsi_cmnd *cmd) + + ppsc_do_claimed(pha,ppsc_start); + +- while (pha->cur_cmd) scsi_sleep(1); ++ while (pha->cur_cmd) ssleep(1); + + return cmd->result; + } +@@ -886,7 +888,7 @@ static void ppsc_reset_pha (PHA *pha) + ppsc_claim(pha); + pha->proto->connect(pha); + pha->proto->reset_bus(pha); +- scsi_sleep(4*HZ); ++ ssleep(4*HZ); + pha->proto->disconnect(pha); + ppsc_unclaim(pha); + +@@ -905,7 +907,7 @@ int ppsc_reset (struct scsi_cmnd * cmd) + pha->abort_flag = PPSC_DO_RESET; + + while (pha->cur_cmd && (k < PPSC_RESET_TMO)) { +- scsi_sleep(HZ/10); ++ ssleep(HZ/10); + k += HZ/10; + } + +@@ -992,11 +994,11 @@ int ppsc_biosparam (struct scsi_device * + { + ip[0] = 0x40; + ip[1] = 0x20; +- ip[2] = (capacity +1) / (ip[0] * ip[1]); ++ ip[2] = (unsigned int)(capacity +1) >> 11; + if (ip[2] > 1024) { + ip[0] = 0xff; + ip[1] = 0x3f; +- ip[2] = (capacity +1) / (ip[0] * ip[1]); ++ ip[2] = (unsigned int)(capacity +1) / (0xff * 0x3f); + if (ip[2] > 1023) + ip[2] = 1023; + } +@@ -1084,7 +1086,7 @@ int ppsc_release_pha (PHA *pha) + } + + +-int ppsc_detect (PSP *proto, Scsi_Host_Template *tpnt, int verbose) ++int ppsc_detect (PSP *proto, struct scsi_host_template *tpnt, int verbose) + { + int i, m, p, d, n, s, z; + struct ppsc_port_list_struct *next_port = NULL; /* shut gcc up */ +@@ -1146,7 +1148,7 @@ int ppsc_detect (PSP *proto, Scsi_Host_T + pha->device[p+1] = '0' + i; + pha->device[p+2] = 0; + +- INIT_WORK(&pha->wq, ppsc_tq_int, pha); ++ INIT_WORK(&pha->wq, ppsc_tq_int); + + init_timer (&pha->timer); + pha->timer.data = (unsigned long) pha; +--- a/drivers/scsi/sparcsi.c ++++ b/drivers/scsi/sparcsi.c +@@ -165,7 +165,7 @@ static int sparcsi_test_proto (PHA *pha) + + WR(1,0x80); udelay(60); + WR(1,0); +- scsi_sleep(5*HZ); ++ ssleep(5*HZ); + pha->private[0] = 1; + } + +@@ -363,14 +363,14 @@ static struct ppsc_protocol sparcsi_psp + sparcsi_reset_bus + }; + +-int sparcsi_detect (Scsi_Host_Template *tpnt) ++int sparcsi_detect (struct scsi_host_template *tpnt) + { + return ppsc_detect( &sparcsi_psp, tpnt, verbose); + } + + #ifdef MODULE + +-Scsi_Host_Template driver_template = PPSC_TEMPLATE(sparcsi); ++struct scsi_host_template driver_template = PPSC_TEMPLATE(sparcsi); + + #include "scsi_module.c" + +--- a/drivers/scsi/ppscsi.h ++++ b/drivers/scsi/ppscsi.h +@@ -13,14 +13,16 @@ + #define PPSC_H_VERSION "0.92" + + #include +-#include ++#include + #include + #include + #include + #include + +-#include "scsi.h" +-#include "hosts.h" ++#include ++#include ++#include ++#include + + + /* ppscsi global functions */ +@@ -40,31 +42,31 @@ extern int ppsc_release(struct Scsi_Host + /* imports for hosts.c */ + + #ifdef CONFIG_PPSCSI_T348 +-extern int t348_detect( Scsi_Host_Template *); ++extern int t348_detect( struct scsi_host_template *); + #endif + + #ifdef CONFIG_PPSCSI_T358 +-extern int t358_detect( Scsi_Host_Template *); ++extern int t358_detect( struct scsi_host_template *); + #endif + + #ifdef CONFIG_PPSCSI_ONSCSI +-extern int onscsi_detect( Scsi_Host_Template *); ++extern int onscsi_detect( struct scsi_host_template *); + #endif + + #ifdef CONFIG_PPSCSI_EPST +-extern int epst_detect( Scsi_Host_Template *); ++extern int epst_detect( struct scsi_host_template *); + #endif + + #ifdef CONFIG_PPSCSI_EPSA2 +-extern int epsa2_detect( Scsi_Host_Template *); ++extern int epsa2_detect( struct scsi_host_template *); + #endif + + #ifdef CONFIG_PPSCSI_VPI0 +-extern int vpi0_detect( Scsi_Host_Template *); ++extern int vpi0_detect( struct scsi_host_template *); + #endif + + #ifdef CONFIG_PPSCSI_SPARCSI +-extern int sparcsi_detect( Scsi_Host_Template *); ++extern int sparcsi_detect( struct scsi_host_template *); + #endif + + #endif +@@ -303,7 +305,7 @@ struct ppsc_protocol { + + typedef struct ppsc_protocol PSP; + +-extern int ppsc_detect( PSP *, Scsi_Host_Template *, int); ++extern int ppsc_detect( PSP *, struct scsi_host_template *, int); + + #ifdef PPSC_HA_MODULE + +@@ -322,11 +324,11 @@ static STT stt[4] = { {"host0",8,host0}, + {"host3",8,host3} }; + #endif + +-MODULE_PARM(host0,"1-8i"); +-MODULE_PARM(host1,"1-8i"); +-MODULE_PARM(host2,"1-8i"); +-MODULE_PARM(host3,"1-8i"); +-MODULE_PARM(verbose,"i"); ++module_param_array(host0, int, NULL, 0); ++module_param_array(host1, int, NULL, 0); ++module_param_array(host2, int, NULL, 0); ++module_param_array(host3, int, NULL, 0); ++module_param(verbose, int, 0); + + static struct ppsc_host_adapter host_structs[4]; + +--- a/drivers/scsi/Makefile ++++ b/drivers/scsi/Makefile +@@ -136,7 +136,7 @@ obj-$(CONFIG_PPSCSI_ONSCSI) += onscsi.o + obj-$(CONFIG_PPSCSI_EPSA2) += epsa2.o + obj-$(CONFIG_PPSCSI_EPST) += epst.o + obj-$(CONFIG_PPSCSI_VPI0) += vpi0.o +-obj-$(CONFIG_PPSCSI_VPI2) += vpi2.o ++obj-n += vpi2.o + obj-$(CONFIG_PPSCSI_SPARCSI) += sparcsi.o + + obj-$(CONFIG_CHR_DEV_ST) += st.o diff --git a/kernel/tools/perf/files/patches/mageia/series b/kernel/tools/perf/files/patches/mageia/series new file mode 100644 index 0000000000..6372abff5a --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/series @@ -0,0 +1,404 @@ +# +# Mageia kernel series file +# +# This file describes the order in which patches should be applied +# in the kernel and why the patch is needed. +# +# Luiz Fernando N. Capitulino +# + +### +### Upstream git +### + +### +### Stable Queue +### + +### +### Arch x86 +### + +# laptop needing pci=assign-busses (#18989, needs to be submitted upstream) +x86-pci-toshiba-equium-a60-assign-busses.patch + +# If users choose a bad video mode, allow to jump to +# a working one (TTL: forever) +x86-boot-video-80x25-if-break.patch + +# Allow poweroff on UP machines running SMP kernels +x86-default_poweroff_up_machines.patch + +# Fix #38760, need to be revised and submitted upstream +# BROKEN: x86-cpufreq-speedstep-dothan-3.patch + +# raise vmalloc to fix https://bugs.mageia.org/show_bug.cgi?id=904 +x86-increase-default-minimum-vmalloc-area-by-64MB-to-192MB.patch + +# slows down boot +Revert-cpufreq-pcc-Enable-autoload-of-pcc-cpufreq-fo.patch + +# +Revert-cpufreq-pcc-cpufreq-update-default-value-of-c.patch + +# breaks nvidia304 +Revert-x86-mm-mtrr-Remove-kernel-internal-MTRR-inter.patch + +# +x86-power-64-Fix-hibernation-return-address-corrupti.patch + +### +### Core +### +base-cacheinfo-silence-DT-warnings.patch + +### +### i2c +### + +### +### PCI core +### + +# BROKEN: pci-pciprobe-CardBusNo.patch + +# http://lkml.org/lkml/2008/9/12/52 +pci-add-ALI-M5229-ide-compatibility-mode-quirk.patch +pci-quirks-drop-devinit-exit.patch + +### +### PNP core +### + +### +### ACPI +### + +# CLEVO M360S acpi irq workaround +acpi-CLEVO-M360S-disable_acpi_irq.patch + +# Clevo M720SR freezes with C3 +acpi-processor-M720SR-limit-to-C2.patch + +# backlight fixes +ACPI-video-Add-a-quirk-to-force-acpi-video-backlight.patch + +### +### Block +### + +# epsa2 SCSI driver, don't know from where it came +scsi-ppscsi-2.6.2.patch + +# epsa2 is far behind +scsi-ppscsi_fixes.patch + +# Fix build of ppscsi on 2.6.24 +scsi-ppscsi-sg-helper-update.patch + +# Update/fix for ppscsi on 2.6.25 +scsi-ppscsi-update-for-scsi_data_buffer.patch + +# https://qa.mandriva.com/show_bug.cgi?id=45393 +scsi-ppscsi-mdvbz45393.patch + +# epsa2 3.0 buildfix +scsi-ppscsi-3.0-buildfix.patch + +# Don't know know why this is needed +scsi-megaraid-new-sysfs-name.patch + +# Looks like fixes from Arnaud, not sure why they're needed +ide-pci-sis5513-965.patch + +mpt-vmware-fix.patch + +# adds aliases to support upgrade from old dm-raid45 patch +dm-raid-aliases.patch + +# disable floppy autoloading (mga #4696) +block-floppy-disable-pnp-modalias.patch + +# prefer ata over ide drivers +ata-prefer-ata-drivers-over-ide-drivers-when-both-are-built.patch + +# Nice SSD speedup +block-Make-CFQ-default-to-IOPS-mode-on-SSDs.patch + +# ahci ids +ahci-add-new-Intel-device-IDs.patch + +# +megaraid_sas-Do-not-fire-MR_DCMD_PD_LIST_QUERY-to-co.patch + +### +### Char +### + +# hard locks Dell R720xd +Revert-ipmi-Start-the-timer-and-thread-on-internal-m.patch + +### +### File-system +### + +# aufs from: http://aufs.sourceforge.net/ (mga#8314) +fs-aufs-4.7.patch +fs-aufs-4.7-modular.patch +fs-aufs-4.7-ver-fix.patch + +# ext4 +fs-ext4-don-t-call-ext4_should_journal_data-on-the-jour.patch +fs-ext4-fix-deadlock-during-page-writeback.patch + +### +### FireWire +### + +# adding module aliases to ease upgrade from ieee1394 +firewire-ieee1394-module-aliases.patch + +### +### GPU/DRM +### + +# new Q57 Host Bridge id +char-agp-intel-new-Q57-id.patch + +# External mach64 drm support from git://anongit.freedesktop.org/git/mesa/drm +gpu-drm-mach64.patch +gpu-drm-mach64-fixes.patch +gpu-drm-mach64-2.6.31.patch +gpu-drm-mach64-fix-for-changed-drm_pci_alloc.patch +gpu-drm-mach64-fix-for-changed-drm_ioctl.patch +gpu-drm-mach64-2.6.36-buildfix.patch +gpu-drm-mach64-2.6.37-buildfix.patch +gpu-drm-mach64-3.0-buildfix.patch +gpu-drm-mach64-include-module.h.patch +gpu-drm-mach64-3.3-buildfix.patch +gpu-drm-mach64-3.6-buildfix.patch +gpu-drm-mach64-3.7-buildfix.patch +gpu-drm-mach64-3.12-buildfix.patch +gpu-drm-mach64-restore-mach64_PCI_IDS.patch +gpu-drm-mach64-linux-3.14-buildfix.patch +gpu-drm-mach64-3.17-buildfix.patch +gpu-drm-mach64-3.18-buildfix.patch + +### +### Hardware Monitoring +### + +### +### Input +### + +input-i8042-quirks-for-Fujitsu-Lifebook-A544-and-Lif.patch + +### +### idle +### + +### +### Kbuild +### + +### +### Media +### + +### +### Misc +### + +### +### MM +### + +### +### Network +### + +# SiS 190 fixes +net-sis190-fix-list-usage.patch + +# netfilter IFWLOG support +net-netfilter-IFWLOG.patch +net-netfilter-IFWLOG-mdv.patch +net-netfilter-IFWLOG-2.6.35-buildfix.patch +net-netfilter-IFWLOG-2.6.37-buildfix.patch +net-ipv4-netfilter-ipt_IFWLOG-3.6-buildfix.patch +net-netfilter-IFWLOG-3.7-buildfix.patch +net-netfilter-IFWLOG-remove-unused-label.patch + +# netfilter psd support +net-netfilter-psd.patch +net-netfilter-psd-mdv.patch +net-netfilter-psd-2.6.35-buildfix.patch + +# iwlwifi fixes +net-wireless-iwlwifi-add-new-8260-PCI-IDs.patch +net-wireless-iwlwifi-add-new-8265.patch +net-wireless-iwlwifi-pcie-enable-interrupts-before-releasing-the-NICs-CPU.patch +net-wireless-iwlwifi-pcie-fix-a-race-in-firmware-loading-flow.patch + +# +net-bcma-add-PCI-ID-for-Foxconn-s-BCM43142-device.patch +net-brcmfmac-restore-stopping-netdev-queue-when-bus-clog.patch + +### +### Platform drivers +### + +# Allow access to Shuttle WMI interface controls +# (Mainly allow turning on/off webcam and wireless on Shuttle DA18IE and DA18IM) +platform-x86-add-shuttle-wmi-driver.patch +platform-x86-shuttle-wmi-drop-devinit-exit.patch +platform-x86-shuttle-wmi-4.2-buildfix.patch + +# +hp-wmi-Fix-wifi-cannot-be-hard-unblocked.patch + +Bluetooth-Add-support-of-13d3-3490-AR3012-device.patch +intel_th-Fix-a-deadlock-in-modprobing.patch +intel_th-pci-Add-Kaby-Lake-PCH-H-support.patch +pinctrl-cherryview-prevent-concurrent-access-to-GPIO.patch + +### +### RTC +### + +### +### Serial +### + +# Export pci_ids.h to user space, needed by ldetect +include-kbuild-export-pci_ids.patch + +### +### Sound +### + +### +### Staging +### + + +### +### TTY +### + +### +### +### + +### +### USB +### + +hid-usbhid-IBM-BladeCenterHS20-quirk.patch + +usb-storage-unusual_devs-add-id.patch +usb-storage-unusual_devs-add-id-2.6.37-buildfix.patch + +# +usb-dwc3-fix-for-the-isoc-transfer-EP_BUSY-flag.patch +usb-renesas_usbhs-fix-NULL-pointer-dereference-in-xf.patch + +# +HID-uhid-fix-timeout-when-probe-races-with-IO.patch + +### +### V4L +### + +# pwc driver name in /proc/bus/devices, /sys fix and "advertisement" removal +media-usb-pwc-lie-in-proc-usb-devices.patch + +# +media-media-usbtv-prevent-access-to-free-d-resources.patch +media-vb2-core-Skip-planes-array-verification-if-pb-.patch +media-videobuf2-v4l2-Verify-planes-array-in-buffer-d.patch + +### +### Video +### + +# Mageia framebuffer boot logo +video-mageia-logo.patch + +### +### 3rdparty +### + +3rd-3rdparty-1.0-tree.patch + +# TODO: fix up patch below to include all archs? +3rd-3rdparty-merge.patch + +# acerhk +3rd-acerhk-0.5.35.patch +3rd-acerhk-kbuild.patch +3rd-acerhk-extra-cflags.patch +3rd-acerhk-proc_dir_entry-owner.patch +3rd-acerhk-fix-build-with-function-tracer.patch +3rd-acerhk-2.6.36-buildfix.patch +3rd-acerhk-fix-include.patch + +# aes2501 +3rd-aes2501-r19.patch +3rd-aes2501-kbuild.patch +3rd-aes2501-rmmod-oops-fix.patch + +# ndiswrapper +3rd-ndiswrapper-1.60.patch +3rd-ndiswrapper-Kconfig.patch +3rd-ndiswrapper-Makefile-build-fix.patch +3rd-ndiswrapper-4.7-buildfix.patch + +# rfswitch +3rd-rfswitch-1.3.patch +3rd-rfswitch-build-fix.patch +3rd-rfswitch-3.0-buildfix.patch + +# viahss +3rd-viahss-0.92.patch +3rd-viahss-config.patch +3rd-viahss-module-license.patch +3rd-viahss-2.6.35-buildfix.patch +3rd-viahss-3.0-buildfix.patch + +# add rtl8723bs support (mga#15874) +3rd-rtl8723bs.patch +3rd-rtl8723bs-4.7-buildfix.patch + +### +### Security +### + +### +### Smack fixes +### + +### +### XEN +### + +### +### ARM +### + +# RPi2 support +# Read MAC address from DT +arm-0001-ARM-bcm2835-dt-Add-the-ethernet-to-the-device-trees.patch + +### +### IA64 +### + +### +### Tools +### + +### +### UAPI +### diff --git a/kernel/tools/perf/files/patches/mageia/usb-dwc3-fix-for-the-isoc-transfer-EP_BUSY-flag.patch b/kernel/tools/perf/files/patches/mageia/usb-dwc3-fix-for-the-isoc-transfer-EP_BUSY-flag.patch new file mode 100644 index 0000000000..d821512445 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/usb-dwc3-fix-for-the-isoc-transfer-EP_BUSY-flag.patch @@ -0,0 +1,42 @@ +From 9cad39fe4e4a4fe95d8ea5a7b0692b0a6e89e38b Mon Sep 17 00:00:00 2001 +From: Konrad Leszczynski +Date: Mon, 8 Feb 2016 16:13:12 +0100 +Subject: [PATCH] usb: dwc3: fix for the isoc transfer EP_BUSY flag + +commit f3af36511e60 ("usb: dwc3: gadget: always +enable IOC on bulk/interrupt transfers") ended up +regressing Isochronous endpoints by clearing +DWC3_EP_BUSY flag too early, which resulted in +choppy audio playback over USB. + +Fix that by partially reverting original commit and +making sure that we check for isochronous endpoints. + +Fixes: f3af36511e60 ("usb: dwc3: gadget: always enable IOC + on bulk/interrupt transfers") +Cc: +Signed-off-by: Konrad Leszczynski +Signed-off-by: Rafal Redzimski +Signed-off-by: Felipe Balbi +--- + drivers/usb/dwc3/gadget.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c +index 5e7b2ba..867adc9 100644 +--- a/drivers/usb/dwc3/gadget.c ++++ b/drivers/usb/dwc3/gadget.c +@@ -2058,6 +2058,10 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, + return 1; + } + ++ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) ++ if ((event->status & DEPEVT_STATUS_IOC) && ++ (trb->ctrl & DWC3_TRB_CTRL_IOC)) ++ return 0; + return 1; + } + +-- +2.9.2 + diff --git a/kernel/tools/perf/files/patches/mageia/usb-renesas_usbhs-fix-NULL-pointer-dereference-in-xf.patch b/kernel/tools/perf/files/patches/mageia/usb-renesas_usbhs-fix-NULL-pointer-dereference-in-xf.patch new file mode 100644 index 0000000000..8f648d4337 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/usb-renesas_usbhs-fix-NULL-pointer-dereference-in-xf.patch @@ -0,0 +1,80 @@ +From 4fdef698383db07d829da567e0e405fc41ff3a89 Mon Sep 17 00:00:00 2001 +From: Yoshihiro Shimoda +Date: Wed, 8 Jun 2016 16:32:49 +0900 +Subject: [PATCH] usb: renesas_usbhs: fix NULL pointer dereference in + xfer_work() + +This patch fixes an issue that the xfer_work() is possible to cause +NULL pointer dereference if the usb cable is disconnected while data +transfer is running. + +In such case, a gadget driver may call usb_ep_disable()) before +xfer_work() is actually called. In this case, the usbhs_pkt_pop() +will call usbhsf_fifo_unselect(), and then usbhs_pipe_to_fifo() +in xfer_work() will return NULL. + +Fixes: e73a989 ("usb: renesas_usbhs: add DMAEngine support") +Cc: # v3.1+ +Signed-off-by: Yoshihiro Shimoda +Signed-off-by: Felipe Balbi +--- + drivers/usb/renesas_usbhs/fifo.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c +index 7be4e7d..280ed5f 100644 +--- a/drivers/usb/renesas_usbhs/fifo.c ++++ b/drivers/usb/renesas_usbhs/fifo.c +@@ -810,20 +810,27 @@ static void xfer_work(struct work_struct *work) + { + struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work); + struct usbhs_pipe *pipe = pkt->pipe; +- struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe); ++ struct usbhs_fifo *fifo; + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct dma_async_tx_descriptor *desc; +- struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt); ++ struct dma_chan *chan; + struct device *dev = usbhs_priv_to_dev(priv); + enum dma_transfer_direction dir; ++ unsigned long flags; + ++ usbhs_lock(priv, flags); ++ fifo = usbhs_pipe_to_fifo(pipe); ++ if (!fifo) ++ goto xfer_work_end; ++ ++ chan = usbhsf_dma_chan_get(fifo, pkt); + dir = usbhs_pipe_is_dir_in(pipe) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV; + + desc = dmaengine_prep_slave_single(chan, pkt->dma + pkt->actual, + pkt->trans, dir, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) +- return; ++ goto xfer_work_end; + + desc->callback = usbhsf_dma_complete; + desc->callback_param = pipe; +@@ -831,7 +838,7 @@ static void xfer_work(struct work_struct *work) + pkt->cookie = dmaengine_submit(desc); + if (pkt->cookie < 0) { + dev_err(dev, "Failed to submit dma descriptor\n"); +- return; ++ goto xfer_work_end; + } + + dev_dbg(dev, " %s %d (%d/ %d)\n", +@@ -842,6 +849,9 @@ static void xfer_work(struct work_struct *work) + usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->trans); + dma_async_issue_pending(chan); + usbhs_pipe_enable(pipe); ++ ++xfer_work_end: ++ usbhs_unlock(priv, flags); + } + + /* +-- +2.9.2 + diff --git a/kernel/tools/perf/files/patches/mageia/usb-storage-unusual_devs-add-id-2.6.37-buildfix.patch b/kernel/tools/perf/files/patches/mageia/usb-storage-unusual_devs-add-id-2.6.37-buildfix.patch new file mode 100644 index 0000000000..fa6655de05 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/usb-storage-unusual_devs-add-id-2.6.37-buildfix.patch @@ -0,0 +1,46 @@ +--- linux/drivers/usb/storage/unusual_devs.h.orig 2012-12-06 18:26:48.639813048 +0200 ++++ linux/drivers/usb/storage/unusual_devs.h 2012-12-06 18:27:16.570440504 +0200 +@@ -2046,16 +2046,16 @@ UNUSUAL_DEV( 0xed10, 0x7636, 0x0001, 0x0 + UNUSUAL_DEV( 0x0584, 0x0001, 0x0100, 0x0102, + "RATOCSystems", + "Compact Flash Adapter", +- US_SC_SCSI, US_PR_BULK, NULL, ++ USB_SC_SCSI, USB_PR_BULK, NULL, + US_FL_SINGLE_LUN | US_FL_MAX_SECTORS_MIN), + + /* + * Panasonic/OEMs compact USB CDROMs status + * KXL-840(CD-ROM11): usb_stor_Bulk_max_lun() is danger, need US_FL_SINGLE_LUN + * KXL-RW11(CDRRW02): usb_stor_Bulk_max_lun() is danger, need US_FL_SINGLE_LUN +- * KXL-RW20(CDRRW03): original IClass is 0xFF, use US_PR_CB and need init reset ++ * KXL-RW20(CDRRW03): original IClass is 0xFF, use USB_PR_CB and need init reset + * KXL-RW31(CDRRW05): work fine with current code +- * KXL-RW21(CDRRW06): original IClass is 0xFF, use US_PR_CB and need init reset ++ * KXL-RW21(CDRRW06): original IClass is 0xFF, use USB_PR_CB and need init reset + * KXL-RW32(CDRRW09): work fine with current code + * KXL-RW40(CDRRW10): work fine with current code + * Checked: Go Taniguchi +@@ -2063,19 +2063,19 @@ UNUSUAL_DEV( 0x0584, 0x0001, 0x0100, 0x0 + UNUSUAL_DEV( 0x04da, 0x0d01, 0x0000, 0xffff, + "Panasonic", + "CD-ROM11", +- US_SC_8020, US_PR_BULK, NULL, US_FL_SINGLE_LUN), ++ USB_SC_8020, USB_PR_BULK, NULL, US_FL_SINGLE_LUN), + UNUSUAL_DEV( 0x04da, 0x0d02, 0x0000, 0xffff, + "Panasonic", + "CDRRW02", +- US_SC_8020, US_PR_BULK, NULL, US_FL_SINGLE_LUN), ++ USB_SC_8020, USB_PR_BULK, NULL, US_FL_SINGLE_LUN), + UNUSUAL_DEV( 0x04da, 0x0d03, 0x0000, 0xffff, + "Panasonic", + "CDRRW03", +- US_SC_8020, US_PR_CB, NULL, US_FL_MAX_SECTORS_MIN), ++ USB_SC_8020, USB_PR_CB, NULL, US_FL_MAX_SECTORS_MIN), + UNUSUAL_DEV( 0x04da, 0x0d06, 0x0000, 0xffff, + "Panasonic", + "CDRRW06", +- US_SC_8020, US_PR_CB, NULL, US_FL_MAX_SECTORS_MIN), ++ USB_SC_8020, USB_PR_CB, NULL, US_FL_MAX_SECTORS_MIN), + + /* Control/Bulk transport for all SubClass values */ + USUAL_DEV(USB_SC_RBC, USB_PR_CB), diff --git a/kernel/tools/perf/files/patches/mageia/usb-storage-unusual_devs-add-id.patch b/kernel/tools/perf/files/patches/mageia/usb-storage-unusual_devs-add-id.patch new file mode 100644 index 0000000000..b9fc02006e --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/usb-storage-unusual_devs-add-id.patch @@ -0,0 +1,55 @@ +Subject: Change to usb storage of unusual_dev. + +This patch is japanease unique USB devices quirks. +There are many unique USB CD, which probides by Panasonic. +I try to use all models. all devices worked fine. + +Signed-off-by: Go Taniguchi + +--- + drivers/usb/storage/unusual_devs.h | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +--- linux/drivers/usb/storage/unusual_devs.h.orig 2014-06-03 21:48:03.211099341 +0300 ++++ linux/drivers/usb/storage/unusual_devs.h 2014-06-04 21:57:21.546299167 +0300 +@@ -2105,6 +2105,40 @@ UNUSUAL_DEV( 0xed10, 0x7636, 0x0001, 0x0 + #include "unusual_uas.h" + #endif + ++UNUSUAL_DEV( 0x0584, 0x0001, 0x0100, 0x0102, ++ "RATOCSystems", ++ "Compact Flash Adapter", ++ US_SC_SCSI, US_PR_BULK, NULL, ++ US_FL_SINGLE_LUN | US_FL_MAX_SECTORS_MIN), ++ ++/* ++ * Panasonic/OEMs compact USB CDROMs status ++ * KXL-840(CD-ROM11): usb_stor_Bulk_max_lun() is danger, need US_FL_SINGLE_LUN ++ * KXL-RW11(CDRRW02): usb_stor_Bulk_max_lun() is danger, need US_FL_SINGLE_LUN ++ * KXL-RW20(CDRRW03): original IClass is 0xFF, use US_PR_CB and need init reset ++ * KXL-RW31(CDRRW05): work fine with current code ++ * KXL-RW21(CDRRW06): original IClass is 0xFF, use US_PR_CB and need init reset ++ * KXL-RW32(CDRRW09): work fine with current code ++ * KXL-RW40(CDRRW10): work fine with current code ++ * Checked: Go Taniguchi ++ */ ++UNUSUAL_DEV( 0x04da, 0x0d01, 0x0000, 0xffff, ++ "Panasonic", ++ "CD-ROM11", ++ US_SC_8020, US_PR_BULK, NULL, US_FL_SINGLE_LUN), ++UNUSUAL_DEV( 0x04da, 0x0d02, 0x0000, 0xffff, ++ "Panasonic", ++ "CDRRW02", ++ US_SC_8020, US_PR_BULK, NULL, US_FL_SINGLE_LUN), ++UNUSUAL_DEV( 0x04da, 0x0d03, 0x0000, 0xffff, ++ "Panasonic", ++ "CDRRW03", ++ US_SC_8020, US_PR_CB, NULL, US_FL_MAX_SECTORS_MIN), ++UNUSUAL_DEV( 0x04da, 0x0d06, 0x0000, 0xffff, ++ "Panasonic", ++ "CDRRW06", ++ US_SC_8020, US_PR_CB, NULL, US_FL_MAX_SECTORS_MIN), ++ + /* Control/Bulk transport for all SubClass values */ + USUAL_DEV(USB_SC_RBC, USB_PR_CB), + USUAL_DEV(USB_SC_8020, USB_PR_CB), diff --git a/kernel/tools/perf/files/patches/mageia/video-mageia-logo.patch b/kernel/tools/perf/files/patches/mageia/video-mageia-logo.patch new file mode 100644 index 0000000000..efc5307e0c --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/video-mageia-logo.patch @@ -0,0 +1,949 @@ + +Mageia framebuffer boot logo + +Signed-off-by: Thomas Backlund + + drivers/video/logo/Kconfig | 5 + drivers/video/logo/Makefile | 1 + drivers/video/logo/logo.c | 5 + drivers/video/logo/logo_mageia_clut224.ppm | 883 +++++++++++++++++++++++++++++ + include/linux/linux_logo.h | 1 + 5 files changed, 895 insertions(+) + +diff -Nurp linux-2.6.37.3/drivers/video/logo/Kconfig linux-2.6.37.3.mga/drivers/video/logo/Kconfig +--- linux-2.6.37.3/drivers/video/logo/Kconfig 2011-01-05 02:50:19.000000000 +0200 ++++ linux-2.6.37.3.mga/drivers/video/logo/Kconfig 2011-03-08 21:50:08.077611366 +0200 +@@ -82,4 +82,9 @@ config LOGO_M32R_CLUT224 + depends on M32R + default y + ++config LOGO_MAGEIA_CLUT224 ++ bool "224-color Mageia logo" ++ depends on LOGO ++ default y ++ + endif # LOGO +diff -Nurp linux-2.6.37.3/drivers/video/logo/logo.c linux-2.6.37.3.mga/drivers/video/logo/logo.c +--- linux-2.6.37.3/drivers/video/logo/logo.c 2011-01-05 02:50:19.000000000 +0200 ++++ linux-2.6.37.3.mga/drivers/video/logo/logo.c 2011-03-08 21:51:27.042063947 +0200 +@@ -63,6 +63,11 @@ const struct linux_logo * __init_refok f + } + + if (depth >= 8) { ++#ifdef CONFIG_LOGO_MAGEIA_CLUT224 ++ /* Mageia logo */ ++ logo = &logo_mageia_clut224; ++ return logo; ++#endif + #ifdef CONFIG_LOGO_LINUX_CLUT224 + /* Generic Linux logo */ + logo = &logo_linux_clut224; +diff -Nurp linux-2.6.37.3/drivers/video/logo/logo_mageia_clut224.ppm linux-2.6.37.3.mga/drivers/video/logo/logo_mageia_clut224.ppm +--- linux-2.6.37.3/drivers/video/logo/logo_mageia_clut224.ppm 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3.mga/drivers/video/logo/logo_mageia_clut224.ppm 2011-03-08 23:47:47.000000000 +0200 +@@ -0,0 +1,883 @@ ++P3 ++80 80 ++255 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 11 16 9 14 29 ++9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 ++9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 ++9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 ++9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 ++9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 ++9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 ++9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 ++9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 9 14 29 ++9 14 29 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ ++0 0 0 0 0 0 0 0 0 0 0 0 8 23 42 32 55 114 37 56 117 37 56 117 ++37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 ++37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 ++37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 ++37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 ++37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 ++37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 ++37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 ++37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 37 56 117 ++37 56 117 37 56 117 18 45 91 9 14 29 0 0 0 0 0 0 0 0 0 0 0 0 ++ ++0 0 0 0 0 0 0 0 0 18 45 91 37 56 117 37 56 117 36 57 118 36 57 118 ++36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 ++36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 ++36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 ++36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 ++36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 ++36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 ++36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 ++36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 36 57 118 ++36 57 118 36 57 118 37 56 117 36 57 118 17 36 71 0 0 0 0 0 0 0 0 0 ++ ++0 0 0 3 11 16 18 45 91 35 58 120 35 58 119 35 58 119 35 58 119 35 58 119 ++35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 ++35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 ++35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 ++35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 ++35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 ++35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 ++35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 ++35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 35 58 119 ++35 58 119 35 58 119 35 58 119 35 58 119 35 58 120 17 36 71 0 0 0 0 0 0 ++ ++0 0 0 11 38 58 37 56 117 34 59 122 35 58 119 35 58 120 35 58 120 35 58 120 ++35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 ++35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 ++35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 ++35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 ++35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 ++35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 ++35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 ++35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 ++35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 35 58 120 9 14 29 0 0 0 ++ ++0 0 0 32 55 114 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 ++34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 ++34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 ++34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 ++34 59 122 34 59 122 34 59 122 35 58 119 63 96 153 63 96 153 63 96 153 34 59 122 ++34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 ++34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 ++34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 ++34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 ++34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 34 59 122 18 45 91 0 0 0 ++ ++8 23 42 34 59 122 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 ++33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 ++33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 ++33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 ++33 60 123 33 60 123 33 60 123 125 157 204 191 220 251 194 222 252 191 218 250 108 152 201 ++32 55 114 32 62 125 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 ++33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 ++33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 ++33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 ++33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 33 60 123 34 59 122 0 0 0 ++ ++11 38 58 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 ++32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 ++32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 ++32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 ++32 61 124 32 62 125 63 96 153 170 209 245 168 209 245 168 209 245 170 209 245 164 205 243 ++63 96 153 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 ++32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 ++32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 ++32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 ++32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 61 124 32 62 125 8 16 31 ++ ++17 36 71 33 60 123 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 ++32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 ++32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 ++32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 ++32 62 125 32 62 125 86 129 181 148 198 240 145 197 239 145 197 239 145 197 239 145 197 239 ++63 96 153 32 61 124 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 ++32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 ++32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 ++32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 ++32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 32 62 125 8 16 31 ++ ++11 38 58 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 ++31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 ++31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 ++31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 ++31 63 126 30 65 129 63 96 153 123 185 232 123 185 232 123 185 232 123 185 232 122 182 230 ++41 91 154 31 63 126 31 63 126 31 63 126 31 63 126 63 96 153 40 74 135 31 63 126 ++31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 ++31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 ++31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 ++31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 31 63 126 8 16 31 ++ ++17 36 71 31 63 126 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 ++30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 ++30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 ++30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 ++30 64 128 30 64 128 30 65 129 85 139 195 97 172 225 100 173 226 100 173 226 85 139 195 ++32 61 124 30 64 128 30 64 128 86 129 181 184 213 246 201 225 254 201 225 254 142 183 225 ++40 74 135 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 ++30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 ++30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 ++30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 30 64 128 8 16 31 ++ ++17 36 71 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 ++30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 ++30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 ++30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 ++30 65 129 30 65 129 29 66 130 31 63 126 58 114 175 58 114 175 41 91 154 29 66 130 ++30 65 129 28 68 132 40 74 135 178 210 243 176 212 247 173 211 246 176 212 247 176 212 247 ++125 157 204 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 ++30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 ++30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 ++30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 30 65 129 8 16 31 ++ ++17 36 71 30 64 128 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 ++29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 ++29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 ++29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 ++29 66 130 29 66 130 29 66 130 29 66 130 30 64 128 28 67 131 29 66 130 29 66 130 ++29 66 130 29 66 130 85 139 195 158 203 242 154 201 241 155 202 241 155 202 241 155 202 241 ++154 201 241 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 ++29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 ++29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 ++29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 29 66 130 6 18 34 ++ ++17 36 71 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 ++28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 ++28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 ++28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 ++28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 ++28 67 131 28 67 131 86 129 181 134 191 236 134 191 236 134 191 236 134 191 236 134 191 236 ++134 191 236 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 ++28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 ++28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 ++28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 28 67 131 6 18 34 ++ ++17 36 71 28 67 131 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 ++28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 ++28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 ++28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 ++28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 ++28 68 132 28 68 132 40 74 135 117 182 230 115 181 230 115 181 230 115 181 230 115 181 230 ++85 139 195 27 69 133 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 ++28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 ++28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 ++28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 28 68 132 6 18 34 ++ ++17 36 71 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 ++27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 ++27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 ++27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 ++27 69 133 27 69 133 27 69 133 27 69 133 26 71 136 63 96 153 108 152 201 142 183 225 ++86 129 181 27 69 133 27 69 133 58 114 175 95 170 224 95 170 224 97 172 225 77 152 208 ++41 91 154 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 ++27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 ++27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 ++27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 27 69 133 6 18 34 ++ ++11 38 71 27 69 133 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 ++26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 ++26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 ++26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 ++26 70 135 26 70 135 26 70 135 26 70 135 86 129 181 197 223 253 188 217 249 188 217 249 ++191 220 251 152 193 232 40 74 135 26 70 135 23 75 141 41 91 154 41 91 154 26 70 135 ++27 69 133 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 ++26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 ++26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 ++26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 26 70 135 6 18 34 ++ ++11 38 71 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 ++26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 ++26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 ++26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 ++26 71 136 26 71 136 26 70 135 41 91 154 172 210 246 170 209 245 170 209 245 170 209 245 ++168 209 245 178 210 243 85 139 195 26 71 136 26 71 136 25 72 137 26 71 136 26 71 136 ++26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 ++26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 ++26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 ++26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 26 71 136 6 18 34 ++ ++11 38 71 26 71 136 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 ++25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 ++25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 ++25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 ++25 72 137 25 72 137 25 72 137 86 129 181 151 200 240 152 200 240 152 200 240 152 200 240 ++152 200 240 151 200 240 122 172 221 27 69 133 24 73 138 25 72 137 25 72 137 25 72 137 ++25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 ++25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 ++25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 ++25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 25 72 137 6 18 34 ++ ++11 38 71 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 ++24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 ++24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 ++24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 ++24 73 138 24 73 138 25 72 137 58 114 175 134 191 236 134 191 236 134 191 236 134 191 236 ++134 191 236 134 191 236 108 152 201 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 ++24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 ++24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 ++24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 ++24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 24 73 138 6 18 34 ++ ++11 38 71 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 ++23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 ++23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 ++23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 ++23 74 139 23 74 139 23 74 139 41 91 154 115 181 230 115 181 230 115 181 230 115 181 230 ++115 181 230 115 181 230 60 128 188 24 73 138 23 74 139 23 74 139 23 74 139 23 74 139 ++23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 ++23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 ++23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 ++23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 23 74 139 5 19 36 ++ ++11 38 71 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 ++23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 ++23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 ++23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 ++23 75 141 23 75 141 23 75 141 23 74 139 58 114 175 97 172 225 97 172 225 97 172 225 ++97 172 225 77 152 208 24 73 138 23 75 141 41 91 154 125 157 204 152 193 232 142 183 225 ++86 129 181 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 ++23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 ++23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 ++23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 23 75 141 5 19 36 ++ ++11 38 71 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 ++22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 ++22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 ++22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 ++22 76 142 22 76 142 22 76 142 22 76 142 21 76 143 30 98 155 58 114 175 60 128 188 ++42 114 176 23 74 139 21 76 143 63 96 153 176 212 247 188 218 250 188 218 250 188 217 249 ++191 218 250 125 157 204 21 77 144 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 ++22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 ++22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 ++22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 22 76 142 5 19 36 ++ ++11 38 71 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 ++21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 ++21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 ++21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 23 75 141 ++58 114 175 125 157 204 152 193 232 108 152 201 41 91 154 21 77 144 21 77 144 21 76 143 ++21 76 143 21 76 143 21 76 143 131 179 222 172 210 246 172 210 246 172 210 246 172 210 246 ++172 210 246 170 209 245 86 129 181 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 ++21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 ++21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 ++21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 21 76 143 5 19 36 ++ ++11 38 71 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 ++21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 ++21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 ++21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 125 157 204 ++194 222 252 191 220 251 191 220 251 191 220 251 184 213 246 86 129 181 21 77 144 21 77 144 ++21 77 144 21 77 144 22 89 156 155 202 241 155 202 242 155 202 242 155 202 242 155 202 242 ++155 202 242 155 202 242 122 172 221 21 76 143 21 77 144 21 77 144 21 77 144 21 77 144 ++21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 ++21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 ++21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 21 77 144 5 19 36 ++ ++11 38 71 20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 ++20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 ++20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 ++20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 21 77 144 85 139 195 176 212 247 ++176 212 247 176 212 247 176 212 247 176 212 247 176 212 247 164 205 243 41 91 154 20 78 145 ++20 78 145 20 78 145 41 91 154 140 193 237 140 193 237 140 193 237 140 193 237 140 193 237 ++137 192 236 143 192 235 100 169 221 20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 ++20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 ++20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 ++20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 20 78 145 5 19 36 ++ ++11 38 71 19 80 148 19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 ++19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 ++19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 ++19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 131 179 222 161 204 243 ++160 204 243 160 204 243 160 204 243 160 204 243 160 204 243 160 204 243 85 139 195 19 79 147 ++19 79 147 19 79 147 19 79 147 111 178 227 123 185 232 121 184 232 122 185 232 122 185 232 ++122 185 232 122 185 232 85 139 195 19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 ++19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 ++19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 ++19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 19 79 147 5 19 36 ++ ++11 38 71 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 ++19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 ++19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 ++19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 145 196 239 145 196 239 ++145 196 239 145 196 239 145 196 239 145 196 239 145 196 239 145 196 239 85 139 195 19 80 148 ++19 80 148 19 80 148 19 79 147 60 128 188 106 176 228 106 176 228 106 176 228 106 176 228 ++106 176 228 100 172 225 22 89 156 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 ++19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 ++19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 ++19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 19 80 148 5 19 36 ++ ++11 38 71 17 82 150 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 ++18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 ++18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 ++18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 111 178 227 132 189 234 ++130 189 235 130 189 235 130 189 235 130 189 235 130 189 235 130 189 235 85 139 195 17 82 150 ++18 81 149 18 81 149 18 81 149 18 81 149 42 114 176 88 166 221 87 167 223 89 168 223 ++77 152 208 30 98 155 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 ++18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 ++18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 ++18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 18 81 149 5 19 36 ++ ++11 38 71 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 ++17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 ++17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 ++17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 16 83 151 85 139 195 115 181 230 ++115 181 230 115 181 230 115 181 230 115 181 230 117 182 230 111 178 227 42 114 176 17 82 150 ++17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 18 81 149 23 96 163 22 89 156 ++18 81 149 16 83 151 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 ++17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 ++17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 ++17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 17 82 150 4 21 38 ++ ++9 48 78 17 82 150 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 ++16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 ++16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 ++16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 22 89 156 83 162 217 ++100 172 225 100 173 226 100 173 226 100 173 226 100 173 226 62 142 198 19 79 147 16 83 151 ++16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 ++16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 ++16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 ++16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 ++16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 16 83 151 4 21 38 ++ ++9 48 78 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 ++16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 ++16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 ++16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 14 87 156 ++60 128 188 77 152 208 84 165 222 65 151 210 42 114 176 16 84 153 16 84 153 16 84 153 ++16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 ++16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 ++16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 ++16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 ++16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 16 84 153 4 21 38 ++ ++9 48 78 16 84 153 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 ++15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 ++15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 ++15 85 154 15 85 154 15 85 154 58 114 175 42 114 176 16 84 153 15 85 154 15 85 154 ++15 85 154 14 86 155 15 85 154 16 84 153 15 85 154 15 85 154 15 85 154 15 85 154 ++15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 ++15 85 154 15 85 154 15 85 154 58 114 175 42 114 176 16 83 151 15 85 154 15 85 154 ++15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 ++15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 ++15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 15 85 154 4 21 38 ++ ++9 48 78 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 ++14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 ++14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 ++15 85 154 42 114 176 178 210 243 204 226 255 204 226 255 178 210 243 42 114 176 14 86 155 ++14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 ++14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 ++14 86 155 85 139 195 191 218 250 204 226 255 201 225 254 142 183 225 23 96 163 14 86 155 ++14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 ++14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 ++14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 14 86 155 4 21 38 ++ ++9 48 78 14 86 155 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 ++14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 ++14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 ++42 114 176 191 218 250 201 225 254 201 225 254 201 225 254 201 225 254 201 225 254 108 152 201 ++13 88 157 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 ++14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 23 96 163 ++142 183 225 201 225 254 201 225 254 201 225 254 201 225 254 201 225 254 163 199 237 23 96 163 ++14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 ++14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 ++14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 14 87 156 4 21 38 ++ ++9 48 78 13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 ++13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 ++13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 14 87 156 42 114 176 ++184 213 246 197 223 253 197 223 253 197 223 253 197 223 253 197 223 253 197 223 253 196 222 253 ++178 210 243 60 128 188 13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 ++13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 23 96 163 91 153 206 184 213 246 ++197 223 253 197 223 253 197 223 253 197 223 253 197 223 253 197 223 253 197 223 253 163 199 237 ++23 96 163 13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 ++13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 ++13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 13 88 157 4 21 38 ++ ++9 48 78 12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 ++12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 ++12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 28 113 174 184 213 246 ++194 222 252 194 222 252 194 222 252 194 222 252 194 222 252 194 222 252 194 222 252 194 222 252 ++194 222 252 196 222 253 172 207 243 125 157 204 60 128 188 13 88 157 12 89 158 12 89 158 ++12 89 158 12 89 158 23 96 163 60 128 188 122 172 221 184 213 246 194 222 252 194 222 252 ++194 222 252 194 222 252 194 222 252 194 222 252 194 222 252 194 222 252 194 222 252 194 222 252 ++163 199 237 12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 ++12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 ++12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 12 89 158 4 21 38 ++ ++9 48 78 12 90 160 12 90 160 12 90 160 12 90 160 12 90 160 12 90 160 12 90 160 ++12 90 160 12 90 160 12 90 160 12 90 160 12 90 160 12 90 160 12 90 160 12 90 160 ++12 90 160 12 90 160 12 90 160 12 90 160 12 90 160 13 88 157 163 199 237 191 220 251 ++191 220 251 191 220 251 191 220 251 191 220 251 191 220 251 191 220 251 191 220 251 191 220 251 ++191 220 251 191 220 251 191 220 251 188 218 250 191 218 250 191 220 251 178 210 243 152 193 232 ++142 183 225 191 220 251 191 220 251 194 222 252 191 220 251 191 220 251 191 220 251 191 220 251 ++191 220 251 191 220 251 191 220 251 191 220 251 191 220 251 191 220 251 191 220 251 191 220 251 ++185 217 250 125 157 204 12 90 160 12 90 160 12 90 160 12 90 160 12 90 160 12 90 160 ++12 90 160 12 90 160 12 90 160 12 90 160 12 90 160 12 90 160 12 90 160 12 90 160 ++12 90 160 12 90 160 12 90 160 12 90 160 12 90 160 12 90 160 12 90 160 1 24 42 ++ ++9 48 78 11 91 161 11 91 161 11 91 161 11 91 161 11 91 161 11 91 161 11 91 161 ++11 91 161 11 91 161 11 91 161 11 91 161 11 91 161 11 91 161 11 91 161 11 91 161 ++11 91 161 11 91 161 11 91 161 11 91 161 11 91 161 91 153 206 188 218 250 188 218 250 ++188 218 250 188 218 250 188 218 250 188 218 250 188 218 250 188 218 250 188 218 250 188 218 250 ++188 218 250 188 218 250 188 218 250 188 218 250 188 218 250 188 218 250 188 218 250 188 218 250 ++188 218 250 188 218 250 188 218 250 188 218 250 188 218 250 188 218 250 188 218 250 188 218 250 ++188 218 250 188 218 250 188 218 250 188 218 250 188 218 250 188 218 250 188 218 250 188 218 250 ++188 218 250 188 218 250 60 128 188 12 89 158 11 91 161 11 91 161 11 91 161 11 91 161 ++11 91 161 11 91 161 11 91 161 11 91 161 11 91 161 11 91 161 11 91 161 11 91 161 ++11 91 161 11 91 161 11 91 161 11 91 161 11 91 161 11 91 161 11 91 161 1 24 42 ++ ++9 48 78 10 92 162 10 92 162 10 92 162 10 92 162 10 92 162 10 92 162 10 92 162 ++10 92 162 10 92 162 10 92 162 10 92 162 10 92 162 10 92 162 10 92 162 10 92 162 ++10 92 162 10 92 162 10 92 162 11 91 161 28 113 174 188 218 250 185 217 250 185 217 250 ++185 217 250 185 217 250 185 217 250 185 217 250 185 217 250 185 217 250 185 217 250 185 217 250 ++185 217 250 185 217 250 185 217 250 185 217 250 185 217 250 185 217 250 185 217 250 185 217 250 ++185 217 250 185 217 250 185 217 250 185 217 250 185 217 250 185 217 250 185 217 250 185 217 250 ++185 217 250 185 217 250 185 217 250 185 217 250 185 217 250 185 217 250 185 217 250 185 217 250 ++185 217 250 185 217 250 163 199 237 10 92 162 10 92 162 10 92 162 10 92 162 10 92 162 ++10 92 162 10 92 162 10 92 162 10 92 162 10 92 162 10 92 162 10 92 162 10 92 162 ++10 92 162 10 92 162 10 92 162 10 92 162 10 92 162 10 92 162 10 92 162 1 24 42 ++ ++2 50 86 9 92 163 9 92 163 9 92 163 9 92 163 9 92 163 9 92 163 9 92 163 ++9 92 163 9 92 163 9 92 163 9 92 163 9 92 163 9 92 163 9 92 163 9 92 163 ++9 92 163 9 92 163 9 92 163 9 92 163 122 172 221 179 214 248 182 215 249 182 215 249 ++182 215 249 182 215 249 182 215 249 182 215 249 152 193 232 182 215 249 182 215 249 182 215 249 ++182 215 249 182 215 249 182 215 249 182 215 249 182 215 249 182 215 249 182 215 249 182 215 249 ++182 215 249 182 215 249 182 215 249 182 215 249 182 215 249 182 215 249 182 215 249 182 215 249 ++182 215 249 182 215 249 172 207 243 163 199 237 182 215 249 182 215 249 182 215 249 182 215 249 ++182 215 249 182 215 249 182 215 249 85 139 195 8 94 166 9 92 163 9 92 163 9 92 163 ++9 92 163 9 92 163 9 92 163 9 92 163 9 92 163 9 92 163 9 92 163 9 92 163 ++9 92 163 9 92 163 9 92 163 9 92 163 9 92 163 9 92 163 9 92 163 1 24 42 ++ ++9 48 78 9 93 164 9 93 164 9 93 164 9 93 164 9 93 164 9 93 164 9 93 164 ++9 93 164 9 93 164 9 93 164 9 93 164 9 93 164 9 93 164 9 93 164 9 93 164 ++9 93 164 9 93 164 9 92 163 28 113 174 179 214 248 179 214 248 179 214 248 179 214 248 ++179 214 248 179 214 248 179 214 248 122 172 221 11 91 161 40 129 186 142 183 225 179 214 248 ++179 214 248 179 214 248 179 214 248 179 214 248 179 214 248 179 214 248 179 214 248 179 214 248 ++179 214 248 179 214 248 179 214 248 179 214 248 179 214 248 179 214 248 179 214 248 179 214 248 ++176 212 247 122 172 221 28 113 174 18 102 171 163 199 237 179 214 248 179 214 248 179 214 248 ++179 214 248 179 214 248 179 214 248 154 201 241 9 93 164 9 93 164 9 93 164 9 93 164 ++9 93 164 9 93 164 9 93 164 9 93 164 9 93 164 9 93 164 9 93 164 9 93 164 ++9 93 164 9 93 164 9 93 164 9 93 164 9 93 164 9 93 164 9 93 164 1 24 42 ++ ++2 50 86 8 94 166 8 94 166 8 94 166 8 94 166 8 94 166 8 94 166 8 94 166 ++8 94 166 8 94 166 8 94 166 8 94 166 8 94 166 8 94 166 8 94 166 8 94 166 ++8 94 166 8 94 166 8 94 166 107 172 224 178 210 243 176 212 247 176 212 247 176 212 247 ++176 212 247 176 212 247 164 205 243 18 102 171 8 94 166 8 94 166 8 94 166 28 113 174 ++92 162 218 163 199 237 173 211 246 176 212 247 176 212 247 176 212 247 176 212 247 176 212 247 ++176 212 247 176 212 247 176 212 247 176 212 247 176 212 247 176 212 247 143 192 235 85 139 195 ++18 102 171 8 94 166 8 94 166 8 94 166 40 129 186 176 212 247 176 212 247 176 212 247 ++176 212 247 176 212 247 176 212 247 176 212 247 62 142 198 9 93 164 8 94 166 8 94 166 ++8 94 166 8 94 166 8 94 166 8 94 166 8 94 166 8 94 166 8 94 166 8 94 166 ++8 94 166 8 94 166 8 94 166 8 94 166 8 94 166 8 94 166 8 94 166 1 24 42 ++ ++2 50 86 7 95 167 7 95 167 7 95 167 7 95 167 7 95 167 7 95 167 7 95 167 ++7 95 167 7 95 167 7 95 167 7 95 167 7 95 167 7 95 167 7 95 167 7 95 167 ++7 95 167 7 95 167 8 94 166 161 204 243 173 211 246 173 211 246 173 211 246 173 211 246 ++172 210 246 178 210 243 62 142 198 7 95 167 7 95 167 7 95 167 7 95 167 8 94 166 ++8 94 166 8 94 166 28 119 185 85 139 195 92 162 218 131 179 222 131 179 222 131 179 222 ++131 179 222 131 179 222 131 179 222 91 153 206 62 142 198 28 113 174 7 95 167 7 96 168 ++7 95 167 7 95 167 7 95 167 7 96 168 9 93 164 107 172 224 173 211 246 173 211 246 ++173 211 246 173 211 246 173 211 246 173 211 246 122 172 221 7 95 167 7 95 167 7 95 167 ++7 95 167 7 95 167 7 95 167 7 95 167 7 95 167 7 95 167 7 95 167 7 95 167 ++7 95 167 7 95 167 7 95 167 7 95 167 7 95 167 7 95 167 7 95 167 1 24 42 ++ ++2 50 86 7 95 167 7 96 168 7 96 168 7 96 168 7 96 168 7 96 168 7 96 168 ++7 96 168 7 96 168 7 96 168 7 96 168 7 96 168 7 96 168 7 96 168 7 96 168 ++7 96 168 7 96 168 60 128 188 170 209 245 170 209 245 170 209 245 170 209 245 170 209 245 ++170 209 245 145 196 239 8 94 166 7 96 168 7 96 168 7 96 168 7 96 168 7 96 168 ++7 96 168 7 96 168 7 96 168 6 97 169 7 96 168 7 96 168 6 97 169 7 96 168 ++6 97 169 7 96 168 6 97 169 7 96 168 7 96 168 7 96 168 7 96 168 7 96 168 ++7 96 168 7 96 168 7 96 168 7 96 168 7 96 168 28 113 174 170 209 245 170 209 245 ++170 209 245 170 209 245 170 209 245 170 209 245 170 209 245 18 102 171 7 96 168 7 96 168 ++7 96 168 7 96 168 7 96 168 7 96 168 7 96 168 7 96 168 7 96 168 7 96 168 ++7 96 168 7 96 168 7 96 168 7 96 168 7 96 168 7 96 168 7 96 168 1 24 42 ++ ++2 50 86 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 ++6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 ++6 97 169 7 96 168 92 162 218 167 207 244 167 207 244 167 207 244 167 207 244 167 207 244 ++167 207 244 91 153 206 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 ++6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 ++6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 ++6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 5 99 172 131 179 222 167 207 244 ++167 207 244 167 207 244 167 207 244 167 207 244 168 209 245 60 128 188 6 97 169 6 97 169 ++6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 ++6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 6 97 169 1 24 42 ++ ++2 50 86 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 ++5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 ++5 98 170 5 98 170 132 189 234 164 205 243 164 205 243 164 205 243 164 205 243 164 205 243 ++164 205 243 28 113 174 5 99 172 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 ++5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 ++5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 ++5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 62 142 198 164 205 243 ++164 205 243 164 205 243 164 205 243 164 205 243 164 205 243 92 162 218 5 98 170 5 98 170 ++5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 ++5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 5 98 170 1 24 42 ++ ++2 50 86 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 ++5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 ++5 99 172 5 99 172 161 204 243 161 204 243 161 204 243 161 204 243 161 204 243 161 204 243 ++139 191 235 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 ++5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 ++5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 ++5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 4 100 173 28 113 174 161 204 243 ++161 204 243 161 204 243 161 204 243 161 204 243 161 204 243 122 172 221 5 99 172 5 99 172 ++5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 ++5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 5 99 172 1 24 42 ++ ++2 50 86 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 ++4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 ++4 100 173 28 119 185 160 204 243 158 203 242 158 203 242 158 203 242 158 203 242 158 203 242 ++100 169 221 5 98 170 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 ++4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 ++4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 ++4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 3 101 174 139 191 235 ++158 203 242 158 203 242 158 203 242 158 203 242 158 203 242 148 198 240 4 100 173 4 100 173 ++4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 ++4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 4 100 173 1 24 42 ++ ++2 50 86 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 ++3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 ++3 101 174 40 129 186 154 201 241 154 201 241 154 201 241 154 201 241 154 201 241 154 201 241 ++77 152 208 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 ++3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 ++3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 ++3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 5 99 172 111 178 227 ++154 201 241 154 201 241 154 201 241 154 201 241 154 201 241 154 201 241 3 101 174 3 101 174 ++3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 ++3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 3 101 174 0 26 44 ++ ++2 50 86 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 ++3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 ++3 102 175 40 129 186 151 200 240 151 200 240 151 200 240 151 200 240 151 200 240 151 200 240 ++62 142 198 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 ++3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 ++3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 ++3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 107 172 224 ++151 200 240 151 200 240 151 200 240 151 200 240 151 200 240 151 200 240 3 102 175 3 102 175 ++3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 ++3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 3 102 175 0 26 44 ++ ++2 50 86 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 ++2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 ++1 104 177 40 129 186 148 198 240 148 198 240 148 198 240 148 198 240 148 198 240 148 198 240 ++40 129 186 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 ++2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 ++2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 ++2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 77 152 208 ++148 198 240 148 198 240 148 198 240 148 198 240 148 198 240 148 198 240 2 103 176 2 103 176 ++2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 ++2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 2 103 176 0 26 44 ++ ++2 50 86 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 ++1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 ++1 104 177 40 129 186 145 196 239 145 197 239 145 197 239 145 197 239 145 197 239 145 197 239 ++51 141 199 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 ++1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 ++1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 ++1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 100 169 221 ++145 196 239 145 197 239 145 197 239 145 197 239 145 197 239 145 197 239 1 104 177 1 104 177 ++1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 ++1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 1 104 177 0 26 44 ++ ++2 50 86 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 ++0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 ++1 106 180 27 129 189 145 196 239 140 193 237 140 193 237 140 193 237 140 193 237 140 193 237 ++77 152 208 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 ++0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 ++0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 ++0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 107 172 224 ++145 196 239 140 193 237 140 193 237 140 193 237 140 193 237 140 193 237 0 105 179 0 105 179 ++0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 ++0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 105 179 0 26 44 ++ ++4 57 93 0 105 179 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 ++1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 ++1 106 180 28 119 185 140 193 237 140 193 237 140 193 237 140 193 237 140 193 237 140 193 237 ++83 162 217 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 ++1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 ++1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 ++1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 122 182 230 ++140 193 237 140 193 237 140 193 237 140 193 237 140 193 237 132 189 234 1 106 180 1 106 180 ++1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 ++1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 1 106 180 0 26 44 ++ ++4 57 93 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 ++2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 ++2 108 181 2 108 181 137 192 236 137 192 236 137 192 236 137 192 236 137 192 236 137 192 236 ++111 178 227 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 ++2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 ++2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 ++2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 8 115 186 137 192 236 ++137 192 236 137 192 236 137 192 236 137 192 236 137 192 236 100 169 221 2 108 181 2 108 181 ++2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 ++2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 2 108 181 0 26 44 ++ ++4 57 93 2 108 181 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 ++4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 ++4 110 182 4 110 182 107 172 224 134 191 236 134 191 236 134 191 236 134 191 236 134 191 236 ++132 189 234 17 119 189 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 ++4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 ++4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 ++4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 51 141 199 134 191 236 ++134 191 236 134 191 236 134 191 236 134 191 236 134 191 236 77 152 208 4 110 182 4 110 182 ++4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 ++4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 4 110 182 0 26 44 ++ ++4 57 93 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 ++5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 ++5 112 184 5 112 184 83 162 217 130 189 234 130 189 234 130 189 234 130 189 234 130 189 234 ++127 187 234 65 151 210 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 ++5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 ++5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 ++5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 92 162 218 130 189 234 ++130 189 234 130 189 234 130 189 234 130 189 234 130 189 235 51 141 199 5 112 184 5 112 184 ++5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 ++5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 5 112 184 6 113 185 0 26 44 ++ ++4 57 93 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 ++6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 ++6 113 185 6 113 185 42 139 203 127 187 234 127 187 234 127 187 234 127 187 234 127 187 234 ++127 187 234 111 178 227 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 ++6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 ++6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 ++6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 19 124 193 127 187 234 127 187 234 ++127 187 234 127 187 234 127 187 234 127 187 234 127 187 234 17 119 189 6 113 185 6 113 185 ++6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 ++6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 6 113 185 3 30 48 ++ ++4 57 93 8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 ++8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 ++8 115 186 8 115 186 17 119 189 117 182 230 124 186 233 124 186 233 124 186 233 124 186 233 ++124 186 233 124 186 233 51 141 199 8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 ++8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 ++8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 ++8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 79 161 217 124 186 233 124 186 233 ++124 186 233 124 186 233 124 186 233 124 186 233 95 168 221 8 115 186 8 115 186 8 115 186 ++8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 ++8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 8 115 186 3 30 48 ++ ++4 57 93 9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 ++9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 ++9 117 188 9 117 188 9 117 188 79 161 217 121 184 232 121 184 232 121 184 232 121 184 232 ++121 184 232 121 184 232 106 176 228 17 119 189 9 117 188 9 117 188 9 117 188 9 117 188 ++9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 ++9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 ++9 117 188 9 117 188 9 117 188 9 117 188 27 133 194 122 182 230 121 184 232 121 184 232 ++121 184 232 121 184 232 121 184 232 121 184 232 51 141 199 9 117 188 9 117 188 9 117 188 ++9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 ++9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 9 117 188 3 30 48 ++ ++4 57 93 11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 ++11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 ++11 119 189 11 119 189 11 119 189 27 133 194 117 182 230 117 182 230 117 182 230 117 182 230 ++117 182 230 117 182 230 117 182 230 79 161 217 11 119 189 11 119 189 11 119 189 11 119 189 ++11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 ++11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 ++11 119 189 11 119 189 11 119 189 17 119 189 100 172 225 117 182 230 117 182 230 117 182 230 ++117 182 230 117 182 230 117 182 230 111 178 227 11 119 189 11 119 189 11 119 189 11 119 189 ++11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 ++11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 11 119 189 3 30 48 ++ ++4 57 93 13 122 191 12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 ++12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 ++12 121 190 12 121 190 12 121 190 13 122 191 88 166 221 115 181 230 115 181 230 115 181 230 ++115 181 230 115 181 230 115 181 230 115 181 230 51 141 199 13 122 191 12 121 190 12 121 190 ++12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 ++12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 ++12 121 190 12 121 190 12 121 190 79 161 217 115 181 230 115 181 230 115 181 230 115 181 230 ++115 181 230 115 181 230 115 181 230 65 151 210 12 121 190 12 121 190 12 121 190 12 121 190 ++12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 ++12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 12 121 190 3 30 48 ++ ++4 57 93 13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 ++13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 ++13 122 191 13 122 191 13 122 191 13 122 191 27 133 194 112 180 229 112 180 229 112 180 229 ++112 180 229 112 180 229 112 180 229 112 180 229 112 180 229 51 141 199 13 122 191 13 122 191 ++13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 ++13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 ++13 122 191 12 121 190 79 161 217 112 180 229 112 180 229 112 180 229 112 180 229 112 180 229 ++112 180 229 112 180 229 100 172 225 13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 ++13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 ++13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 13 122 191 3 30 48 ++ ++12 68 101 15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 ++15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 ++15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 65 151 210 109 178 229 109 178 229 ++109 178 229 109 178 229 109 178 229 109 178 229 109 178 229 109 178 229 65 151 210 15 124 193 ++15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 ++15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 ++17 128 195 79 161 217 109 178 229 109 178 229 109 178 229 109 178 229 109 178 229 109 178 229 ++109 178 229 109 178 229 42 139 203 15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 ++15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 ++15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 15 124 193 3 30 48 ++ ++4 57 93 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 ++16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 ++16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 89 168 223 106 176 228 ++106 176 228 106 176 228 106 176 228 106 176 228 106 176 228 106 176 228 106 176 228 81 164 221 ++27 133 194 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 ++16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 42 139 203 ++94 170 224 106 176 228 106 176 228 106 176 228 106 176 228 106 176 228 106 176 228 106 176 228 ++106 176 228 65 151 210 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 ++16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 ++16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 16 126 194 3 30 48 ++ ++12 68 101 17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 ++17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 ++17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 28 137 198 97 172 225 ++103 175 227 103 175 227 103 175 227 103 175 227 103 175 227 103 175 227 103 175 227 103 175 227 ++103 175 227 65 151 210 28 137 198 17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 ++17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 42 139 203 79 161 217 103 175 227 ++103 175 227 103 175 227 103 175 227 103 175 227 103 175 227 103 175 227 103 175 227 103 175 227 ++88 166 221 17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 ++17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 ++17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 17 128 195 3 30 48 ++ ++12 68 101 19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 ++19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 ++19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 31 139 202 ++95 170 224 100 173 226 100 173 226 100 173 226 100 173 226 100 173 226 100 173 226 100 173 226 ++100 173 226 100 173 226 100 173 226 81 164 221 65 151 210 42 139 203 42 139 203 19 130 197 ++22 132 197 42 139 203 42 139 203 65 151 210 89 168 223 100 173 226 100 173 226 100 173 226 ++100 173 226 100 173 226 100 173 226 100 173 226 100 173 226 100 173 226 100 173 226 84 165 222 ++22 132 197 19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 ++19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 ++19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 19 130 197 20 131 198 3 30 48 ++ ++12 68 101 19 130 197 20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 ++20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 ++20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 ++31 139 202 93 169 223 97 172 225 97 172 225 97 172 225 97 172 225 97 172 225 97 172 225 ++97 172 225 97 172 225 97 172 225 97 172 225 97 172 225 97 172 225 97 172 225 97 172 225 ++97 172 225 97 172 225 97 172 225 97 172 225 97 172 225 97 172 225 97 172 225 97 172 225 ++97 172 225 97 172 225 97 172 225 97 172 225 97 172 225 97 172 225 81 164 221 23 135 201 ++20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 ++20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 ++20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 20 131 198 3 30 48 ++ ++12 68 101 21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 ++21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 ++21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 ++23 135 201 31 139 202 89 168 223 94 170 224 94 170 224 94 170 224 94 170 224 94 170 224 ++94 170 224 94 170 224 94 170 224 94 170 224 94 170 224 94 170 224 94 170 224 94 170 224 ++94 170 224 94 170 224 94 170 224 94 170 224 94 170 224 94 170 224 94 170 224 94 170 224 ++94 170 224 94 170 224 94 170 224 94 170 224 94 170 224 81 164 221 24 137 202 21 133 199 ++21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 ++21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 ++21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 21 133 199 23 135 201 3 30 48 ++ ++12 68 101 23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 ++23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 ++23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 ++22 130 192 21 125 186 28 122 176 77 152 208 89 168 223 90 169 224 90 169 224 90 169 224 ++90 169 224 90 169 224 90 169 224 90 169 224 90 169 224 90 169 224 90 169 224 90 169 224 ++90 169 224 90 169 224 90 169 224 90 169 224 90 169 224 90 169 224 90 169 224 90 169 224 ++90 169 224 90 169 224 90 169 224 90 169 224 62 142 198 17 118 175 21 125 186 22 132 197 ++23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 ++23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 ++23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 23 135 201 3 30 48 ++ ++12 68 101 24 137 202 24 137 202 24 137 202 24 137 202 24 137 202 24 137 202 24 137 202 ++24 137 202 24 137 202 24 137 202 24 137 202 24 137 202 24 137 202 24 137 202 24 137 202 ++24 137 202 24 137 202 24 137 202 24 137 202 24 137 202 22 130 192 17 118 175 21 111 162 ++21 111 162 21 111 162 21 111 162 21 111 162 40 129 186 83 162 217 87 167 223 87 167 223 ++87 167 223 87 167 223 87 167 223 87 167 223 87 167 223 87 167 223 87 167 223 87 167 223 ++87 167 223 87 167 223 87 167 223 87 167 223 87 167 223 87 167 223 87 167 223 87 167 223 ++87 167 223 87 167 223 77 152 208 28 122 176 21 111 162 21 111 162 21 111 162 21 111 162 ++22 114 165 17 118 175 22 132 197 24 137 202 24 137 202 24 137 202 24 137 202 24 137 202 ++24 137 202 24 137 202 24 137 202 24 137 202 24 137 202 24 137 202 24 137 202 24 137 202 ++24 137 202 24 137 202 24 137 202 24 137 202 24 137 202 24 137 202 26 139 203 3 30 48 ++ ++12 68 101 26 139 203 26 139 203 26 139 203 26 139 203 26 139 203 26 139 203 26 139 203 ++26 139 203 26 139 203 26 139 203 26 139 203 26 139 203 26 139 203 26 139 203 26 139 203 ++26 139 203 26 139 203 26 139 203 26 139 203 28 122 176 21 111 162 21 111 162 21 111 162 ++21 111 162 21 111 162 21 111 162 21 111 162 21 111 162 24 115 166 51 141 199 79 161 217 ++84 166 222 84 166 222 84 166 222 84 166 222 84 166 222 84 166 222 84 166 222 84 166 222 ++84 166 222 84 166 222 84 166 222 84 166 222 84 166 222 84 166 222 84 166 222 84 166 222 ++79 161 217 40 129 186 22 112 163 21 111 162 21 111 162 21 111 162 21 111 162 21 111 162 ++21 111 162 22 112 163 21 111 162 22 130 192 26 139 203 26 139 203 26 139 203 26 139 203 ++26 139 203 26 139 203 26 139 203 26 139 203 26 139 203 26 139 203 26 139 203 26 139 203 ++26 139 203 26 139 203 26 139 203 26 139 203 26 139 203 26 139 203 26 139 203 3 30 48 ++ ++9 48 78 27 140 204 27 140 204 27 140 204 27 140 204 27 140 204 27 140 204 27 140 204 ++27 140 204 27 140 204 27 140 204 27 140 204 27 140 204 27 140 204 27 140 204 27 140 204 ++27 140 204 27 140 204 27 140 204 27 140 204 17 118 175 22 112 163 22 112 163 22 112 163 ++22 112 163 22 112 163 22 112 163 22 112 163 22 112 163 22 112 163 22 112 163 21 111 162 ++40 129 186 62 142 198 79 161 217 81 164 221 81 164 221 81 164 221 81 164 221 81 164 221 ++81 164 221 81 164 221 81 164 221 81 164 221 81 164 221 79 161 217 62 142 198 28 122 176 ++22 112 163 22 112 163 22 112 163 22 112 163 22 112 163 22 112 163 22 112 163 22 112 163 ++22 112 163 22 112 163 22 112 163 21 125 186 27 140 204 27 140 204 27 140 204 27 140 204 ++27 140 204 27 140 204 27 140 204 27 140 204 27 140 204 27 140 204 27 140 204 27 140 204 ++27 140 204 27 140 204 27 140 204 27 140 204 27 140 204 27 140 204 27 140 204 4 18 26 ++ ++4 18 26 28 142 206 28 142 206 28 142 206 28 142 206 28 142 206 28 142 206 28 142 206 ++28 142 206 28 142 206 28 142 206 28 142 206 28 142 206 28 142 206 28 142 206 28 142 206 ++28 142 206 28 142 206 28 142 206 28 142 206 28 137 198 28 122 176 22 114 165 22 114 165 ++22 114 165 22 114 165 22 114 165 22 114 165 22 114 165 22 114 165 22 114 165 22 114 165 ++22 114 165 22 114 165 22 114 165 28 122 176 40 129 186 51 141 199 51 141 199 51 141 199 ++51 141 199 51 141 199 51 141 199 28 122 176 28 122 176 22 112 163 22 114 165 22 114 165 ++22 114 165 22 114 165 22 114 165 22 114 165 22 114 165 22 114 165 22 114 165 22 114 165 ++22 114 165 22 114 165 28 122 176 27 140 204 28 142 206 28 142 206 28 142 206 28 142 206 ++28 142 206 28 142 206 28 142 206 28 142 206 28 142 206 28 142 206 28 142 206 28 142 206 ++28 142 206 28 142 206 28 142 206 28 142 206 28 142 206 28 142 206 28 122 176 0 0 0 ++ ++0 0 0 19 91 130 30 144 207 30 144 207 30 144 207 30 144 207 30 144 207 30 144 207 ++30 144 207 30 144 207 30 144 207 30 144 207 30 144 207 30 144 207 30 144 207 30 144 207 ++30 144 207 30 144 207 30 144 207 30 144 207 30 144 207 30 144 207 28 140 203 27 129 189 ++28 122 176 25 117 166 24 115 166 24 115 166 24 115 166 24 115 166 24 115 166 24 115 166 ++24 115 166 24 115 166 24 115 166 24 115 166 24 115 166 22 112 163 24 115 166 22 112 163 ++24 115 166 22 112 163 24 115 166 25 117 166 24 115 166 24 115 166 24 115 166 24 115 166 ++24 115 166 24 115 166 24 115 166 24 115 166 24 115 166 22 114 165 28 122 176 28 122 176 ++27 133 194 29 142 204 30 144 207 30 144 207 30 144 207 30 144 207 30 144 207 30 144 207 ++30 144 207 30 144 207 30 144 207 30 144 207 30 144 207 30 144 207 30 144 207 30 144 207 ++30 144 207 30 144 207 30 144 207 30 144 207 30 144 207 31 146 208 9 48 78 0 0 0 ++ ++0 0 0 4 18 26 28 137 198 31 146 208 31 146 208 31 146 208 31 146 208 31 146 208 ++31 146 208 31 146 208 31 146 208 31 146 208 31 146 208 31 146 208 31 146 208 31 146 208 ++31 146 208 31 146 208 31 146 208 31 146 208 31 146 208 31 146 208 31 146 208 31 146 208 ++31 146 208 32 148 210 30 144 206 28 137 198 27 133 194 27 129 189 27 129 189 28 122 176 ++28 122 176 28 122 176 25 117 166 25 117 166 25 117 166 25 117 166 25 117 166 25 117 166 ++25 117 166 25 117 166 25 117 166 25 117 166 25 117 166 25 117 166 28 122 176 28 122 176 ++28 122 176 27 129 189 27 129 189 28 137 198 28 137 198 31 146 208 31 146 208 31 146 208 ++31 146 208 31 146 208 31 146 208 31 146 208 31 146 208 31 146 208 31 146 208 31 146 208 ++31 146 208 31 146 208 31 146 208 31 146 208 31 146 208 31 146 208 31 146 208 31 146 208 ++31 146 208 31 146 208 31 146 208 31 146 208 31 146 208 25 117 166 0 0 0 0 0 0 ++ ++0 0 0 0 0 0 8 23 42 28 137 198 32 148 210 32 148 210 32 148 210 32 148 210 ++32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 ++32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 ++32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 ++32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 ++32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 ++32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 ++32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 ++32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 32 148 210 ++32 148 210 32 148 210 32 148 210 32 148 210 25 117 166 3 11 16 0 0 0 0 0 0 ++ ++0 0 0 0 0 0 0 0 0 4 18 26 19 91 130 34 149 211 34 149 211 34 149 211 ++34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 ++34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 ++34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 ++34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 ++34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 ++34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 ++34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 ++34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 34 149 211 ++34 149 211 34 149 211 31 139 202 18 76 106 3 11 16 0 0 0 0 0 0 0 0 0 ++ ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 18 26 9 48 78 18 76 106 ++18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 ++18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 ++18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 ++18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 ++18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 ++18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 ++18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 ++18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 18 76 106 ++18 76 106 11 38 58 3 11 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ +diff -Nurp linux-2.6.37.3/drivers/video/logo/Makefile linux-2.6.37.3.mga/drivers/video/logo/Makefile +--- linux-2.6.37.3/drivers/video/logo/Makefile 2011-01-05 02:50:19.000000000 +0200 ++++ linux-2.6.37.3.mga/drivers/video/logo/Makefile 2011-03-08 21:51:35.728113700 +0200 +@@ -15,6 +15,7 @@ obj-$(CONFIG_LOGO_SUPERH_MONO) += logo_ + obj-$(CONFIG_LOGO_SUPERH_VGA16) += logo_superh_vga16.o + obj-$(CONFIG_LOGO_SUPERH_CLUT224) += logo_superh_clut224.o + obj-$(CONFIG_LOGO_M32R_CLUT224) += logo_m32r_clut224.o ++obj-$(CONFIG_LOGO_MAGEIA_CLUT224) += logo_mageia_clut224.o + + obj-$(CONFIG_SPU_BASE) += logo_spe_clut224.o + +diff -Nurp linux-2.6.37.3/include/linux/linux_logo.h linux-2.6.37.3.mga/include/linux/linux_logo.h +--- linux-2.6.37.3/include/linux/linux_logo.h 2011-01-05 02:50:19.000000000 +0200 ++++ linux-2.6.37.3.mga/include/linux/linux_logo.h 2011-03-08 21:51:20.263024073 +0200 +@@ -47,6 +47,7 @@ extern const struct linux_logo logo_supe + extern const struct linux_logo logo_superh_clut224; + extern const struct linux_logo logo_m32r_clut224; + extern const struct linux_logo logo_spe_clut224; ++extern const struct linux_logo logo_mageia_clut224; + + extern const struct linux_logo *fb_find_logo(int depth); + #ifdef CONFIG_FB_LOGO_EXTRA diff --git a/kernel/tools/perf/files/patches/mageia/x86-boot-video-80x25-if-break.patch b/kernel/tools/perf/files/patches/mageia/x86-boot-video-80x25-if-break.patch new file mode 100644 index 0000000000..e7e92f47db --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/x86-boot-video-80x25-if-break.patch @@ -0,0 +1,24 @@ +Automatically switches textmode if the user selects a wrong one. + +Original author of the idea/first patch is unknown. + +Signed-off-by: Herton Ronaldo Krzesinski +Signed-off-by: Luiz Fernando N. Capitulino + +-- + arch/x86/boot/video.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/x86/boot/video.c ++++ b/arch/x86/boot/video.c +@@ -325,8 +325,8 @@ void set_video(void) + if (!set_mode(mode)) + break; + +- printf("Undefined video mode number: %x\n", mode); +- mode = ASK_VGA; ++ printf("Undefined video mode number: %x, jump to 80x25\n", mode); ++ mode = VIDEO_80x25; + } + boot_params.hdr.vid_mode = mode; + vesa_store_edid(); diff --git a/kernel/tools/perf/files/patches/mageia/x86-default_poweroff_up_machines.patch b/kernel/tools/perf/files/patches/mageia/x86-default_poweroff_up_machines.patch new file mode 100644 index 0000000000..28ce1a0d42 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/x86-default_poweroff_up_machines.patch @@ -0,0 +1,58 @@ +From: Olaf Dabrunz +Subject: [apm] default to "power_off" when SMP kernel is used on single processo +r machines +Reference: SUSE221667 + +This patch turns on support for the APM power_off function by default when the +SMP kernel is used on single processor machines. + +It is a bit ugly to use a separate variable to make sure the default value is +only used when needed and the power_off variable is not initialized twice. But +I did not find a better way to do this with the way the current initialization +system works. + +Signed-off-by: Olaf Dabrunz + + + arch/x86/kernel/apm_32.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +--- a/arch/x86/kernel/apm_32.c ++++ b/arch/x86/kernel/apm_32.c +@@ -388,6 +388,7 @@ static bool smp __read_mostly; + static int apm_disabled = -1; + #ifdef CONFIG_SMP + static bool power_off; ++static int power_off_set; + #else + static bool power_off = 1; + #endif +@@ -1843,6 +1844,14 @@ static int apm(void *unused) + } + } + ++#ifdef CONFIG_SMP ++ if (!power_off_set) { ++ power_off = (num_online_cpus() == 1); ++ /* remember not to initialize (with default value) again */ ++ power_off_set = 1; ++ } ++#endif ++ + /* Install our power off handler.. */ + if (power_off) + pm_power_off = apm_power_off; +@@ -1886,8 +1895,12 @@ static int __init apm_setup(char *str) + if (strncmp(str, "debug", 5) == 0) + debug = !invert; + if ((strncmp(str, "power-off", 9) == 0) || +- (strncmp(str, "power_off", 9) == 0)) ++ (strncmp(str, "power_off", 9) == 0)) { + power_off = !invert; ++#ifdef CONFIG_SMP ++ power_off_set = 1; ++#endif ++ } + if (strncmp(str, "smp", 3) == 0) { + smp = !invert; + idle_threshold = 100; diff --git a/kernel/tools/perf/files/patches/mageia/x86-increase-default-minimum-vmalloc-area-by-64MB-to-192MB.patch b/kernel/tools/perf/files/patches/mageia/x86-increase-default-minimum-vmalloc-area-by-64MB-to-192MB.patch new file mode 100644 index 0000000000..05d57ee230 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/x86-increase-default-minimum-vmalloc-area-by-64MB-to-192MB.patch @@ -0,0 +1,28 @@ +From 2db91ae7c0862bc83c1fe8b8bd14b8de3e2c02b8 Mon Sep 17 00:00:00 2001 +From: Anssi Hannula +Date: Sat, 30 Apr 2011 17:09:04 +0300 +Subject: [PATCH] x86: increase default minimum vmalloc area by 64MB to 192MB + +This fixes issues like https://bugs.mageia.org/show_bug.cgi?id=904. + +Signed-off-by: Anssi Hannula +--- + arch/x86/mm/pgtable_32.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/arch/x86/mm/pgtable_32.c b/arch/x86/mm/pgtable_32.c +index cac7184..5801fb7 100644 +--- a/arch/x86/mm/pgtable_32.c ++++ b/arch/x86/mm/pgtable_32.c +@@ -19,7 +19,7 @@ + #include + #include + +-unsigned int __VMALLOC_RESERVE = 128 << 20; ++unsigned int __VMALLOC_RESERVE = 192 << 20; + + /* + * Associate a virtual page frame with a given physical page frame +-- +1.7.3 + diff --git a/kernel/tools/perf/files/patches/mageia/x86-pci-toshiba-equium-a60-assign-busses.patch b/kernel/tools/perf/files/patches/mageia/x86-pci-toshiba-equium-a60-assign-busses.patch new file mode 100644 index 0000000000..f9b4b1c74c --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/x86-pci-toshiba-equium-a60-assign-busses.patch @@ -0,0 +1,29 @@ + +The Toshiba Equium A6 Laptop needs pci-assign-busses in order to detect +the Wireless card Netgear MA521 + +More info here: http://qa.mandriva.com/show_bug.cgi?id=18989 + +Signed-off-by: Thomas Backlund + +--- + arch/x86/pci/common.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/arch/x86/pci/common.c ++++ b/arch/x86/pci/common.c +@@ -245,6 +245,14 @@ static const struct dmi_system_id __devi + DMI_MATCH(DMI_PRODUCT_NAME, "SX20S"), + }, + }, ++ { ++ .callback = assign_all_busses, ++ .ident = "Toshiba Equium A6 Laptop", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Equium A60"), ++ }, ++ }, + #endif /* __i386__ */ + { + .callback = set_bf_sort, diff --git a/kernel/tools/perf/files/patches/mageia/x86-power-64-Fix-hibernation-return-address-corrupti.patch b/kernel/tools/perf/files/patches/mageia/x86-power-64-Fix-hibernation-return-address-corrupti.patch new file mode 100644 index 0000000000..640b76a3df --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/x86-power-64-Fix-hibernation-return-address-corrupti.patch @@ -0,0 +1,101 @@ +From 4ce827b4cc58bec7952591b96cce2b28553e4d5b Mon Sep 17 00:00:00 2001 +From: Josh Poimboeuf +Date: Thu, 28 Jul 2016 23:15:21 +0200 +Subject: [PATCH] x86/power/64: Fix hibernation return address corruption + +In kernel bug 150021, a kernel panic was reported when restoring a +hibernate image. Only a picture of the oops was reported, so I can't +paste the whole thing here. But here are the most interesting parts: + + kernel tried to execute NX-protected page - exploit attempt? (uid: 0) + BUG: unable to handle kernel paging request at ffff8804615cfd78 + ... + RIP: ffff8804615cfd78 + RSP: ffff8804615f0000 + RBP: ffff8804615cfdc0 + ... + Call Trace: + do_signal+0x23 + exit_to_usermode_loop+0x64 + ... + +The RIP is on the same page as RBP, so it apparently started executing +on the stack. + +The bug was bisected to commit ef0f3ed5a4ac (x86/asm/power: Create +stack frames in hibernate_asm_64.S), which in retrospect seems quite +dangerous, since that code saves and restores the stack pointer from a +global variable ('saved_context'). + +There are a lot of moving parts in the hibernate save and restore paths, +so I don't know exactly what caused the panic. Presumably, a FRAME_END +was executed without the corresponding FRAME_BEGIN, or vice versa. That +would corrupt the return address on the stack and would be consistent +with the details of the above panic. + +[ rjw: One major problem is that by the time the FRAME_BEGIN in + restore_registers() is executed, the stack pointer value may not + be valid any more. Namely, the stack area pointed to by it + previously may have been overwritten by some image memory contents + and that page frame may now be used for whatever different purpose + it had been allocated for before hibernation. In that case, the + FRAME_BEGIN will corrupt that memory. ] + +Instead of doing the frame pointer save/restore around the bounds of the +affected functions, just do it around the call to swsusp_save(). + +That has the same effect of ensuring that if swsusp_save() sleeps, the +frame pointers will be correct. It's also a much more obviously safe +way to do it than the original patch. And objtool still doesn't report +any warnings. + +Fixes: ef0f3ed5a4ac (x86/asm/power: Create stack frames in hibernate_asm_64.S) +Link: https://bugzilla.kernel.org/show_bug.cgi?id=150021 +Cc: 4.6+ # 4.6+ +Reported-by: Andre Reinke +Tested-by: Andre Reinke +Signed-off-by: Josh Poimboeuf +Acked-by: Ingo Molnar +Signed-off-by: Rafael J. Wysocki +--- + arch/x86/power/hibernate_asm_64.S | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/arch/x86/power/hibernate_asm_64.S b/arch/x86/power/hibernate_asm_64.S +index 3177c2b..8eee0e9 100644 +--- a/arch/x86/power/hibernate_asm_64.S ++++ b/arch/x86/power/hibernate_asm_64.S +@@ -24,7 +24,6 @@ + #include + + ENTRY(swsusp_arch_suspend) +- FRAME_BEGIN + movq $saved_context, %rax + movq %rsp, pt_regs_sp(%rax) + movq %rbp, pt_regs_bp(%rax) +@@ -48,6 +47,7 @@ ENTRY(swsusp_arch_suspend) + movq %cr3, %rax + movq %rax, restore_cr3(%rip) + ++ FRAME_BEGIN + call swsusp_save + FRAME_END + ret +@@ -104,7 +104,6 @@ ENTRY(core_restore_code) + /* code below belongs to the image kernel */ + .align PAGE_SIZE + ENTRY(restore_registers) +- FRAME_BEGIN + /* go back to the original page tables */ + movq %r9, %cr3 + +@@ -145,6 +144,5 @@ ENTRY(restore_registers) + /* tell the hibernation core that we've just restored the memory */ + movq %rax, in_suspend(%rip) + +- FRAME_END + ret + ENDPROC(restore_registers) +-- +2.9.2 + diff --git a/kernel/tools/perf/pspec.xml b/kernel/tools/perf/pspec.xml index df49e366d6..6cf2a47595 100644 --- a/kernel/tools/perf/pspec.xml +++ b/kernel/tools/perf/pspec.xml @@ -12,7 +12,7 @@ app:gui Performance analyser tool that makes full use of the Linux performance counter subsystem perf is a new tool which is used to optimize, validate and measure applications, workloads or the full system through the Linux performance counter subsystem. - https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.6.tar.gz + https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.7.tar.gz libunwind-devel audit-devel @@ -36,7 +36,130 @@ - patches/linux/patch-4.6.3.xz + + + + + patches/mageia/Revert-ipmi-Start-the-timer-and-thread-on-internal-m.patch + patches/mageia/x86-pci-toshiba-equium-a60-assign-busses.patch + patches/mageia/x86-boot-video-80x25-if-break.patch + patches/mageia/x86-default_poweroff_up_machines.patch + patches/mageia/x86-increase-default-minimum-vmalloc-area-by-64MB-to-192MB.patch + patches/mageia/Revert-cpufreq-pcc-Enable-autoload-of-pcc-cpufreq-fo.patch + patches/mageia/Revert-cpufreq-pcc-cpufreq-update-default-value-of-c.patch + patches/mageia/Revert-x86-mm-mtrr-Remove-kernel-internal-MTRR-inter.patch + patches/mageia/x86-power-64-Fix-hibernation-return-address-corrupti.patch + patches/mageia/base-cacheinfo-silence-DT-warnings.patch + patches/mageia/pci-add-ALI-M5229-ide-compatibility-mode-quirk.patch + patches/mageia/pci-quirks-drop-devinit-exit.patch + patches/mageia/acpi-CLEVO-M360S-disable_acpi_irq.patch + patches/mageia/acpi-processor-M720SR-limit-to-C2.patch + patches/mageia/ACPI-video-Add-a-quirk-to-force-acpi-video-backlight.patch + + patches/mageia/scsi-megaraid-new-sysfs-name.patch + patches/mageia/ide-pci-sis5513-965.patch + patches/mageia/mpt-vmware-fix.patch + patches/mageia/dm-raid-aliases.patch + patches/mageia/block-floppy-disable-pnp-modalias.patch + patches/mageia/ata-prefer-ata-drivers-over-ide-drivers-when-both-are-built.patch + patches/mageia/block-Make-CFQ-default-to-IOPS-mode-on-SSDs.patch + patches/mageia/fs-aufs-4.7.patch + patches/mageia/fs-aufs-4.7-modular.patch + patches/mageia/fs-aufs-4.7-ver-fix.patch + patches/mageia/fs-ext4-don-t-call-ext4_should_journal_data-on-the-jour.patch + patches/mageia/fs-ext4-fix-deadlock-during-page-writeback.patch + patches/mageia/firewire-ieee1394-module-aliases.patch + patches/mageia/char-agp-intel-new-Q57-id.patch + + + patches/mageia/input-i8042-quirks-for-Fujitsu-Lifebook-A544-and-Lif.patch + patches/mageia/net-sis190-fix-list-usage.patch + patches/mageia/net-netfilter-IFWLOG.patch + patches/mageia/net-netfilter-IFWLOG-mdv.patch + patches/mageia/net-netfilter-IFWLOG-2.6.35-buildfix.patch + patches/mageia/net-netfilter-IFWLOG-2.6.37-buildfix.patch + patches/mageia/net-ipv4-netfilter-ipt_IFWLOG-3.6-buildfix.patch + patches/mageia/net-netfilter-IFWLOG-3.7-buildfix.patch + patches/mageia/net-netfilter-IFWLOG-remove-unused-label.patch + patches/mageia/net-netfilter-psd.patch + patches/mageia/net-netfilter-psd-mdv.patch + patches/mageia/net-netfilter-psd-2.6.35-buildfix.patch + patches/mageia/net-wireless-iwlwifi-add-new-8260-PCI-IDs.patch + patches/mageia/net-wireless-iwlwifi-add-new-8265.patch + patches/mageia/net-wireless-iwlwifi-pcie-enable-interrupts-before-releasing-the-NICs-CPU.patch + patches/mageia/net-wireless-iwlwifi-pcie-fix-a-race-in-firmware-loading-flow.patch + patches/mageia/net-bcma-add-PCI-ID-for-Foxconn-s-BCM43142-device.patch + patches/mageia/net-brcmfmac-restore-stopping-netdev-queue-when-bus-clog.patch + patches/mageia/platform-x86-add-shuttle-wmi-driver.patch + patches/mageia/platform-x86-shuttle-wmi-drop-devinit-exit.patch + patches/mageia/platform-x86-shuttle-wmi-4.2-buildfix.patch + patches/mageia/hp-wmi-Fix-wifi-cannot-be-hard-unblocked.patch + patches/mageia/Bluetooth-Add-support-of-13d3-3490-AR3012-device.patch + patches/mageia/intel_th-Fix-a-deadlock-in-modprobing.patch + patches/mageia/intel_th-pci-Add-Kaby-Lake-PCH-H-support.patch + patches/mageia/pinctrl-cherryview-prevent-concurrent-access-to-GPIO.patch + patches/mageia/include-kbuild-export-pci_ids.patch + patches/mageia/hid-usbhid-IBM-BladeCenterHS20-quirk.patch + patches/mageia/usb-storage-unusual_devs-add-id.patch + patches/mageia/usb-storage-unusual_devs-add-id-2.6.37-buildfix.patch + patches/mageia/usb-dwc3-fix-for-the-isoc-transfer-EP_BUSY-flag.patch + patches/mageia/usb-renesas_usbhs-fix-NULL-pointer-dereference-in-xf.patch + patches/mageia/HID-uhid-fix-timeout-when-probe-races-with-IO.patch + patches/mageia/media-usb-pwc-lie-in-proc-usb-devices.patch + patches/mageia/media-media-usbtv-prevent-access-to-free-d-resources.patch + patches/mageia/media-vb2-core-Skip-planes-array-verification-if-pb-.patch + patches/mageia/media-videobuf2-v4l2-Verify-planes-array-in-buffer-d.patch + patches/mageia/3rd-3rdparty-1.0-tree.patch + patches/mageia/3rd-3rdparty-merge.patch + patches/mageia/3rd-acerhk-0.5.35.patch + patches/mageia/3rd-acerhk-kbuild.patch + patches/mageia/3rd-acerhk-extra-cflags.patch + patches/mageia/3rd-acerhk-proc_dir_entry-owner.patch + patches/mageia/3rd-acerhk-fix-build-with-function-tracer.patch + patches/mageia/3rd-acerhk-2.6.36-buildfix.patch + patches/mageia/3rd-acerhk-fix-include.patch + + + patches/mageia/3rd-ndiswrapper-1.60.patch + patches/mageia/3rd-ndiswrapper-Kconfig.patch + patches/mageia/3rd-ndiswrapper-Makefile-build-fix.patch + patches/mageia/3rd-ndiswrapper-4.7-buildfix.patch + patches/mageia/3rd-rfswitch-1.3.patch + patches/mageia/3rd-rfswitch-build-fix.patch + patches/mageia/3rd-rfswitch-3.0-buildfix.patch + patches/mageia/3rd-viahss-0.92.patch + patches/mageia/3rd-viahss-config.patch + patches/mageia/3rd-viahss-module-license.patch + patches/mageia/3rd-viahss-2.6.35-buildfix.patch + patches/mageia/3rd-viahss-3.0-buildfix.patch + patches/mageia/3rd-rtl8723bs.patch + patches/mageia/3rd-rtl8723bs-4.7-buildfix.patch + patches/mageia/ahci-add-new-Intel-device-IDs.patch + patches/mageia/megaraid_sas-Do-not-fire-MR_DCMD_PD_LIST_QUERY-to-co.patch + patches/mageia/arm-0001-ARM-bcm2835-dt-Add-the-ethernet-to-the-device-trees.patch @@ -68,6 +191,13 @@ + + 2016-07-13 + 4.7.0 + Version bump + Ertuğrul Erata + ertugrulerata@gmail.com + 2016-07-13 4.6.3